1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_ORDERED_MAPS --
9 -- Copyright (C) 2004-2015, 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 System
; use type System
.Address
;
42 package body Ada
.Containers
.Indefinite_Ordered_Maps
is
43 pragma Suppress
(All_Checks
);
45 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
46 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
47 -- See comment in Ada.Containers.Helpers
49 -----------------------------
50 -- Node Access Subprograms --
51 -----------------------------
53 -- These subprograms provide a functional interface to access fields
54 -- of a node, and a procedural interface for modifying these values.
56 function Color
(Node
: Node_Access
) return Color_Type
;
57 pragma Inline
(Color
);
59 function Left
(Node
: Node_Access
) return Node_Access
;
62 function Parent
(Node
: Node_Access
) return Node_Access
;
63 pragma Inline
(Parent
);
65 function Right
(Node
: Node_Access
) return Node_Access
;
66 pragma Inline
(Right
);
68 procedure Set_Parent
(Node
: Node_Access
; Parent
: Node_Access
);
69 pragma Inline
(Set_Parent
);
71 procedure Set_Left
(Node
: Node_Access
; Left
: Node_Access
);
72 pragma Inline
(Set_Left
);
74 procedure Set_Right
(Node
: Node_Access
; Right
: Node_Access
);
75 pragma Inline
(Set_Right
);
77 procedure Set_Color
(Node
: Node_Access
; Color
: Color_Type
);
78 pragma Inline
(Set_Color
);
80 -----------------------
81 -- Local Subprograms --
82 -----------------------
84 function Copy_Node
(Source
: Node_Access
) return Node_Access
;
85 pragma Inline
(Copy_Node
);
87 procedure Free
(X
: in out Node_Access
);
89 function Is_Equal_Node_Node
90 (L
, R
: Node_Access
) return Boolean;
91 pragma Inline
(Is_Equal_Node_Node
);
93 function Is_Greater_Key_Node
95 Right
: Node_Access
) return Boolean;
96 pragma Inline
(Is_Greater_Key_Node
);
98 function Is_Less_Key_Node
100 Right
: Node_Access
) return Boolean;
101 pragma Inline
(Is_Less_Key_Node
);
103 --------------------------
104 -- Local Instantiations --
105 --------------------------
107 package Tree_Operations
is
108 new Red_Black_Trees
.Generic_Operations
(Tree_Types
);
110 procedure Delete_Tree
is
111 new Tree_Operations
.Generic_Delete_Tree
(Free
);
113 function Copy_Tree
is
114 new Tree_Operations
.Generic_Copy_Tree
(Copy_Node
, Delete_Tree
);
119 new Red_Black_Trees
.Generic_Keys
120 (Tree_Operations
=> Tree_Operations
,
121 Key_Type
=> Key_Type
,
122 Is_Less_Key_Node
=> Is_Less_Key_Node
,
123 Is_Greater_Key_Node
=> Is_Greater_Key_Node
);
125 procedure Free_Key
is
126 new Ada
.Unchecked_Deallocation
(Key_Type
, Key_Access
);
128 procedure Free_Element
is
129 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
132 new Tree_Operations
.Generic_Equal
(Is_Equal_Node_Node
);
138 function "<" (Left
, Right
: Cursor
) return Boolean is
140 if Checks
and then Left
.Node
= null then
141 raise Constraint_Error
with "Left cursor of ""<"" equals No_Element";
144 if Checks
and then Right
.Node
= null then
145 raise Constraint_Error
with "Right cursor of ""<"" equals No_Element";
148 if Checks
and then Left
.Node
.Key
= null then
149 raise Program_Error
with "Left cursor in ""<"" is bad";
152 if Checks
and then Right
.Node
.Key
= null then
153 raise Program_Error
with "Right cursor in ""<"" is bad";
156 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
157 "Left cursor in ""<"" is bad");
159 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
160 "Right cursor in ""<"" is bad");
162 return Left
.Node
.Key
.all < Right
.Node
.Key
.all;
165 function "<" (Left
: Cursor
; Right
: Key_Type
) return Boolean is
167 if Checks
and then Left
.Node
= null then
168 raise Constraint_Error
with "Left cursor of ""<"" equals No_Element";
171 if Checks
and then Left
.Node
.Key
= null then
172 raise Program_Error
with "Left cursor in ""<"" is bad";
175 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
176 "Left cursor in ""<"" is bad");
178 return Left
.Node
.Key
.all < Right
;
181 function "<" (Left
: Key_Type
; Right
: Cursor
) return Boolean is
183 if Checks
and then Right
.Node
= null then
184 raise Constraint_Error
with "Right cursor of ""<"" equals No_Element";
187 if Checks
and then Right
.Node
.Key
= null then
188 raise Program_Error
with "Right cursor in ""<"" is bad";
191 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
192 "Right cursor in ""<"" is bad");
194 return Left
< Right
.Node
.Key
.all;
201 function "=" (Left
, Right
: Map
) return Boolean is
203 return Is_Equal
(Left
.Tree
, Right
.Tree
);
210 function ">" (Left
, Right
: Cursor
) return Boolean is
212 if Checks
and then Left
.Node
= null then
213 raise Constraint_Error
with "Left cursor of "">"" equals No_Element";
216 if Checks
and then Right
.Node
= null then
217 raise Constraint_Error
with "Right cursor of "">"" equals No_Element";
220 if Checks
and then Left
.Node
.Key
= null then
221 raise Program_Error
with "Left cursor in ""<"" is bad";
224 if Checks
and then Right
.Node
.Key
= null then
225 raise Program_Error
with "Right cursor in ""<"" is bad";
228 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
229 "Left cursor in "">"" is bad");
231 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
232 "Right cursor in "">"" is bad");
234 return Right
.Node
.Key
.all < Left
.Node
.Key
.all;
237 function ">" (Left
: Cursor
; Right
: Key_Type
) return Boolean is
239 if Checks
and then Left
.Node
= null then
240 raise Constraint_Error
with "Left cursor of "">"" equals No_Element";
243 if Checks
and then Left
.Node
.Key
= null then
244 raise Program_Error
with "Left cursor in ""<"" is bad";
247 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
248 "Left cursor in "">"" is bad");
250 return Right
< Left
.Node
.Key
.all;
253 function ">" (Left
: Key_Type
; Right
: Cursor
) return Boolean is
255 if Checks
and then Right
.Node
= null then
256 raise Constraint_Error
with "Right cursor of "">"" equals No_Element";
259 if Checks
and then Right
.Node
.Key
= null then
260 raise Program_Error
with "Right cursor in ""<"" is bad";
263 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
264 "Right cursor in "">"" is bad");
266 return Right
.Node
.Key
.all < Left
;
273 procedure Adjust
is new Tree_Operations
.Generic_Adjust
(Copy_Tree
);
275 procedure Adjust
(Container
: in out Map
) is
277 Adjust
(Container
.Tree
);
284 procedure Assign
(Target
: in out Map
; Source
: Map
) is
285 procedure Insert_Item
(Node
: Node_Access
);
286 pragma Inline
(Insert_Item
);
288 procedure Insert_Items
is
289 new Tree_Operations
.Generic_Iteration
(Insert_Item
);
295 procedure Insert_Item
(Node
: Node_Access
) is
297 Target
.Insert
(Key
=> Node
.Key
.all, New_Item
=> Node
.Element
.all);
300 -- Start of processing for Assign
303 if Target
'Address = Source
'Address then
308 Insert_Items
(Source
.Tree
);
315 function Ceiling
(Container
: Map
; Key
: Key_Type
) return Cursor
is
316 Node
: constant Node_Access
:= Key_Ops
.Ceiling
(Container
.Tree
, Key
);
318 return (if Node
= null then No_Element
319 else Cursor
'(Container'Unrestricted_Access, Node));
326 procedure Clear is new Tree_Operations.Generic_Clear (Delete_Tree);
328 procedure Clear (Container : in out Map) is
330 Clear (Container.Tree);
337 function Color (Node : Node_Access) return Color_Type is
342 ------------------------
343 -- Constant_Reference --
344 ------------------------
346 function Constant_Reference
347 (Container : aliased Map;
348 Position : Cursor) return Constant_Reference_Type
351 if Checks and then Position.Container = null then
352 raise Constraint_Error with
353 "Position cursor has no element";
356 if Checks and then Position.Container /= Container'Unrestricted_Access
358 raise Program_Error with
359 "Position cursor designates wrong map";
362 if Checks and then Position.Node.Element = null then
363 raise Program_Error with "Node has no element";
366 pragma Assert (Vet (Container.Tree, Position.Node),
367 "Position cursor in Constant_Reference is bad");
370 TC : constant Tamper_Counts_Access :=
371 Container.Tree.TC'Unrestricted_Access;
373 return R : constant Constant_Reference_Type :=
374 (Element => Position.Node.Element.all'Access,
375 Control => (Controlled with TC))
380 end Constant_Reference;
382 function Constant_Reference
383 (Container : aliased Map;
384 Key : Key_Type) return Constant_Reference_Type
386 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
389 if Checks and then Node = null then
390 raise Constraint_Error with "key not in map";
393 if Checks and then Node.Element = null then
394 raise Program_Error with "Node has no element";
398 TC : constant Tamper_Counts_Access :=
399 Container.Tree.TC'Unrestricted_Access;
401 return R : constant Constant_Reference_Type :=
402 (Element => Node.Element.all'Access,
403 Control => (Controlled with TC))
408 end Constant_Reference;
414 function Contains (Container : Map; Key : Key_Type) return Boolean is
416 return Find (Container, Key) /= No_Element;
423 function Copy (Source : Map) return Map is
425 return Target : Map do
426 Target.Assign (Source);
434 function Copy_Node (Source : Node_Access) return Node_Access is
435 K : Key_Access := new Key_Type'(Source
.Key
.all);
439 E
:= new Element_Type
'(Source.Element.all);
441 return new Node_Type'(Parent
=> null,
444 Color
=> Source
.Color
,
460 (Container
: in out Map
;
461 Position
: in out Cursor
)
464 if Checks
and then Position
.Node
= null then
465 raise Constraint_Error
with
466 "Position cursor of Delete equals No_Element";
470 (Position
.Node
.Key
= null or else Position
.Node
.Element
= null)
472 raise Program_Error
with "Position cursor of Delete is bad";
475 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
477 raise Program_Error
with
478 "Position cursor of Delete designates wrong map";
481 pragma Assert
(Vet
(Container
.Tree
, Position
.Node
),
482 "Position cursor of Delete is bad");
484 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, Position
.Node
);
485 Free
(Position
.Node
);
487 Position
.Container
:= null;
490 procedure Delete
(Container
: in out Map
; Key
: Key_Type
) is
491 X
: Node_Access
:= Key_Ops
.Find
(Container
.Tree
, Key
);
494 if Checks
and then X
= null then
495 raise Constraint_Error
with "key not in map";
498 Delete_Node_Sans_Free
(Container
.Tree
, X
);
506 procedure Delete_First
(Container
: in out Map
) is
507 X
: Node_Access
:= Container
.Tree
.First
;
510 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, X
);
519 procedure Delete_Last
(Container
: in out Map
) is
520 X
: Node_Access
:= Container
.Tree
.Last
;
523 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, X
);
532 function Element
(Position
: Cursor
) return Element_Type
is
534 if Checks
and then Position
.Node
= null then
535 raise Constraint_Error
with
536 "Position cursor of function Element equals No_Element";
539 if Checks
and then Position
.Node
.Element
= null then
540 raise Program_Error
with
541 "Position cursor of function Element is bad";
544 pragma Assert
(Vet
(Position
.Container
.Tree
, Position
.Node
),
545 "Position cursor of function Element is bad");
547 return Position
.Node
.Element
.all;
550 function Element
(Container
: Map
; Key
: Key_Type
) return Element_Type
is
551 Node
: constant Node_Access
:= Key_Ops
.Find
(Container
.Tree
, Key
);
554 if Checks
and then Node
= null then
555 raise Constraint_Error
with "key not in map";
558 return Node
.Element
.all;
561 ---------------------
562 -- Equivalent_Keys --
563 ---------------------
565 function Equivalent_Keys
(Left
, Right
: Key_Type
) return Boolean is
567 return (if Left
< Right
or else Right
< Left
then False else True);
574 procedure Exclude
(Container
: in out Map
; Key
: Key_Type
) is
575 X
: Node_Access
:= Key_Ops
.Find
(Container
.Tree
, Key
);
578 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, X
);
587 procedure Finalize
(Object
: in out Iterator
) is
589 if Object
.Container
/= null then
590 Unbusy
(Object
.Container
.Tree
.TC
);
598 function Find
(Container
: Map
; Key
: Key_Type
) return Cursor
is
599 Node
: constant Node_Access
:= Key_Ops
.Find
(Container
.Tree
, Key
);
601 return (if Node
= null then No_Element
602 else Cursor
'(Container'Unrestricted_Access, Node));
609 function First (Container : Map) return Cursor is
610 T : Tree_Type renames Container.Tree;
612 return (if T.First = null then No_Element
613 else Cursor'(Container
'Unrestricted_Access, T
.First
));
616 function First
(Object
: Iterator
) return Cursor
is
618 -- The value of the iterator object's Node component influences the
619 -- behavior of the First (and Last) selector function.
621 -- When the Node component is null, this means the iterator object was
622 -- constructed without a start expression, in which case the (forward)
623 -- iteration starts from the (logical) beginning of the entire sequence
624 -- of items (corresponding to Container.First for a forward iterator).
626 -- Otherwise, this is iteration over a partial sequence of items. When
627 -- the Node component is non-null, the iterator object was constructed
628 -- with a start expression, that specifies the position from which the
629 -- (forward) partial iteration begins.
631 if Object
.Node
= null then
632 return Object
.Container
.First
;
634 return Cursor
'(Object.Container, Object.Node);
642 function First_Element (Container : Map) return Element_Type is
643 T : Tree_Type renames Container.Tree;
645 if Checks and then T.First = null then
646 raise Constraint_Error with "map is empty";
649 return T.First.Element.all;
656 function First_Key (Container : Map) return Key_Type is
657 T : Tree_Type renames Container.Tree;
659 if Checks and then T.First = null then
660 raise Constraint_Error with "map is empty";
663 return T.First.Key.all;
670 function Floor (Container : Map; Key : Key_Type) return Cursor is
671 Node : constant Node_Access := Key_Ops.Floor (Container.Tree, Key);
673 return (if Node = null then No_Element
674 else Cursor'(Container
'Unrestricted_Access, Node
));
681 procedure Free
(X
: in out Node_Access
) is
682 procedure Deallocate
is
683 new Ada
.Unchecked_Deallocation
(Node_Type
, Node_Access
);
702 Free_Element
(X
.Element
);
713 Free_Element
(X
.Element
);
726 ------------------------
727 -- Get_Element_Access --
728 ------------------------
730 function Get_Element_Access
731 (Position
: Cursor
) return not null Element_Access
is
733 return Position
.Node
.Element
;
734 end Get_Element_Access
;
740 function Has_Element
(Position
: Cursor
) return Boolean is
742 return Position
/= No_Element
;
750 (Container
: in out Map
;
752 New_Item
: Element_Type
)
761 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
764 TE_Check
(Container
.Tree
.TC
);
766 K
:= Position
.Node
.Key
;
767 E
:= Position
.Node
.Element
;
769 Position
.Node
.Key
:= new Key_Type
'(Key);
772 -- The element allocator may need an accessibility check in the
773 -- case the actual type is class-wide or has access discriminants
774 -- (see RM 4.8(10.1) and AI12-0035).
776 pragma Unsuppress (Accessibility_Check);
779 Position.Node.Element := new Element_Type'(New_Item
);
797 (Container
: in out Map
;
799 New_Item
: Element_Type
;
800 Position
: out Cursor
;
801 Inserted
: out Boolean)
803 function New_Node
return Node_Access
;
804 pragma Inline
(New_Node
);
806 procedure Insert_Post
is
807 new Key_Ops
.Generic_Insert_Post
(New_Node
);
809 procedure Insert_Sans_Hint
is
810 new Key_Ops
.Generic_Conditional_Insert
(Insert_Post
);
816 function New_Node
return Node_Access
is
817 Node
: Node_Access
:= new Node_Type
;
819 -- The element allocator may need an accessibility check in the case
820 -- the actual type is class-wide or has access discriminants (see
821 -- RM 4.8(10.1) and AI12-0035).
823 pragma Unsuppress
(Accessibility_Check
);
826 Node
.Key
:= new Key_Type
'(Key);
827 Node.Element := new Element_Type'(New_Item
);
833 -- On exception, deallocate key and elem. Note that free
834 -- deallocates both the key and the elem.
840 -- Start of processing for Insert
849 Position
.Container
:= Container
'Unrestricted_Access;
853 (Container
: in out Map
;
855 New_Item
: Element_Type
)
858 pragma Unreferenced
(Position
);
863 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
865 if Checks
and then not Inserted
then
866 raise Constraint_Error
with "key already in map";
874 function Is_Empty
(Container
: Map
) return Boolean is
876 return Container
.Tree
.Length
= 0;
879 ------------------------
880 -- Is_Equal_Node_Node --
881 ------------------------
883 function Is_Equal_Node_Node
(L
, R
: Node_Access
) return Boolean is
885 return (if L
.Key
.all < R
.Key
.all then False
886 elsif R
.Key
.all < L
.Key
.all then False
887 else L
.Element
.all = R
.Element
.all);
888 end Is_Equal_Node_Node
;
890 -------------------------
891 -- Is_Greater_Key_Node --
892 -------------------------
894 function Is_Greater_Key_Node
896 Right
: Node_Access
) return Boolean
899 -- k > node same as node < k
901 return Right
.Key
.all < Left
;
902 end Is_Greater_Key_Node
;
904 ----------------------
905 -- Is_Less_Key_Node --
906 ----------------------
908 function Is_Less_Key_Node
910 Right
: Node_Access
) return Boolean is
912 return Left
< Right
.Key
.all;
913 end Is_Less_Key_Node
;
921 Process
: not null access procedure (Position
: Cursor
))
923 procedure Process_Node
(Node
: Node_Access
);
924 pragma Inline
(Process_Node
);
926 procedure Local_Iterate
is
927 new Tree_Operations
.Generic_Iteration
(Process_Node
);
933 procedure Process_Node
(Node
: Node_Access
) is
935 Process
(Cursor
'(Container'Unrestricted_Access, Node));
938 Busy : With_Busy (Container.Tree.TC'Unrestricted_Access);
940 -- Start of processing for Iterate
943 Local_Iterate (Container.Tree);
947 (Container : Map) return Map_Iterator_Interfaces.Reversible_Iterator'Class
950 -- The value of the Node component influences the behavior of the First
951 -- and Last selector functions of the iterator object. When the Node
952 -- component is null (as is the case here), this means the iterator
953 -- object was constructed without a start expression. This is a complete
954 -- iterator, meaning that the iteration starts from the (logical)
955 -- beginning of the sequence of items.
957 -- Note: For a forward iterator, Container.First is the beginning, and
958 -- for a reverse iterator, Container.Last is the beginning.
960 return It : constant Iterator :=
961 (Limited_Controlled with
962 Container => Container'Unrestricted_Access,
965 Busy (Container.Tree.TC'Unrestricted_Access.all);
972 return Map_Iterator_Interfaces.Reversible_Iterator'Class
975 -- It was formerly the case that when Start = No_Element, the partial
976 -- iterator was defined to behave the same as for a complete iterator,
977 -- and iterate over the entire sequence of items. However, those
978 -- semantics were unintuitive and arguably error-prone (it is too easy
979 -- to accidentally create an endless loop), and so they were changed,
980 -- per the ARG meeting in Denver on 2011/11. However, there was no
981 -- consensus about what positive meaning this corner case should have,
982 -- and so it was decided to simply raise an exception. This does imply,
983 -- however, that it is not possible to use a partial iterator to specify
984 -- an empty sequence of items.
986 if Checks and then Start = No_Element then
987 raise Constraint_Error with
988 "Start position for iterator equals No_Element";
991 if Checks and then Start.Container /= Container'Unrestricted_Access then
992 raise Program_Error with
993 "Start cursor of Iterate designates wrong map";
996 pragma Assert (Vet (Container.Tree, Start.Node),
997 "Start cursor of Iterate is bad");
999 -- The value of the Node component influences the behavior of the First
1000 -- and Last selector functions of the iterator object. When the Node
1001 -- component is non-null (as is the case here), it means that this
1002 -- is a partial iteration, over a subset of the complete sequence of
1003 -- items. The iterator object was constructed with a start expression,
1004 -- indicating the position from which the iteration begins. Note that
1005 -- the start position has the same value irrespective of whether this
1006 -- is a forward or reverse iteration.
1008 return It : constant Iterator :=
1009 (Limited_Controlled with
1010 Container => Container'Unrestricted_Access,
1013 Busy (Container.Tree.TC'Unrestricted_Access.all);
1021 function Key (Position : Cursor) return Key_Type is
1023 if Checks and then Position.Node = null then
1024 raise Constraint_Error with
1025 "Position cursor of function Key equals No_Element";
1028 if Checks and then Position.Node.Key = null then
1029 raise Program_Error with
1030 "Position cursor of function Key is bad";
1033 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1034 "Position cursor of function Key is bad");
1036 return Position.Node.Key.all;
1043 function Last (Container : Map) return Cursor is
1044 T : Tree_Type renames Container.Tree;
1046 return (if T.Last = null then No_Element
1047 else Cursor'(Container
'Unrestricted_Access, T
.Last
));
1050 function Last
(Object
: Iterator
) return Cursor
is
1052 -- The value of the iterator object's Node component influences the
1053 -- behavior of the Last (and First) selector function.
1055 -- When the Node component is null, this means the iterator object was
1056 -- constructed without a start expression, in which case the (reverse)
1057 -- iteration starts from the (logical) beginning of the entire sequence
1058 -- (corresponding to Container.Last, for a reverse iterator).
1060 -- Otherwise, this is iteration over a partial sequence of items. When
1061 -- the Node component is non-null, the iterator object was constructed
1062 -- with a start expression, that specifies the position from which the
1063 -- (reverse) partial iteration begins.
1065 if Object
.Node
= null then
1066 return Object
.Container
.Last
;
1068 return Cursor
'(Object.Container, Object.Node);
1076 function Last_Element (Container : Map) return Element_Type is
1077 T : Tree_Type renames Container.Tree;
1080 if Checks and then T.Last = null then
1081 raise Constraint_Error with "map is empty";
1084 return T.Last.Element.all;
1091 function Last_Key (Container : Map) return Key_Type is
1092 T : Tree_Type renames Container.Tree;
1095 if Checks and then T.Last = null then
1096 raise Constraint_Error with "map is empty";
1099 return T.Last.Key.all;
1106 function Left (Node : Node_Access) return Node_Access is
1115 function Length (Container : Map) return Count_Type is
1117 return Container.Tree.Length;
1124 procedure Move is new Tree_Operations.Generic_Move (Clear);
1126 procedure Move (Target : in out Map; Source : in out Map) is
1128 Move (Target => Target.Tree, Source => Source.Tree);
1135 function Next (Position : Cursor) return Cursor is
1137 if Position = No_Element then
1141 pragma Assert (Position.Node /= null);
1142 pragma Assert (Position.Node.Key /= null);
1143 pragma Assert (Position.Node.Element /= null);
1144 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1145 "Position cursor of Next is bad");
1148 Node : constant Node_Access :=
1149 Tree_Operations.Next (Position.Node);
1151 return (if Node = null then No_Element
1152 else Cursor'(Position
.Container
, Node
));
1156 procedure Next
(Position
: in out Cursor
) is
1158 Position
:= Next
(Position
);
1163 Position
: Cursor
) return Cursor
1166 if Position
.Container
= null then
1170 if Checks
and then Position
.Container
/= Object
.Container
then
1171 raise Program_Error
with
1172 "Position cursor of Next designates wrong map";
1175 return Next
(Position
);
1182 function Parent
(Node
: Node_Access
) return Node_Access
is
1191 function Previous
(Position
: Cursor
) return Cursor
is
1193 if Position
= No_Element
then
1197 pragma Assert
(Position
.Node
/= null);
1198 pragma Assert
(Position
.Node
.Key
/= null);
1199 pragma Assert
(Position
.Node
.Element
/= null);
1200 pragma Assert
(Vet
(Position
.Container
.Tree
, Position
.Node
),
1201 "Position cursor of Previous is bad");
1204 Node
: constant Node_Access
:=
1205 Tree_Operations
.Previous
(Position
.Node
);
1207 return (if Node
= null then No_Element
1208 else Cursor
'(Position.Container, Node));
1212 procedure Previous (Position : in out Cursor) is
1214 Position := Previous (Position);
1219 Position : Cursor) return Cursor
1222 if Position.Container = null then
1226 if Checks and then Position.Container /= Object.Container then
1227 raise Program_Error with
1228 "Position cursor of Previous designates wrong map";
1231 return Previous (Position);
1234 ----------------------
1235 -- Pseudo_Reference --
1236 ----------------------
1238 function Pseudo_Reference
1239 (Container : aliased Map'Class) return Reference_Control_Type
1241 TC : constant Tamper_Counts_Access :=
1242 Container.Tree.TC'Unrestricted_Access;
1244 return R : constant Reference_Control_Type := (Controlled with TC) do
1247 end Pseudo_Reference;
1253 procedure Query_Element
1255 Process : not null access procedure (Key : Key_Type;
1256 Element : Element_Type))
1259 if Checks and then Position.Node = null then
1260 raise Constraint_Error with
1261 "Position cursor of Query_Element equals No_Element";
1265 (Position.Node.Key = null or else Position.Node.Element = null)
1267 raise Program_Error with
1268 "Position cursor of Query_Element is bad";
1271 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1272 "Position cursor of Query_Element is bad");
1275 T : Tree_Type renames Position.Container.Tree;
1276 Lock : With_Lock (T.TC'Unrestricted_Access);
1277 K : Key_Type renames Position.Node.Key.all;
1278 E : Element_Type renames Position.Node.Element.all;
1289 (Stream : not null access Root_Stream_Type'Class;
1290 Container : out Map)
1293 (Stream : not null access Root_Stream_Type'Class) return Node_Access;
1294 pragma Inline (Read_Node);
1297 new Tree_Operations.Generic_Read (Clear, Read_Node);
1304 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1306 Node : Node_Access := new Node_Type;
1308 Node.Key := new Key_Type'(Key_Type
'Input (Stream
));
1309 Node
.Element
:= new Element_Type
'(Element_Type'Input (Stream));
1313 Free (Node); -- Note that Free deallocates key and elem too
1317 -- Start of processing for Read
1320 Read (Stream, Container.Tree);
1324 (Stream : not null access Root_Stream_Type'Class;
1328 raise Program_Error with "attempt to stream map cursor";
1332 (Stream : not null access Root_Stream_Type'Class;
1333 Item : out Reference_Type)
1336 raise Program_Error with "attempt to stream reference";
1340 (Stream : not null access Root_Stream_Type'Class;
1341 Item : out Constant_Reference_Type)
1344 raise Program_Error with "attempt to stream reference";
1352 (Container : aliased in out Map;
1353 Position : Cursor) return Reference_Type
1356 if Checks and then Position.Container = null then
1357 raise Constraint_Error with
1358 "Position cursor has no element";
1361 if Checks and then Position.Container /= Container'Unrestricted_Access
1363 raise Program_Error with
1364 "Position cursor designates wrong map";
1367 if Checks and then Position.Node.Element = null then
1368 raise Program_Error with "Node has no element";
1371 pragma Assert (Vet (Container.Tree, Position.Node),
1372 "Position cursor in function Reference is bad");
1375 TC : constant Tamper_Counts_Access :=
1376 Container.Tree.TC'Unrestricted_Access;
1378 return R : constant Reference_Type :=
1379 (Element => Position.Node.Element.all'Access,
1380 Control => (Controlled with TC))
1388 (Container : aliased in out Map;
1389 Key : Key_Type) return Reference_Type
1391 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
1394 if Checks and then Node = null then
1395 raise Constraint_Error with "key not in map";
1398 if Checks and then Node.Element = null then
1399 raise Program_Error with "Node has no element";
1403 TC : constant Tamper_Counts_Access :=
1404 Container.Tree.TC'Unrestricted_Access;
1406 return R : constant Reference_Type :=
1407 (Element => Node.Element.all'Access,
1408 Control => (Controlled with TC))
1420 (Container : in out Map;
1422 New_Item : Element_Type)
1424 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
1430 if Checks and then Node = null then
1431 raise Constraint_Error with "key not in map";
1434 TE_Check (Container.Tree.TC);
1439 Node.Key := new Key_Type'(Key
);
1442 -- The element allocator may need an accessibility check in the case
1443 -- the actual type is class-wide or has access discriminants (see
1444 -- RM 4.8(10.1) and AI12-0035).
1446 pragma Unsuppress
(Accessibility_Check
);
1449 Node
.Element
:= new Element_Type
'(New_Item);
1461 ---------------------
1462 -- Replace_Element --
1463 ---------------------
1465 procedure Replace_Element
1466 (Container : in out Map;
1468 New_Item : Element_Type)
1471 if Checks and then Position.Node = null then
1472 raise Constraint_Error with
1473 "Position cursor of Replace_Element equals No_Element";
1477 (Position.Node.Key = null or else Position.Node.Element = null)
1479 raise Program_Error with
1480 "Position cursor of Replace_Element is bad";
1483 if Checks and then Position.Container /= Container'Unrestricted_Access
1485 raise Program_Error with
1486 "Position cursor of Replace_Element designates wrong map";
1489 TE_Check (Container.Tree.TC);
1491 pragma Assert (Vet (Container.Tree, Position.Node),
1492 "Position cursor of Replace_Element is bad");
1495 X : Element_Access := Position.Node.Element;
1497 -- The element allocator may need an accessibility check in the case
1498 -- the actual type is class-wide or has access discriminants (see
1499 -- RM 4.8(10.1) and AI12-0035).
1501 pragma Unsuppress (Accessibility_Check);
1504 Position.Node.Element := new Element_Type'(New_Item
);
1507 end Replace_Element
;
1509 ---------------------
1510 -- Reverse_Iterate --
1511 ---------------------
1513 procedure Reverse_Iterate
1515 Process
: not null access procedure (Position
: Cursor
))
1517 procedure Process_Node
(Node
: Node_Access
);
1518 pragma Inline
(Process_Node
);
1520 procedure Local_Reverse_Iterate
is
1521 new Tree_Operations
.Generic_Reverse_Iteration
(Process_Node
);
1527 procedure Process_Node
(Node
: Node_Access
) is
1529 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1532 Busy : With_Busy (Container.Tree.TC'Unrestricted_Access);
1534 -- Start of processing for Reverse_Iterate
1537 Local_Reverse_Iterate (Container.Tree);
1538 end Reverse_Iterate;
1544 function Right (Node : Node_Access) return Node_Access is
1553 procedure Set_Color (Node : Node_Access; Color : Color_Type) is
1555 Node.Color := Color;
1562 procedure Set_Left (Node : Node_Access; Left : Node_Access) is
1571 procedure Set_Parent (Node : Node_Access; Parent : Node_Access) is
1573 Node.Parent := Parent;
1580 procedure Set_Right (Node : Node_Access; Right : Node_Access) is
1582 Node.Right := Right;
1585 --------------------
1586 -- Update_Element --
1587 --------------------
1589 procedure Update_Element
1590 (Container : in out Map;
1592 Process : not null access procedure (Key : Key_Type;
1593 Element : in out Element_Type))
1596 if Checks and then Position.Node = null then
1597 raise Constraint_Error with
1598 "Position cursor of Update_Element equals No_Element";
1602 (Position.Node.Key = null or else Position.Node.Element = null)
1604 raise Program_Error with
1605 "Position cursor of Update_Element is bad";
1608 if Checks and then Position.Container /= Container'Unrestricted_Access
1610 raise Program_Error with
1611 "Position cursor of Update_Element designates wrong map";
1614 pragma Assert (Vet (Container.Tree, Position.Node),
1615 "Position cursor of Update_Element is bad");
1618 T : Tree_Type renames Position.Container.Tree;
1619 Lock : With_Lock (T.TC'Unrestricted_Access);
1620 K : Key_Type renames Position.Node.Key.all;
1621 E : Element_Type renames Position.Node.Element.all;
1632 (Stream : not null access Root_Stream_Type'Class;
1635 procedure Write_Node
1636 (Stream : not null access Root_Stream_Type'Class;
1637 Node : Node_Access);
1638 pragma Inline (Write_Node);
1641 new Tree_Operations.Generic_Write (Write_Node);
1647 procedure Write_Node
1648 (Stream : not null access Root_Stream_Type'Class;
1652 Key_Type'Output (Stream, Node.Key.all);
1653 Element_Type'Output (Stream, Node.Element.all);
1656 -- Start of processing for Write
1659 Write (Stream, Container.Tree);
1663 (Stream : not null access Root_Stream_Type'Class;
1667 raise Program_Error with "attempt to stream map cursor";
1671 (Stream : not null access Root_Stream_Type'Class;
1672 Item : Reference_Type)
1675 raise Program_Error with "attempt to stream reference";
1679 (Stream : not null access Root_Stream_Type'Class;
1680 Item : Constant_Reference_Type)
1683 raise Program_Error with "attempt to stream reference";
1686 end Ada.Containers.Indefinite_Ordered_Maps;