1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . O R D E R E D _ S E T S --
9 -- Copyright (C) 2004-2017, Free Software Foundation, Inc. --
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. --
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. --
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/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada
.Unchecked_Deallocation
;
32 with Ada
.Containers
.Helpers
; use Ada
.Containers
.Helpers
;
34 with Ada
.Containers
.Red_Black_Trees
.Generic_Operations
;
35 pragma Elaborate_All
(Ada
.Containers
.Red_Black_Trees
.Generic_Operations
);
37 with Ada
.Containers
.Red_Black_Trees
.Generic_Keys
;
38 pragma Elaborate_All
(Ada
.Containers
.Red_Black_Trees
.Generic_Keys
);
40 with Ada
.Containers
.Red_Black_Trees
.Generic_Set_Operations
;
41 pragma Elaborate_All
(Ada
.Containers
.Red_Black_Trees
.Generic_Set_Operations
);
43 with System
; use type System
.Address
;
45 package body Ada
.Containers
.Ordered_Sets
is
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
51 ------------------------------
52 -- Access to Fields of Node --
53 ------------------------------
55 -- These subprograms provide functional notation for access to fields
56 -- of a node, and procedural notation for modifying these fields.
58 function Color
(Node
: Node_Access
) return Color_Type
;
59 pragma Inline
(Color
);
61 function Left
(Node
: Node_Access
) return Node_Access
;
64 function Parent
(Node
: Node_Access
) return Node_Access
;
65 pragma Inline
(Parent
);
67 function Right
(Node
: Node_Access
) return Node_Access
;
68 pragma Inline
(Right
);
70 procedure Set_Color
(Node
: Node_Access
; Color
: Color_Type
);
71 pragma Inline
(Set_Color
);
73 procedure Set_Left
(Node
: Node_Access
; Left
: Node_Access
);
74 pragma Inline
(Set_Left
);
76 procedure Set_Right
(Node
: Node_Access
; Right
: Node_Access
);
77 pragma Inline
(Set_Right
);
79 procedure Set_Parent
(Node
: Node_Access
; Parent
: Node_Access
);
80 pragma Inline
(Set_Parent
);
82 -----------------------
83 -- Local Subprograms --
84 -----------------------
86 function Copy_Node
(Source
: Node_Access
) return Node_Access
;
87 pragma Inline
(Copy_Node
);
89 procedure Free
(X
: in out Node_Access
);
91 procedure Insert_Sans_Hint
92 (Tree
: in out Tree_Type
;
93 New_Item
: Element_Type
;
94 Node
: out Node_Access
;
95 Inserted
: out Boolean);
97 procedure Insert_With_Hint
98 (Dst_Tree
: in out Tree_Type
;
99 Dst_Hint
: Node_Access
;
100 Src_Node
: Node_Access
;
101 Dst_Node
: out Node_Access
);
103 function Is_Equal_Node_Node
(L
, R
: Node_Access
) return Boolean;
104 pragma Inline
(Is_Equal_Node_Node
);
106 function Is_Greater_Element_Node
107 (Left
: Element_Type
;
108 Right
: Node_Access
) return Boolean;
109 pragma Inline
(Is_Greater_Element_Node
);
111 function Is_Less_Element_Node
112 (Left
: Element_Type
;
113 Right
: Node_Access
) return Boolean;
114 pragma Inline
(Is_Less_Element_Node
);
116 function Is_Less_Node_Node
(L
, R
: Node_Access
) return Boolean;
117 pragma Inline
(Is_Less_Node_Node
);
119 procedure Replace_Element
120 (Tree
: in out Tree_Type
;
122 Item
: Element_Type
);
124 --------------------------
125 -- Local Instantiations --
126 --------------------------
128 package Tree_Operations
is
129 new Red_Black_Trees
.Generic_Operations
(Tree_Types
);
131 procedure Delete_Tree
is
132 new Tree_Operations
.Generic_Delete_Tree
(Free
);
134 function Copy_Tree
is
135 new Tree_Operations
.Generic_Copy_Tree
(Copy_Node
, Delete_Tree
);
140 new Tree_Operations
.Generic_Equal
(Is_Equal_Node_Node
);
142 package Element_Keys
is
143 new Red_Black_Trees
.Generic_Keys
144 (Tree_Operations
=> Tree_Operations
,
145 Key_Type
=> Element_Type
,
146 Is_Less_Key_Node
=> Is_Less_Element_Node
,
147 Is_Greater_Key_Node
=> Is_Greater_Element_Node
);
150 new Generic_Set_Operations
151 (Tree_Operations
=> Tree_Operations
,
152 Insert_With_Hint
=> Insert_With_Hint
,
153 Copy_Tree
=> Copy_Tree
,
154 Delete_Tree
=> Delete_Tree
,
155 Is_Less
=> Is_Less_Node_Node
,
162 function "<" (Left
, Right
: Cursor
) return Boolean is
164 if Checks
and then Left
.Node
= null then
165 raise Constraint_Error
with "Left cursor equals No_Element";
168 if Checks
and then Right
.Node
= null then
169 raise Constraint_Error
with "Right cursor equals No_Element";
172 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
173 "bad Left cursor in ""<""");
175 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
176 "bad Right cursor in ""<""");
178 return Left
.Node
.Element
< Right
.Node
.Element
;
181 function "<" (Left
: Cursor
; Right
: Element_Type
) return Boolean is
183 if Checks
and then Left
.Node
= null then
184 raise Constraint_Error
with "Left cursor equals No_Element";
187 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
188 "bad Left cursor in ""<""");
190 return Left
.Node
.Element
< Right
;
193 function "<" (Left
: Element_Type
; Right
: Cursor
) return Boolean is
195 if Checks
and then Right
.Node
= null then
196 raise Constraint_Error
with "Right cursor equals No_Element";
199 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
200 "bad Right cursor in ""<""");
202 return Left
< Right
.Node
.Element
;
209 function "=" (Left
, Right
: Set
) return Boolean is
211 return Is_Equal
(Left
.Tree
, Right
.Tree
);
218 function ">" (Left
, Right
: Cursor
) return Boolean is
220 if Checks
and then Left
.Node
= null then
221 raise Constraint_Error
with "Left cursor equals No_Element";
224 if Checks
and then Right
.Node
= null then
225 raise Constraint_Error
with "Right cursor equals No_Element";
228 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
229 "bad Left cursor in "">""");
231 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
232 "bad Right cursor in "">""");
234 -- L > R same as R < L
236 return Right
.Node
.Element
< Left
.Node
.Element
;
239 function ">" (Left
: Element_Type
; Right
: Cursor
) return Boolean is
241 if Checks
and then Right
.Node
= null then
242 raise Constraint_Error
with "Right cursor equals No_Element";
245 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
246 "bad Right cursor in "">""");
248 return Right
.Node
.Element
< Left
;
251 function ">" (Left
: Cursor
; Right
: Element_Type
) return Boolean is
253 if Checks
and then Left
.Node
= null then
254 raise Constraint_Error
with "Left cursor equals No_Element";
257 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
258 "bad Left cursor in "">""");
260 return Right
< Left
.Node
.Element
;
267 procedure Adjust
is new Tree_Operations
.Generic_Adjust
(Copy_Tree
);
269 procedure Adjust
(Container
: in out Set
) is
271 Adjust
(Container
.Tree
);
278 procedure Assign
(Target
: in out Set
; Source
: Set
) is
280 if Target
'Address = Source
'Address then
285 Target
.Union
(Source
);
292 function Ceiling
(Container
: Set
; Item
: Element_Type
) return Cursor
is
293 Node
: constant Node_Access
:=
294 Element_Keys
.Ceiling
(Container
.Tree
, Item
);
296 return (if Node
= null then No_Element
297 else Cursor
'(Container'Unrestricted_Access, Node));
304 procedure Clear is new Tree_Operations.Generic_Clear (Delete_Tree);
306 procedure Clear (Container : in out Set) is
308 Clear (Container.Tree);
315 function Color (Node : Node_Access) return Color_Type is
320 ------------------------
321 -- Constant_Reference --
322 ------------------------
324 function Constant_Reference
325 (Container : aliased Set;
326 Position : Cursor) return Constant_Reference_Type
329 if Checks and then Position.Container = null then
330 raise Constraint_Error with "Position cursor has no element";
333 if Checks and then Position.Container /= Container'Unrestricted_Access
335 raise Program_Error with
336 "Position cursor designates wrong container";
340 (Vet (Container.Tree, Position.Node),
341 "bad cursor in Constant_Reference");
344 Tree : Tree_Type renames Position.Container.all.Tree;
345 TC : constant Tamper_Counts_Access :=
346 Tree.TC'Unrestricted_Access;
348 return R : constant Constant_Reference_Type :=
349 (Element => Position.Node.Element'Access,
350 Control => (Controlled with TC))
355 end Constant_Reference;
363 Item : Element_Type) return Boolean
366 return Find (Container, Item) /= No_Element;
373 function Copy (Source : Set) return Set is
375 return Target : Set do
376 Target.Assign (Source);
384 function Copy_Node (Source : Node_Access) return Node_Access is
385 Target : constant Node_Access :=
386 new Node_Type'(Parent
=> null,
389 Color
=> Source
.Color
,
390 Element
=> Source
.Element
);
399 procedure Delete
(Container
: in out Set
; Position
: in out Cursor
) is
401 if Checks
and then Position
.Node
= null then
402 raise Constraint_Error
with "Position cursor equals No_Element";
405 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
407 raise Program_Error
with "Position cursor designates wrong set";
410 pragma Assert
(Vet
(Container
.Tree
, Position
.Node
),
411 "bad cursor in Delete");
413 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, Position
.Node
);
414 Free
(Position
.Node
);
415 Position
.Container
:= null;
418 procedure Delete
(Container
: in out Set
; Item
: Element_Type
) is
419 X
: Node_Access
:= Element_Keys
.Find
(Container
.Tree
, Item
);
422 if Checks
and then X
= null then
423 raise Constraint_Error
with "attempt to delete element not in set";
426 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, X
);
434 procedure Delete_First
(Container
: in out Set
) is
435 Tree
: Tree_Type
renames Container
.Tree
;
436 X
: Node_Access
:= Tree
.First
;
439 Tree_Operations
.Delete_Node_Sans_Free
(Tree
, X
);
448 procedure Delete_Last
(Container
: in out Set
) is
449 Tree
: Tree_Type
renames Container
.Tree
;
450 X
: Node_Access
:= Tree
.Last
;
453 Tree_Operations
.Delete_Node_Sans_Free
(Tree
, X
);
462 procedure Difference
(Target
: in out Set
; Source
: Set
) is
464 Set_Ops
.Difference
(Target
.Tree
, Source
.Tree
);
467 function Difference
(Left
, Right
: Set
) return Set
is
468 Tree
: constant Tree_Type
:= Set_Ops
.Difference
(Left
.Tree
, Right
.Tree
);
470 return Set
'(Controlled with Tree);
477 function Element (Position : Cursor) return Element_Type is
479 if Checks and then Position.Node = null then
480 raise Constraint_Error with "Position cursor equals No_Element";
483 pragma Assert (Vet (Position.Container.Tree, Position.Node),
484 "bad cursor in Element");
486 return Position.Node.Element;
489 -------------------------
490 -- Equivalent_Elements --
491 -------------------------
493 function Equivalent_Elements (Left, Right : Element_Type) return Boolean is
495 return (if Left < Right or else Right < Left then False else True);
496 end Equivalent_Elements;
498 ---------------------
499 -- Equivalent_Sets --
500 ---------------------
502 function Equivalent_Sets (Left, Right : Set) return Boolean is
503 function Is_Equivalent_Node_Node (L, R : Node_Access) return Boolean;
504 pragma Inline (Is_Equivalent_Node_Node);
506 function Is_Equivalent is
507 new Tree_Operations.Generic_Equal (Is_Equivalent_Node_Node);
509 -----------------------------
510 -- Is_Equivalent_Node_Node --
511 -----------------------------
513 function Is_Equivalent_Node_Node (L, R : Node_Access) return Boolean is
515 return (if L.Element < R.Element then False
516 elsif R.Element < L.Element then False
518 end Is_Equivalent_Node_Node;
520 -- Start of processing for Equivalent_Sets
523 return Is_Equivalent (Left.Tree, Right.Tree);
530 procedure Exclude (Container : in out Set; Item : Element_Type) is
531 X : Node_Access := Element_Keys.Find (Container.Tree, Item);
535 Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
544 procedure Finalize (Object : in out Iterator) is
546 if Object.Container /= null then
547 Unbusy (Object.Container.Tree.TC);
555 function Find (Container : Set; Item : Element_Type) return Cursor is
556 Node : constant Node_Access := Element_Keys.Find (Container.Tree, Item);
558 return (if Node = null then No_Element
559 else Cursor'(Container
'Unrestricted_Access, Node
));
566 function First
(Container
: Set
) return Cursor
is
569 (if Container
.Tree
.First
= null then No_Element
570 else Cursor
'(Container'Unrestricted_Access, Container.Tree.First));
573 function First (Object : Iterator) return Cursor is
575 -- The value of the iterator object's Node component influences the
576 -- behavior of the First (and Last) selector function.
578 -- When the Node component is null, this means the iterator object was
579 -- constructed without a start expression, in which case the (forward)
580 -- iteration starts from the (logical) beginning of the entire sequence
581 -- of items (corresponding to Container.First, for a forward iterator).
583 -- Otherwise, this is iteration over a partial sequence of items. When
584 -- the Node component is non-null, the iterator object was constructed
585 -- with a start expression, that specifies the position from which the
586 -- (forward) partial iteration begins.
588 if Object.Node = null then
589 return Object.Container.First;
591 return Cursor'(Object
.Container
, Object
.Node
);
599 function First_Element
(Container
: Set
) return Element_Type
is
601 if Checks
and then Container
.Tree
.First
= null then
602 raise Constraint_Error
with "set is empty";
605 return Container
.Tree
.First
.Element
;
612 function Floor
(Container
: Set
; Item
: Element_Type
) return Cursor
is
613 Node
: constant Node_Access
:= Element_Keys
.Floor
(Container
.Tree
, Item
);
615 return (if Node
= null then No_Element
616 else Cursor
'(Container'Unrestricted_Access, Node));
623 procedure Free (X : in out Node_Access) is
624 procedure Deallocate is
625 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
639 package body Generic_Keys is
641 -----------------------
642 -- Local Subprograms --
643 -----------------------
645 function Is_Greater_Key_Node
647 Right : Node_Access) return Boolean;
648 pragma Inline (Is_Greater_Key_Node);
650 function Is_Less_Key_Node
652 Right : Node_Access) return Boolean;
653 pragma Inline (Is_Less_Key_Node);
655 --------------------------
656 -- Local Instantiations --
657 --------------------------
660 new Red_Black_Trees.Generic_Keys
661 (Tree_Operations => Tree_Operations,
662 Key_Type => Key_Type,
663 Is_Less_Key_Node => Is_Less_Key_Node,
664 Is_Greater_Key_Node => Is_Greater_Key_Node);
670 function Ceiling (Container : Set; Key : Key_Type) return Cursor is
671 Node : constant Node_Access := Key_Keys.Ceiling (Container.Tree, Key);
673 return (if Node = null then No_Element
674 else Cursor'(Container
'Unrestricted_Access, Node
));
677 ------------------------
678 -- Constant_Reference --
679 ------------------------
681 function Constant_Reference
682 (Container
: aliased Set
;
683 Key
: Key_Type
) return Constant_Reference_Type
685 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
688 if Checks
and then Node
= null then
689 raise Constraint_Error
with "key not in set";
693 Tree
: Tree_Type
renames Container
'Unrestricted_Access.all.Tree
;
694 TC
: constant Tamper_Counts_Access
:=
695 Tree
.TC
'Unrestricted_Access;
697 return R
: constant Constant_Reference_Type
:=
698 (Element
=> Node
.Element
'Access,
699 Control
=> (Controlled
with TC
))
704 end Constant_Reference
;
710 function Contains
(Container
: Set
; Key
: Key_Type
) return Boolean is
712 return Find
(Container
, Key
) /= No_Element
;
719 procedure Delete
(Container
: in out Set
; Key
: Key_Type
) is
720 X
: Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
723 if Checks
and then X
= null then
724 raise Constraint_Error
with "attempt to delete key not in set";
727 Delete_Node_Sans_Free
(Container
.Tree
, X
);
735 function Element
(Container
: Set
; Key
: Key_Type
) return Element_Type
is
736 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
739 if Checks
and then Node
= null then
740 raise Constraint_Error
with "key not in set";
746 ---------------------
747 -- Equivalent_Keys --
748 ---------------------
750 function Equivalent_Keys
(Left
, Right
: Key_Type
) return Boolean is
752 return (if Left
< Right
or else Right
< Left
then False else True);
759 procedure Exclude
(Container
: in out Set
; Key
: Key_Type
) is
760 X
: Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
763 Delete_Node_Sans_Free
(Container
.Tree
, X
);
772 procedure Finalize
(Control
: in out Reference_Control_Type
) is
774 if Control
.Container
/= null then
775 Impl
.Reference_Control_Type
(Control
).Finalize
;
777 if Checks
and then not (Key
(Control
.Pos
) = Control
.Old_Key
.all)
779 Delete
(Control
.Container
.all, Key
(Control
.Pos
));
783 Control
.Container
:= null;
784 Control
.Old_Key
:= null;
792 function Find
(Container
: Set
; Key
: Key_Type
) return Cursor
is
793 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
795 return (if Node
= null then No_Element
796 else Cursor
'(Container'Unrestricted_Access, Node));
803 function Floor (Container : Set; Key : Key_Type) return Cursor is
804 Node : constant Node_Access := Key_Keys.Floor (Container.Tree, Key);
806 return (if Node = null then No_Element
807 else Cursor'(Container
'Unrestricted_Access, Node
));
810 -------------------------
811 -- Is_Greater_Key_Node --
812 -------------------------
814 function Is_Greater_Key_Node
816 Right
: Node_Access
) return Boolean
819 return Key
(Right
.Element
) < Left
;
820 end Is_Greater_Key_Node
;
822 ----------------------
823 -- Is_Less_Key_Node --
824 ----------------------
826 function Is_Less_Key_Node
828 Right
: Node_Access
) return Boolean
831 return Left
< Key
(Right
.Element
);
832 end Is_Less_Key_Node
;
838 function Key
(Position
: Cursor
) return Key_Type
is
840 if Checks
and then Position
.Node
= null then
841 raise Constraint_Error
with
842 "Position cursor equals No_Element";
845 pragma Assert
(Vet
(Position
.Container
.Tree
, Position
.Node
),
846 "bad cursor in Key");
848 return Key
(Position
.Node
.Element
);
856 (Stream
: not null access Root_Stream_Type
'Class;
857 Item
: out Reference_Type
)
860 raise Program_Error
with "attempt to stream reference";
863 ------------------------------
864 -- Reference_Preserving_Key --
865 ------------------------------
867 function Reference_Preserving_Key
868 (Container
: aliased in out Set
;
869 Position
: Cursor
) return Reference_Type
872 if Checks
and then Position
.Container
= null then
873 raise Constraint_Error
with "Position cursor has no element";
876 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
878 raise Program_Error
with
879 "Position cursor designates wrong container";
883 (Vet
(Container
.Tree
, Position
.Node
),
884 "bad cursor in function Reference_Preserving_Key");
887 Tree
: Tree_Type
renames Container
.Tree
;
889 return R
: constant Reference_Type
:=
890 (Element
=> Position
.Node
.Element
'Access,
893 Tree
.TC
'Unrestricted_Access,
894 Container
=> Container
'Access,
896 Old_Key
=> new Key_Type
'(Key (Position))))
901 end Reference_Preserving_Key;
903 function Reference_Preserving_Key
904 (Container : aliased in out Set;
905 Key : Key_Type) return Reference_Type
907 Node : constant Node_Access := Key_Keys.Find (Container.Tree, Key);
910 if Checks and then Node = null then
911 raise Constraint_Error with "Key not in set";
915 Tree : Tree_Type renames Container.Tree;
917 return R : constant Reference_Type :=
918 (Element => Node.Element'Access,
921 Tree.TC'Unrestricted_Access,
922 Container => Container'Access,
923 Pos => Find (Container, Key),
924 Old_Key => new Key_Type'(Key
)))
929 end Reference_Preserving_Key
;
936 (Container
: in out Set
;
938 New_Item
: Element_Type
)
940 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
943 if Checks
and then Node
= null then
944 raise Constraint_Error
with
945 "attempt to replace key not in set";
948 Replace_Element
(Container
.Tree
, Node
, New_Item
);
951 -----------------------------------
952 -- Update_Element_Preserving_Key --
953 -----------------------------------
955 procedure Update_Element_Preserving_Key
956 (Container
: in out Set
;
958 Process
: not null access procedure (Element
: in out Element_Type
))
960 Tree
: Tree_Type
renames Container
.Tree
;
963 if Checks
and then Position
.Node
= null then
964 raise Constraint_Error
with
965 "Position cursor equals No_Element";
968 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
970 raise Program_Error
with
971 "Position cursor designates wrong set";
974 pragma Assert
(Vet
(Container
.Tree
, Position
.Node
),
975 "bad cursor in Update_Element_Preserving_Key");
978 E
: Element_Type
renames Position
.Node
.Element
;
979 K
: constant Key_Type
:= Key
(E
);
980 Lock
: With_Lock
(Tree
.TC
'Unrestricted_Access);
983 if Equivalent_Keys
(K
, Key
(E
)) then
989 X
: Node_Access
:= Position
.Node
;
991 Tree_Operations
.Delete_Node_Sans_Free
(Tree
, X
);
995 raise Program_Error
with "key was modified";
996 end Update_Element_Preserving_Key
;
1003 (Stream
: not null access Root_Stream_Type
'Class;
1004 Item
: Reference_Type
)
1007 raise Program_Error
with "attempt to stream reference";
1012 ------------------------
1013 -- Get_Element_Access --
1014 ------------------------
1016 function Get_Element_Access
1017 (Position
: Cursor
) return not null Element_Access
is
1019 return Position
.Node
.Element
'Access;
1020 end Get_Element_Access
;
1026 function Has_Element
(Position
: Cursor
) return Boolean is
1028 return Position
/= No_Element
;
1035 procedure Include
(Container
: in out Set
; New_Item
: Element_Type
) is
1040 Insert
(Container
, New_Item
, Position
, Inserted
);
1042 if not Inserted
then
1043 TE_Check
(Container
.Tree
.TC
);
1045 Position
.Node
.Element
:= New_Item
;
1054 (Container
: in out Set
;
1055 New_Item
: Element_Type
;
1056 Position
: out Cursor
;
1057 Inserted
: out Boolean)
1066 Position
.Container
:= Container
'Unrestricted_Access;
1070 (Container
: in out Set
;
1071 New_Item
: Element_Type
)
1074 pragma Unreferenced
(Position
);
1079 Insert
(Container
, New_Item
, Position
, Inserted
);
1081 if Checks
and then not Inserted
then
1082 raise Constraint_Error
with
1083 "attempt to insert element already in set";
1087 ----------------------
1088 -- Insert_Sans_Hint --
1089 ----------------------
1091 procedure Insert_Sans_Hint
1092 (Tree
: in out Tree_Type
;
1093 New_Item
: Element_Type
;
1094 Node
: out Node_Access
;
1095 Inserted
: out Boolean)
1097 function New_Node
return Node_Access
;
1098 pragma Inline
(New_Node
);
1100 procedure Insert_Post
is
1101 new Element_Keys
.Generic_Insert_Post
(New_Node
);
1103 procedure Conditional_Insert_Sans_Hint
is
1104 new Element_Keys
.Generic_Conditional_Insert
(Insert_Post
);
1110 function New_Node
return Node_Access
is
1112 return new Node_Type
'(Parent => null,
1115 Color => Red_Black_Trees.Red,
1116 Element => New_Item);
1119 -- Start of processing for Insert_Sans_Hint
1122 Conditional_Insert_Sans_Hint
1127 end Insert_Sans_Hint;
1129 ----------------------
1130 -- Insert_With_Hint --
1131 ----------------------
1133 procedure Insert_With_Hint
1134 (Dst_Tree : in out Tree_Type;
1135 Dst_Hint : Node_Access;
1136 Src_Node : Node_Access;
1137 Dst_Node : out Node_Access)
1140 pragma Unreferenced (Success);
1142 function New_Node return Node_Access;
1143 pragma Inline (New_Node);
1145 procedure Insert_Post is
1146 new Element_Keys.Generic_Insert_Post (New_Node);
1148 procedure Insert_Sans_Hint is
1149 new Element_Keys.Generic_Conditional_Insert (Insert_Post);
1151 procedure Local_Insert_With_Hint is
1152 new Element_Keys.Generic_Conditional_Insert_With_Hint
1160 function New_Node return Node_Access is
1161 Node : constant Node_Access :=
1162 new Node_Type'(Parent
=> null,
1166 Element
=> Src_Node
.Element
);
1171 -- Start of processing for Insert_With_Hint
1174 Local_Insert_With_Hint
1180 end Insert_With_Hint
;
1186 procedure Intersection
(Target
: in out Set
; Source
: Set
) is
1188 Set_Ops
.Intersection
(Target
.Tree
, Source
.Tree
);
1191 function Intersection
(Left
, Right
: Set
) return Set
is
1192 Tree
: constant Tree_Type
:=
1193 Set_Ops
.Intersection
(Left
.Tree
, Right
.Tree
);
1195 return Set
'(Controlled with Tree);
1202 function Is_Empty (Container : Set) return Boolean is
1204 return Container.Tree.Length = 0;
1207 ------------------------
1208 -- Is_Equal_Node_Node --
1209 ------------------------
1211 function Is_Equal_Node_Node (L, R : Node_Access) return Boolean is
1213 return L.Element = R.Element;
1214 end Is_Equal_Node_Node;
1216 -----------------------------
1217 -- Is_Greater_Element_Node --
1218 -----------------------------
1220 function Is_Greater_Element_Node
1221 (Left : Element_Type;
1222 Right : Node_Access) return Boolean
1225 -- Compute e > node same as node < e
1227 return Right.Element < Left;
1228 end Is_Greater_Element_Node;
1230 --------------------------
1231 -- Is_Less_Element_Node --
1232 --------------------------
1234 function Is_Less_Element_Node
1235 (Left : Element_Type;
1236 Right : Node_Access) return Boolean
1239 return Left < Right.Element;
1240 end Is_Less_Element_Node;
1242 -----------------------
1243 -- Is_Less_Node_Node --
1244 -----------------------
1246 function Is_Less_Node_Node (L, R : Node_Access) return Boolean is
1248 return L.Element < R.Element;
1249 end Is_Less_Node_Node;
1255 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
1257 return Set_Ops.Is_Subset (Subset => Subset.Tree, Of_Set => Of_Set.Tree);
1266 Process : not null access procedure (Position : Cursor))
1268 procedure Process_Node (Node : Node_Access);
1269 pragma Inline (Process_Node);
1271 procedure Local_Iterate is
1272 new Tree_Operations.Generic_Iteration (Process_Node);
1278 procedure Process_Node (Node : Node_Access) is
1280 Process (Cursor'(Container
'Unrestricted_Access, Node
));
1283 T
: Tree_Type
renames Container
'Unrestricted_Access.all.Tree
;
1284 Busy
: With_Busy
(T
.TC
'Unrestricted_Access);
1286 -- Start of processing for Iterate
1292 function Iterate
(Container
: Set
)
1293 return Set_Iterator_Interfaces
.Reversible_Iterator
'Class
1296 -- The value of the Node component influences the behavior of the First
1297 -- and Last selector functions of the iterator object. When the Node
1298 -- component is null (as is the case here), this means the iterator
1299 -- object was constructed without a start expression. This is a complete
1300 -- iterator, meaning that the iteration starts from the (logical)
1301 -- beginning of the sequence of items.
1303 -- Note: For a forward iterator, Container.First is the beginning, and
1304 -- for a reverse iterator, Container.Last is the beginning.
1306 Busy
(Container
.Tree
.TC
'Unrestricted_Access.all);
1308 return It
: constant Iterator
:=
1309 Iterator
'(Limited_Controlled with
1310 Container => Container'Unrestricted_Access,
1314 function Iterate (Container : Set; Start : Cursor)
1315 return Set_Iterator_Interfaces.Reversible_Iterator'Class
1318 -- It was formerly the case that when Start = No_Element, the partial
1319 -- iterator was defined to behave the same as for a complete iterator,
1320 -- and iterate over the entire sequence of items. However, those
1321 -- semantics were unintuitive and arguably error-prone (it is too easy
1322 -- to accidentally create an endless loop), and so they were changed,
1323 -- per the ARG meeting in Denver on 2011/11. However, there was no
1324 -- consensus about what positive meaning this corner case should have,
1325 -- and so it was decided to simply raise an exception. This does imply,
1326 -- however, that it is not possible to use a partial iterator to specify
1327 -- an empty sequence of items.
1329 if Checks and then Start = No_Element then
1330 raise Constraint_Error with
1331 "Start position for iterator equals No_Element";
1334 if Checks and then Start.Container /= Container'Unrestricted_Access then
1335 raise Program_Error with
1336 "Start cursor of Iterate designates wrong set";
1339 pragma Assert (Vet (Container.Tree, Start.Node),
1340 "Start cursor of Iterate is bad");
1342 -- The value of the Node component influences the behavior of the First
1343 -- and Last selector functions of the iterator object. When the Node
1344 -- component is non-null (as is the case here), it means that this is a
1345 -- partial iteration, over a subset of the complete sequence of
1346 -- items. The iterator object was constructed with a start expression,
1347 -- indicating the position from which the iteration begins. Note that
1348 -- the start position has the same value irrespective of whether this is
1349 -- a forward or reverse iteration.
1351 Busy (Container.Tree.TC'Unrestricted_Access.all);
1353 return It : constant Iterator :=
1354 Iterator'(Limited_Controlled
with
1355 Container
=> Container
'Unrestricted_Access,
1356 Node
=> Start
.Node
);
1363 function Last
(Container
: Set
) return Cursor
is
1366 (if Container
.Tree
.Last
= null then No_Element
1367 else Cursor
'(Container'Unrestricted_Access, Container.Tree.Last));
1370 function Last (Object : Iterator) return Cursor is
1372 -- The value of the iterator object's Node component influences the
1373 -- behavior of the Last (and First) selector function.
1375 -- When the Node component is null, this means the iterator object was
1376 -- constructed without a start expression, in which case the (reverse)
1377 -- iteration starts from the (logical) beginning of the entire sequence
1378 -- (corresponding to Container.Last, for a reverse iterator).
1380 -- Otherwise, this is iteration over a partial sequence of items. When
1381 -- the Node component is non-null, the iterator object was constructed
1382 -- with a start expression, that specifies the position from which the
1383 -- (reverse) partial iteration begins.
1385 if Object.Node = null then
1386 return Object.Container.Last;
1388 return Cursor'(Object
.Container
, Object
.Node
);
1396 function Last_Element
(Container
: Set
) return Element_Type
is
1398 if Checks
and then Container
.Tree
.Last
= null then
1399 raise Constraint_Error
with "set is empty";
1402 return Container
.Tree
.Last
.Element
;
1409 function Left
(Node
: Node_Access
) return Node_Access
is
1418 function Length
(Container
: Set
) return Count_Type
is
1420 return Container
.Tree
.Length
;
1427 procedure Move
is new Tree_Operations
.Generic_Move
(Clear
);
1429 procedure Move
(Target
: in out Set
; Source
: in out Set
) is
1431 Move
(Target
=> Target
.Tree
, Source
=> Source
.Tree
);
1438 function Next
(Position
: Cursor
) return Cursor
is
1440 if Position
= No_Element
then
1444 pragma Assert
(Vet
(Position
.Container
.Tree
, Position
.Node
),
1445 "bad cursor in Next");
1448 Node
: constant Node_Access
:=
1449 Tree_Operations
.Next
(Position
.Node
);
1451 return (if Node
= null then No_Element
1452 else Cursor
'(Position.Container, Node));
1456 procedure Next (Position : in out Cursor) is
1458 Position := Next (Position);
1461 function Next (Object : Iterator; Position : Cursor) return Cursor is
1463 if Position.Container = null then
1467 if Checks and then Position.Container /= Object.Container then
1468 raise Program_Error with
1469 "Position cursor of Next designates wrong set";
1472 return Next (Position);
1479 function Overlap (Left, Right : Set) return Boolean is
1481 return Set_Ops.Overlap (Left.Tree, Right.Tree);
1488 function Parent (Node : Node_Access) return Node_Access is
1497 function Previous (Position : Cursor) return Cursor is
1499 if Position = No_Element then
1503 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1504 "bad cursor in Previous");
1507 Node : constant Node_Access :=
1508 Tree_Operations.Previous (Position.Node);
1510 return (if Node = null then No_Element
1511 else Cursor'(Position
.Container
, Node
));
1515 procedure Previous
(Position
: in out Cursor
) is
1517 Position
:= Previous
(Position
);
1520 function Previous
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
1522 if Position
.Container
= null then
1526 if Checks
and then Position
.Container
/= Object
.Container
then
1527 raise Program_Error
with
1528 "Position cursor of Previous designates wrong set";
1531 return Previous
(Position
);
1534 ----------------------
1535 -- Pseudo_Reference --
1536 ----------------------
1538 function Pseudo_Reference
1539 (Container
: aliased Set
'Class) return Reference_Control_Type
1541 TC
: constant Tamper_Counts_Access
:=
1542 Container
.Tree
.TC
'Unrestricted_Access;
1544 return R
: constant Reference_Control_Type
:= (Controlled
with TC
) do
1547 end Pseudo_Reference
;
1553 procedure Query_Element
1555 Process
: not null access procedure (Element
: Element_Type
))
1558 if Checks
and then Position
.Node
= null then
1559 raise Constraint_Error
with "Position cursor equals No_Element";
1562 pragma Assert
(Vet
(Position
.Container
.Tree
, Position
.Node
),
1563 "bad cursor in Query_Element");
1566 T
: Tree_Type
renames Position
.Container
.Tree
;
1567 Lock
: With_Lock
(T
.TC
'Unrestricted_Access);
1569 Process
(Position
.Node
.Element
);
1578 (Stream
: not null access Root_Stream_Type
'Class;
1579 Container
: out Set
)
1582 (Stream
: not null access Root_Stream_Type
'Class) return Node_Access
;
1583 pragma Inline
(Read_Node
);
1586 new Tree_Operations
.Generic_Read
(Clear
, Read_Node
);
1593 (Stream
: not null access Root_Stream_Type
'Class) return Node_Access
1595 Node
: Node_Access
:= new Node_Type
;
1597 Element_Type
'Read (Stream
, Node
.Element
);
1605 -- Start of processing for Read
1608 Read
(Stream
, Container
.Tree
);
1612 (Stream
: not null access Root_Stream_Type
'Class;
1616 raise Program_Error
with "attempt to stream set cursor";
1620 (Stream
: not null access Root_Stream_Type
'Class;
1621 Item
: out Constant_Reference_Type
)
1624 raise Program_Error
with "attempt to stream reference";
1631 procedure Replace
(Container
: in out Set
; New_Item
: Element_Type
) is
1632 Node
: constant Node_Access
:=
1633 Element_Keys
.Find
(Container
.Tree
, New_Item
);
1636 if Checks
and then Node
= null then
1637 raise Constraint_Error
with
1638 "attempt to replace element not in set";
1641 TE_Check
(Container
.Tree
.TC
);
1643 Node
.Element
:= New_Item
;
1646 ---------------------
1647 -- Replace_Element --
1648 ---------------------
1650 procedure Replace_Element
1651 (Tree
: in out Tree_Type
;
1653 Item
: Element_Type
)
1655 pragma Assert
(Node
/= null);
1657 function New_Node
return Node_Access
;
1658 pragma Inline
(New_Node
);
1660 procedure Local_Insert_Post
is
1661 new Element_Keys
.Generic_Insert_Post
(New_Node
);
1663 procedure Local_Insert_Sans_Hint
is
1664 new Element_Keys
.Generic_Conditional_Insert
(Local_Insert_Post
);
1666 procedure Local_Insert_With_Hint
is
1667 new Element_Keys
.Generic_Conditional_Insert_With_Hint
1669 Local_Insert_Sans_Hint
);
1675 function New_Node
return Node_Access
is
1677 Node
.Element
:= Item
;
1679 Node
.Parent
:= null;
1686 Result
: Node_Access
;
1690 -- Start of processing for Replace_Element
1693 -- Replace_Element assigns value Item to the element designated by Node,
1694 -- per certain semantic constraints.
1696 -- If Item is equivalent to the element, then element is replaced and
1697 -- there's nothing else to do. This is the easy case.
1699 -- If Item is not equivalent, then the node will (possibly) have to move
1700 -- to some other place in the tree. This is slighly more complicated,
1701 -- because we must ensure that Item is not equivalent to some other
1702 -- element in the tree (in which case, the replacement is not allowed).
1704 -- Determine whether Item is equivalent to element on the specified
1708 Lock
: With_Lock
(Tree
.TC
'Unrestricted_Access);
1710 Compare
:= (if Item
< Node
.Element
then False
1711 elsif Node
.Element
< Item
then False
1716 -- Item is equivalent to the node's element, so we will not have to
1721 Node
.Element
:= Item
;
1725 -- The replacement Item is not equivalent to the element on the
1726 -- specified node, which means that it will need to be re-inserted in a
1727 -- different position in the tree. We must now determine whether Item is
1728 -- equivalent to some other element in the tree (which would prohibit
1729 -- the assignment and hence the move).
1731 -- Ceiling returns the smallest element equivalent or greater than the
1732 -- specified Item; if there is no such element, then it returns null.
1734 Hint
:= Element_Keys
.Ceiling
(Tree
, Item
);
1736 if Hint
/= null then
1738 Lock
: With_Lock
(Tree
.TC
'Unrestricted_Access);
1740 Compare
:= Item
< Hint
.Element
;
1743 -- Item >= Hint.Element
1745 if Checks
and then not Compare
then
1747 -- Ceiling returns an element that is equivalent or greater
1748 -- than Item. If Item is "not less than" the element, then
1749 -- by elimination we know that Item is equivalent to the element.
1751 -- But this means that it is not possible to assign the value of
1752 -- Item to the specified element (on Node), because a different
1753 -- element (on Hint) equivalent to Item already exsits. (Were we
1754 -- to change Node's element value, we would have to move Node, but
1755 -- we would be unable to move the Node, because its new position
1756 -- in the tree is already occupied by an equivalent element.)
1758 raise Program_Error
with "attempt to replace existing element";
1761 -- Item is not equivalent to any other element in the tree, so it is
1762 -- safe to assign the value of Item to Node.Element. This means that
1763 -- the node will have to move to a different position in the tree
1764 -- (because its element will have a different value).
1766 -- The nearest (greater) neighbor of Item is Hint. This will be the
1767 -- insertion position of Node (because its element will have Item as
1770 -- If Node equals Hint, the relative position of Node does not
1771 -- change. This allows us to perform an optimization: we need not
1772 -- remove Node from the tree and then reinsert it with its new value,
1773 -- because it would only be placed in the exact same position.
1778 Node
.Element
:= Item
;
1783 -- If we get here, it is because Item was greater than all elements in
1784 -- the tree (Hint = null), or because Item was less than some element at
1785 -- a different place in the tree (Item < Hint.Element). In either case,
1786 -- we remove Node from the tree (without actually deallocating it), and
1787 -- then insert Item into the tree, onto the same Node (so no new node is
1788 -- actually allocated).
1790 Tree_Operations
.Delete_Node_Sans_Free
(Tree
, Node
); -- Checks busy-bit
1792 Local_Insert_With_Hint
-- use unconditional insert here instead???
1797 Inserted
=> Inserted
);
1799 pragma Assert
(Inserted
);
1800 pragma Assert
(Result
= Node
);
1801 end Replace_Element
;
1803 procedure Replace_Element
1804 (Container
: in out Set
;
1806 New_Item
: Element_Type
)
1809 if Checks
and then Position
.Node
= null then
1810 raise Constraint_Error
with
1811 "Position cursor equals No_Element";
1814 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
1816 raise Program_Error
with
1817 "Position cursor designates wrong set";
1820 pragma Assert
(Vet
(Container
.Tree
, Position
.Node
),
1821 "bad cursor in Replace_Element");
1823 Replace_Element
(Container
.Tree
, Position
.Node
, New_Item
);
1824 end Replace_Element
;
1826 ---------------------
1827 -- Reverse_Iterate --
1828 ---------------------
1830 procedure Reverse_Iterate
1832 Process
: not null access procedure (Position
: Cursor
))
1834 procedure Process_Node
(Node
: Node_Access
);
1835 pragma Inline
(Process_Node
);
1837 procedure Local_Reverse_Iterate
is
1838 new Tree_Operations
.Generic_Reverse_Iteration
(Process_Node
);
1844 procedure Process_Node
(Node
: Node_Access
) is
1846 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1849 T : Tree_Type renames Container.Tree'Unrestricted_Access.all;
1850 Busy : With_Busy (T.TC'Unrestricted_Access);
1852 -- Start of processing for Reverse_Iterate
1855 Local_Reverse_Iterate (T);
1856 end Reverse_Iterate;
1862 function Right (Node : Node_Access) return Node_Access is
1871 procedure Set_Color (Node : Node_Access; Color : Color_Type) is
1873 Node.Color := Color;
1880 procedure Set_Left (Node : Node_Access; Left : Node_Access) is
1889 procedure Set_Parent (Node : Node_Access; Parent : Node_Access) is
1891 Node.Parent := Parent;
1898 procedure Set_Right (Node : Node_Access; Right : Node_Access) is
1900 Node.Right := Right;
1903 --------------------------
1904 -- Symmetric_Difference --
1905 --------------------------
1907 procedure Symmetric_Difference (Target : in out Set; Source : Set) is
1909 Set_Ops.Symmetric_Difference (Target.Tree, Source.Tree);
1910 end Symmetric_Difference;
1912 function Symmetric_Difference (Left, Right : Set) return Set is
1913 Tree : constant Tree_Type :=
1914 Set_Ops.Symmetric_Difference (Left.Tree, Right.Tree);
1916 return Set'(Controlled
with Tree
);
1917 end Symmetric_Difference
;
1923 function To_Set
(New_Item
: Element_Type
) return Set
is
1927 pragma Unreferenced
(Node
, Inserted
);
1929 Insert_Sans_Hint
(Tree
, New_Item
, Node
, Inserted
);
1930 return Set
'(Controlled with Tree);
1937 procedure Union (Target : in out Set; Source : Set) is
1939 Set_Ops.Union (Target.Tree, Source.Tree);
1942 function Union (Left, Right : Set) return Set is
1943 Tree : constant Tree_Type :=
1944 Set_Ops.Union (Left.Tree, Right.Tree);
1946 return Set'(Controlled
with Tree
);
1954 (Stream
: not null access Root_Stream_Type
'Class;
1957 procedure Write_Node
1958 (Stream
: not null access Root_Stream_Type
'Class;
1959 Node
: Node_Access
);
1960 pragma Inline
(Write_Node
);
1963 new Tree_Operations
.Generic_Write
(Write_Node
);
1969 procedure Write_Node
1970 (Stream
: not null access Root_Stream_Type
'Class;
1974 Element_Type
'Write (Stream
, Node
.Element
);
1977 -- Start of processing for Write
1980 Write
(Stream
, Container
.Tree
);
1984 (Stream
: not null access Root_Stream_Type
'Class;
1988 raise Program_Error
with "attempt to stream set cursor";
1992 (Stream
: not null access Root_Stream_Type
'Class;
1993 Item
: Constant_Reference_Type
)
1996 raise Program_Error
with "attempt to stream reference";
1999 end Ada
.Containers
.Ordered_Sets
;