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