File : a-ciorse.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                         GNAT LIBRARY COMPONENTS                          --
   4 --                                                                          --
   5 --                 ADA.CONTAINERS.INDEFINITE_ORDERED_SETS                   --
   6 --                                                                          --
   7 --                                 B o d y                                  --
   8 --                                                                          --
   9 --          Copyright (C) 2004-2015, Free Software Foundation, Inc.         --
  10 --                                                                          --
  11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  12 -- terms of the  GNU General Public License as published  by the Free Soft- --
  13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
  14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  16 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
  17 --                                                                          --
  18 --                                                                          --
  19 --                                                                          --
  20 --                                                                          --
  21 --                                                                          --
  22 -- You should have received a copy of the GNU General Public License and    --
  23 -- a copy of the GCC Runtime Library Exception along with this program;     --
  24 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
  25 -- <http://www.gnu.org/licenses/>.                                          --
  26 --                                                                          --
  27 -- This unit was originally developed by Matthew J Heaney.                  --
  28 ------------------------------------------------------------------------------
  29 
  30 with Ada.Containers.Helpers; use Ada.Containers.Helpers;
  31 
  32 with Ada.Containers.Red_Black_Trees.Generic_Operations;
  33 pragma Elaborate_All (Ada.Containers.Red_Black_Trees.Generic_Operations);
  34 
  35 with Ada.Containers.Red_Black_Trees.Generic_Keys;
  36 pragma Elaborate_All (Ada.Containers.Red_Black_Trees.Generic_Keys);
  37 
  38 with Ada.Containers.Red_Black_Trees.Generic_Set_Operations;
  39 pragma Elaborate_All (Ada.Containers.Red_Black_Trees.Generic_Set_Operations);
  40 
  41 with Ada.Unchecked_Deallocation;
  42 
  43 with System; use type System.Address;
  44 
  45 package body Ada.Containers.Indefinite_Ordered_Sets is
  46 
  47    pragma Warnings (Off, "variable ""Busy*"" is not referenced");
  48    pragma Warnings (Off, "variable ""Lock*"" is not referenced");
  49    --  See comment in Ada.Containers.Helpers
  50 
  51    -----------------------
  52    -- Local Subprograms --
  53    -----------------------
  54 
  55    function Color (Node : Node_Access) return Color_Type;
  56    pragma Inline (Color);
  57 
  58    function Copy_Node (Source : Node_Access) return Node_Access;
  59    pragma Inline (Copy_Node);
  60 
  61    procedure Free (X : in out Node_Access);
  62 
  63    procedure Insert_Sans_Hint
  64      (Tree     : in out Tree_Type;
  65       New_Item : Element_Type;
  66       Node     : out Node_Access;
  67       Inserted : out Boolean);
  68 
  69    procedure Insert_With_Hint
  70      (Dst_Tree : in out Tree_Type;
  71       Dst_Hint : Node_Access;
  72       Src_Node : Node_Access;
  73       Dst_Node : out Node_Access);
  74 
  75    function Is_Greater_Element_Node
  76      (Left  : Element_Type;
  77       Right : Node_Access) return Boolean;
  78    pragma Inline (Is_Greater_Element_Node);
  79 
  80    function Is_Less_Element_Node
  81      (Left  : Element_Type;
  82       Right : Node_Access) return Boolean;
  83    pragma Inline (Is_Less_Element_Node);
  84 
  85    function Is_Less_Node_Node (L, R : Node_Access) return Boolean;
  86    pragma Inline (Is_Less_Node_Node);
  87 
  88    function Left (Node : Node_Access) return Node_Access;
  89    pragma Inline (Left);
  90 
  91    function Parent (Node : Node_Access) return Node_Access;
  92    pragma Inline (Parent);
  93 
  94    procedure Replace_Element
  95      (Tree : in out Tree_Type;
  96       Node : Node_Access;
  97       Item : Element_Type);
  98 
  99    function Right (Node : Node_Access) return Node_Access;
 100    pragma Inline (Right);
 101 
 102    procedure Set_Color (Node : Node_Access; Color : Color_Type);
 103    pragma Inline (Set_Color);
 104 
 105    procedure Set_Left (Node : Node_Access; Left : Node_Access);
 106    pragma Inline (Set_Left);
 107 
 108    procedure Set_Parent (Node   : Node_Access; Parent : Node_Access);
 109    pragma Inline (Set_Parent);
 110 
 111    procedure Set_Right (Node : Node_Access; Right : Node_Access);
 112    pragma Inline (Set_Right);
 113 
 114    --------------------------
 115    -- Local Instantiations --
 116    --------------------------
 117 
 118    procedure Free_Element is
 119      new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
 120 
 121    package Tree_Operations is
 122      new Red_Black_Trees.Generic_Operations (Tree_Types);
 123 
 124    procedure Delete_Tree is
 125      new Tree_Operations.Generic_Delete_Tree (Free);
 126 
 127    function Copy_Tree is
 128      new Tree_Operations.Generic_Copy_Tree (Copy_Node, Delete_Tree);
 129 
 130    use Tree_Operations;
 131 
 132    package Element_Keys is
 133      new Red_Black_Trees.Generic_Keys
 134        (Tree_Operations     => Tree_Operations,
 135         Key_Type            => Element_Type,
 136         Is_Less_Key_Node    => Is_Less_Element_Node,
 137         Is_Greater_Key_Node => Is_Greater_Element_Node);
 138 
 139    package Set_Ops is
 140       new Generic_Set_Operations
 141         (Tree_Operations  => Tree_Operations,
 142          Insert_With_Hint => Insert_With_Hint,
 143          Copy_Tree        => Copy_Tree,
 144          Delete_Tree      => Delete_Tree,
 145          Is_Less          => Is_Less_Node_Node,
 146          Free             => Free);
 147 
 148    ---------
 149    -- "<" --
 150    ---------
 151 
 152    function "<" (Left, Right : Cursor) return Boolean is
 153    begin
 154       if Checks and then Left.Node = null then
 155          raise Constraint_Error with "Left cursor equals No_Element";
 156       end if;
 157 
 158       if Checks and then Right.Node = null then
 159          raise Constraint_Error with "Right cursor equals No_Element";
 160       end if;
 161 
 162       if Checks and then Left.Node.Element = null then
 163          raise Program_Error with "Left cursor is bad";
 164       end if;
 165 
 166       if Checks and then Right.Node.Element = null then
 167          raise Program_Error with "Right cursor is bad";
 168       end if;
 169 
 170       pragma Assert (Vet (Left.Container.Tree, Left.Node),
 171                      "bad Left cursor in ""<""");
 172 
 173       pragma Assert (Vet (Right.Container.Tree, Right.Node),
 174                      "bad Right cursor in ""<""");
 175 
 176       return Left.Node.Element.all < Right.Node.Element.all;
 177    end "<";
 178 
 179    function "<" (Left : Cursor; Right : Element_Type) return Boolean is
 180    begin
 181       if Checks and then Left.Node = null then
 182          raise Constraint_Error with "Left cursor equals No_Element";
 183       end if;
 184 
 185       if Checks and then Left.Node.Element = null then
 186          raise Program_Error with "Left cursor is bad";
 187       end if;
 188 
 189       pragma Assert (Vet (Left.Container.Tree, Left.Node),
 190                      "bad Left cursor in ""<""");
 191 
 192       return Left.Node.Element.all < Right;
 193    end "<";
 194 
 195    function "<" (Left : Element_Type; Right : Cursor) return Boolean is
 196    begin
 197       if Checks and then Right.Node = null then
 198          raise Constraint_Error with "Right cursor equals No_Element";
 199       end if;
 200 
 201       if Checks and then Right.Node.Element = null then
 202          raise Program_Error with "Right cursor is bad";
 203       end if;
 204 
 205       pragma Assert (Vet (Right.Container.Tree, Right.Node),
 206                      "bad Right cursor in ""<""");
 207 
 208       return Left < Right.Node.Element.all;
 209    end "<";
 210 
 211    ---------
 212    -- "=" --
 213    ---------
 214 
 215    function "=" (Left, Right : Set) return Boolean is
 216 
 217       function Is_Equal_Node_Node (L, R : Node_Access) return Boolean;
 218       pragma Inline (Is_Equal_Node_Node);
 219 
 220       function Is_Equal is
 221         new Tree_Operations.Generic_Equal (Is_Equal_Node_Node);
 222 
 223       ------------------------
 224       -- Is_Equal_Node_Node --
 225       ------------------------
 226 
 227       function Is_Equal_Node_Node (L, R : Node_Access) return Boolean is
 228       begin
 229          return L.Element.all = R.Element.all;
 230       end Is_Equal_Node_Node;
 231 
 232    --  Start of processing for "="
 233 
 234    begin
 235       return Is_Equal (Left.Tree, Right.Tree);
 236    end "=";
 237 
 238    ---------
 239    -- ">" --
 240    ---------
 241 
 242    function ">" (Left, Right : Cursor) return Boolean is
 243    begin
 244       if Checks and then Left.Node = null then
 245          raise Constraint_Error with "Left cursor equals No_Element";
 246       end if;
 247 
 248       if Checks and then Right.Node = null then
 249          raise Constraint_Error with "Right cursor equals No_Element";
 250       end if;
 251 
 252       if Checks and then Left.Node.Element = null then
 253          raise Program_Error with "Left cursor is bad";
 254       end if;
 255 
 256       if Checks and then Right.Node.Element = null then
 257          raise Program_Error with "Right cursor is bad";
 258       end if;
 259 
 260       pragma Assert (Vet (Left.Container.Tree, Left.Node),
 261                      "bad Left cursor in "">""");
 262 
 263       pragma Assert (Vet (Right.Container.Tree, Right.Node),
 264                      "bad Right cursor in "">""");
 265 
 266       --  L > R same as R < L
 267 
 268       return Right.Node.Element.all < Left.Node.Element.all;
 269    end ">";
 270 
 271    function ">" (Left : Cursor; Right : Element_Type) return Boolean is
 272    begin
 273       if Checks and then Left.Node = null then
 274          raise Constraint_Error with "Left cursor equals No_Element";
 275       end if;
 276 
 277       if Checks and then Left.Node.Element = null then
 278          raise Program_Error with "Left cursor is bad";
 279       end if;
 280 
 281       pragma Assert (Vet (Left.Container.Tree, Left.Node),
 282                      "bad Left cursor in "">""");
 283 
 284       return Right < Left.Node.Element.all;
 285    end ">";
 286 
 287    function ">" (Left : Element_Type; Right : Cursor) return Boolean is
 288    begin
 289       if Checks and then Right.Node = null then
 290          raise Constraint_Error with "Right cursor equals No_Element";
 291       end if;
 292 
 293       if Checks and then Right.Node.Element = null then
 294          raise Program_Error with "Right cursor is bad";
 295       end if;
 296 
 297       pragma Assert (Vet (Right.Container.Tree, Right.Node),
 298                      "bad Right cursor in "">""");
 299 
 300       return Right.Node.Element.all < Left;
 301    end ">";
 302 
 303    ------------
 304    -- Adjust --
 305    ------------
 306 
 307    procedure Adjust is new Tree_Operations.Generic_Adjust (Copy_Tree);
 308 
 309    procedure Adjust (Container : in out Set) is
 310    begin
 311       Adjust (Container.Tree);
 312    end Adjust;
 313 
 314    ------------
 315    -- Assign --
 316    ------------
 317 
 318    procedure Assign (Target : in out Set; Source : Set) is
 319    begin
 320       if Target'Address = Source'Address then
 321          return;
 322       end if;
 323 
 324       Target.Clear;
 325       Target.Union (Source);
 326    end Assign;
 327 
 328    -------------
 329    -- Ceiling --
 330    -------------
 331 
 332    function Ceiling (Container : Set; Item : Element_Type) return Cursor is
 333       Node : constant Node_Access :=
 334         Element_Keys.Ceiling (Container.Tree, Item);
 335    begin
 336       return (if Node = null then No_Element
 337               else Cursor'(Container'Unrestricted_Access, Node));
 338    end Ceiling;
 339 
 340    -----------
 341    -- Clear --
 342    -----------
 343 
 344    procedure Clear is
 345       new Tree_Operations.Generic_Clear (Delete_Tree);
 346 
 347    procedure Clear (Container : in out Set) is
 348    begin
 349       Clear (Container.Tree);
 350    end Clear;
 351 
 352    -----------
 353    -- Color --
 354    -----------
 355 
 356    function Color (Node : Node_Access) return Color_Type is
 357    begin
 358       return Node.Color;
 359    end Color;
 360 
 361    ------------------------
 362    -- Constant_Reference --
 363    ------------------------
 364 
 365    function Constant_Reference
 366      (Container : aliased Set;
 367       Position  : Cursor) return Constant_Reference_Type
 368    is
 369    begin
 370       if Checks and then Position.Container = null then
 371          raise Constraint_Error with "Position cursor has no element";
 372       end if;
 373 
 374       if Checks and then Position.Container /= Container'Unrestricted_Access
 375       then
 376          raise Program_Error with
 377            "Position cursor designates wrong container";
 378       end if;
 379 
 380       if Checks and then Position.Node.Element = null then
 381          raise Program_Error with "Node has no element";
 382       end if;
 383 
 384       pragma Assert
 385         (Vet (Container.Tree, Position.Node),
 386          "bad cursor in Constant_Reference");
 387 
 388       declare
 389          Tree : Tree_Type renames Position.Container.all.Tree;
 390          TC : constant Tamper_Counts_Access :=
 391            Tree.TC'Unrestricted_Access;
 392       begin
 393          return R : constant Constant_Reference_Type :=
 394            (Element => Position.Node.Element.all'Access,
 395             Control => (Controlled with TC))
 396          do
 397             Lock (TC.all);
 398          end return;
 399       end;
 400    end Constant_Reference;
 401 
 402    --------------
 403    -- Contains --
 404    --------------
 405 
 406    function Contains (Container : Set; Item : Element_Type) return Boolean is
 407    begin
 408       return Find (Container, Item) /= No_Element;
 409    end Contains;
 410 
 411    ----------
 412    -- Copy --
 413    ----------
 414 
 415    function Copy (Source : Set) return Set is
 416    begin
 417       return Target : Set do
 418          Target.Assign (Source);
 419       end return;
 420    end Copy;
 421 
 422    ---------------
 423    -- Copy_Node --
 424    ---------------
 425 
 426    function Copy_Node (Source : Node_Access) return Node_Access is
 427       Element : Element_Access := new Element_Type'(Source.Element.all);
 428 
 429    begin
 430       return new Node_Type'(Parent  => null,
 431                             Left    => null,
 432                             Right   => null,
 433                             Color   => Source.Color,
 434                             Element => Element);
 435 
 436    exception
 437       when others =>
 438          Free_Element (Element);
 439          raise;
 440    end Copy_Node;
 441 
 442    ------------
 443    -- Delete --
 444    ------------
 445 
 446    procedure Delete (Container : in out Set; Position : in out Cursor) is
 447    begin
 448       if Checks and then Position.Node = null then
 449          raise Constraint_Error with "Position cursor equals No_Element";
 450       end if;
 451 
 452       if Checks and then Position.Node.Element = null then
 453          raise Program_Error with "Position cursor is bad";
 454       end if;
 455 
 456       if Checks and then Position.Container /= Container'Unrestricted_Access
 457       then
 458          raise Program_Error with "Position cursor designates wrong set";
 459       end if;
 460 
 461       pragma Assert (Vet (Container.Tree, Position.Node),
 462                      "bad cursor in Delete");
 463 
 464       Tree_Operations.Delete_Node_Sans_Free (Container.Tree, Position.Node);
 465       Free (Position.Node);
 466       Position.Container := null;
 467    end Delete;
 468 
 469    procedure Delete (Container : in out Set; Item : Element_Type) is
 470       X : Node_Access := Element_Keys.Find (Container.Tree, Item);
 471    begin
 472       if Checks and then X = null then
 473          raise Constraint_Error with "attempt to delete element not in set";
 474       end if;
 475 
 476       Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
 477       Free (X);
 478    end Delete;
 479 
 480    ------------------
 481    -- Delete_First --
 482    ------------------
 483 
 484    procedure Delete_First (Container : in out Set) is
 485       Tree : Tree_Type renames Container.Tree;
 486       X    : Node_Access := Tree.First;
 487    begin
 488       if X /= null then
 489          Tree_Operations.Delete_Node_Sans_Free (Tree, X);
 490          Free (X);
 491       end if;
 492    end Delete_First;
 493 
 494    -----------------
 495    -- Delete_Last --
 496    -----------------
 497 
 498    procedure Delete_Last (Container : in out Set) is
 499       Tree : Tree_Type renames Container.Tree;
 500       X    : Node_Access := Tree.Last;
 501    begin
 502       if X /= null then
 503          Tree_Operations.Delete_Node_Sans_Free (Tree, X);
 504          Free (X);
 505       end if;
 506    end Delete_Last;
 507 
 508    ----------------
 509    -- Difference --
 510    ----------------
 511 
 512    procedure Difference (Target : in out Set; Source : Set) is
 513    begin
 514       Set_Ops.Difference (Target.Tree, Source.Tree);
 515    end Difference;
 516 
 517    function Difference (Left, Right : Set) return Set is
 518       Tree : constant Tree_Type := Set_Ops.Difference (Left.Tree, Right.Tree);
 519    begin
 520       return Set'(Controlled with Tree);
 521    end Difference;
 522 
 523    -------------
 524    -- Element --
 525    -------------
 526 
 527    function Element (Position : Cursor) return Element_Type is
 528    begin
 529       if Checks and then Position.Node = null then
 530          raise Constraint_Error with "Position cursor equals No_Element";
 531       end if;
 532 
 533       if Checks and then Position.Node.Element = null then
 534          raise Program_Error with "Position cursor is bad";
 535       end if;
 536 
 537       pragma Assert (Vet (Position.Container.Tree, Position.Node),
 538                      "bad cursor in Element");
 539 
 540       return Position.Node.Element.all;
 541    end Element;
 542 
 543    -------------------------
 544    -- Equivalent_Elements --
 545    -------------------------
 546 
 547    function Equivalent_Elements (Left, Right : Element_Type) return Boolean is
 548    begin
 549       if Left < Right or else Right < Left then
 550          return False;
 551       else
 552          return True;
 553       end if;
 554    end Equivalent_Elements;
 555 
 556    ---------------------
 557    -- Equivalent_Sets --
 558    ---------------------
 559 
 560    function Equivalent_Sets (Left, Right : Set) return Boolean is
 561 
 562       function Is_Equivalent_Node_Node (L, R : Node_Access) return Boolean;
 563       pragma Inline (Is_Equivalent_Node_Node);
 564 
 565       function Is_Equivalent is
 566          new Tree_Operations.Generic_Equal (Is_Equivalent_Node_Node);
 567 
 568       -----------------------------
 569       -- Is_Equivalent_Node_Node --
 570       -----------------------------
 571 
 572       function Is_Equivalent_Node_Node (L, R : Node_Access) return Boolean is
 573       begin
 574          if L.Element.all < R.Element.all then
 575             return False;
 576          elsif R.Element.all < L.Element.all then
 577             return False;
 578          else
 579             return True;
 580          end if;
 581       end Is_Equivalent_Node_Node;
 582 
 583    --  Start of processing for Equivalent_Sets
 584 
 585    begin
 586       return Is_Equivalent (Left.Tree, Right.Tree);
 587    end Equivalent_Sets;
 588 
 589    -------------
 590    -- Exclude --
 591    -------------
 592 
 593    procedure Exclude (Container : in out Set; Item : Element_Type) is
 594       X : Node_Access := Element_Keys.Find (Container.Tree, Item);
 595    begin
 596       if X /= null then
 597          Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
 598          Free (X);
 599       end if;
 600    end Exclude;
 601 
 602    --------------
 603    -- Finalize --
 604    --------------
 605 
 606    procedure Finalize (Object : in out Iterator) is
 607    begin
 608       if Object.Container /= null then
 609          Unbusy (Object.Container.Tree.TC);
 610       end if;
 611    end Finalize;
 612 
 613    ----------
 614    -- Find --
 615    ----------
 616 
 617    function Find (Container : Set; Item : Element_Type) return Cursor is
 618       Node : constant Node_Access := Element_Keys.Find (Container.Tree, Item);
 619    begin
 620       if Node = null then
 621          return No_Element;
 622       else
 623          return Cursor'(Container'Unrestricted_Access, Node);
 624       end if;
 625    end Find;
 626 
 627    -----------
 628    -- First --
 629    -----------
 630 
 631    function First (Container : Set) return Cursor is
 632    begin
 633       return
 634         (if Container.Tree.First = null then No_Element
 635          else Cursor'(Container'Unrestricted_Access, Container.Tree.First));
 636    end First;
 637 
 638    function First (Object : Iterator) return Cursor is
 639    begin
 640       --  The value of the iterator object's Node component influences the
 641       --  behavior of the First (and Last) selector function.
 642 
 643       --  When the Node component is null, this means the iterator object was
 644       --  constructed without a start expression, in which case the (forward)
 645       --  iteration starts from the (logical) beginning of the entire sequence
 646       --  of items (corresponding to Container.First, for a forward iterator).
 647 
 648       --  Otherwise, this is iteration over a partial sequence of items. When
 649       --  the Node component is non-null, the iterator object was constructed
 650       --  with a start expression, that specifies the position from which the
 651       --  (forward) partial iteration begins.
 652 
 653       if Object.Node = null then
 654          return Object.Container.First;
 655       else
 656          return Cursor'(Object.Container, Object.Node);
 657       end if;
 658    end First;
 659 
 660    -------------------
 661    -- First_Element --
 662    -------------------
 663 
 664    function First_Element (Container : Set) return Element_Type is
 665    begin
 666       if Checks and then Container.Tree.First = null then
 667          raise Constraint_Error with "set is empty";
 668       end if;
 669 
 670       return Container.Tree.First.Element.all;
 671    end First_Element;
 672 
 673    -----------
 674    -- Floor --
 675    -----------
 676 
 677    function Floor (Container : Set; Item : Element_Type) return Cursor is
 678       Node : constant Node_Access := Element_Keys.Floor (Container.Tree, Item);
 679    begin
 680       return (if Node = null then No_Element
 681               else Cursor'(Container'Unrestricted_Access, Node));
 682    end Floor;
 683 
 684    ----------
 685    -- Free --
 686    ----------
 687 
 688    procedure Free (X : in out Node_Access) is
 689       procedure Deallocate is
 690         new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
 691 
 692    begin
 693       if X = null then
 694          return;
 695       end if;
 696 
 697       X.Parent := X;
 698       X.Left := X;
 699       X.Right := X;
 700 
 701       begin
 702          Free_Element (X.Element);
 703       exception
 704          when others =>
 705             X.Element := null;
 706             Deallocate (X);
 707             raise;
 708       end;
 709 
 710       Deallocate (X);
 711    end Free;
 712 
 713    ------------------
 714    -- Generic_Keys --
 715    ------------------
 716 
 717    package body Generic_Keys is
 718 
 719       -----------------------
 720       -- Local Subprograms --
 721       -----------------------
 722 
 723       function Is_Greater_Key_Node
 724         (Left  : Key_Type;
 725          Right : Node_Access) return Boolean;
 726       pragma Inline (Is_Greater_Key_Node);
 727 
 728       function Is_Less_Key_Node
 729         (Left  : Key_Type;
 730          Right : Node_Access) return Boolean;
 731       pragma Inline (Is_Less_Key_Node);
 732 
 733       --------------------------
 734       -- Local Instantiations --
 735       --------------------------
 736 
 737       package Key_Keys is
 738         new Red_Black_Trees.Generic_Keys
 739           (Tree_Operations     => Tree_Operations,
 740            Key_Type            => Key_Type,
 741            Is_Less_Key_Node    => Is_Less_Key_Node,
 742            Is_Greater_Key_Node => Is_Greater_Key_Node);
 743 
 744       -------------
 745       -- Ceiling --
 746       -------------
 747 
 748       function Ceiling (Container : Set; Key : Key_Type) return Cursor is
 749          Node : constant Node_Access := Key_Keys.Ceiling (Container.Tree, Key);
 750       begin
 751          return (if Node = null then No_Element
 752                  else Cursor'(Container'Unrestricted_Access, Node));
 753       end Ceiling;
 754 
 755       ------------------------
 756       -- Constant_Reference --
 757       ------------------------
 758 
 759       function Constant_Reference
 760         (Container : aliased Set;
 761          Key       : Key_Type) return Constant_Reference_Type
 762       is
 763          Node : constant Node_Access := Key_Keys.Find (Container.Tree, Key);
 764 
 765       begin
 766          if Checks and then Node = null then
 767             raise Constraint_Error with "Key not in set";
 768          end if;
 769 
 770          if Checks and then Node.Element = null then
 771             raise Program_Error with "Node has no element";
 772          end if;
 773 
 774          declare
 775             Tree : Tree_Type renames Container'Unrestricted_Access.all.Tree;
 776             TC : constant Tamper_Counts_Access :=
 777               Tree.TC'Unrestricted_Access;
 778          begin
 779             return R : constant Constant_Reference_Type :=
 780               (Element => Node.Element.all'Access,
 781                Control => (Controlled with TC))
 782             do
 783                Lock (TC.all);
 784             end return;
 785          end;
 786       end Constant_Reference;
 787 
 788       --------------
 789       -- Contains --
 790       --------------
 791 
 792       function Contains (Container : Set; Key : Key_Type) return Boolean is
 793       begin
 794          return Find (Container, Key) /= No_Element;
 795       end Contains;
 796 
 797       ------------
 798       -- Delete --
 799       ------------
 800 
 801       procedure Delete (Container : in out Set; Key : Key_Type) is
 802          X : Node_Access := Key_Keys.Find (Container.Tree, Key);
 803 
 804       begin
 805          if Checks and then X = null then
 806             raise Constraint_Error with "attempt to delete key not in set";
 807          end if;
 808 
 809          Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
 810          Free (X);
 811       end Delete;
 812 
 813       -------------
 814       -- Element --
 815       -------------
 816 
 817       function Element (Container : Set; Key : Key_Type) return Element_Type is
 818          Node : constant Node_Access := Key_Keys.Find (Container.Tree, Key);
 819       begin
 820          if Checks and then Node = null then
 821             raise Constraint_Error with "key not in set";
 822          end if;
 823 
 824          return Node.Element.all;
 825       end Element;
 826 
 827       ---------------------
 828       -- Equivalent_Keys --
 829       ---------------------
 830 
 831       function Equivalent_Keys (Left, Right : Key_Type) return Boolean is
 832       begin
 833          if Left < Right or else Right < Left then
 834             return False;
 835          else
 836             return True;
 837          end if;
 838       end Equivalent_Keys;
 839 
 840       -------------
 841       -- Exclude --
 842       -------------
 843 
 844       procedure Exclude (Container : in out Set; Key : Key_Type) is
 845          X : Node_Access := Key_Keys.Find (Container.Tree, Key);
 846       begin
 847          if X /= null then
 848             Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
 849             Free (X);
 850          end if;
 851       end Exclude;
 852 
 853       --------------
 854       -- Finalize --
 855       --------------
 856 
 857       procedure Finalize (Control : in out Reference_Control_Type) is
 858       begin
 859          if Control.Container /= null then
 860             Impl.Reference_Control_Type (Control).Finalize;
 861 
 862             if Checks and then not (Key (Control.Pos) = Control.Old_Key.all)
 863             then
 864                Delete (Control.Container.all, Key (Control.Pos));
 865                raise Program_Error;
 866             end if;
 867 
 868             Control.Container := null;
 869             Control.Old_Key   := null;
 870          end if;
 871       end Finalize;
 872 
 873       ----------
 874       -- Find --
 875       ----------
 876 
 877       function Find (Container : Set; Key : Key_Type) return Cursor is
 878          Node : constant Node_Access := Key_Keys.Find (Container.Tree, Key);
 879       begin
 880          return (if Node = null then No_Element
 881                  else Cursor'(Container'Unrestricted_Access, Node));
 882       end Find;
 883 
 884       -----------
 885       -- Floor --
 886       -----------
 887 
 888       function Floor (Container : Set; Key : Key_Type) return Cursor is
 889          Node : constant Node_Access := Key_Keys.Floor (Container.Tree, Key);
 890       begin
 891          return (if Node = null then No_Element
 892                  else Cursor'(Container'Unrestricted_Access, Node));
 893       end Floor;
 894 
 895       -------------------------
 896       -- Is_Greater_Key_Node --
 897       -------------------------
 898 
 899       function Is_Greater_Key_Node
 900         (Left  : Key_Type;
 901          Right : Node_Access) return Boolean
 902       is
 903       begin
 904          return Key (Right.Element.all) < Left;
 905       end Is_Greater_Key_Node;
 906 
 907       ----------------------
 908       -- Is_Less_Key_Node --
 909       ----------------------
 910 
 911       function Is_Less_Key_Node
 912         (Left  : Key_Type;
 913          Right : Node_Access) return Boolean
 914       is
 915       begin
 916          return Left < Key (Right.Element.all);
 917       end Is_Less_Key_Node;
 918 
 919       ---------
 920       -- Key --
 921       ---------
 922 
 923       function Key (Position : Cursor) return Key_Type is
 924       begin
 925          if Checks and then Position.Node = null then
 926             raise Constraint_Error with
 927               "Position cursor equals No_Element";
 928          end if;
 929 
 930          if Checks and then Position.Node.Element = null then
 931             raise Program_Error with
 932               "Position cursor is bad";
 933          end if;
 934 
 935          pragma Assert (Vet (Position.Container.Tree, Position.Node),
 936                         "bad cursor in Key");
 937 
 938          return Key (Position.Node.Element.all);
 939       end Key;
 940 
 941       -------------
 942       -- Replace --
 943       -------------
 944 
 945       procedure Replace
 946         (Container : in out Set;
 947          Key       : Key_Type;
 948          New_Item  : Element_Type)
 949       is
 950          Node : constant Node_Access := Key_Keys.Find (Container.Tree, Key);
 951 
 952       begin
 953          if Checks and then Node = null then
 954             raise Constraint_Error with
 955               "attempt to replace key not in set";
 956          end if;
 957 
 958          Replace_Element (Container.Tree, Node, New_Item);
 959       end Replace;
 960 
 961       ----------
 962       -- Read --
 963       ----------
 964 
 965       procedure Read
 966         (Stream : not null access Root_Stream_Type'Class;
 967          Item   : out Reference_Type)
 968       is
 969       begin
 970          raise Program_Error with "attempt to stream reference";
 971       end Read;
 972 
 973       ------------------------------
 974       -- Reference_Preserving_Key --
 975       ------------------------------
 976 
 977       function Reference_Preserving_Key
 978         (Container : aliased in out Set;
 979          Position  : Cursor) return Reference_Type
 980       is
 981       begin
 982          if Checks and then Position.Container = null then
 983             raise Constraint_Error with "Position cursor has no element";
 984          end if;
 985 
 986          if Checks and then Position.Container /= Container'Unrestricted_Access
 987          then
 988             raise Program_Error with
 989               "Position cursor designates wrong container";
 990          end if;
 991 
 992          if Checks and then Position.Node.Element = null then
 993             raise Program_Error with "Node has no element";
 994          end if;
 995 
 996          pragma Assert
 997            (Vet (Container.Tree, Position.Node),
 998             "bad cursor in function Reference_Preserving_Key");
 999 
1000          declare
1001             Tree : Tree_Type renames Container.Tree;
1002          begin
1003             return R : constant Reference_Type :=
1004               (Element   => Position.Node.Element.all'Unchecked_Access,
1005                Control =>
1006                  (Controlled with
1007                     Tree.TC'Unrestricted_Access,
1008                     Container => Container'Access,
1009                     Pos       => Position,
1010                     Old_Key   => new Key_Type'(Key (Position))))
1011          do
1012                Lock (Tree.TC);
1013             end return;
1014          end;
1015       end Reference_Preserving_Key;
1016 
1017       function Reference_Preserving_Key
1018         (Container : aliased in out Set;
1019          Key       : Key_Type) return Reference_Type
1020       is
1021          Node : constant Node_Access := Key_Keys.Find (Container.Tree, Key);
1022 
1023       begin
1024          if Checks and then Node = null then
1025             raise Constraint_Error with "Key not in set";
1026          end if;
1027 
1028          if Checks and then Node.Element = null then
1029             raise Program_Error with "Node has no element";
1030          end if;
1031 
1032          declare
1033             Tree : Tree_Type renames Container.Tree;
1034          begin
1035             return R : constant Reference_Type :=
1036               (Element  => Node.Element.all'Unchecked_Access,
1037                Control =>
1038                  (Controlled with
1039                     Tree.TC'Unrestricted_Access,
1040                     Container => Container'Access,
1041                     Pos       => Find (Container, Key),
1042                     Old_Key   => new Key_Type'(Key)))
1043             do
1044                Lock (Tree.TC);
1045             end return;
1046          end;
1047       end Reference_Preserving_Key;
1048 
1049       -----------------------------------
1050       -- Update_Element_Preserving_Key --
1051       -----------------------------------
1052 
1053       procedure Update_Element_Preserving_Key
1054         (Container : in out Set;
1055          Position  : Cursor;
1056          Process   : not null access
1057                         procedure (Element : in out Element_Type))
1058       is
1059          Tree : Tree_Type renames Container.Tree;
1060 
1061       begin
1062          if Checks and then Position.Node = null then
1063             raise Constraint_Error with "Position cursor equals No_Element";
1064          end if;
1065 
1066          if Checks and then Position.Node.Element = null then
1067             raise Program_Error with "Position cursor is bad";
1068          end if;
1069 
1070          if Checks and then Position.Container /= Container'Unrestricted_Access
1071          then
1072             raise Program_Error with "Position cursor designates wrong set";
1073          end if;
1074 
1075          pragma Assert (Vet (Container.Tree, Position.Node),
1076                         "bad cursor in Update_Element_Preserving_Key");
1077 
1078          declare
1079             E : Element_Type renames Position.Node.Element.all;
1080             K : constant Key_Type := Key (E);
1081             Lock : With_Lock (Tree.TC'Unrestricted_Access);
1082          begin
1083             Process (E);
1084             if Equivalent_Keys (K, Key (E)) then
1085                return;
1086             end if;
1087          end;
1088 
1089          declare
1090             X : Node_Access := Position.Node;
1091          begin
1092             Tree_Operations.Delete_Node_Sans_Free (Tree, X);
1093             Free (X);
1094          end;
1095 
1096          raise Program_Error with "key was modified";
1097       end Update_Element_Preserving_Key;
1098 
1099       -----------
1100       -- Write --
1101       -----------
1102 
1103       procedure Write
1104         (Stream : not null access Root_Stream_Type'Class;
1105          Item   : Reference_Type)
1106       is
1107       begin
1108          raise Program_Error with "attempt to stream reference";
1109       end Write;
1110 
1111    end Generic_Keys;
1112 
1113    ------------------------
1114    -- Get_Element_Access --
1115    ------------------------
1116 
1117    function Get_Element_Access
1118      (Position : Cursor) return not null Element_Access is
1119    begin
1120       return Position.Node.Element;
1121    end Get_Element_Access;
1122 
1123    -----------------
1124    -- Has_Element --
1125    -----------------
1126 
1127    function Has_Element (Position : Cursor) return Boolean is
1128    begin
1129       return Position /= No_Element;
1130    end Has_Element;
1131 
1132    -------------
1133    -- Include --
1134    -------------
1135 
1136    procedure Include (Container : in out Set; New_Item : Element_Type) is
1137       Position : Cursor;
1138       Inserted : Boolean;
1139 
1140       X : Element_Access;
1141 
1142    begin
1143       Insert (Container, New_Item, Position, Inserted);
1144 
1145       if not Inserted then
1146          TE_Check (Container.Tree.TC);
1147 
1148          declare
1149             --  The element allocator may need an accessibility check in the
1150             --  case the actual type is class-wide or has access discriminants
1151             --  (see RM 4.8(10.1) and AI12-0035).
1152 
1153             pragma Unsuppress (Accessibility_Check);
1154 
1155          begin
1156             X := Position.Node.Element;
1157             Position.Node.Element := new Element_Type'(New_Item);
1158             Free_Element (X);
1159          end;
1160       end if;
1161    end Include;
1162 
1163    ------------
1164    -- Insert --
1165    ------------
1166 
1167    procedure Insert
1168      (Container : in out Set;
1169       New_Item  : Element_Type;
1170       Position  : out Cursor;
1171       Inserted  : out Boolean)
1172    is
1173    begin
1174       Insert_Sans_Hint
1175         (Container.Tree,
1176          New_Item,
1177          Position.Node,
1178          Inserted);
1179 
1180       Position.Container := Container'Unrestricted_Access;
1181    end Insert;
1182 
1183    procedure Insert (Container : in out Set; New_Item  : Element_Type) is
1184       Position : Cursor;
1185       pragma Unreferenced (Position);
1186 
1187       Inserted : Boolean;
1188 
1189    begin
1190       Insert (Container, New_Item, Position, Inserted);
1191 
1192       if Checks and then not Inserted then
1193          raise Constraint_Error with
1194            "attempt to insert element already in set";
1195       end if;
1196    end Insert;
1197 
1198    ----------------------
1199    -- Insert_Sans_Hint --
1200    ----------------------
1201 
1202    procedure Insert_Sans_Hint
1203      (Tree     : in out Tree_Type;
1204       New_Item : Element_Type;
1205       Node     : out Node_Access;
1206       Inserted : out Boolean)
1207    is
1208       function New_Node return Node_Access;
1209       pragma Inline (New_Node);
1210 
1211       procedure Insert_Post is
1212         new Element_Keys.Generic_Insert_Post (New_Node);
1213 
1214       procedure Conditional_Insert_Sans_Hint is
1215         new Element_Keys.Generic_Conditional_Insert (Insert_Post);
1216 
1217       --------------
1218       -- New_Node --
1219       --------------
1220 
1221       function New_Node return Node_Access is
1222          --  The element allocator may need an accessibility check in the case
1223          --  the actual type is class-wide or has access discriminants (see
1224          --  RM 4.8(10.1) and AI12-0035).
1225 
1226          pragma Unsuppress (Accessibility_Check);
1227 
1228          Element : Element_Access := new Element_Type'(New_Item);
1229 
1230       begin
1231          return new Node_Type'(Parent  => null,
1232                                Left    => null,
1233                                Right   => null,
1234                                Color   => Red_Black_Trees.Red,
1235                                Element => Element);
1236 
1237       exception
1238          when others =>
1239             Free_Element (Element);
1240             raise;
1241       end New_Node;
1242 
1243    --  Start of processing for Insert_Sans_Hint
1244 
1245    begin
1246       Conditional_Insert_Sans_Hint
1247         (Tree,
1248          New_Item,
1249          Node,
1250          Inserted);
1251    end Insert_Sans_Hint;
1252 
1253    ----------------------
1254    -- Insert_With_Hint --
1255    ----------------------
1256 
1257    procedure Insert_With_Hint
1258      (Dst_Tree : in out Tree_Type;
1259       Dst_Hint : Node_Access;
1260       Src_Node : Node_Access;
1261       Dst_Node : out Node_Access)
1262    is
1263       Success : Boolean;
1264       pragma Unreferenced (Success);
1265 
1266       function New_Node return Node_Access;
1267 
1268       procedure Insert_Post is
1269         new Element_Keys.Generic_Insert_Post (New_Node);
1270 
1271       procedure Insert_Sans_Hint is
1272         new Element_Keys.Generic_Conditional_Insert (Insert_Post);
1273 
1274       procedure Insert_With_Hint is
1275          new Element_Keys.Generic_Conditional_Insert_With_Hint
1276             (Insert_Post,
1277              Insert_Sans_Hint);
1278 
1279       --------------
1280       -- New_Node --
1281       --------------
1282 
1283       function New_Node return Node_Access is
1284          Element : Element_Access := new Element_Type'(Src_Node.Element.all);
1285          Node    : Node_Access;
1286 
1287       begin
1288          begin
1289             Node := new Node_Type;
1290          exception
1291             when others =>
1292                Free_Element (Element);
1293                raise;
1294          end;
1295 
1296          Node.Element := Element;
1297          return Node;
1298       end New_Node;
1299 
1300    --  Start of processing for Insert_With_Hint
1301 
1302    begin
1303       Insert_With_Hint
1304         (Dst_Tree,
1305          Dst_Hint,
1306          Src_Node.Element.all,
1307          Dst_Node,
1308          Success);
1309    end Insert_With_Hint;
1310 
1311    ------------------
1312    -- Intersection --
1313    ------------------
1314 
1315    procedure Intersection (Target : in out Set; Source : Set) is
1316    begin
1317       Set_Ops.Intersection (Target.Tree, Source.Tree);
1318    end Intersection;
1319 
1320    function Intersection (Left, Right : Set) return Set is
1321       Tree : constant Tree_Type :=
1322         Set_Ops.Intersection (Left.Tree, Right.Tree);
1323    begin
1324       return Set'(Controlled with Tree);
1325    end Intersection;
1326 
1327    --------------
1328    -- Is_Empty --
1329    --------------
1330 
1331    function Is_Empty (Container : Set) return Boolean is
1332    begin
1333       return Container.Tree.Length = 0;
1334    end Is_Empty;
1335 
1336    -----------------------------
1337    -- Is_Greater_Element_Node --
1338    -----------------------------
1339 
1340    function Is_Greater_Element_Node
1341      (Left  : Element_Type;
1342       Right : Node_Access) return Boolean
1343    is
1344    begin
1345       --  e > node same as node < e
1346 
1347       return Right.Element.all < Left;
1348    end Is_Greater_Element_Node;
1349 
1350    --------------------------
1351    -- Is_Less_Element_Node --
1352    --------------------------
1353 
1354    function Is_Less_Element_Node
1355      (Left  : Element_Type;
1356       Right : Node_Access) return Boolean
1357    is
1358    begin
1359       return Left < Right.Element.all;
1360    end Is_Less_Element_Node;
1361 
1362    -----------------------
1363    -- Is_Less_Node_Node --
1364    -----------------------
1365 
1366    function Is_Less_Node_Node (L, R : Node_Access) return Boolean is
1367    begin
1368       return L.Element.all < R.Element.all;
1369    end Is_Less_Node_Node;
1370 
1371    ---------------
1372    -- Is_Subset --
1373    ---------------
1374 
1375    function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
1376    begin
1377       return Set_Ops.Is_Subset (Subset => Subset.Tree, Of_Set => Of_Set.Tree);
1378    end Is_Subset;
1379 
1380    -------------
1381    -- Iterate --
1382    -------------
1383 
1384    procedure Iterate
1385      (Container : Set;
1386       Process   : not null access procedure (Position : Cursor))
1387    is
1388       procedure Process_Node (Node : Node_Access);
1389       pragma Inline (Process_Node);
1390 
1391       procedure Local_Iterate is
1392         new Tree_Operations.Generic_Iteration (Process_Node);
1393 
1394       ------------------
1395       -- Process_Node --
1396       ------------------
1397 
1398       procedure Process_Node (Node : Node_Access) is
1399       begin
1400          Process (Cursor'(Container'Unrestricted_Access, Node));
1401       end Process_Node;
1402 
1403       T : Tree_Type renames Container'Unrestricted_Access.all.Tree;
1404       Busy : With_Busy (T.TC'Unrestricted_Access);
1405 
1406    --  Start of processing for Iterate
1407 
1408    begin
1409       Local_Iterate (T);
1410    end Iterate;
1411 
1412    function Iterate
1413      (Container : Set)
1414       return Set_Iterator_Interfaces.Reversible_Iterator'class
1415    is
1416    begin
1417       --  The value of the Node component influences the behavior of the First
1418       --  and Last selector functions of the iterator object. When the Node
1419       --  component is null (as is the case here), this means the iterator
1420       --  object was constructed without a start expression. This is a complete
1421       --  iterator, meaning that the iteration starts from the (logical)
1422       --  beginning of the sequence of items.
1423 
1424       --  Note: For a forward iterator, Container.First is the beginning, and
1425       --  for a reverse iterator, Container.Last is the beginning.
1426 
1427       return It : constant Iterator :=
1428         Iterator'(Limited_Controlled with
1429                     Container => Container'Unrestricted_Access,
1430                     Node      => null)
1431       do
1432          Busy (Container.Tree.TC'Unrestricted_Access.all);
1433       end return;
1434    end Iterate;
1435 
1436    function Iterate
1437      (Container : Set;
1438       Start     : Cursor)
1439       return Set_Iterator_Interfaces.Reversible_Iterator'class
1440    is
1441    begin
1442       --  It was formerly the case that when Start = No_Element, the partial
1443       --  iterator was defined to behave the same as for a complete iterator,
1444       --  and iterate over the entire sequence of items. However, those
1445       --  semantics were unintuitive and arguably error-prone (it is too easy
1446       --  to accidentally create an endless loop), and so they were changed,
1447       --  per the ARG meeting in Denver on 2011/11. However, there was no
1448       --  consensus about what positive meaning this corner case should have,
1449       --  and so it was decided to simply raise an exception. This does imply,
1450       --  however, that it is not possible to use a partial iterator to specify
1451       --  an empty sequence of items.
1452 
1453       if Checks and then Start = No_Element then
1454          raise Constraint_Error with
1455            "Start position for iterator equals No_Element";
1456       end if;
1457 
1458       if Checks and then Start.Container /= Container'Unrestricted_Access then
1459          raise Program_Error with
1460            "Start cursor of Iterate designates wrong set";
1461       end if;
1462 
1463       pragma Assert (Vet (Container.Tree, Start.Node),
1464                      "Start cursor of Iterate is bad");
1465 
1466       --  The value of the Node component influences the behavior of the First
1467       --  and Last selector functions of the iterator object. When the Node
1468       --  component is non-null (as is the case here), it means that this is a
1469       --  partial iteration, over a subset of the complete sequence of
1470       --  items. The iterator object was constructed with a start expression,
1471       --  indicating the position from which the iteration begins. Note that
1472       --  the start position has the same value irrespective of whether this is
1473       --  a forward or reverse iteration.
1474 
1475       return It : constant Iterator :=
1476         (Limited_Controlled with
1477            Container => Container'Unrestricted_Access,
1478            Node      => Start.Node)
1479       do
1480          Busy (Container.Tree.TC'Unrestricted_Access.all);
1481       end return;
1482    end Iterate;
1483 
1484    ----------
1485    -- Last --
1486    ----------
1487 
1488    function Last (Container : Set) return Cursor is
1489    begin
1490       return
1491         (if Container.Tree.Last = null then No_Element
1492          else Cursor'(Container'Unrestricted_Access, Container.Tree.Last));
1493    end Last;
1494 
1495    function Last (Object : Iterator) return Cursor is
1496    begin
1497       --  The value of the iterator object's Node component influences the
1498       --  behavior of the Last (and First) selector function.
1499 
1500       --  When the Node component is null, this means the iterator object was
1501       --  constructed without a start expression, in which case the (reverse)
1502       --  iteration starts from the (logical) beginning of the entire sequence
1503       --  (corresponding to Container.Last, for a reverse iterator).
1504 
1505       --  Otherwise, this is iteration over a partial sequence of items. When
1506       --  the Node component is non-null, the iterator object was constructed
1507       --  with a start expression, that specifies the position from which the
1508       --  (reverse) partial iteration begins.
1509 
1510       if Object.Node = null then
1511          return Object.Container.Last;
1512       else
1513          return Cursor'(Object.Container, Object.Node);
1514       end if;
1515    end Last;
1516 
1517    ------------------
1518    -- Last_Element --
1519    ------------------
1520 
1521    function Last_Element (Container : Set) return Element_Type is
1522    begin
1523       if Checks and then Container.Tree.Last = null then
1524          raise Constraint_Error with "set is empty";
1525       end if;
1526 
1527       return Container.Tree.Last.Element.all;
1528    end Last_Element;
1529 
1530    ----------
1531    -- Left --
1532    ----------
1533 
1534    function Left (Node : Node_Access) return Node_Access is
1535    begin
1536       return Node.Left;
1537    end Left;
1538 
1539    ------------
1540    -- Length --
1541    ------------
1542 
1543    function Length (Container : Set) return Count_Type is
1544    begin
1545       return Container.Tree.Length;
1546    end Length;
1547 
1548    ----------
1549    -- Move --
1550    ----------
1551 
1552    procedure Move is new Tree_Operations.Generic_Move (Clear);
1553 
1554    procedure Move (Target : in out Set; Source : in out Set) is
1555    begin
1556       Move (Target => Target.Tree, Source => Source.Tree);
1557    end Move;
1558 
1559    ----------
1560    -- Next --
1561    ----------
1562 
1563    procedure Next (Position : in out Cursor) is
1564    begin
1565       Position := Next (Position);
1566    end Next;
1567 
1568    function Next (Position : Cursor) return Cursor is
1569    begin
1570       if Position = No_Element then
1571          return No_Element;
1572       end if;
1573 
1574       if Checks and then Position.Node.Element = null then
1575          raise Program_Error with "Position cursor is bad";
1576       end if;
1577 
1578       pragma Assert (Vet (Position.Container.Tree, Position.Node),
1579                      "bad cursor in Next");
1580 
1581       declare
1582          Node : constant Node_Access := Tree_Operations.Next (Position.Node);
1583       begin
1584          return (if Node = null then No_Element
1585                  else Cursor'(Position.Container, Node));
1586       end;
1587    end Next;
1588 
1589    function Next
1590      (Object   : Iterator;
1591       Position : Cursor) return Cursor
1592    is
1593    begin
1594       if Position.Container = null then
1595          return No_Element;
1596       end if;
1597 
1598       if Checks and then Position.Container /= Object.Container then
1599          raise Program_Error with
1600            "Position cursor of Next designates wrong set";
1601       end if;
1602 
1603       return Next (Position);
1604    end Next;
1605 
1606    -------------
1607    -- Overlap --
1608    -------------
1609 
1610    function Overlap (Left, Right : Set) return Boolean is
1611    begin
1612       return Set_Ops.Overlap (Left.Tree, Right.Tree);
1613    end Overlap;
1614 
1615    ------------
1616    -- Parent --
1617    ------------
1618 
1619    function Parent (Node : Node_Access) return Node_Access is
1620    begin
1621       return Node.Parent;
1622    end Parent;
1623 
1624    --------------
1625    -- Previous --
1626    --------------
1627 
1628    procedure Previous (Position : in out Cursor) is
1629    begin
1630       Position := Previous (Position);
1631    end Previous;
1632 
1633    function Previous (Position : Cursor) return Cursor is
1634    begin
1635       if Position = No_Element then
1636          return No_Element;
1637       end if;
1638 
1639       if Checks and then Position.Node.Element = null then
1640          raise Program_Error with "Position cursor is bad";
1641       end if;
1642 
1643       pragma Assert (Vet (Position.Container.Tree, Position.Node),
1644                      "bad cursor in Previous");
1645 
1646       declare
1647          Node : constant Node_Access :=
1648            Tree_Operations.Previous (Position.Node);
1649       begin
1650          return (if Node = null then No_Element
1651                  else Cursor'(Position.Container, Node));
1652       end;
1653    end Previous;
1654 
1655    function Previous
1656      (Object   : Iterator;
1657       Position : Cursor) return Cursor
1658    is
1659    begin
1660       if Position.Container = null then
1661          return No_Element;
1662       end if;
1663 
1664       if Checks and then Position.Container /= Object.Container then
1665          raise Program_Error with
1666            "Position cursor of Previous designates wrong set";
1667       end if;
1668 
1669       return Previous (Position);
1670    end Previous;
1671 
1672    ----------------------
1673    -- Pseudo_Reference --
1674    ----------------------
1675 
1676    function Pseudo_Reference
1677      (Container : aliased Set'Class) return Reference_Control_Type
1678    is
1679       TC : constant Tamper_Counts_Access :=
1680         Container.Tree.TC'Unrestricted_Access;
1681    begin
1682       return R : constant Reference_Control_Type := (Controlled with TC) do
1683          Lock (TC.all);
1684       end return;
1685    end Pseudo_Reference;
1686 
1687    -------------------
1688    -- Query_Element --
1689    -------------------
1690 
1691    procedure Query_Element
1692      (Position  : Cursor;
1693       Process   : not null access procedure (Element : Element_Type))
1694    is
1695    begin
1696       if Checks and then Position.Node = null then
1697          raise Constraint_Error with "Position cursor equals No_Element";
1698       end if;
1699 
1700       if Checks and then Position.Node.Element = null then
1701          raise Program_Error with "Position cursor is bad";
1702       end if;
1703 
1704       pragma Assert (Vet (Position.Container.Tree, Position.Node),
1705                      "bad cursor in Query_Element");
1706 
1707       declare
1708          T : Tree_Type renames Position.Container.Tree;
1709          Lock : With_Lock (T.TC'Unrestricted_Access);
1710       begin
1711          Process (Position.Node.Element.all);
1712       end;
1713    end Query_Element;
1714 
1715    ----------
1716    -- Read --
1717    ----------
1718 
1719    procedure Read
1720      (Stream    : not null access Root_Stream_Type'Class;
1721       Container : out Set)
1722    is
1723       function Read_Node
1724         (Stream : not null access Root_Stream_Type'Class) return Node_Access;
1725       pragma Inline (Read_Node);
1726 
1727       procedure Read is
1728          new Tree_Operations.Generic_Read (Clear, Read_Node);
1729 
1730       ---------------
1731       -- Read_Node --
1732       ---------------
1733 
1734       function Read_Node
1735         (Stream : not null access Root_Stream_Type'Class) return Node_Access
1736       is
1737          Node : Node_Access := new Node_Type;
1738 
1739       begin
1740          Node.Element := new Element_Type'(Element_Type'Input (Stream));
1741          return Node;
1742 
1743       exception
1744          when others =>
1745             Free (Node);  --  Note that Free deallocates elem too
1746             raise;
1747       end Read_Node;
1748 
1749    --  Start of processing for Read
1750 
1751    begin
1752       Read (Stream, Container.Tree);
1753    end Read;
1754 
1755    procedure Read
1756      (Stream : not null access Root_Stream_Type'Class;
1757       Item   : out Cursor)
1758    is
1759    begin
1760       raise Program_Error with "attempt to stream set cursor";
1761    end Read;
1762 
1763    procedure Read
1764      (Stream : not null access Root_Stream_Type'Class;
1765       Item   : out Constant_Reference_Type)
1766    is
1767    begin
1768       raise Program_Error with "attempt to stream reference";
1769    end Read;
1770 
1771    -------------
1772    -- Replace --
1773    -------------
1774 
1775    procedure Replace (Container : in out Set; New_Item : Element_Type) is
1776       Node : constant Node_Access :=
1777         Element_Keys.Find (Container.Tree, New_Item);
1778 
1779       X : Element_Access;
1780       pragma Warnings (Off, X);
1781 
1782    begin
1783       if Checks and then Node = null then
1784          raise Constraint_Error with "attempt to replace element not in set";
1785       end if;
1786 
1787       TE_Check (Container.Tree.TC);
1788 
1789       declare
1790          --  The element allocator may need an accessibility check in the case
1791          --  the actual type is class-wide or has access discriminants (see
1792          --  RM 4.8(10.1) and AI12-0035).
1793 
1794          pragma Unsuppress (Accessibility_Check);
1795 
1796       begin
1797          X := Node.Element;
1798          Node.Element := new Element_Type'(New_Item);
1799          Free_Element (X);
1800       end;
1801    end Replace;
1802 
1803    ---------------------
1804    -- Replace_Element --
1805    ---------------------
1806 
1807    procedure Replace_Element
1808      (Tree : in out Tree_Type;
1809       Node : Node_Access;
1810       Item : Element_Type)
1811    is
1812       pragma Assert (Node /= null);
1813       pragma Assert (Node.Element /= null);
1814 
1815       function New_Node return Node_Access;
1816       pragma Inline (New_Node);
1817 
1818       procedure Local_Insert_Post is
1819         new Element_Keys.Generic_Insert_Post (New_Node);
1820 
1821       procedure Local_Insert_Sans_Hint is
1822         new Element_Keys.Generic_Conditional_Insert (Local_Insert_Post);
1823 
1824       procedure Local_Insert_With_Hint is
1825         new Element_Keys.Generic_Conditional_Insert_With_Hint
1826           (Local_Insert_Post,
1827            Local_Insert_Sans_Hint);
1828 
1829       --------------
1830       -- New_Node --
1831       --------------
1832 
1833       function New_Node return Node_Access is
1834 
1835          --  The element allocator may need an accessibility check in the case
1836          --  the actual type is class-wide or has access discriminants (see
1837          --  RM 4.8(10.1) and AI12-0035).
1838 
1839          pragma Unsuppress (Accessibility_Check);
1840 
1841       begin
1842          Node.Element := new Element_Type'(Item);  -- OK if fails
1843          Node.Color := Red;
1844          Node.Parent := null;
1845          Node.Right := null;
1846          Node.Left := null;
1847          return Node;
1848       end New_Node;
1849 
1850       Hint     : Node_Access;
1851       Result   : Node_Access;
1852       Inserted : Boolean;
1853       Compare  : Boolean;
1854 
1855       X : Element_Access := Node.Element;
1856 
1857    --  Start of processing for Replace_Element
1858 
1859    begin
1860       --  Replace_Element assigns value Item to the element designated by Node,
1861       --  per certain semantic constraints, described as follows.
1862 
1863       --  If Item is equivalent to the element, then element is replaced and
1864       --  there's nothing else to do. This is the easy case.
1865 
1866       --  If Item is not equivalent, then the node will (possibly) have to move
1867       --  to some other place in the tree. This is slighly more complicated,
1868       --  because we must ensure that Item is not equivalent to some other
1869       --  element in the tree (in which case, the replacement is not allowed).
1870 
1871       --  Determine whether Item is equivalent to element on the specified
1872       --  node.
1873 
1874       declare
1875          Lock : With_Lock (Tree.TC'Unrestricted_Access);
1876       begin
1877          Compare := (if Item < Node.Element.all then False
1878                      elsif Node.Element.all < Item then False
1879                      else True);
1880       end;
1881 
1882       if Compare then
1883          --  Item is equivalent to the node's element, so we will not have to
1884          --  move the node.
1885 
1886          TE_Check (Tree.TC);
1887 
1888          declare
1889             --  The element allocator may need an accessibility check in the
1890             --  case the actual type is class-wide or has access discriminants
1891             --  (see RM 4.8(10.1) and AI12-0035).
1892 
1893             pragma Unsuppress (Accessibility_Check);
1894 
1895          begin
1896             Node.Element := new Element_Type'(Item);
1897             Free_Element (X);
1898          end;
1899 
1900          return;
1901       end if;
1902 
1903       --  The replacement Item is not equivalent to the element on the
1904       --  specified node, which means that it will need to be re-inserted in a
1905       --  different position in the tree. We must now determine whether Item is
1906       --  equivalent to some other element in the tree (which would prohibit
1907       --  the assignment and hence the move).
1908 
1909       --  Ceiling returns the smallest element equivalent or greater than the
1910       --  specified Item; if there is no such element, then it returns null.
1911 
1912       Hint := Element_Keys.Ceiling (Tree, Item);
1913 
1914       if Hint /= null then
1915          declare
1916             Lock : With_Lock (Tree.TC'Unrestricted_Access);
1917          begin
1918             Compare := Item < Hint.Element.all;
1919          end;
1920 
1921          --  Item >= Hint.Element
1922 
1923          if Checks and then not Compare then
1924 
1925             --  Ceiling returns an element that is equivalent or greater
1926             --  than Item. If Item is "not less than" the element, then
1927             --  by elimination we know that Item is equivalent to the element.
1928 
1929             --  But this means that it is not possible to assign the value of
1930             --  Item to the specified element (on Node), because a different
1931             --  element (on Hint) equivalent to Item already exsits. (Were we
1932             --  to change Node's element value, we would have to move Node, but
1933             --  we would be unable to move the Node, because its new position
1934             --  in the tree is already occupied by an equivalent element.)
1935 
1936             raise Program_Error with "attempt to replace existing element";
1937          end if;
1938 
1939          --  Item is not equivalent to any other element in the tree, so it is
1940          --  safe to assign the value of Item to Node.Element. This means that
1941          --  the node will have to move to a different position in the tree
1942          --  (because its element will have a different value).
1943 
1944          --  The nearest (greater) neighbor of Item is Hint. This will be the
1945          --  insertion position of Node (because its element will have Item as
1946          --  its new value).
1947 
1948          --  If Node equals Hint, the relative position of Node does not
1949          --  change. This allows us to perform an optimization: we need not
1950          --  remove Node from the tree and then reinsert it with its new value,
1951          --  because it would only be placed in the exact same position.
1952 
1953          if Hint = Node then
1954             TE_Check (Tree.TC);
1955 
1956             declare
1957                --  The element allocator may need an accessibility check in the
1958                --  case actual type is class-wide or has access discriminants
1959                --  (see RM 4.8(10.1) and AI12-0035).
1960 
1961                pragma Unsuppress (Accessibility_Check);
1962 
1963             begin
1964                Node.Element := new Element_Type'(Item);
1965                Free_Element (X);
1966             end;
1967 
1968             return;
1969          end if;
1970       end if;
1971 
1972       --  If we get here, it is because Item was greater than all elements in
1973       --  the tree (Hint = null), or because Item was less than some element at
1974       --  a different place in the tree (Item < Hint.Element.all). In either
1975       --  case, we remove Node from the tree (without actually deallocating
1976       --  it), and then insert Item into the tree, onto the same Node (so no
1977       --  new node is actually allocated).
1978 
1979       Tree_Operations.Delete_Node_Sans_Free (Tree, Node);  -- Checks busy-bit
1980 
1981       Local_Insert_With_Hint
1982         (Tree     => Tree,
1983          Position => Hint,
1984          Key      => Item,
1985          Node     => Result,
1986          Inserted => Inserted);
1987 
1988       pragma Assert (Inserted);
1989       pragma Assert (Result = Node);
1990 
1991       Free_Element (X);
1992    end Replace_Element;
1993 
1994    procedure Replace_Element
1995     (Container : in out Set;
1996      Position  : Cursor;
1997      New_Item  : Element_Type)
1998    is
1999    begin
2000       if Checks and then Position.Node = null then
2001          raise Constraint_Error with "Position cursor equals No_Element";
2002       end if;
2003 
2004       if Checks and then Position.Node.Element = null then
2005          raise Program_Error with "Position cursor is bad";
2006       end if;
2007 
2008       if Checks and then Position.Container /= Container'Unrestricted_Access
2009       then
2010          raise Program_Error with "Position cursor designates wrong set";
2011       end if;
2012 
2013       pragma Assert (Vet (Container.Tree, Position.Node),
2014                      "bad cursor in Replace_Element");
2015 
2016       Replace_Element (Container.Tree, Position.Node, New_Item);
2017    end Replace_Element;
2018 
2019    ---------------------
2020    -- Reverse_Iterate --
2021    ---------------------
2022 
2023    procedure Reverse_Iterate
2024      (Container : Set;
2025       Process   : not null access procedure (Position : Cursor))
2026    is
2027       procedure Process_Node (Node : Node_Access);
2028       pragma Inline (Process_Node);
2029 
2030       procedure Local_Reverse_Iterate is
2031          new Tree_Operations.Generic_Reverse_Iteration (Process_Node);
2032 
2033       ------------------
2034       -- Process_Node --
2035       ------------------
2036 
2037       procedure Process_Node (Node : Node_Access) is
2038       begin
2039          Process (Cursor'(Container'Unrestricted_Access, Node));
2040       end Process_Node;
2041 
2042       T : Tree_Type renames Container.Tree'Unrestricted_Access.all;
2043       Busy : With_Busy (T.TC'Unrestricted_Access);
2044 
2045    --  Start of processing for Reverse_Iterate
2046 
2047    begin
2048       Local_Reverse_Iterate (T);
2049    end Reverse_Iterate;
2050 
2051    -----------
2052    -- Right --
2053    -----------
2054 
2055    function Right (Node : Node_Access) return Node_Access is
2056    begin
2057       return Node.Right;
2058    end Right;
2059 
2060    ---------------
2061    -- Set_Color --
2062    ---------------
2063 
2064    procedure Set_Color (Node : Node_Access; Color : Color_Type) is
2065    begin
2066       Node.Color := Color;
2067    end Set_Color;
2068 
2069    --------------
2070    -- Set_Left --
2071    --------------
2072 
2073    procedure Set_Left (Node : Node_Access; Left : Node_Access) is
2074    begin
2075       Node.Left := Left;
2076    end Set_Left;
2077 
2078    ----------------
2079    -- Set_Parent --
2080    ----------------
2081 
2082    procedure Set_Parent (Node : Node_Access; Parent : Node_Access) is
2083    begin
2084       Node.Parent := Parent;
2085    end Set_Parent;
2086 
2087    ---------------
2088    -- Set_Right --
2089    ---------------
2090 
2091    procedure Set_Right (Node : Node_Access; Right : Node_Access) is
2092    begin
2093       Node.Right := Right;
2094    end Set_Right;
2095 
2096    --------------------------
2097    -- Symmetric_Difference --
2098    --------------------------
2099 
2100    procedure Symmetric_Difference (Target : in out Set; Source : Set) is
2101    begin
2102       Set_Ops.Symmetric_Difference (Target.Tree, Source.Tree);
2103    end Symmetric_Difference;
2104 
2105    function Symmetric_Difference (Left, Right : Set) return Set is
2106       Tree : constant Tree_Type :=
2107         Set_Ops.Symmetric_Difference (Left.Tree, Right.Tree);
2108    begin
2109       return Set'(Controlled with Tree);
2110    end Symmetric_Difference;
2111 
2112    ------------
2113    -- To_Set --
2114    ------------
2115 
2116    function To_Set (New_Item : Element_Type) return Set is
2117       Tree     : Tree_Type;
2118       Node     : Node_Access;
2119       Inserted : Boolean;
2120       pragma Unreferenced (Node, Inserted);
2121    begin
2122       Insert_Sans_Hint (Tree, New_Item, Node, Inserted);
2123       return Set'(Controlled with Tree);
2124    end To_Set;
2125 
2126    -----------
2127    -- Union --
2128    -----------
2129 
2130    procedure Union (Target : in out Set; Source : Set) is
2131    begin
2132       Set_Ops.Union (Target.Tree, Source.Tree);
2133    end Union;
2134 
2135    function Union (Left, Right : Set) return Set is
2136       Tree : constant Tree_Type := Set_Ops.Union (Left.Tree, Right.Tree);
2137    begin
2138       return Set'(Controlled with Tree);
2139    end Union;
2140 
2141    -----------
2142    -- Write --
2143    -----------
2144 
2145    procedure Write
2146      (Stream    : not null access Root_Stream_Type'Class;
2147       Container : Set)
2148    is
2149       procedure Write_Node
2150         (Stream : not null access Root_Stream_Type'Class;
2151          Node   : Node_Access);
2152       pragma Inline (Write_Node);
2153 
2154       procedure Write is
2155          new Tree_Operations.Generic_Write (Write_Node);
2156 
2157       ----------------
2158       -- Write_Node --
2159       ----------------
2160 
2161       procedure Write_Node
2162         (Stream : not null access Root_Stream_Type'Class;
2163          Node   : Node_Access)
2164       is
2165       begin
2166          Element_Type'Output (Stream, Node.Element.all);
2167       end Write_Node;
2168 
2169    --  Start of processing for Write
2170 
2171    begin
2172       Write (Stream, Container.Tree);
2173    end Write;
2174 
2175    procedure Write
2176      (Stream : not null access Root_Stream_Type'Class;
2177       Item   : Cursor)
2178    is
2179    begin
2180       raise Program_Error with "attempt to stream set cursor";
2181    end Write;
2182 
2183    procedure Write
2184      (Stream : not null access Root_Stream_Type'Class;
2185       Item   : Constant_Reference_Type)
2186    is
2187    begin
2188       raise Program_Error with "attempt to stream reference";
2189    end Write;
2190 
2191 end Ada.Containers.Indefinite_Ordered_Sets;