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-2014, 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
.Red_Black_Trees
.Generic_Operations
;
33 pragma Elaborate_All
(Ada
.Containers
.Red_Black_Trees
.Generic_Operations
);
35 with Ada
.Containers
.Red_Black_Trees
.Generic_Keys
;
36 pragma Elaborate_All
(Ada
.Containers
.Red_Black_Trees
.Generic_Keys
);
38 with Ada
.Containers
.Red_Black_Trees
.Generic_Set_Operations
;
39 pragma Elaborate_All
(Ada
.Containers
.Red_Black_Trees
.Generic_Set_Operations
);
41 with System
; use type System
.Address
;
43 package body Ada
.Containers
.Ordered_Sets
is
45 ------------------------------
46 -- Access to Fields of Node --
47 ------------------------------
49 -- These subprograms provide functional notation for access to fields
50 -- of a node, and procedural notation for modifying these fields.
52 function Color
(Node
: Node_Access
) return Color_Type
;
53 pragma Inline
(Color
);
55 function Left
(Node
: Node_Access
) return Node_Access
;
58 function Parent
(Node
: Node_Access
) return Node_Access
;
59 pragma Inline
(Parent
);
61 function Right
(Node
: Node_Access
) return Node_Access
;
62 pragma Inline
(Right
);
64 procedure Set_Color
(Node
: Node_Access
; Color
: Color_Type
);
65 pragma Inline
(Set_Color
);
67 procedure Set_Left
(Node
: Node_Access
; Left
: Node_Access
);
68 pragma Inline
(Set_Left
);
70 procedure Set_Right
(Node
: Node_Access
; Right
: Node_Access
);
71 pragma Inline
(Set_Right
);
73 procedure Set_Parent
(Node
: Node_Access
; Parent
: Node_Access
);
74 pragma Inline
(Set_Parent
);
76 -----------------------
77 -- Local Subprograms --
78 -----------------------
80 function Copy_Node
(Source
: Node_Access
) return Node_Access
;
81 pragma Inline
(Copy_Node
);
83 procedure Free
(X
: in out Node_Access
);
85 procedure Insert_Sans_Hint
86 (Tree
: in out Tree_Type
;
87 New_Item
: Element_Type
;
88 Node
: out Node_Access
;
89 Inserted
: out Boolean);
91 procedure Insert_With_Hint
92 (Dst_Tree
: in out Tree_Type
;
93 Dst_Hint
: Node_Access
;
94 Src_Node
: Node_Access
;
95 Dst_Node
: out Node_Access
);
97 function Is_Equal_Node_Node
(L
, R
: Node_Access
) return Boolean;
98 pragma Inline
(Is_Equal_Node_Node
);
100 function Is_Greater_Element_Node
101 (Left
: Element_Type
;
102 Right
: Node_Access
) return Boolean;
103 pragma Inline
(Is_Greater_Element_Node
);
105 function Is_Less_Element_Node
106 (Left
: Element_Type
;
107 Right
: Node_Access
) return Boolean;
108 pragma Inline
(Is_Less_Element_Node
);
110 function Is_Less_Node_Node
(L
, R
: Node_Access
) return Boolean;
111 pragma Inline
(Is_Less_Node_Node
);
113 procedure Replace_Element
114 (Tree
: in out Tree_Type
;
116 Item
: Element_Type
);
118 --------------------------
119 -- Local Instantiations --
120 --------------------------
122 package Tree_Operations
is
123 new Red_Black_Trees
.Generic_Operations
(Tree_Types
);
125 procedure Delete_Tree
is
126 new Tree_Operations
.Generic_Delete_Tree
(Free
);
128 function Copy_Tree
is
129 new Tree_Operations
.Generic_Copy_Tree
(Copy_Node
, Delete_Tree
);
134 new Tree_Operations
.Generic_Equal
(Is_Equal_Node_Node
);
136 package Element_Keys
is
137 new Red_Black_Trees
.Generic_Keys
138 (Tree_Operations
=> Tree_Operations
,
139 Key_Type
=> Element_Type
,
140 Is_Less_Key_Node
=> Is_Less_Element_Node
,
141 Is_Greater_Key_Node
=> Is_Greater_Element_Node
);
144 new Generic_Set_Operations
145 (Tree_Operations
=> Tree_Operations
,
146 Insert_With_Hint
=> Insert_With_Hint
,
147 Copy_Tree
=> Copy_Tree
,
148 Delete_Tree
=> Delete_Tree
,
149 Is_Less
=> Is_Less_Node_Node
,
156 function "<" (Left
, Right
: Cursor
) return Boolean is
158 if Left
.Node
= null then
159 raise Constraint_Error
with "Left cursor equals No_Element";
162 if Right
.Node
= null then
163 raise Constraint_Error
with "Right cursor equals No_Element";
166 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
167 "bad Left cursor in ""<""");
169 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
170 "bad Right cursor in ""<""");
172 return Left
.Node
.Element
< Right
.Node
.Element
;
175 function "<" (Left
: Cursor
; Right
: Element_Type
) return Boolean is
177 if Left
.Node
= null then
178 raise Constraint_Error
with "Left cursor equals No_Element";
181 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
182 "bad Left cursor in ""<""");
184 return Left
.Node
.Element
< Right
;
187 function "<" (Left
: Element_Type
; Right
: Cursor
) return Boolean is
189 if Right
.Node
= null then
190 raise Constraint_Error
with "Right cursor equals No_Element";
193 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
194 "bad Right cursor in ""<""");
196 return Left
< Right
.Node
.Element
;
203 function "=" (Left
, Right
: Set
) return Boolean is
205 return Is_Equal
(Left
.Tree
, Right
.Tree
);
212 function ">" (Left
, Right
: Cursor
) return Boolean is
214 if Left
.Node
= null then
215 raise Constraint_Error
with "Left cursor equals No_Element";
218 if Right
.Node
= null then
219 raise Constraint_Error
with "Right cursor equals No_Element";
222 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
223 "bad Left cursor in "">""");
225 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
226 "bad Right cursor in "">""");
228 -- L > R same as R < L
230 return Right
.Node
.Element
< Left
.Node
.Element
;
233 function ">" (Left
: Element_Type
; Right
: Cursor
) return Boolean is
235 if Right
.Node
= null then
236 raise Constraint_Error
with "Right cursor equals No_Element";
239 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
240 "bad Right cursor in "">""");
242 return Right
.Node
.Element
< Left
;
245 function ">" (Left
: Cursor
; Right
: Element_Type
) return Boolean is
247 if Left
.Node
= null then
248 raise Constraint_Error
with "Left cursor equals No_Element";
251 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
252 "bad Left cursor in "">""");
254 return Right
< Left
.Node
.Element
;
261 procedure Adjust
is new Tree_Operations
.Generic_Adjust
(Copy_Tree
);
263 procedure Adjust
(Container
: in out Set
) is
265 Adjust
(Container
.Tree
);
268 procedure Adjust
(Control
: in out Reference_Control_Type
) is
270 if Control
.Container
/= null then
272 Tree
: Tree_Type
renames Control
.Container
.all.Tree
;
273 B
: Natural renames Tree
.Busy
;
274 L
: Natural renames Tree
.Lock
;
286 procedure Assign
(Target
: in out Set
; Source
: Set
) is
288 if Target
'Address = Source
'Address then
293 Target
.Union
(Source
);
300 function Ceiling
(Container
: Set
; Item
: Element_Type
) return Cursor
is
301 Node
: constant Node_Access
:=
302 Element_Keys
.Ceiling
(Container
.Tree
, Item
);
304 return (if Node
= null then No_Element
305 else Cursor
'(Container'Unrestricted_Access, Node));
312 procedure Clear is new Tree_Operations.Generic_Clear (Delete_Tree);
314 procedure Clear (Container : in out Set) is
316 Clear (Container.Tree);
323 function Color (Node : Node_Access) return Color_Type is
328 ------------------------
329 -- Constant_Reference --
330 ------------------------
332 function Constant_Reference
333 (Container : aliased Set;
334 Position : Cursor) return Constant_Reference_Type
337 if Position.Container = null then
338 raise Constraint_Error with "Position cursor has no element";
341 if Position.Container /= Container'Unrestricted_Access then
342 raise Program_Error with
343 "Position cursor designates wrong container";
347 (Vet (Container.Tree, Position.Node),
348 "bad cursor in Constant_Reference");
351 Tree : Tree_Type renames Position.Container.all.Tree;
352 B : Natural renames Tree.Busy;
353 L : Natural renames Tree.Lock;
355 return R : constant Constant_Reference_Type :=
356 (Element => Position.Node.Element'Access,
357 Control => (Controlled with Container'Unrestricted_Access))
363 end Constant_Reference;
371 Item : Element_Type) return Boolean
374 return Find (Container, Item) /= No_Element;
381 function Copy (Source : Set) return Set is
383 return Target : Set do
384 Target.Assign (Source);
392 function Copy_Node (Source : Node_Access) return Node_Access is
393 Target : constant Node_Access :=
394 new Node_Type'(Parent
=> null,
397 Color
=> Source
.Color
,
398 Element
=> Source
.Element
);
407 procedure Delete
(Container
: in out Set
; Position
: in out Cursor
) is
409 if Position
.Node
= null then
410 raise Constraint_Error
with "Position cursor equals No_Element";
413 if Position
.Container
/= Container
'Unrestricted_Access then
414 raise Program_Error
with "Position cursor designates wrong set";
417 pragma Assert
(Vet
(Container
.Tree
, Position
.Node
),
418 "bad cursor in Delete");
420 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, Position
.Node
);
421 Free
(Position
.Node
);
422 Position
.Container
:= null;
425 procedure Delete
(Container
: in out Set
; Item
: Element_Type
) is
426 X
: Node_Access
:= Element_Keys
.Find
(Container
.Tree
, Item
);
430 raise Constraint_Error
with "attempt to delete element not in set";
433 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, X
);
441 procedure Delete_First
(Container
: in out Set
) is
442 Tree
: Tree_Type
renames Container
.Tree
;
443 X
: Node_Access
:= Tree
.First
;
446 Tree_Operations
.Delete_Node_Sans_Free
(Tree
, X
);
455 procedure Delete_Last
(Container
: in out Set
) is
456 Tree
: Tree_Type
renames Container
.Tree
;
457 X
: Node_Access
:= Tree
.Last
;
460 Tree_Operations
.Delete_Node_Sans_Free
(Tree
, X
);
469 procedure Difference
(Target
: in out Set
; Source
: Set
) is
471 Set_Ops
.Difference
(Target
.Tree
, Source
.Tree
);
474 function Difference
(Left
, Right
: Set
) return Set
is
475 Tree
: constant Tree_Type
:= Set_Ops
.Difference
(Left
.Tree
, Right
.Tree
);
477 return Set
'(Controlled with Tree);
484 function Element (Position : Cursor) return Element_Type is
486 if Position.Node = null then
487 raise Constraint_Error with "Position cursor equals No_Element";
490 pragma Assert (Vet (Position.Container.Tree, Position.Node),
491 "bad cursor in Element");
493 return Position.Node.Element;
496 -------------------------
497 -- Equivalent_Elements --
498 -------------------------
500 function Equivalent_Elements (Left, Right : Element_Type) return Boolean is
502 return (if Left < Right or else Right < Left then False else True);
503 end Equivalent_Elements;
505 ---------------------
506 -- Equivalent_Sets --
507 ---------------------
509 function Equivalent_Sets (Left, Right : Set) return Boolean is
510 function Is_Equivalent_Node_Node (L, R : Node_Access) return Boolean;
511 pragma Inline (Is_Equivalent_Node_Node);
513 function Is_Equivalent is
514 new Tree_Operations.Generic_Equal (Is_Equivalent_Node_Node);
516 -----------------------------
517 -- Is_Equivalent_Node_Node --
518 -----------------------------
520 function Is_Equivalent_Node_Node (L, R : Node_Access) return Boolean is
522 return (if L.Element < R.Element then False
523 elsif R.Element < L.Element then False
525 end Is_Equivalent_Node_Node;
527 -- Start of processing for Equivalent_Sets
530 return Is_Equivalent (Left.Tree, Right.Tree);
537 procedure Exclude (Container : in out Set; Item : Element_Type) is
538 X : Node_Access := Element_Keys.Find (Container.Tree, Item);
542 Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
551 procedure Finalize (Object : in out Iterator) is
553 if Object.Container /= null then
555 B : Natural renames Object.Container.all.Tree.Busy;
562 procedure Finalize (Control : in out Reference_Control_Type) is
564 if Control.Container /= null then
566 Tree : Tree_Type renames Control.Container.all.Tree;
567 B : Natural renames Tree.Busy;
568 L : Natural renames Tree.Lock;
574 Control.Container := null;
582 function Find (Container : Set; Item : Element_Type) return Cursor is
583 Node : constant Node_Access := Element_Keys.Find (Container.Tree, Item);
585 return (if Node = null then No_Element
586 else Cursor'(Container
'Unrestricted_Access, Node
));
593 function First
(Container
: Set
) return Cursor
is
596 (if Container
.Tree
.First
= null then No_Element
597 else Cursor
'(Container'Unrestricted_Access, Container.Tree.First));
600 function First (Object : Iterator) return Cursor is
602 -- The value of the iterator object's Node component influences the
603 -- behavior of the First (and Last) selector function.
605 -- When the Node component is null, this means the iterator object was
606 -- constructed without a start expression, in which case the (forward)
607 -- iteration starts from the (logical) beginning of the entire sequence
608 -- of items (corresponding to Container.First, for a forward iterator).
610 -- Otherwise, this is iteration over a partial sequence of items. When
611 -- the Node component is non-null, the iterator object was constructed
612 -- with a start expression, that specifies the position from which the
613 -- (forward) partial iteration begins.
615 if Object.Node = null then
616 return Object.Container.First;
618 return Cursor'(Object
.Container
, Object
.Node
);
626 function First_Element
(Container
: Set
) return Element_Type
is
628 if Container
.Tree
.First
= null then
629 raise Constraint_Error
with "set is empty";
632 return Container
.Tree
.First
.Element
;
639 function Floor
(Container
: Set
; Item
: Element_Type
) return Cursor
is
640 Node
: constant Node_Access
:= Element_Keys
.Floor
(Container
.Tree
, Item
);
642 return (if Node
= null then No_Element
643 else Cursor
'(Container'Unrestricted_Access, Node));
650 procedure Free (X : in out Node_Access) is
651 procedure Deallocate is
652 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
666 package body Generic_Keys is
668 -----------------------
669 -- Local Subprograms --
670 -----------------------
672 function Is_Greater_Key_Node
674 Right : Node_Access) return Boolean;
675 pragma Inline (Is_Greater_Key_Node);
677 function Is_Less_Key_Node
679 Right : Node_Access) return Boolean;
680 pragma Inline (Is_Less_Key_Node);
682 --------------------------
683 -- Local Instantiations --
684 --------------------------
687 new Red_Black_Trees.Generic_Keys
688 (Tree_Operations => Tree_Operations,
689 Key_Type => Key_Type,
690 Is_Less_Key_Node => Is_Less_Key_Node,
691 Is_Greater_Key_Node => Is_Greater_Key_Node);
697 procedure Adjust (Control : in out Reference_Control_Type) is
699 if Control.Container /= null then
701 Tree : Tree_Type renames Control.Container.Tree;
702 B : Natural renames Tree.Busy;
703 L : Natural renames Tree.Lock;
715 function Ceiling (Container : Set; Key : Key_Type) return Cursor is
716 Node : constant Node_Access := Key_Keys.Ceiling (Container.Tree, Key);
718 return (if Node = null then No_Element
719 else Cursor'(Container
'Unrestricted_Access, Node
));
722 ------------------------
723 -- Constant_Reference --
724 ------------------------
726 function Constant_Reference
727 (Container
: aliased Set
;
728 Key
: Key_Type
) return Constant_Reference_Type
730 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
734 raise Constraint_Error
with "key not in set";
738 Tree
: Tree_Type
renames Container
'Unrestricted_Access.all.Tree
;
739 B
: Natural renames Tree
.Busy
;
740 L
: Natural renames Tree
.Lock
;
742 return R
: constant Constant_Reference_Type
:=
743 (Element
=> Node
.Element
'Access,
744 Control
=> (Controlled
with Container
'Unrestricted_Access))
750 end Constant_Reference
;
756 function Contains
(Container
: Set
; Key
: Key_Type
) return Boolean is
758 return Find
(Container
, Key
) /= No_Element
;
765 procedure Delete
(Container
: in out Set
; Key
: Key_Type
) is
766 X
: Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
770 raise Constraint_Error
with "attempt to delete key not in set";
773 Delete_Node_Sans_Free
(Container
.Tree
, X
);
781 function Element
(Container
: Set
; Key
: Key_Type
) return Element_Type
is
782 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
786 raise Constraint_Error
with "key not in set";
792 ---------------------
793 -- Equivalent_Keys --
794 ---------------------
796 function Equivalent_Keys
(Left
, Right
: Key_Type
) return Boolean is
798 return (if Left
< Right
or else Right
< Left
then False else True);
805 procedure Exclude
(Container
: in out Set
; Key
: Key_Type
) is
806 X
: Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
809 Delete_Node_Sans_Free
(Container
.Tree
, X
);
818 procedure Finalize
(Control
: in out Reference_Control_Type
) is
820 if Control
.Container
/= null then
822 Tree
: Tree_Type
renames Control
.Container
.Tree
;
823 B
: Natural renames Tree
.Busy
;
824 L
: Natural renames Tree
.Lock
;
830 if not (Key
(Control
.Pos
) = Control
.Old_Key
.all) then
831 Delete
(Control
.Container
.all, Key
(Control
.Pos
));
835 Control
.Container
:= null;
836 Control
.Old_Key
:= null;
844 function Find
(Container
: Set
; Key
: Key_Type
) return Cursor
is
845 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
847 return (if Node
= null then No_Element
848 else Cursor
'(Container'Unrestricted_Access, Node));
855 function Floor (Container : Set; Key : Key_Type) return Cursor is
856 Node : constant Node_Access := Key_Keys.Floor (Container.Tree, Key);
858 return (if Node = null then No_Element
859 else Cursor'(Container
'Unrestricted_Access, Node
));
862 -------------------------
863 -- Is_Greater_Key_Node --
864 -------------------------
866 function Is_Greater_Key_Node
868 Right
: Node_Access
) return Boolean
871 return Key
(Right
.Element
) < Left
;
872 end Is_Greater_Key_Node
;
874 ----------------------
875 -- Is_Less_Key_Node --
876 ----------------------
878 function Is_Less_Key_Node
880 Right
: Node_Access
) return Boolean
883 return Left
< Key
(Right
.Element
);
884 end Is_Less_Key_Node
;
890 function Key
(Position
: Cursor
) return Key_Type
is
892 if Position
.Node
= null then
893 raise Constraint_Error
with
894 "Position cursor equals No_Element";
897 pragma Assert
(Vet
(Position
.Container
.Tree
, Position
.Node
),
898 "bad cursor in Key");
900 return Key
(Position
.Node
.Element
);
908 (Stream
: not null access Root_Stream_Type
'Class;
909 Item
: out Reference_Type
)
912 raise Program_Error
with "attempt to stream reference";
915 ------------------------------
916 -- Reference_Preserving_Key --
917 ------------------------------
919 function Reference_Preserving_Key
920 (Container
: aliased in out Set
;
921 Position
: Cursor
) return Reference_Type
924 if Position
.Container
= null then
925 raise Constraint_Error
with "Position cursor has no element";
928 if Position
.Container
/= Container
'Unrestricted_Access then
929 raise Program_Error
with
930 "Position cursor designates wrong container";
934 (Vet
(Container
.Tree
, Position
.Node
),
935 "bad cursor in function Reference_Preserving_Key");
938 Tree
: Tree_Type
renames Container
.Tree
;
939 B
: Natural renames Tree
.Busy
;
940 L
: Natural renames Tree
.Lock
;
943 return R
: constant Reference_Type
:=
944 (Element
=> Position
.Node
.Element
'Access,
947 Container
=> Container
'Access,
949 Old_Key
=> new Key_Type
'(Key (Position))))
955 end Reference_Preserving_Key;
957 function Reference_Preserving_Key
958 (Container : aliased in out Set;
959 Key : Key_Type) return Reference_Type
961 Node : constant Node_Access := Key_Keys.Find (Container.Tree, Key);
965 raise Constraint_Error with "key not in set";
969 Tree : Tree_Type renames Container.Tree;
970 B : Natural renames Tree.Busy;
971 L : Natural renames Tree.Lock;
974 return R : constant Reference_Type :=
975 (Element => Node.Element'Access,
978 Container => Container'Access,
979 Pos => Find (Container, Key),
980 Old_Key => new Key_Type'(Key
)))
986 end Reference_Preserving_Key
;
993 (Container
: in out Set
;
995 New_Item
: Element_Type
)
997 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.Tree
, Key
);
1001 raise Constraint_Error
with
1002 "attempt to replace key not in set";
1005 Replace_Element
(Container
.Tree
, Node
, New_Item
);
1008 -----------------------------------
1009 -- Update_Element_Preserving_Key --
1010 -----------------------------------
1012 procedure Update_Element_Preserving_Key
1013 (Container
: in out Set
;
1015 Process
: not null access procedure (Element
: in out Element_Type
))
1017 Tree
: Tree_Type
renames Container
.Tree
;
1020 if Position
.Node
= null then
1021 raise Constraint_Error
with
1022 "Position cursor equals No_Element";
1025 if Position
.Container
/= Container
'Unrestricted_Access then
1026 raise Program_Error
with
1027 "Position cursor designates wrong set";
1030 pragma Assert
(Vet
(Container
.Tree
, Position
.Node
),
1031 "bad cursor in Update_Element_Preserving_Key");
1034 E
: Element_Type
renames Position
.Node
.Element
;
1035 K
: constant Key_Type
:= Key
(E
);
1037 B
: Natural renames Tree
.Busy
;
1038 L
: Natural renames Tree
.Lock
;
1048 Eq
:= Equivalent_Keys
(K
, Key
(E
));
1065 X
: Node_Access
:= Position
.Node
;
1067 Tree_Operations
.Delete_Node_Sans_Free
(Tree
, X
);
1071 raise Program_Error
with "key was modified";
1072 end Update_Element_Preserving_Key
;
1079 (Stream
: not null access Root_Stream_Type
'Class;
1080 Item
: Reference_Type
)
1083 raise Program_Error
with "attempt to stream reference";
1092 function Has_Element
(Position
: Cursor
) return Boolean is
1094 return Position
/= No_Element
;
1101 procedure Include
(Container
: in out Set
; New_Item
: Element_Type
) is
1106 Insert
(Container
, New_Item
, Position
, Inserted
);
1108 if not Inserted
then
1109 if Container
.Tree
.Lock
> 0 then
1110 raise Program_Error
with
1111 "attempt to tamper with elements (set is locked)";
1114 Position
.Node
.Element
:= New_Item
;
1123 (Container
: in out Set
;
1124 New_Item
: Element_Type
;
1125 Position
: out Cursor
;
1126 Inserted
: out Boolean)
1135 Position
.Container
:= Container
'Unrestricted_Access;
1139 (Container
: in out Set
;
1140 New_Item
: Element_Type
)
1143 pragma Unreferenced
(Position
);
1148 Insert
(Container
, New_Item
, Position
, Inserted
);
1150 if not Inserted
then
1151 raise Constraint_Error
with
1152 "attempt to insert element already in set";
1156 ----------------------
1157 -- Insert_Sans_Hint --
1158 ----------------------
1160 procedure Insert_Sans_Hint
1161 (Tree
: in out Tree_Type
;
1162 New_Item
: Element_Type
;
1163 Node
: out Node_Access
;
1164 Inserted
: out Boolean)
1166 function New_Node
return Node_Access
;
1167 pragma Inline
(New_Node
);
1169 procedure Insert_Post
is
1170 new Element_Keys
.Generic_Insert_Post
(New_Node
);
1172 procedure Conditional_Insert_Sans_Hint
is
1173 new Element_Keys
.Generic_Conditional_Insert
(Insert_Post
);
1179 function New_Node
return Node_Access
is
1181 return new Node_Type
'(Parent => null,
1184 Color => Red_Black_Trees.Red,
1185 Element => New_Item);
1188 -- Start of processing for Insert_Sans_Hint
1191 Conditional_Insert_Sans_Hint
1196 end Insert_Sans_Hint;
1198 ----------------------
1199 -- Insert_With_Hint --
1200 ----------------------
1202 procedure Insert_With_Hint
1203 (Dst_Tree : in out Tree_Type;
1204 Dst_Hint : Node_Access;
1205 Src_Node : Node_Access;
1206 Dst_Node : out Node_Access)
1209 pragma Unreferenced (Success);
1211 function New_Node return Node_Access;
1212 pragma Inline (New_Node);
1214 procedure Insert_Post is
1215 new Element_Keys.Generic_Insert_Post (New_Node);
1217 procedure Insert_Sans_Hint is
1218 new Element_Keys.Generic_Conditional_Insert (Insert_Post);
1220 procedure Local_Insert_With_Hint is
1221 new Element_Keys.Generic_Conditional_Insert_With_Hint
1229 function New_Node return Node_Access is
1230 Node : constant Node_Access :=
1231 new Node_Type'(Parent
=> null,
1235 Element
=> Src_Node
.Element
);
1240 -- Start of processing for Insert_With_Hint
1243 Local_Insert_With_Hint
1249 end Insert_With_Hint
;
1255 procedure Intersection
(Target
: in out Set
; Source
: Set
) is
1257 Set_Ops
.Intersection
(Target
.Tree
, Source
.Tree
);
1260 function Intersection
(Left
, Right
: Set
) return Set
is
1261 Tree
: constant Tree_Type
:=
1262 Set_Ops
.Intersection
(Left
.Tree
, Right
.Tree
);
1264 return Set
'(Controlled with Tree);
1271 function Is_Empty (Container : Set) return Boolean is
1273 return Container.Tree.Length = 0;
1276 ------------------------
1277 -- Is_Equal_Node_Node --
1278 ------------------------
1280 function Is_Equal_Node_Node (L, R : Node_Access) return Boolean is
1282 return L.Element = R.Element;
1283 end Is_Equal_Node_Node;
1285 -----------------------------
1286 -- Is_Greater_Element_Node --
1287 -----------------------------
1289 function Is_Greater_Element_Node
1290 (Left : Element_Type;
1291 Right : Node_Access) return Boolean
1294 -- Compute e > node same as node < e
1296 return Right.Element < Left;
1297 end Is_Greater_Element_Node;
1299 --------------------------
1300 -- Is_Less_Element_Node --
1301 --------------------------
1303 function Is_Less_Element_Node
1304 (Left : Element_Type;
1305 Right : Node_Access) return Boolean
1308 return Left < Right.Element;
1309 end Is_Less_Element_Node;
1311 -----------------------
1312 -- Is_Less_Node_Node --
1313 -----------------------
1315 function Is_Less_Node_Node (L, R : Node_Access) return Boolean is
1317 return L.Element < R.Element;
1318 end Is_Less_Node_Node;
1324 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
1326 return Set_Ops.Is_Subset (Subset => Subset.Tree, Of_Set => Of_Set.Tree);
1335 Process : not null access procedure (Position : Cursor))
1337 procedure Process_Node (Node : Node_Access);
1338 pragma Inline (Process_Node);
1340 procedure Local_Iterate is
1341 new Tree_Operations.Generic_Iteration (Process_Node);
1347 procedure Process_Node (Node : Node_Access) is
1349 Process (Cursor'(Container
'Unrestricted_Access, Node
));
1352 T
: Tree_Type
renames Container
'Unrestricted_Access.all.Tree
;
1353 B
: Natural renames T
.Busy
;
1355 -- Start of processing for Iterate
1371 function Iterate
(Container
: Set
)
1372 return Set_Iterator_Interfaces
.Reversible_Iterator
'Class
1374 B
: Natural renames Container
'Unrestricted_Access.all.Tree
.Busy
;
1377 -- The value of the Node component influences the behavior of the First
1378 -- and Last selector functions of the iterator object. When the Node
1379 -- component is null (as is the case here), this means the iterator
1380 -- object was constructed without a start expression. This is a complete
1381 -- iterator, meaning that the iteration starts from the (logical)
1382 -- beginning of the sequence of items.
1384 -- Note: For a forward iterator, Container.First is the beginning, and
1385 -- for a reverse iterator, Container.Last is the beginning.
1389 return It
: constant Iterator
:=
1390 Iterator
'(Limited_Controlled with
1391 Container => Container'Unrestricted_Access,
1395 function Iterate (Container : Set; Start : Cursor)
1396 return Set_Iterator_Interfaces.Reversible_Iterator'Class
1398 B : Natural renames Container'Unrestricted_Access.all.Tree.Busy;
1401 -- It was formerly the case that when Start = No_Element, the partial
1402 -- iterator was defined to behave the same as for a complete iterator,
1403 -- and iterate over the entire sequence of items. However, those
1404 -- semantics were unintuitive and arguably error-prone (it is too easy
1405 -- to accidentally create an endless loop), and so they were changed,
1406 -- per the ARG meeting in Denver on 2011/11. However, there was no
1407 -- consensus about what positive meaning this corner case should have,
1408 -- and so it was decided to simply raise an exception. This does imply,
1409 -- however, that it is not possible to use a partial iterator to specify
1410 -- an empty sequence of items.
1412 if Start = No_Element then
1413 raise Constraint_Error with
1414 "Start position for iterator equals No_Element";
1417 if Start.Container /= Container'Unrestricted_Access then
1418 raise Program_Error with
1419 "Start cursor of Iterate designates wrong set";
1422 pragma Assert (Vet (Container.Tree, Start.Node),
1423 "Start cursor of Iterate is bad");
1425 -- The value of the Node component influences the behavior of the First
1426 -- and Last selector functions of the iterator object. When the Node
1427 -- component is non-null (as is the case here), it means that this is a
1428 -- partial iteration, over a subset of the complete sequence of
1429 -- items. The iterator object was constructed with a start expression,
1430 -- indicating the position from which the iteration begins. Note that
1431 -- the start position has the same value irrespective of whether this is
1432 -- a forward or reverse iteration.
1436 return It : constant Iterator :=
1437 Iterator'(Limited_Controlled
with
1438 Container
=> Container
'Unrestricted_Access,
1439 Node
=> Start
.Node
);
1446 function Last
(Container
: Set
) return Cursor
is
1449 (if Container
.Tree
.Last
= null then No_Element
1450 else Cursor
'(Container'Unrestricted_Access, Container.Tree.Last));
1453 function Last (Object : Iterator) return Cursor is
1455 -- The value of the iterator object's Node component influences the
1456 -- behavior of the Last (and First) selector function.
1458 -- When the Node component is null, this means the iterator object was
1459 -- constructed without a start expression, in which case the (reverse)
1460 -- iteration starts from the (logical) beginning of the entire sequence
1461 -- (corresponding to Container.Last, for a reverse iterator).
1463 -- Otherwise, this is iteration over a partial sequence of items. When
1464 -- the Node component is non-null, the iterator object was constructed
1465 -- with a start expression, that specifies the position from which the
1466 -- (reverse) partial iteration begins.
1468 if Object.Node = null then
1469 return Object.Container.Last;
1471 return Cursor'(Object
.Container
, Object
.Node
);
1479 function Last_Element
(Container
: Set
) return Element_Type
is
1481 if Container
.Tree
.Last
= null then
1482 raise Constraint_Error
with "set is empty";
1484 return Container
.Tree
.Last
.Element
;
1492 function Left
(Node
: Node_Access
) return Node_Access
is
1501 function Length
(Container
: Set
) return Count_Type
is
1503 return Container
.Tree
.Length
;
1510 procedure Move
is new Tree_Operations
.Generic_Move
(Clear
);
1512 procedure Move
(Target
: in out Set
; Source
: in out Set
) is
1514 Move
(Target
=> Target
.Tree
, Source
=> Source
.Tree
);
1521 function Next
(Position
: Cursor
) return Cursor
is
1523 if Position
= No_Element
then
1527 pragma Assert
(Vet
(Position
.Container
.Tree
, Position
.Node
),
1528 "bad cursor in Next");
1531 Node
: constant Node_Access
:=
1532 Tree_Operations
.Next
(Position
.Node
);
1534 return (if Node
= null then No_Element
1535 else Cursor
'(Position.Container, Node));
1539 procedure Next (Position : in out Cursor) is
1541 Position := Next (Position);
1544 function Next (Object : Iterator; Position : Cursor) return Cursor is
1546 if Position.Container = null then
1550 if Position.Container /= Object.Container then
1551 raise Program_Error with
1552 "Position cursor of Next designates wrong set";
1555 return Next (Position);
1562 function Overlap (Left, Right : Set) return Boolean is
1564 return Set_Ops.Overlap (Left.Tree, Right.Tree);
1571 function Parent (Node : Node_Access) return Node_Access is
1580 function Previous (Position : Cursor) return Cursor is
1582 if Position = No_Element then
1586 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1587 "bad cursor in Previous");
1590 Node : constant Node_Access :=
1591 Tree_Operations.Previous (Position.Node);
1593 return (if Node = null then No_Element
1594 else Cursor'(Position
.Container
, Node
));
1598 procedure Previous
(Position
: in out Cursor
) is
1600 Position
:= Previous
(Position
);
1603 function Previous
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
1605 if Position
.Container
= null then
1609 if Position
.Container
/= Object
.Container
then
1610 raise Program_Error
with
1611 "Position cursor of Previous designates wrong set";
1614 return Previous
(Position
);
1621 procedure Query_Element
1623 Process
: not null access procedure (Element
: Element_Type
))
1626 if Position
.Node
= null then
1627 raise Constraint_Error
with "Position cursor equals No_Element";
1630 pragma Assert
(Vet
(Position
.Container
.Tree
, Position
.Node
),
1631 "bad cursor in Query_Element");
1634 T
: Tree_Type
renames Position
.Container
.Tree
;
1636 B
: Natural renames T
.Busy
;
1637 L
: Natural renames T
.Lock
;
1644 Process
(Position
.Node
.Element
);
1662 (Stream
: not null access Root_Stream_Type
'Class;
1663 Container
: out Set
)
1666 (Stream
: not null access Root_Stream_Type
'Class) return Node_Access
;
1667 pragma Inline
(Read_Node
);
1670 new Tree_Operations
.Generic_Read
(Clear
, Read_Node
);
1677 (Stream
: not null access Root_Stream_Type
'Class) return Node_Access
1679 Node
: Node_Access
:= new Node_Type
;
1681 Element_Type
'Read (Stream
, Node
.Element
);
1689 -- Start of processing for Read
1692 Read
(Stream
, Container
.Tree
);
1696 (Stream
: not null access Root_Stream_Type
'Class;
1700 raise Program_Error
with "attempt to stream set cursor";
1704 (Stream
: not null access Root_Stream_Type
'Class;
1705 Item
: out Constant_Reference_Type
)
1708 raise Program_Error
with "attempt to stream reference";
1715 procedure Replace
(Container
: in out Set
; New_Item
: Element_Type
) is
1716 Node
: constant Node_Access
:=
1717 Element_Keys
.Find
(Container
.Tree
, New_Item
);
1721 raise Constraint_Error
with
1722 "attempt to replace element not in set";
1725 if Container
.Tree
.Lock
> 0 then
1726 raise Program_Error
with
1727 "attempt to tamper with elements (set is locked)";
1730 Node
.Element
:= New_Item
;
1733 ---------------------
1734 -- Replace_Element --
1735 ---------------------
1737 procedure Replace_Element
1738 (Tree
: in out Tree_Type
;
1740 Item
: Element_Type
)
1742 pragma Assert
(Node
/= null);
1744 function New_Node
return Node_Access
;
1745 pragma Inline
(New_Node
);
1747 procedure Local_Insert_Post
is
1748 new Element_Keys
.Generic_Insert_Post
(New_Node
);
1750 procedure Local_Insert_Sans_Hint
is
1751 new Element_Keys
.Generic_Conditional_Insert
(Local_Insert_Post
);
1753 procedure Local_Insert_With_Hint
is
1754 new Element_Keys
.Generic_Conditional_Insert_With_Hint
1756 Local_Insert_Sans_Hint
);
1762 function New_Node
return Node_Access
is
1764 Node
.Element
:= Item
;
1766 Node
.Parent
:= null;
1773 Result
: Node_Access
;
1777 -- Per AI05-0022, the container implementation is required to detect
1778 -- element tampering by a generic actual subprogram.
1780 B
: Natural renames Tree
.Busy
;
1781 L
: Natural renames Tree
.Lock
;
1783 -- Start of processing for Replace_Element
1786 -- Replace_Element assigns value Item to the element designated by Node,
1787 -- per certain semantic constraints.
1789 -- If Item is equivalent to the element, then element is replaced and
1790 -- there's nothing else to do. This is the easy case.
1792 -- If Item is not equivalent, then the node will (possibly) have to move
1793 -- to some other place in the tree. This is slighly more complicated,
1794 -- because we must ensure that Item is not equivalent to some other
1795 -- element in the tree (in which case, the replacement is not allowed).
1797 -- Determine whether Item is equivalent to element on the specified
1804 Compare
:= (if Item
< Node
.Element
then False
1805 elsif Node
.Element
< Item
then False
1820 -- Item is equivalent to the node's element, so we will not have to
1823 if Tree
.Lock
> 0 then
1824 raise Program_Error
with
1825 "attempt to tamper with elements (set is locked)";
1828 Node
.Element
:= Item
;
1832 -- The replacement Item is not equivalent to the element on the
1833 -- specified node, which means that it will need to be re-inserted in a
1834 -- different position in the tree. We must now determine whether Item is
1835 -- equivalent to some other element in the tree (which would prohibit
1836 -- the assignment and hence the move).
1838 -- Ceiling returns the smallest element equivalent or greater than the
1839 -- specified Item; if there is no such element, then it returns null.
1841 Hint
:= Element_Keys
.Ceiling
(Tree
, Item
);
1843 if Hint
/= null then
1848 Compare
:= Item
< Hint
.Element
;
1861 -- Item >= Hint.Element
1865 -- Ceiling returns an element that is equivalent or greater
1866 -- than Item. If Item is "not less than" the element, then
1867 -- by elimination we know that Item is equivalent to the element.
1869 -- But this means that it is not possible to assign the value of
1870 -- Item to the specified element (on Node), because a different
1871 -- element (on Hint) equivalent to Item already exsits. (Were we
1872 -- to change Node's element value, we would have to move Node, but
1873 -- we would be unable to move the Node, because its new position
1874 -- in the tree is already occupied by an equivalent element.)
1876 raise Program_Error
with "attempt to replace existing element";
1879 -- Item is not equivalent to any other element in the tree, so it is
1880 -- safe to assign the value of Item to Node.Element. This means that
1881 -- the node will have to move to a different position in the tree
1882 -- (because its element will have a different value).
1884 -- The nearest (greater) neighbor of Item is Hint. This will be the
1885 -- insertion position of Node (because its element will have Item as
1888 -- If Node equals Hint, the relative position of Node does not
1889 -- change. This allows us to perform an optimization: we need not
1890 -- remove Node from the tree and then reinsert it with its new value,
1891 -- because it would only be placed in the exact same position.
1894 if Tree
.Lock
> 0 then
1895 raise Program_Error
with
1896 "attempt to tamper with elements (set is locked)";
1899 Node
.Element
:= Item
;
1904 -- If we get here, it is because Item was greater than all elements in
1905 -- the tree (Hint = null), or because Item was less than some element at
1906 -- a different place in the tree (Item < Hint.Element). In either case,
1907 -- we remove Node from the tree (without actually deallocating it), and
1908 -- then insert Item into the tree, onto the same Node (so no new node is
1909 -- actually allocated).
1911 Tree_Operations
.Delete_Node_Sans_Free
(Tree
, Node
); -- Checks busy-bit
1913 Local_Insert_With_Hint
-- use unconditional insert here instead???
1918 Inserted
=> Inserted
);
1920 pragma Assert
(Inserted
);
1921 pragma Assert
(Result
= Node
);
1922 end Replace_Element
;
1924 procedure Replace_Element
1925 (Container
: in out Set
;
1927 New_Item
: Element_Type
)
1930 if Position
.Node
= null then
1931 raise Constraint_Error
with
1932 "Position cursor equals No_Element";
1935 if Position
.Container
/= Container
'Unrestricted_Access then
1936 raise Program_Error
with
1937 "Position cursor designates wrong set";
1940 pragma Assert
(Vet
(Container
.Tree
, Position
.Node
),
1941 "bad cursor in Replace_Element");
1943 Replace_Element
(Container
.Tree
, Position
.Node
, New_Item
);
1944 end Replace_Element
;
1946 ---------------------
1947 -- Reverse_Iterate --
1948 ---------------------
1950 procedure Reverse_Iterate
1952 Process
: not null access procedure (Position
: Cursor
))
1954 procedure Process_Node
(Node
: Node_Access
);
1955 pragma Inline
(Process_Node
);
1957 procedure Local_Reverse_Iterate
is
1958 new Tree_Operations
.Generic_Reverse_Iteration
(Process_Node
);
1964 procedure Process_Node
(Node
: Node_Access
) is
1966 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1969 T : Tree_Type renames Container.Tree'Unrestricted_Access.all;
1970 B : Natural renames T.Busy;
1972 -- Start of processing for Reverse_Iterate
1978 Local_Reverse_Iterate (T);
1986 end Reverse_Iterate;
1992 function Right (Node : Node_Access) return Node_Access is
2001 procedure Set_Color (Node : Node_Access; Color : Color_Type) is
2003 Node.Color := Color;
2010 procedure Set_Left (Node : Node_Access; Left : Node_Access) is
2019 procedure Set_Parent (Node : Node_Access; Parent : Node_Access) is
2021 Node.Parent := Parent;
2028 procedure Set_Right (Node : Node_Access; Right : Node_Access) is
2030 Node.Right := Right;
2033 --------------------------
2034 -- Symmetric_Difference --
2035 --------------------------
2037 procedure Symmetric_Difference (Target : in out Set; Source : Set) is
2039 Set_Ops.Symmetric_Difference (Target.Tree, Source.Tree);
2040 end Symmetric_Difference;
2042 function Symmetric_Difference (Left, Right : Set) return Set is
2043 Tree : constant Tree_Type :=
2044 Set_Ops.Symmetric_Difference (Left.Tree, Right.Tree);
2046 return Set'(Controlled
with Tree
);
2047 end Symmetric_Difference
;
2053 function To_Set
(New_Item
: Element_Type
) return Set
is
2057 pragma Unreferenced
(Node
, Inserted
);
2059 Insert_Sans_Hint
(Tree
, New_Item
, Node
, Inserted
);
2060 return Set
'(Controlled with Tree);
2067 procedure Union (Target : in out Set; Source : Set) is
2069 Set_Ops.Union (Target.Tree, Source.Tree);
2072 function Union (Left, Right : Set) return Set is
2073 Tree : constant Tree_Type :=
2074 Set_Ops.Union (Left.Tree, Right.Tree);
2076 return Set'(Controlled
with Tree
);
2084 (Stream
: not null access Root_Stream_Type
'Class;
2087 procedure Write_Node
2088 (Stream
: not null access Root_Stream_Type
'Class;
2089 Node
: Node_Access
);
2090 pragma Inline
(Write_Node
);
2093 new Tree_Operations
.Generic_Write
(Write_Node
);
2099 procedure Write_Node
2100 (Stream
: not null access Root_Stream_Type
'Class;
2104 Element_Type
'Write (Stream
, Node
.Element
);
2107 -- Start of processing for Write
2110 Write
(Stream
, Container
.Tree
);
2114 (Stream
: not null access Root_Stream_Type
'Class;
2118 raise Program_Error
with "attempt to stream set cursor";
2122 (Stream
: not null access Root_Stream_Type
'Class;
2123 Item
: Constant_Reference_Type
)
2126 raise Program_Error
with "attempt to stream reference";
2129 end Ada
.Containers
.Ordered_Sets
;