1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . F O R M A L _ O R D E R E D _ M A P S --
9 -- Copyright (C) 2010-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/>. --
26 ------------------------------------------------------------------------------
28 with Ada
.Containers
.Red_Black_Trees
.Generic_Bounded_Operations
;
30 (Ada
.Containers
.Red_Black_Trees
.Generic_Bounded_Operations
);
32 with Ada
.Containers
.Red_Black_Trees
.Generic_Bounded_Keys
;
33 pragma Elaborate_All
(Ada
.Containers
.Red_Black_Trees
.Generic_Bounded_Keys
);
35 with System
; use type System
.Address
;
37 package body Ada
.Containers
.Formal_Ordered_Maps
is
38 pragma SPARK_Mode
(Off
);
40 -----------------------------
41 -- Node Access Subprograms --
42 -----------------------------
44 -- These subprograms provide a functional interface to access fields
45 -- of a node, and a procedural interface for modifying these values.
48 (Node
: Node_Type
) return Ada
.Containers
.Red_Black_Trees
.Color_Type
;
49 pragma Inline
(Color
);
51 function Left_Son
(Node
: Node_Type
) return Count_Type
;
52 pragma Inline
(Left_Son
);
54 function Parent
(Node
: Node_Type
) return Count_Type
;
55 pragma Inline
(Parent
);
57 function Right_Son
(Node
: Node_Type
) return Count_Type
;
58 pragma Inline
(Right_Son
);
61 (Node
: in out Node_Type
;
62 Color
: Ada
.Containers
.Red_Black_Trees
.Color_Type
);
63 pragma Inline
(Set_Color
);
65 procedure Set_Left
(Node
: in out Node_Type
; Left
: Count_Type
);
66 pragma Inline
(Set_Left
);
68 procedure Set_Right
(Node
: in out Node_Type
; Right
: Count_Type
);
69 pragma Inline
(Set_Right
);
71 procedure Set_Parent
(Node
: in out Node_Type
; Parent
: Count_Type
);
72 pragma Inline
(Set_Parent
);
74 -----------------------
75 -- Local Subprograms --
76 -----------------------
78 -- All need comments ???
81 with procedure Set_Element
(Node
: in out Node_Type
);
82 procedure Generic_Allocate
83 (Tree
: in out Tree_Types
.Tree_Type
'Class;
84 Node
: out Count_Type
);
86 procedure Free
(Tree
: in out Map
; X
: Count_Type
);
88 function Is_Greater_Key_Node
90 Right
: Node_Type
) return Boolean;
91 pragma Inline
(Is_Greater_Key_Node
);
93 function Is_Less_Key_Node
95 Right
: Node_Type
) return Boolean;
96 pragma Inline
(Is_Less_Key_Node
);
98 --------------------------
99 -- Local Instantiations --
100 --------------------------
102 package Tree_Operations
is
103 new Red_Black_Trees
.Generic_Bounded_Operations
104 (Tree_Types
=> Tree_Types
,
111 new Red_Black_Trees
.Generic_Bounded_Keys
112 (Tree_Operations
=> Tree_Operations
,
113 Key_Type
=> Key_Type
,
114 Is_Less_Key_Node
=> Is_Less_Key_Node
,
115 Is_Greater_Key_Node
=> Is_Greater_Key_Node
);
121 function "=" (Left
, Right
: Map
) return Boolean is
127 if Length
(Left
) /= Length
(Right
) then
131 if Is_Empty
(Left
) then
135 Lst
:= Next
(Left
, Last
(Left
).Node
);
137 Node
:= First
(Left
).Node
;
138 while Node
/= Lst
loop
139 ENode
:= Find
(Right
, Left
.Nodes
(Node
).Key
).Node
;
142 Left
.Nodes
(Node
).Element
/= Right
.Nodes
(ENode
).Element
147 Node
:= Next
(Left
, Node
);
157 procedure Assign
(Target
: in out Map
; Source
: Map
) is
158 procedure Append_Element
(Source_Node
: Count_Type
);
160 procedure Append_Elements
is
161 new Tree_Operations
.Generic_Iteration
(Append_Element
);
167 procedure Append_Element
(Source_Node
: Count_Type
) is
168 SN
: Node_Type
renames Source
.Nodes
(Source_Node
);
170 procedure Set_Element
(Node
: in out Node_Type
);
171 pragma Inline
(Set_Element
);
173 function New_Node
return Count_Type
;
174 pragma Inline
(New_Node
);
176 procedure Insert_Post
is new Key_Ops
.Generic_Insert_Post
(New_Node
);
178 procedure Unconditional_Insert_Sans_Hint
is
179 new Key_Ops
.Generic_Unconditional_Insert
(Insert_Post
);
181 procedure Unconditional_Insert_Avec_Hint
is
182 new Key_Ops
.Generic_Unconditional_Insert_With_Hint
184 Unconditional_Insert_Sans_Hint
);
186 procedure Allocate
is new Generic_Allocate
(Set_Element
);
192 function New_Node
return Count_Type
is
195 Allocate
(Target
, Result
);
203 procedure Set_Element
(Node
: in out Node_Type
) is
206 Node
.Element
:= SN
.Element
;
209 Target_Node
: Count_Type
;
211 -- Start of processing for Append_Element
214 Unconditional_Insert_Avec_Hint
218 Node
=> Target_Node
);
221 -- Start of processing for Assign
224 if Target
'Address = Source
'Address then
228 if Target
.Capacity
< Length
(Source
) then
229 raise Storage_Error
with "not enough capacity"; -- SE or CE? ???
232 Tree_Operations
.Clear_Tree
(Target
);
233 Append_Elements
(Source
);
240 function Ceiling
(Container
: Map
; Key
: Key_Type
) return Cursor
is
241 Node
: constant Count_Type
:= Key_Ops
.Ceiling
(Container
, Key
);
248 return (Node
=> Node
);
255 procedure Clear
(Container
: in out Map
) is
257 Tree_Operations
.Clear_Tree
(Container
);
264 function Color
(Node
: Node_Type
) return Color_Type
is
273 function Contains
(Container
: Map
; Key
: Key_Type
) return Boolean is
275 return Find
(Container
, Key
) /= No_Element
;
282 function Copy
(Source
: Map
; Capacity
: Count_Type
:= 0) return Map
is
283 Node
: Count_Type
:= 1;
287 if 0 < Capacity
and then Capacity
< Source
.Capacity
then
288 raise Capacity_Error
;
291 return Target
: Map
(Count_Type
'Max (Source
.Capacity
, Capacity
)) do
292 if Length
(Source
) > 0 then
293 Target
.Length
:= Source
.Length
;
294 Target
.Root
:= Source
.Root
;
295 Target
.First
:= Source
.First
;
296 Target
.Last
:= Source
.Last
;
297 Target
.Free
:= Source
.Free
;
299 while Node
<= Source
.Capacity
loop
300 Target
.Nodes
(Node
).Element
:=
301 Source
.Nodes
(Node
).Element
;
302 Target
.Nodes
(Node
).Key
:=
303 Source
.Nodes
(Node
).Key
;
304 Target
.Nodes
(Node
).Parent
:=
305 Source
.Nodes
(Node
).Parent
;
306 Target
.Nodes
(Node
).Left
:=
307 Source
.Nodes
(Node
).Left
;
308 Target
.Nodes
(Node
).Right
:=
309 Source
.Nodes
(Node
).Right
;
310 Target
.Nodes
(Node
).Color
:=
311 Source
.Nodes
(Node
).Color
;
312 Target
.Nodes
(Node
).Has_Element
:=
313 Source
.Nodes
(Node
).Has_Element
;
317 while Node
<= Target
.Capacity
loop
319 Formal_Ordered_Maps
.Free
(Tree
=> Target
, X
=> N
);
326 ---------------------
327 -- Current_To_Last --
328 ---------------------
330 function Current_To_Last
(Container
: Map
; Current
: Cursor
) return Map
is
331 Curs
: Cursor
:= First
(Container
);
332 C
: Map
(Container
.Capacity
) := Copy
(Container
, Container
.Capacity
);
336 if Curs
= No_Element
then
340 elsif Current
/= No_Element
and not Has_Element
(Container
, Current
) then
341 raise Constraint_Error
;
344 while Curs
.Node
/= Current
.Node
loop
347 Curs
:= Next
(Container
, (Node
=> Node
));
358 procedure Delete
(Container
: in out Map
; Position
: in out Cursor
) is
360 if not Has_Element
(Container
, Position
) then
361 raise Constraint_Error
with
362 "Position cursor of Delete has no element";
365 pragma Assert
(Vet
(Container
, Position
.Node
),
366 "Position cursor of Delete is bad");
368 Tree_Operations
.Delete_Node_Sans_Free
(Container
,
370 Formal_Ordered_Maps
.Free
(Container
, Position
.Node
);
373 procedure Delete
(Container
: in out Map
; Key
: Key_Type
) is
374 X
: constant Node_Access
:= Key_Ops
.Find
(Container
, Key
);
378 raise Constraint_Error
with "key not in map";
381 Tree_Operations
.Delete_Node_Sans_Free
(Container
, X
);
382 Formal_Ordered_Maps
.Free
(Container
, X
);
389 procedure Delete_First
(Container
: in out Map
) is
390 X
: constant Node_Access
:= First
(Container
).Node
;
393 Tree_Operations
.Delete_Node_Sans_Free
(Container
, X
);
394 Formal_Ordered_Maps
.Free
(Container
, X
);
402 procedure Delete_Last
(Container
: in out Map
) is
403 X
: constant Node_Access
:= Last
(Container
).Node
;
406 Tree_Operations
.Delete_Node_Sans_Free
(Container
, X
);
407 Formal_Ordered_Maps
.Free
(Container
, X
);
415 function Element
(Container
: Map
; Position
: Cursor
) return Element_Type
is
417 if not Has_Element
(Container
, Position
) then
418 raise Constraint_Error
with
419 "Position cursor of function Element has no element";
422 pragma Assert
(Vet
(Container
, Position
.Node
),
423 "Position cursor of function Element is bad");
425 return Container
.Nodes
(Position
.Node
).Element
;
429 function Element
(Container
: Map
; Key
: Key_Type
) return Element_Type
is
430 Node
: constant Node_Access
:= Find
(Container
, Key
).Node
;
434 raise Constraint_Error
with "key not in map";
437 return Container
.Nodes
(Node
).Element
;
440 ---------------------
441 -- Equivalent_Keys --
442 ---------------------
444 function Equivalent_Keys
(Left
, Right
: Key_Type
) return Boolean is
459 procedure Exclude
(Container
: in out Map
; Key
: Key_Type
) is
460 X
: constant Node_Access
:= Key_Ops
.Find
(Container
, Key
);
463 Tree_Operations
.Delete_Node_Sans_Free
(Container
, X
);
464 Formal_Ordered_Maps
.Free
(Container
, X
);
472 function Find
(Container
: Map
; Key
: Key_Type
) return Cursor
is
473 Node
: constant Count_Type
:= Key_Ops
.Find
(Container
, Key
);
480 return (Node
=> Node
);
487 function First
(Container
: Map
) return Cursor
is
489 if Length
(Container
) = 0 then
493 return (Node
=> Container
.First
);
500 function First_Element
(Container
: Map
) return Element_Type
is
502 if Is_Empty
(Container
) then
503 raise Constraint_Error
with "map is empty";
506 return Container
.Nodes
(First
(Container
).Node
).Element
;
513 function First_Key
(Container
: Map
) return Key_Type
is
515 if Is_Empty
(Container
) then
516 raise Constraint_Error
with "map is empty";
519 return Container
.Nodes
(First
(Container
).Node
).Key
;
522 -----------------------
523 -- First_To_Previous --
524 -----------------------
526 function First_To_Previous
528 Current
: Cursor
) return Map
530 Curs
: Cursor
:= Current
;
531 C
: Map
(Container
.Capacity
) := Copy
(Container
, Container
.Capacity
);
535 if Curs
= No_Element
then
538 elsif not Has_Element
(Container
, Curs
) then
539 raise Constraint_Error
;
542 while Curs
.Node
/= 0 loop
545 Curs
:= Next
(Container
, (Node
=> Node
));
550 end First_To_Previous
;
556 function Floor
(Container
: Map
; Key
: Key_Type
) return Cursor
is
557 Node
: constant Count_Type
:= Key_Ops
.Floor
(Container
, Key
);
564 return (Node
=> Node
);
576 Tree
.Nodes
(X
).Has_Element
:= False;
577 Tree_Operations
.Free
(Tree
, X
);
580 ----------------------
581 -- Generic_Allocate --
582 ----------------------
584 procedure Generic_Allocate
585 (Tree
: in out Tree_Types
.Tree_Type
'Class;
586 Node
: out Count_Type
)
588 procedure Allocate
is
589 new Tree_Operations
.Generic_Allocate
(Set_Element
);
591 Allocate
(Tree
, Node
);
592 Tree
.Nodes
(Node
).Has_Element
:= True;
593 end Generic_Allocate
;
599 function Has_Element
(Container
: Map
; Position
: Cursor
) return Boolean is
601 if Position
.Node
= 0 then
605 return Container
.Nodes
(Position
.Node
).Has_Element
;
613 (Container
: in out Map
;
615 New_Item
: Element_Type
)
621 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
625 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
628 N
.Element
:= New_Item
;
634 (Container
: in out Map
;
636 New_Item
: Element_Type
;
637 Position
: out Cursor
;
638 Inserted
: out Boolean)
640 function New_Node
return Node_Access
;
643 procedure Insert_Post
is
644 new Key_Ops
.Generic_Insert_Post
(New_Node
);
646 procedure Insert_Sans_Hint
is
647 new Key_Ops
.Generic_Conditional_Insert
(Insert_Post
);
653 function New_Node
return Node_Access
is
654 procedure Initialize
(Node
: in out Node_Type
);
655 procedure Allocate_Node
is new Generic_Allocate
(Initialize
);
657 procedure Initialize
(Node
: in out Node_Type
) is
660 Node
.Element
:= New_Item
;
666 Allocate_Node
(Container
, X
);
670 -- Start of processing for Insert
681 (Container
: in out Map
;
683 New_Item
: Element_Type
)
689 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
692 raise Constraint_Error
with "key already in map";
700 function Is_Empty
(Container
: Map
) return Boolean is
702 return Length
(Container
) = 0;
705 -------------------------
706 -- Is_Greater_Key_Node --
707 -------------------------
709 function Is_Greater_Key_Node
711 Right
: Node_Type
) return Boolean
714 -- k > node same as node < k
716 return Right
.Key
< Left
;
717 end Is_Greater_Key_Node
;
719 ----------------------
720 -- Is_Less_Key_Node --
721 ----------------------
723 function Is_Less_Key_Node
725 Right
: Node_Type
) return Boolean
728 return Left
< Right
.Key
;
729 end Is_Less_Key_Node
;
735 function Key
(Container
: Map
; Position
: Cursor
) return Key_Type
is
737 if not Has_Element
(Container
, Position
) then
738 raise Constraint_Error
with
739 "Position cursor of function Key has no element";
742 pragma Assert
(Vet
(Container
, Position
.Node
),
743 "Position cursor of function Key is bad");
745 return Container
.Nodes
(Position
.Node
).Key
;
752 function Last
(Container
: Map
) return Cursor
is
754 if Length
(Container
) = 0 then
758 return (Node
=> Container
.Last
);
765 function Last_Element
(Container
: Map
) return Element_Type
is
767 if Is_Empty
(Container
) then
768 raise Constraint_Error
with "map is empty";
771 return Container
.Nodes
(Last
(Container
).Node
).Element
;
778 function Last_Key
(Container
: Map
) return Key_Type
is
780 if Is_Empty
(Container
) then
781 raise Constraint_Error
with "map is empty";
784 return Container
.Nodes
(Last
(Container
).Node
).Key
;
791 function Left_Son
(Node
: Node_Type
) return Count_Type
is
800 function Length
(Container
: Map
) return Count_Type
is
802 return Container
.Length
;
809 procedure Move
(Target
: in out Map
; Source
: in out Map
) is
810 NN
: Tree_Types
.Nodes_Type
renames Source
.Nodes
;
814 if Target
'Address = Source
'Address then
818 if Target
.Capacity
< Length
(Source
) then
819 raise Constraint_Error
with -- ???
820 "Source length exceeds Target capacity";
826 X
:= First
(Source
).Node
;
829 -- Here we insert a copy of the source element into the target, and
830 -- then delete the element from the source. Another possibility is
831 -- that delete it first (and hang onto its index), then insert it.
834 Insert
(Target
, NN
(X
).Key
, NN
(X
).Element
); -- optimize???
836 Tree_Operations
.Delete_Node_Sans_Free
(Source
, X
);
837 Formal_Ordered_Maps
.Free
(Source
, X
);
845 procedure Next
(Container
: Map
; Position
: in out Cursor
) is
847 Position
:= Next
(Container
, Position
);
850 function Next
(Container
: Map
; Position
: Cursor
) return Cursor
is
852 if Position
= No_Element
then
856 if not Has_Element
(Container
, Position
) then
857 raise Constraint_Error
;
860 pragma Assert
(Vet
(Container
, Position
.Node
),
861 "bad cursor in Next");
863 return (Node
=> Tree_Operations
.Next
(Container
, Position
.Node
));
870 function Overlap
(Left
, Right
: Map
) return Boolean is
872 if Length
(Left
) = 0 or Length
(Right
) = 0 then
877 L_Node
: Count_Type
:= First
(Left
).Node
;
878 R_Node
: Count_Type
:= First
(Right
).Node
;
879 L_Last
: constant Count_Type
:= Next
(Left
, Last
(Left
).Node
);
880 R_Last
: constant Count_Type
:= Next
(Right
, Last
(Right
).Node
);
883 if Left
'Address = Right
'Address then
889 or else R_Node
= R_Last
894 if Left
.Nodes
(L_Node
).Key
< Right
.Nodes
(R_Node
).Key
then
895 L_Node
:= Next
(Left
, L_Node
);
897 elsif Right
.Nodes
(R_Node
).Key
< Left
.Nodes
(L_Node
).Key
then
898 R_Node
:= Next
(Right
, R_Node
);
911 function Parent
(Node
: Node_Type
) return Count_Type
is
920 procedure Previous
(Container
: Map
; Position
: in out Cursor
) is
922 Position
:= Previous
(Container
, Position
);
925 function Previous
(Container
: Map
; Position
: Cursor
) return Cursor
is
927 if Position
= No_Element
then
931 if not Has_Element
(Container
, Position
) then
932 raise Constraint_Error
;
935 pragma Assert
(Vet
(Container
, Position
.Node
),
936 "bad cursor in Previous");
939 Node
: constant Count_Type
:=
940 Tree_Operations
.Previous
(Container
, Position
.Node
);
947 return (Node
=> Node
);
956 (Container
: in out Map
;
958 New_Item
: Element_Type
)
962 Node
: constant Node_Access
:= Key_Ops
.Find
(Container
, Key
);
966 raise Constraint_Error
with "key not in map";
970 N
: Node_Type
renames Container
.Nodes
(Node
);
973 N
.Element
:= New_Item
;
978 ---------------------
979 -- Replace_Element --
980 ---------------------
982 procedure Replace_Element
983 (Container
: in out Map
;
985 New_Item
: Element_Type
)
988 if not Has_Element
(Container
, Position
) then
989 raise Constraint_Error
with
990 "Position cursor of Replace_Element has no element";
993 pragma Assert
(Vet
(Container
, Position
.Node
),
994 "Position cursor of Replace_Element is bad");
996 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
1003 function Right_Son
(Node
: Node_Type
) return Count_Type
is
1012 procedure Set_Color
(Node
: in out Node_Type
; Color
: Color_Type
) is
1014 Node
.Color
:= Color
;
1021 procedure Set_Left
(Node
: in out Node_Type
; Left
: Count_Type
) is
1030 procedure Set_Parent
(Node
: in out Node_Type
; Parent
: Count_Type
) is
1032 Node
.Parent
:= Parent
;
1039 procedure Set_Right
(Node
: in out Node_Type
; Right
: Count_Type
) is
1041 Node
.Right
:= Right
;
1048 function Strict_Equal
(Left
, Right
: Map
) return Boolean is
1049 LNode
: Count_Type
:= First
(Left
).Node
;
1050 RNode
: Count_Type
:= First
(Right
).Node
;
1053 if Length
(Left
) /= Length
(Right
) then
1057 while LNode
= RNode
loop
1062 if Left
.Nodes
(LNode
).Element
/= Right
.Nodes
(RNode
).Element
1063 or else Left
.Nodes
(LNode
).Key
/= Right
.Nodes
(RNode
).Key
1068 LNode
:= Next
(Left
, LNode
);
1069 RNode
:= Next
(Right
, RNode
);
1075 end Ada
.Containers
.Formal_Ordered_Maps
;