1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_ORDERED_MAPS --
9 -- Copyright (C) 2004-2012, 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 System
; use type System
.Address
;
40 package body Ada
.Containers
.Indefinite_Ordered_Maps
is
41 pragma Suppress
(All_Checks
);
43 type Iterator
is new Limited_Controlled
and
44 Map_Iterator_Interfaces
.Reversible_Iterator
with
46 Container
: Map_Access
;
50 overriding
procedure Finalize
(Object
: in out Iterator
);
52 overriding
function First
(Object
: Iterator
) return Cursor
;
53 overriding
function Last
(Object
: Iterator
) return Cursor
;
55 overriding
function Next
57 Position
: Cursor
) return Cursor
;
59 overriding
function Previous
61 Position
: Cursor
) return Cursor
;
63 -----------------------------
64 -- Node Access Subprograms --
65 -----------------------------
67 -- These subprograms provide a functional interface to access fields
68 -- of a node, and a procedural interface for modifying these values.
70 function Color
(Node
: Node_Access
) return Color_Type
;
71 pragma Inline
(Color
);
73 function Left
(Node
: Node_Access
) return Node_Access
;
76 function Parent
(Node
: Node_Access
) return Node_Access
;
77 pragma Inline
(Parent
);
79 function Right
(Node
: Node_Access
) return Node_Access
;
80 pragma Inline
(Right
);
82 procedure Set_Parent
(Node
: Node_Access
; Parent
: Node_Access
);
83 pragma Inline
(Set_Parent
);
85 procedure Set_Left
(Node
: Node_Access
; Left
: Node_Access
);
86 pragma Inline
(Set_Left
);
88 procedure Set_Right
(Node
: Node_Access
; Right
: Node_Access
);
89 pragma Inline
(Set_Right
);
91 procedure Set_Color
(Node
: Node_Access
; Color
: Color_Type
);
92 pragma Inline
(Set_Color
);
94 -----------------------
95 -- Local Subprograms --
96 -----------------------
98 function Copy_Node
(Source
: Node_Access
) return Node_Access
;
99 pragma Inline
(Copy_Node
);
101 procedure Free
(X
: in out Node_Access
);
103 function Is_Equal_Node_Node
104 (L
, R
: Node_Access
) return Boolean;
105 pragma Inline
(Is_Equal_Node_Node
);
107 function Is_Greater_Key_Node
109 Right
: Node_Access
) return Boolean;
110 pragma Inline
(Is_Greater_Key_Node
);
112 function Is_Less_Key_Node
114 Right
: Node_Access
) return Boolean;
115 pragma Inline
(Is_Less_Key_Node
);
117 --------------------------
118 -- Local Instantiations --
119 --------------------------
121 package Tree_Operations
is
122 new Red_Black_Trees
.Generic_Operations
(Tree_Types
);
124 procedure Delete_Tree
is
125 new Tree_Operations
.Generic_Delete_Tree
(Free
);
127 function Copy_Tree
is
128 new Tree_Operations
.Generic_Copy_Tree
(Copy_Node
, Delete_Tree
);
133 new Red_Black_Trees
.Generic_Keys
134 (Tree_Operations
=> Tree_Operations
,
135 Key_Type
=> Key_Type
,
136 Is_Less_Key_Node
=> Is_Less_Key_Node
,
137 Is_Greater_Key_Node
=> Is_Greater_Key_Node
);
139 procedure Free_Key
is
140 new Ada
.Unchecked_Deallocation
(Key_Type
, Key_Access
);
142 procedure Free_Element
is
143 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
146 new Tree_Operations
.Generic_Equal
(Is_Equal_Node_Node
);
152 function "<" (Left
, Right
: Cursor
) return Boolean is
154 if Left
.Node
= null then
155 raise Constraint_Error
with "Left cursor of ""<"" equals No_Element";
158 if Right
.Node
= null then
159 raise Constraint_Error
with "Right cursor of ""<"" equals No_Element";
162 if Left
.Node
.Key
= null then
163 raise Program_Error
with "Left cursor in ""<"" is bad";
166 if Right
.Node
.Key
= null then
167 raise Program_Error
with "Right cursor in ""<"" is bad";
170 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
171 "Left cursor in ""<"" is bad");
173 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
174 "Right cursor in ""<"" is bad");
176 return Left
.Node
.Key
.all < Right
.Node
.Key
.all;
179 function "<" (Left
: Cursor
; Right
: Key_Type
) return Boolean is
181 if Left
.Node
= null then
182 raise Constraint_Error
with "Left cursor of ""<"" equals No_Element";
185 if Left
.Node
.Key
= null then
186 raise Program_Error
with "Left cursor in ""<"" is bad";
189 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
190 "Left cursor in ""<"" is bad");
192 return Left
.Node
.Key
.all < Right
;
195 function "<" (Left
: Key_Type
; Right
: Cursor
) return Boolean is
197 if Right
.Node
= null then
198 raise Constraint_Error
with "Right cursor of ""<"" equals No_Element";
201 if Right
.Node
.Key
= null then
202 raise Program_Error
with "Right cursor in ""<"" is bad";
205 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
206 "Right cursor in ""<"" is bad");
208 return Left
< Right
.Node
.Key
.all;
215 function "=" (Left
, Right
: Map
) return Boolean is
217 return Is_Equal
(Left
.Tree
, Right
.Tree
);
224 function ">" (Left
, Right
: Cursor
) return Boolean is
226 if Left
.Node
= null then
227 raise Constraint_Error
with "Left cursor of "">"" equals No_Element";
230 if Right
.Node
= null then
231 raise Constraint_Error
with "Right cursor of "">"" equals No_Element";
234 if Left
.Node
.Key
= null then
235 raise Program_Error
with "Left cursor in ""<"" is bad";
238 if Right
.Node
.Key
= null then
239 raise Program_Error
with "Right cursor in ""<"" is bad";
242 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
243 "Left cursor in "">"" is bad");
245 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
246 "Right cursor in "">"" is bad");
248 return Right
.Node
.Key
.all < Left
.Node
.Key
.all;
251 function ">" (Left
: Cursor
; Right
: Key_Type
) return Boolean is
253 if Left
.Node
= null then
254 raise Constraint_Error
with "Left cursor of "">"" equals No_Element";
257 if Left
.Node
.Key
= null then
258 raise Program_Error
with "Left cursor in ""<"" is bad";
261 pragma Assert
(Vet
(Left
.Container
.Tree
, Left
.Node
),
262 "Left cursor in "">"" is bad");
264 return Right
< Left
.Node
.Key
.all;
267 function ">" (Left
: Key_Type
; Right
: Cursor
) return Boolean is
269 if Right
.Node
= null then
270 raise Constraint_Error
with "Right cursor of "">"" equals No_Element";
273 if Right
.Node
.Key
= null then
274 raise Program_Error
with "Right cursor in ""<"" is bad";
277 pragma Assert
(Vet
(Right
.Container
.Tree
, Right
.Node
),
278 "Right cursor in "">"" is bad");
280 return Right
.Node
.Key
.all < Left
;
287 procedure Adjust
is new Tree_Operations
.Generic_Adjust
(Copy_Tree
);
289 procedure Adjust
(Container
: in out Map
) is
291 Adjust
(Container
.Tree
);
294 procedure Adjust
(Control
: in out Reference_Control_Type
) is
296 if Control
.Container
/= null then
298 T
: Tree_Type
renames Control
.Container
.all.Tree
;
299 B
: Natural renames T
.Busy
;
300 L
: Natural renames T
.Lock
;
312 procedure Assign
(Target
: in out Map
; Source
: Map
) is
313 procedure Insert_Item
(Node
: Node_Access
);
314 pragma Inline
(Insert_Item
);
316 procedure Insert_Items
is
317 new Tree_Operations
.Generic_Iteration
(Insert_Item
);
323 procedure Insert_Item
(Node
: Node_Access
) is
325 Target
.Insert
(Key
=> Node
.Key
.all, New_Item
=> Node
.Element
.all);
328 -- Start of processing for Assign
331 if Target
'Address = Source
'Address then
336 Insert_Items
(Target
.Tree
);
343 function Ceiling
(Container
: Map
; Key
: Key_Type
) return Cursor
is
344 Node
: constant Node_Access
:= Key_Ops
.Ceiling
(Container
.Tree
, Key
);
346 return (if Node
= null then No_Element
347 else Cursor
'(Container'Unrestricted_Access, Node));
354 procedure Clear is new Tree_Operations.Generic_Clear (Delete_Tree);
356 procedure Clear (Container : in out Map) is
358 Clear (Container.Tree);
365 function Color (Node : Node_Access) return Color_Type is
370 ------------------------
371 -- Constant_Reference --
372 ------------------------
374 function Constant_Reference
375 (Container : aliased Map;
376 Position : Cursor) return Constant_Reference_Type
379 if Position.Container = null then
380 raise Constraint_Error with
381 "Position cursor has no element";
384 if Position.Container /= Container'Unrestricted_Access then
385 raise Program_Error with
386 "Position cursor designates wrong map";
389 if Position.Node.Element = null then
390 raise Program_Error with "Node has no element";
393 pragma Assert (Vet (Container.Tree, Position.Node),
394 "Position cursor in Constant_Reference is bad");
397 T : Tree_Type renames Container'Unrestricted_Access.all.Tree;
398 B : Natural renames T.Busy;
399 L : Natural renames T.Lock;
401 return R : constant Constant_Reference_Type :=
402 (Element => Position.Node.Element.all'Access,
403 Control => (Controlled with Container'Unrestricted_Access))
409 end Constant_Reference;
411 function Constant_Reference
412 (Container : aliased Map;
413 Key : Key_Type) return Constant_Reference_Type
415 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
419 raise Constraint_Error with "key not in map";
422 if Node.Element = null then
423 raise Program_Error with "Node has no element";
427 T : Tree_Type renames Container'Unrestricted_Access.all.Tree;
428 B : Natural renames T.Busy;
429 L : Natural renames T.Lock;
431 return R : constant Constant_Reference_Type :=
432 (Element => Node.Element.all'Access,
433 Control => (Controlled with Container'Unrestricted_Access))
439 end Constant_Reference;
445 function Contains (Container : Map; Key : Key_Type) return Boolean is
447 return Find (Container, Key) /= No_Element;
454 function Copy (Source : Map) return Map is
456 return Target : Map do
457 Target.Assign (Source);
465 function Copy_Node (Source : Node_Access) return Node_Access is
466 K : Key_Access := new Key_Type'(Source
.Key
.all);
470 E
:= new Element_Type
'(Source.Element.all);
472 return new Node_Type'(Parent
=> null,
475 Color
=> Source
.Color
,
490 (Container
: in out Map
;
491 Position
: in out Cursor
)
494 if Position
.Node
= null then
495 raise Constraint_Error
with
496 "Position cursor of Delete equals No_Element";
499 if Position
.Node
.Key
= null
500 or else Position
.Node
.Element
= null
502 raise Program_Error
with "Position cursor of Delete is bad";
505 if Position
.Container
/= Container
'Unrestricted_Access then
506 raise Program_Error
with
507 "Position cursor of Delete designates wrong map";
510 pragma Assert
(Vet
(Container
.Tree
, Position
.Node
),
511 "Position cursor of Delete is bad");
513 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, Position
.Node
);
514 Free
(Position
.Node
);
516 Position
.Container
:= null;
519 procedure Delete
(Container
: in out Map
; Key
: Key_Type
) is
520 X
: Node_Access
:= Key_Ops
.Find
(Container
.Tree
, Key
);
524 raise Constraint_Error
with "key not in map";
527 Delete_Node_Sans_Free
(Container
.Tree
, X
);
535 procedure Delete_First
(Container
: in out Map
) is
536 X
: Node_Access
:= Container
.Tree
.First
;
539 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, X
);
548 procedure Delete_Last
(Container
: in out Map
) is
549 X
: Node_Access
:= Container
.Tree
.Last
;
552 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, X
);
561 function Element
(Position
: Cursor
) return Element_Type
is
563 if Position
.Node
= null then
564 raise Constraint_Error
with
565 "Position cursor of function Element equals No_Element";
568 if Position
.Node
.Element
= null then
569 raise Program_Error
with
570 "Position cursor of function Element is bad";
573 pragma Assert
(Vet
(Position
.Container
.Tree
, Position
.Node
),
574 "Position cursor of function Element is bad");
576 return Position
.Node
.Element
.all;
579 function Element
(Container
: Map
; Key
: Key_Type
) return Element_Type
is
580 Node
: constant Node_Access
:= Key_Ops
.Find
(Container
.Tree
, Key
);
584 raise Constraint_Error
with "key not in map";
587 return Node
.Element
.all;
590 ---------------------
591 -- Equivalent_Keys --
592 ---------------------
594 function Equivalent_Keys
(Left
, Right
: Key_Type
) return Boolean is
596 return (if Left
< Right
or else Right
< Left
then False else True);
603 procedure Exclude
(Container
: in out Map
; Key
: Key_Type
) is
604 X
: Node_Access
:= Key_Ops
.Find
(Container
.Tree
, Key
);
607 Tree_Operations
.Delete_Node_Sans_Free
(Container
.Tree
, X
);
616 procedure Finalize
(Object
: in out Iterator
) is
618 if Object
.Container
/= null then
620 B
: Natural renames Object
.Container
.all.Tree
.Busy
;
627 procedure Finalize
(Control
: in out Reference_Control_Type
) is
629 if Control
.Container
/= null then
631 T
: Tree_Type
renames Control
.Container
.all.Tree
;
632 B
: Natural renames T
.Busy
;
633 L
: Natural renames T
.Lock
;
639 Control
.Container
:= null;
647 function Find
(Container
: Map
; Key
: Key_Type
) return Cursor
is
648 Node
: constant Node_Access
:= Key_Ops
.Find
(Container
.Tree
, Key
);
650 return (if Node
= null then No_Element
651 else Cursor
'(Container'Unrestricted_Access, Node));
658 function First (Container : Map) return Cursor is
659 T : Tree_Type renames Container.Tree;
661 return (if T.First = null then No_Element
662 else Cursor'(Container
'Unrestricted_Access, T
.First
));
665 function First
(Object
: Iterator
) return Cursor
is
667 -- The value of the iterator object's Node component influences the
668 -- behavior of the First (and Last) selector function.
670 -- When the Node component is null, this means the iterator object was
671 -- constructed without a start expression, in which case the (forward)
672 -- iteration starts from the (logical) beginning of the entire sequence
673 -- of items (corresponding to Container.First for a forward iterator).
675 -- Otherwise, this is iteration over a partial sequence of items. When
676 -- the Node component is non-null, the iterator object was constructed
677 -- with a start expression, that specifies the position from which the
678 -- (forward) partial iteration begins.
680 if Object
.Node
= null then
681 return Object
.Container
.First
;
683 return Cursor
'(Object.Container, Object.Node);
691 function First_Element (Container : Map) return Element_Type is
692 T : Tree_Type renames Container.Tree;
694 if T.First = null then
695 raise Constraint_Error with "map is empty";
697 return T.First.Element.all;
705 function First_Key (Container : Map) return Key_Type is
706 T : Tree_Type renames Container.Tree;
708 if T.First = null then
709 raise Constraint_Error with "map is empty";
711 return T.First.Key.all;
719 function Floor (Container : Map; Key : Key_Type) return Cursor is
720 Node : constant Node_Access := Key_Ops.Floor (Container.Tree, Key);
722 return (if Node = null then No_Element
723 else Cursor'(Container
'Unrestricted_Access, Node
));
730 procedure Free
(X
: in out Node_Access
) is
731 procedure Deallocate
is
732 new Ada
.Unchecked_Deallocation
(Node_Type
, Node_Access
);
751 Free_Element
(X
.Element
);
762 Free_Element
(X
.Element
);
779 function Has_Element
(Position
: Cursor
) return Boolean is
781 return Position
/= No_Element
;
789 (Container
: in out Map
;
791 New_Item
: Element_Type
)
800 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
803 if Container
.Tree
.Lock
> 0 then
804 raise Program_Error
with
805 "attempt to tamper with elements (map is locked)";
808 K
:= Position
.Node
.Key
;
809 E
:= Position
.Node
.Element
;
811 Position
.Node
.Key
:= new Key_Type
'(Key);
814 -- The element allocator may need an accessibility check in the
815 -- case the actual type is class-wide or has access discriminants
816 -- (see RM 4.8(10.1) and AI12-0035).
818 pragma Unsuppress (Accessibility_Check);
821 Position.Node.Element := new Element_Type'(New_Item
);
839 (Container
: in out Map
;
841 New_Item
: Element_Type
;
842 Position
: out Cursor
;
843 Inserted
: out Boolean)
845 function New_Node
return Node_Access
;
846 pragma Inline
(New_Node
);
848 procedure Insert_Post
is
849 new Key_Ops
.Generic_Insert_Post
(New_Node
);
851 procedure Insert_Sans_Hint
is
852 new Key_Ops
.Generic_Conditional_Insert
(Insert_Post
);
858 function New_Node
return Node_Access
is
859 Node
: Node_Access
:= new Node_Type
;
861 -- The element allocator may need an accessibility check in the case
862 -- the actual type is class-wide or has access discriminants (see
863 -- RM 4.8(10.1) and AI12-0035).
865 pragma Unsuppress
(Accessibility_Check
);
868 Node
.Key
:= new Key_Type
'(Key);
869 Node.Element := new Element_Type'(New_Item
);
875 -- On exception, deallocate key and elem. Note that free
876 -- deallocates both the key and the elem.
882 -- Start of processing for Insert
891 Position
.Container
:= Container
'Unrestricted_Access;
895 (Container
: in out Map
;
897 New_Item
: Element_Type
)
900 pragma Unreferenced
(Position
);
905 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
908 raise Constraint_Error
with "key already in map";
916 function Is_Empty
(Container
: Map
) return Boolean is
918 return Container
.Tree
.Length
= 0;
921 ------------------------
922 -- Is_Equal_Node_Node --
923 ------------------------
925 function Is_Equal_Node_Node
(L
, R
: Node_Access
) return Boolean is
927 return (if L
.Key
.all < R
.Key
.all then False
928 elsif R
.Key
.all < L
.Key
.all then False
929 else L
.Element
.all = R
.Element
.all);
930 end Is_Equal_Node_Node
;
932 -------------------------
933 -- Is_Greater_Key_Node --
934 -------------------------
936 function Is_Greater_Key_Node
938 Right
: Node_Access
) return Boolean
941 -- k > node same as node < k
943 return Right
.Key
.all < Left
;
944 end Is_Greater_Key_Node
;
946 ----------------------
947 -- Is_Less_Key_Node --
948 ----------------------
950 function Is_Less_Key_Node
952 Right
: Node_Access
) return Boolean is
954 return Left
< Right
.Key
.all;
955 end Is_Less_Key_Node
;
963 Process
: not null access procedure (Position
: Cursor
))
965 procedure Process_Node
(Node
: Node_Access
);
966 pragma Inline
(Process_Node
);
968 procedure Local_Iterate
is
969 new Tree_Operations
.Generic_Iteration
(Process_Node
);
975 procedure Process_Node
(Node
: Node_Access
) is
977 Process
(Cursor
'(Container'Unrestricted_Access, Node));
980 B : Natural renames Container'Unrestricted_Access.all.Tree.Busy;
982 -- Start of processing for Iterate
988 Local_Iterate (Container.Tree);
999 (Container : Map) return Map_Iterator_Interfaces.Reversible_Iterator'Class
1001 B : Natural renames Container'Unrestricted_Access.all.Tree.Busy;
1004 -- The value of the Node component influences the behavior of the First
1005 -- and Last selector functions of the iterator object. When the Node
1006 -- component is null (as is the case here), this means the iterator
1007 -- object was constructed without a start expression. This is a complete
1008 -- iterator, meaning that the iteration starts from the (logical)
1009 -- beginning of the sequence of items.
1011 -- Note: For a forward iterator, Container.First is the beginning, and
1012 -- for a reverse iterator, Container.Last is the beginning.
1014 return It : constant Iterator :=
1015 (Limited_Controlled with
1016 Container => Container'Unrestricted_Access,
1026 return Map_Iterator_Interfaces.Reversible_Iterator'Class
1028 B : Natural renames Container'Unrestricted_Access.all.Tree.Busy;
1031 -- It was formerly the case that when Start = No_Element, the partial
1032 -- iterator was defined to behave the same as for a complete iterator,
1033 -- and iterate over the entire sequence of items. However, those
1034 -- semantics were unintuitive and arguably error-prone (it is too easy
1035 -- to accidentally create an endless loop), and so they were changed,
1036 -- per the ARG meeting in Denver on 2011/11. However, there was no
1037 -- consensus about what positive meaning this corner case should have,
1038 -- and so it was decided to simply raise an exception. This does imply,
1039 -- however, that it is not possible to use a partial iterator to specify
1040 -- an empty sequence of items.
1042 if Start = No_Element then
1043 raise Constraint_Error with
1044 "Start position for iterator equals No_Element";
1047 if Start.Container /= Container'Unrestricted_Access then
1048 raise Program_Error with
1049 "Start cursor of Iterate designates wrong map";
1052 pragma Assert (Vet (Container.Tree, Start.Node),
1053 "Start cursor of Iterate is bad");
1055 -- The value of the Node component influences the behavior of the First
1056 -- and Last selector functions of the iterator object. When the Node
1057 -- component is non-null (as is the case here), it means that this
1058 -- is a partial iteration, over a subset of the complete sequence of
1059 -- items. The iterator object was constructed with a start expression,
1060 -- indicating the position from which the iteration begins. Note that
1061 -- the start position has the same value irrespective of whether this
1062 -- is a forward or reverse iteration.
1064 return It : constant Iterator :=
1065 (Limited_Controlled with
1066 Container => Container'Unrestricted_Access,
1077 function Key (Position : Cursor) return Key_Type is
1079 if Position.Node = null then
1080 raise Constraint_Error with
1081 "Position cursor of function Key equals No_Element";
1084 if Position.Node.Key = null then
1085 raise Program_Error with
1086 "Position cursor of function Key is bad";
1089 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1090 "Position cursor of function Key is bad");
1092 return Position.Node.Key.all;
1099 function Last (Container : Map) return Cursor is
1100 T : Tree_Type renames Container.Tree;
1102 return (if T.Last = null then No_Element
1103 else Cursor'(Container
'Unrestricted_Access, T
.Last
));
1106 function Last
(Object
: Iterator
) return Cursor
is
1108 -- The value of the iterator object's Node component influences the
1109 -- behavior of the Last (and First) selector function.
1111 -- When the Node component is null, this means the iterator object was
1112 -- constructed without a start expression, in which case the (reverse)
1113 -- iteration starts from the (logical) beginning of the entire sequence
1114 -- (corresponding to Container.Last, for a reverse iterator).
1116 -- Otherwise, this is iteration over a partial sequence of items. When
1117 -- the Node component is non-null, the iterator object was constructed
1118 -- with a start expression, that specifies the position from which the
1119 -- (reverse) partial iteration begins.
1121 if Object
.Node
= null then
1122 return Object
.Container
.Last
;
1124 return Cursor
'(Object.Container, Object.Node);
1132 function Last_Element (Container : Map) return Element_Type is
1133 T : Tree_Type renames Container.Tree;
1136 if T.Last = null then
1137 raise Constraint_Error with "map is empty";
1140 return T.Last.Element.all;
1147 function Last_Key (Container : Map) return Key_Type is
1148 T : Tree_Type renames Container.Tree;
1151 if T.Last = null then
1152 raise Constraint_Error with "map is empty";
1155 return T.Last.Key.all;
1162 function Left (Node : Node_Access) return Node_Access is
1171 function Length (Container : Map) return Count_Type is
1173 return Container.Tree.Length;
1180 procedure Move is new Tree_Operations.Generic_Move (Clear);
1182 procedure Move (Target : in out Map; Source : in out Map) is
1184 Move (Target => Target.Tree, Source => Source.Tree);
1191 function Next (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 Next is bad");
1204 Node : constant Node_Access :=
1205 Tree_Operations.Next (Position.Node);
1207 return (if Node = null then No_Element
1208 else Cursor'(Position
.Container
, Node
));
1212 procedure Next
(Position
: in out Cursor
) is
1214 Position
:= Next
(Position
);
1219 Position
: Cursor
) return Cursor
1222 if Position
.Container
= null then
1226 if Position
.Container
/= Object
.Container
then
1227 raise Program_Error
with
1228 "Position cursor of Next designates wrong map";
1231 return Next
(Position
);
1238 function Parent
(Node
: Node_Access
) return Node_Access
is
1247 function Previous
(Position
: Cursor
) return Cursor
is
1249 if Position
= No_Element
then
1253 pragma Assert
(Position
.Node
/= null);
1254 pragma Assert
(Position
.Node
.Key
/= null);
1255 pragma Assert
(Position
.Node
.Element
/= null);
1256 pragma Assert
(Vet
(Position
.Container
.Tree
, Position
.Node
),
1257 "Position cursor of Previous is bad");
1260 Node
: constant Node_Access
:=
1261 Tree_Operations
.Previous
(Position
.Node
);
1263 return (if Node
= null then No_Element
1264 else Cursor
'(Position.Container, Node));
1268 procedure Previous (Position : in out Cursor) is
1270 Position := Previous (Position);
1275 Position : Cursor) return Cursor
1278 if Position.Container = null then
1282 if Position.Container /= Object.Container then
1283 raise Program_Error with
1284 "Position cursor of Previous designates wrong map";
1287 return Previous (Position);
1294 procedure Query_Element
1296 Process : not null access procedure (Key : Key_Type;
1297 Element : Element_Type))
1300 if Position.Node = null then
1301 raise Constraint_Error with
1302 "Position cursor of Query_Element equals No_Element";
1305 if Position.Node.Key = null
1306 or else Position.Node.Element = null
1308 raise Program_Error with
1309 "Position cursor of Query_Element is bad";
1312 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1313 "Position cursor of Query_Element is bad");
1316 T : Tree_Type renames Position.Container.Tree;
1318 B : Natural renames T.Busy;
1319 L : Natural renames T.Lock;
1326 K : Key_Type renames Position.Node.Key.all;
1327 E : Element_Type renames Position.Node.Element.all;
1348 (Stream : not null access Root_Stream_Type'Class;
1349 Container : out Map)
1352 (Stream : not null access Root_Stream_Type'Class) return Node_Access;
1353 pragma Inline (Read_Node);
1356 new Tree_Operations.Generic_Read (Clear, Read_Node);
1363 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1365 Node : Node_Access := new Node_Type;
1367 Node.Key := new Key_Type'(Key_Type
'Input (Stream
));
1368 Node
.Element
:= new Element_Type
'(Element_Type'Input (Stream));
1372 Free (Node); -- Note that Free deallocates key and elem too
1376 -- Start of processing for Read
1379 Read (Stream, Container.Tree);
1383 (Stream : not null access Root_Stream_Type'Class;
1387 raise Program_Error with "attempt to stream map cursor";
1391 (Stream : not null access Root_Stream_Type'Class;
1392 Item : out Reference_Type)
1395 raise Program_Error with "attempt to stream reference";
1399 (Stream : not null access Root_Stream_Type'Class;
1400 Item : out Constant_Reference_Type)
1403 raise Program_Error with "attempt to stream reference";
1411 (Container : aliased in out Map;
1412 Position : Cursor) return Reference_Type
1415 if Position.Container = null then
1416 raise Constraint_Error with
1417 "Position cursor has no element";
1420 if Position.Container /= Container'Unrestricted_Access then
1421 raise Program_Error with
1422 "Position cursor designates wrong map";
1425 if Position.Node.Element = null then
1426 raise Program_Error with "Node has no element";
1429 pragma Assert (Vet (Container.Tree, Position.Node),
1430 "Position cursor in function Reference is bad");
1433 T : Tree_Type renames Container'Unrestricted_Access.all.Tree;
1434 B : Natural renames T.Busy;
1435 L : Natural renames T.Lock;
1437 return R : constant Reference_Type :=
1438 (Element => Position.Node.Element.all'Access,
1439 Control => (Controlled with Position.Container))
1448 (Container : aliased in out Map;
1449 Key : Key_Type) return Reference_Type
1451 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
1455 raise Constraint_Error with "key not in map";
1458 if Node.Element = null then
1459 raise Program_Error with "Node has no element";
1463 T : Tree_Type renames Container'Unrestricted_Access.all.Tree;
1464 B : Natural renames T.Busy;
1465 L : Natural renames T.Lock;
1467 return R : constant Reference_Type :=
1468 (Element => Node.Element.all'Access,
1469 Control => (Controlled with Container'Unrestricted_Access))
1482 (Container : in out Map;
1484 New_Item : Element_Type)
1486 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
1493 raise Constraint_Error with "key not in map";
1496 if Container.Tree.Lock > 0 then
1497 raise Program_Error with
1498 "attempt to tamper with elements (map is locked)";
1504 Node.Key := new Key_Type'(Key
);
1507 -- The element allocator may need an accessibility check in the case
1508 -- the actual type is class-wide or has access discriminants (see
1509 -- RM 4.8(10.1) and AI12-0035).
1511 pragma Unsuppress
(Accessibility_Check
);
1514 Node
.Element
:= new Element_Type
'(New_Item);
1526 ---------------------
1527 -- Replace_Element --
1528 ---------------------
1530 procedure Replace_Element
1531 (Container : in out Map;
1533 New_Item : Element_Type)
1536 if Position.Node = null then
1537 raise Constraint_Error with
1538 "Position cursor of Replace_Element equals No_Element";
1541 if Position.Node.Key = null
1542 or else Position.Node.Element = null
1544 raise Program_Error with
1545 "Position cursor of Replace_Element is bad";
1548 if Position.Container /= Container'Unrestricted_Access then
1549 raise Program_Error with
1550 "Position cursor of Replace_Element designates wrong map";
1553 if Container.Tree.Lock > 0 then
1554 raise Program_Error with
1555 "attempt to tamper with elements (map is locked)";
1558 pragma Assert (Vet (Container.Tree, Position.Node),
1559 "Position cursor of Replace_Element is bad");
1562 X : Element_Access := Position.Node.Element;
1564 -- The element allocator may need an accessibility check in the case
1565 -- the actual type is class-wide or has access discriminants (see
1566 -- RM 4.8(10.1) and AI12-0035).
1568 pragma Unsuppress (Accessibility_Check);
1571 Position.Node.Element := new Element_Type'(New_Item
);
1574 end Replace_Element
;
1576 ---------------------
1577 -- Reverse_Iterate --
1578 ---------------------
1580 procedure Reverse_Iterate
1582 Process
: not null access procedure (Position
: Cursor
))
1584 procedure Process_Node
(Node
: Node_Access
);
1585 pragma Inline
(Process_Node
);
1587 procedure Local_Reverse_Iterate
is
1588 new Tree_Operations
.Generic_Reverse_Iteration
(Process_Node
);
1594 procedure Process_Node
(Node
: Node_Access
) is
1596 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1599 B : Natural renames Container.Tree'Unrestricted_Access.all.Busy;
1601 -- Start of processing for Reverse_Iterate
1607 Local_Reverse_Iterate (Container.Tree);
1615 end Reverse_Iterate;
1621 function Right (Node : Node_Access) return Node_Access is
1630 procedure Set_Color (Node : Node_Access; Color : Color_Type) is
1632 Node.Color := Color;
1639 procedure Set_Left (Node : Node_Access; Left : Node_Access) is
1648 procedure Set_Parent (Node : Node_Access; Parent : Node_Access) is
1650 Node.Parent := Parent;
1657 procedure Set_Right (Node : Node_Access; Right : Node_Access) is
1659 Node.Right := Right;
1662 --------------------
1663 -- Update_Element --
1664 --------------------
1666 procedure Update_Element
1667 (Container : in out Map;
1669 Process : not null access procedure (Key : Key_Type;
1670 Element : in out Element_Type))
1673 if Position.Node = null then
1674 raise Constraint_Error with
1675 "Position cursor of Update_Element equals No_Element";
1678 if Position.Node.Key = null
1679 or else Position.Node.Element = null
1681 raise Program_Error with
1682 "Position cursor of Update_Element is bad";
1685 if Position.Container /= Container'Unrestricted_Access then
1686 raise Program_Error with
1687 "Position cursor of Update_Element designates wrong map";
1690 pragma Assert (Vet (Container.Tree, Position.Node),
1691 "Position cursor of Update_Element is bad");
1694 T : Tree_Type renames Position.Container.Tree;
1696 B : Natural renames T.Busy;
1697 L : Natural renames T.Lock;
1704 K : Key_Type renames Position.Node.Key.all;
1705 E : Element_Type renames Position.Node.Element.all;
1727 (Stream : not null access Root_Stream_Type'Class;
1730 procedure Write_Node
1731 (Stream : not null access Root_Stream_Type'Class;
1732 Node : Node_Access);
1733 pragma Inline (Write_Node);
1736 new Tree_Operations.Generic_Write (Write_Node);
1742 procedure Write_Node
1743 (Stream : not null access Root_Stream_Type'Class;
1747 Key_Type'Output (Stream, Node.Key.all);
1748 Element_Type'Output (Stream, Node.Element.all);
1751 -- Start of processing for Write
1754 Write (Stream, Container.Tree);
1758 (Stream : not null access Root_Stream_Type'Class;
1762 raise Program_Error with "attempt to stream map cursor";
1766 (Stream : not null access Root_Stream_Type'Class;
1767 Item : Reference_Type)
1770 raise Program_Error with "attempt to stream reference";
1774 (Stream : not null access Root_Stream_Type'Class;
1775 Item : Constant_Reference_Type)
1778 raise Program_Error with "attempt to stream reference";
1781 end Ada.Containers.Indefinite_Ordered_Maps;