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
with
40 pragma Annotate
(CodePeer
, Skip_Analysis
);
42 -----------------------------
43 -- Node Access Subprograms --
44 -----------------------------
46 -- These subprograms provide a functional interface to access fields
47 -- of a node, and a procedural interface for modifying these values.
50 (Node
: Node_Type
) return Ada
.Containers
.Red_Black_Trees
.Color_Type
;
51 pragma Inline
(Color
);
53 function Left_Son
(Node
: Node_Type
) return Count_Type
;
54 pragma Inline
(Left_Son
);
56 function Parent
(Node
: Node_Type
) return Count_Type
;
57 pragma Inline
(Parent
);
59 function Right_Son
(Node
: Node_Type
) return Count_Type
;
60 pragma Inline
(Right_Son
);
63 (Node
: in out Node_Type
;
64 Color
: Ada
.Containers
.Red_Black_Trees
.Color_Type
);
65 pragma Inline
(Set_Color
);
67 procedure Set_Left
(Node
: in out Node_Type
; Left
: Count_Type
);
68 pragma Inline
(Set_Left
);
70 procedure Set_Right
(Node
: in out Node_Type
; Right
: Count_Type
);
71 pragma Inline
(Set_Right
);
73 procedure Set_Parent
(Node
: in out Node_Type
; Parent
: Count_Type
);
74 pragma Inline
(Set_Parent
);
76 -----------------------
77 -- Local Subprograms --
78 -----------------------
80 -- All need comments ???
83 with procedure Set_Element
(Node
: in out Node_Type
);
84 procedure Generic_Allocate
85 (Tree
: in out Tree_Types
.Tree_Type
'Class;
86 Node
: out Count_Type
);
88 procedure Free
(Tree
: in out Map
; X
: Count_Type
);
90 function Is_Greater_Key_Node
92 Right
: Node_Type
) return Boolean;
93 pragma Inline
(Is_Greater_Key_Node
);
95 function Is_Less_Key_Node
97 Right
: Node_Type
) return Boolean;
98 pragma Inline
(Is_Less_Key_Node
);
100 --------------------------
101 -- Local Instantiations --
102 --------------------------
104 package Tree_Operations
is
105 new Red_Black_Trees
.Generic_Bounded_Operations
106 (Tree_Types
=> Tree_Types
,
113 new Red_Black_Trees
.Generic_Bounded_Keys
114 (Tree_Operations
=> Tree_Operations
,
115 Key_Type
=> Key_Type
,
116 Is_Less_Key_Node
=> Is_Less_Key_Node
,
117 Is_Greater_Key_Node
=> Is_Greater_Key_Node
);
123 function "=" (Left
, Right
: Map
) return Boolean is
129 if Length
(Left
) /= Length
(Right
) then
133 if Is_Empty
(Left
) then
137 Lst
:= Next
(Left
, Last
(Left
).Node
);
139 Node
:= First
(Left
).Node
;
140 while Node
/= Lst
loop
141 ENode
:= Find
(Right
, Left
.Nodes
(Node
).Key
).Node
;
144 Left
.Nodes
(Node
).Element
/= Right
.Nodes
(ENode
).Element
149 Node
:= Next
(Left
, Node
);
159 procedure Assign
(Target
: in out Map
; Source
: Map
) is
160 procedure Append_Element
(Source_Node
: Count_Type
);
162 procedure Append_Elements
is
163 new Tree_Operations
.Generic_Iteration
(Append_Element
);
169 procedure Append_Element
(Source_Node
: Count_Type
) is
170 SN
: Node_Type
renames Source
.Nodes
(Source_Node
);
172 procedure Set_Element
(Node
: in out Node_Type
);
173 pragma Inline
(Set_Element
);
175 function New_Node
return Count_Type
;
176 pragma Inline
(New_Node
);
178 procedure Insert_Post
is new Key_Ops
.Generic_Insert_Post
(New_Node
);
180 procedure Unconditional_Insert_Sans_Hint
is
181 new Key_Ops
.Generic_Unconditional_Insert
(Insert_Post
);
183 procedure Unconditional_Insert_Avec_Hint
is
184 new Key_Ops
.Generic_Unconditional_Insert_With_Hint
186 Unconditional_Insert_Sans_Hint
);
188 procedure Allocate
is new Generic_Allocate
(Set_Element
);
194 function New_Node
return Count_Type
is
197 Allocate
(Target
, Result
);
205 procedure Set_Element
(Node
: in out Node_Type
) is
208 Node
.Element
:= SN
.Element
;
211 Target_Node
: Count_Type
;
213 -- Start of processing for Append_Element
216 Unconditional_Insert_Avec_Hint
220 Node
=> Target_Node
);
223 -- Start of processing for Assign
226 if Target
'Address = Source
'Address then
230 if Target
.Capacity
< Length
(Source
) then
231 raise Storage_Error
with "not enough capacity"; -- SE or CE? ???
234 Tree_Operations
.Clear_Tree
(Target
);
235 Append_Elements
(Source
);
242 function Ceiling
(Container
: Map
; Key
: Key_Type
) return Cursor
is
243 Node
: constant Count_Type
:= Key_Ops
.Ceiling
(Container
, Key
);
250 return (Node
=> Node
);
257 procedure Clear
(Container
: in out Map
) is
259 Tree_Operations
.Clear_Tree
(Container
);
266 function Color
(Node
: Node_Type
) return Color_Type
is
275 function Contains
(Container
: Map
; Key
: Key_Type
) return Boolean is
277 return Find
(Container
, Key
) /= No_Element
;
284 function Copy
(Source
: Map
; Capacity
: Count_Type
:= 0) return Map
is
285 Node
: Count_Type
:= 1;
289 if 0 < Capacity
and then Capacity
< Source
.Capacity
then
290 raise Capacity_Error
;
293 return Target
: Map
(Count_Type
'Max (Source
.Capacity
, Capacity
)) do
294 if Length
(Source
) > 0 then
295 Target
.Length
:= Source
.Length
;
296 Target
.Root
:= Source
.Root
;
297 Target
.First
:= Source
.First
;
298 Target
.Last
:= Source
.Last
;
299 Target
.Free
:= Source
.Free
;
301 while Node
<= Source
.Capacity
loop
302 Target
.Nodes
(Node
).Element
:=
303 Source
.Nodes
(Node
).Element
;
304 Target
.Nodes
(Node
).Key
:=
305 Source
.Nodes
(Node
).Key
;
306 Target
.Nodes
(Node
).Parent
:=
307 Source
.Nodes
(Node
).Parent
;
308 Target
.Nodes
(Node
).Left
:=
309 Source
.Nodes
(Node
).Left
;
310 Target
.Nodes
(Node
).Right
:=
311 Source
.Nodes
(Node
).Right
;
312 Target
.Nodes
(Node
).Color
:=
313 Source
.Nodes
(Node
).Color
;
314 Target
.Nodes
(Node
).Has_Element
:=
315 Source
.Nodes
(Node
).Has_Element
;
319 while Node
<= Target
.Capacity
loop
321 Formal_Ordered_Maps
.Free
(Tree
=> Target
, X
=> N
);
328 ---------------------
329 -- Current_To_Last --
330 ---------------------
332 function Current_To_Last
(Container
: Map
; Current
: Cursor
) return Map
is
333 Curs
: Cursor
:= First
(Container
);
334 C
: Map
(Container
.Capacity
) := Copy
(Container
, Container
.Capacity
);
338 if Curs
= No_Element
then
342 elsif Current
/= No_Element
and not Has_Element
(Container
, Current
) then
343 raise Constraint_Error
;
346 while Curs
.Node
/= Current
.Node
loop
349 Curs
:= Next
(Container
, (Node
=> Node
));
360 procedure Delete
(Container
: in out Map
; Position
: in out Cursor
) is
362 if not Has_Element
(Container
, Position
) then
363 raise Constraint_Error
with
364 "Position cursor of Delete has no element";
367 pragma Assert
(Vet
(Container
, Position
.Node
),
368 "Position cursor of Delete is bad");
370 Tree_Operations
.Delete_Node_Sans_Free
(Container
,
372 Formal_Ordered_Maps
.Free
(Container
, Position
.Node
);
375 procedure Delete
(Container
: in out Map
; Key
: Key_Type
) is
376 X
: constant Node_Access
:= Key_Ops
.Find
(Container
, Key
);
380 raise Constraint_Error
with "key not in map";
383 Tree_Operations
.Delete_Node_Sans_Free
(Container
, X
);
384 Formal_Ordered_Maps
.Free
(Container
, X
);
391 procedure Delete_First
(Container
: in out Map
) is
392 X
: constant Node_Access
:= First
(Container
).Node
;
395 Tree_Operations
.Delete_Node_Sans_Free
(Container
, X
);
396 Formal_Ordered_Maps
.Free
(Container
, X
);
404 procedure Delete_Last
(Container
: in out Map
) is
405 X
: constant Node_Access
:= Last
(Container
).Node
;
408 Tree_Operations
.Delete_Node_Sans_Free
(Container
, X
);
409 Formal_Ordered_Maps
.Free
(Container
, X
);
417 function Element
(Container
: Map
; Position
: Cursor
) return Element_Type
is
419 if not Has_Element
(Container
, Position
) then
420 raise Constraint_Error
with
421 "Position cursor of function Element has no element";
424 pragma Assert
(Vet
(Container
, Position
.Node
),
425 "Position cursor of function Element is bad");
427 return Container
.Nodes
(Position
.Node
).Element
;
431 function Element
(Container
: Map
; Key
: Key_Type
) return Element_Type
is
432 Node
: constant Node_Access
:= Find
(Container
, Key
).Node
;
436 raise Constraint_Error
with "key not in map";
439 return Container
.Nodes
(Node
).Element
;
442 ---------------------
443 -- Equivalent_Keys --
444 ---------------------
446 function Equivalent_Keys
(Left
, Right
: Key_Type
) return Boolean is
461 procedure Exclude
(Container
: in out Map
; Key
: Key_Type
) is
462 X
: constant Node_Access
:= Key_Ops
.Find
(Container
, Key
);
465 Tree_Operations
.Delete_Node_Sans_Free
(Container
, X
);
466 Formal_Ordered_Maps
.Free
(Container
, X
);
474 function Find
(Container
: Map
; Key
: Key_Type
) return Cursor
is
475 Node
: constant Count_Type
:= Key_Ops
.Find
(Container
, Key
);
482 return (Node
=> Node
);
489 function First
(Container
: Map
) return Cursor
is
491 if Length
(Container
) = 0 then
495 return (Node
=> Container
.First
);
502 function First_Element
(Container
: Map
) return Element_Type
is
504 if Is_Empty
(Container
) then
505 raise Constraint_Error
with "map is empty";
508 return Container
.Nodes
(First
(Container
).Node
).Element
;
515 function First_Key
(Container
: Map
) return Key_Type
is
517 if Is_Empty
(Container
) then
518 raise Constraint_Error
with "map is empty";
521 return Container
.Nodes
(First
(Container
).Node
).Key
;
524 -----------------------
525 -- First_To_Previous --
526 -----------------------
528 function First_To_Previous
530 Current
: Cursor
) return Map
532 Curs
: Cursor
:= Current
;
533 C
: Map
(Container
.Capacity
) := Copy
(Container
, Container
.Capacity
);
537 if Curs
= No_Element
then
540 elsif not Has_Element
(Container
, Curs
) then
541 raise Constraint_Error
;
544 while Curs
.Node
/= 0 loop
547 Curs
:= Next
(Container
, (Node
=> Node
));
552 end First_To_Previous
;
558 function Floor
(Container
: Map
; Key
: Key_Type
) return Cursor
is
559 Node
: constant Count_Type
:= Key_Ops
.Floor
(Container
, Key
);
566 return (Node
=> Node
);
578 Tree
.Nodes
(X
).Has_Element
:= False;
579 Tree_Operations
.Free
(Tree
, X
);
582 ----------------------
583 -- Generic_Allocate --
584 ----------------------
586 procedure Generic_Allocate
587 (Tree
: in out Tree_Types
.Tree_Type
'Class;
588 Node
: out Count_Type
)
590 procedure Allocate
is
591 new Tree_Operations
.Generic_Allocate
(Set_Element
);
593 Allocate
(Tree
, Node
);
594 Tree
.Nodes
(Node
).Has_Element
:= True;
595 end Generic_Allocate
;
601 function Has_Element
(Container
: Map
; Position
: Cursor
) return Boolean is
603 if Position
.Node
= 0 then
607 return Container
.Nodes
(Position
.Node
).Has_Element
;
615 (Container
: in out Map
;
617 New_Item
: Element_Type
)
623 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
627 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
630 N
.Element
:= New_Item
;
636 (Container
: in out Map
;
638 New_Item
: Element_Type
;
639 Position
: out Cursor
;
640 Inserted
: out Boolean)
642 function New_Node
return Node_Access
;
645 procedure Insert_Post
is
646 new Key_Ops
.Generic_Insert_Post
(New_Node
);
648 procedure Insert_Sans_Hint
is
649 new Key_Ops
.Generic_Conditional_Insert
(Insert_Post
);
655 function New_Node
return Node_Access
is
656 procedure Initialize
(Node
: in out Node_Type
);
657 procedure Allocate_Node
is new Generic_Allocate
(Initialize
);
659 procedure Initialize
(Node
: in out Node_Type
) is
662 Node
.Element
:= New_Item
;
668 Allocate_Node
(Container
, X
);
672 -- Start of processing for Insert
683 (Container
: in out Map
;
685 New_Item
: Element_Type
)
691 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
694 raise Constraint_Error
with "key already in map";
702 function Is_Empty
(Container
: Map
) return Boolean is
704 return Length
(Container
) = 0;
707 -------------------------
708 -- Is_Greater_Key_Node --
709 -------------------------
711 function Is_Greater_Key_Node
713 Right
: Node_Type
) return Boolean
716 -- k > node same as node < k
718 return Right
.Key
< Left
;
719 end Is_Greater_Key_Node
;
721 ----------------------
722 -- Is_Less_Key_Node --
723 ----------------------
725 function Is_Less_Key_Node
727 Right
: Node_Type
) return Boolean
730 return Left
< Right
.Key
;
731 end Is_Less_Key_Node
;
737 function Key
(Container
: Map
; Position
: Cursor
) return Key_Type
is
739 if not Has_Element
(Container
, Position
) then
740 raise Constraint_Error
with
741 "Position cursor of function Key has no element";
744 pragma Assert
(Vet
(Container
, Position
.Node
),
745 "Position cursor of function Key is bad");
747 return Container
.Nodes
(Position
.Node
).Key
;
754 function Last
(Container
: Map
) return Cursor
is
756 if Length
(Container
) = 0 then
760 return (Node
=> Container
.Last
);
767 function Last_Element
(Container
: Map
) return Element_Type
is
769 if Is_Empty
(Container
) then
770 raise Constraint_Error
with "map is empty";
773 return Container
.Nodes
(Last
(Container
).Node
).Element
;
780 function Last_Key
(Container
: Map
) return Key_Type
is
782 if Is_Empty
(Container
) then
783 raise Constraint_Error
with "map is empty";
786 return Container
.Nodes
(Last
(Container
).Node
).Key
;
793 function Left_Son
(Node
: Node_Type
) return Count_Type
is
802 function Length
(Container
: Map
) return Count_Type
is
804 return Container
.Length
;
811 procedure Move
(Target
: in out Map
; Source
: in out Map
) is
812 NN
: Tree_Types
.Nodes_Type
renames Source
.Nodes
;
816 if Target
'Address = Source
'Address then
820 if Target
.Capacity
< Length
(Source
) then
821 raise Constraint_Error
with -- ???
822 "Source length exceeds Target capacity";
828 X
:= First
(Source
).Node
;
831 -- Here we insert a copy of the source element into the target, and
832 -- then delete the element from the source. Another possibility is
833 -- that delete it first (and hang onto its index), then insert it.
836 Insert
(Target
, NN
(X
).Key
, NN
(X
).Element
); -- optimize???
838 Tree_Operations
.Delete_Node_Sans_Free
(Source
, X
);
839 Formal_Ordered_Maps
.Free
(Source
, X
);
847 procedure Next
(Container
: Map
; Position
: in out Cursor
) is
849 Position
:= Next
(Container
, Position
);
852 function Next
(Container
: Map
; Position
: Cursor
) return Cursor
is
854 if Position
= No_Element
then
858 if not Has_Element
(Container
, Position
) then
859 raise Constraint_Error
;
862 pragma Assert
(Vet
(Container
, Position
.Node
),
863 "bad cursor in Next");
865 return (Node
=> Tree_Operations
.Next
(Container
, Position
.Node
));
872 function Overlap
(Left
, Right
: Map
) return Boolean is
874 if Length
(Left
) = 0 or Length
(Right
) = 0 then
879 L_Node
: Count_Type
:= First
(Left
).Node
;
880 R_Node
: Count_Type
:= First
(Right
).Node
;
881 L_Last
: constant Count_Type
:= Next
(Left
, Last
(Left
).Node
);
882 R_Last
: constant Count_Type
:= Next
(Right
, Last
(Right
).Node
);
885 if Left
'Address = Right
'Address then
891 or else R_Node
= R_Last
896 if Left
.Nodes
(L_Node
).Key
< Right
.Nodes
(R_Node
).Key
then
897 L_Node
:= Next
(Left
, L_Node
);
899 elsif Right
.Nodes
(R_Node
).Key
< Left
.Nodes
(L_Node
).Key
then
900 R_Node
:= Next
(Right
, R_Node
);
913 function Parent
(Node
: Node_Type
) return Count_Type
is
922 procedure Previous
(Container
: Map
; Position
: in out Cursor
) is
924 Position
:= Previous
(Container
, Position
);
927 function Previous
(Container
: Map
; Position
: Cursor
) return Cursor
is
929 if Position
= No_Element
then
933 if not Has_Element
(Container
, Position
) then
934 raise Constraint_Error
;
937 pragma Assert
(Vet
(Container
, Position
.Node
),
938 "bad cursor in Previous");
941 Node
: constant Count_Type
:=
942 Tree_Operations
.Previous
(Container
, Position
.Node
);
949 return (Node
=> Node
);
958 (Container
: in out Map
;
960 New_Item
: Element_Type
)
964 Node
: constant Node_Access
:= Key_Ops
.Find
(Container
, Key
);
968 raise Constraint_Error
with "key not in map";
972 N
: Node_Type
renames Container
.Nodes
(Node
);
975 N
.Element
:= New_Item
;
980 ---------------------
981 -- Replace_Element --
982 ---------------------
984 procedure Replace_Element
985 (Container
: in out Map
;
987 New_Item
: Element_Type
)
990 if not Has_Element
(Container
, Position
) then
991 raise Constraint_Error
with
992 "Position cursor of Replace_Element has no element";
995 pragma Assert
(Vet
(Container
, Position
.Node
),
996 "Position cursor of Replace_Element is bad");
998 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
1005 function Right_Son
(Node
: Node_Type
) return Count_Type
is
1014 procedure Set_Color
(Node
: in out Node_Type
; Color
: Color_Type
) is
1016 Node
.Color
:= Color
;
1023 procedure Set_Left
(Node
: in out Node_Type
; Left
: Count_Type
) is
1032 procedure Set_Parent
(Node
: in out Node_Type
; Parent
: Count_Type
) is
1034 Node
.Parent
:= Parent
;
1041 procedure Set_Right
(Node
: in out Node_Type
; Right
: Count_Type
) is
1043 Node
.Right
:= Right
;
1050 function Strict_Equal
(Left
, Right
: Map
) return Boolean is
1051 LNode
: Count_Type
:= First
(Left
).Node
;
1052 RNode
: Count_Type
:= First
(Right
).Node
;
1055 if Length
(Left
) /= Length
(Right
) then
1059 while LNode
= RNode
loop
1064 if Left
.Nodes
(LNode
).Element
/= Right
.Nodes
(RNode
).Element
1065 or else Left
.Nodes
(LNode
).Key
/= Right
.Nodes
(RNode
).Key
1070 LNode
:= Next
(Left
, LNode
);
1071 RNode
:= Next
(Right
, RNode
);
1077 end Ada
.Containers
.Formal_Ordered_Maps
;