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 _ H A S H E D _ M A P S --
9 -- Copyright (C) 2010-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/>. --
26 ------------------------------------------------------------------------------
28 with Ada
.Containers
.Hash_Tables
.Generic_Bounded_Operations
;
29 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Bounded_Operations
);
31 with Ada
.Containers
.Hash_Tables
.Generic_Bounded_Keys
;
32 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Bounded_Keys
);
34 with Ada
.Containers
.Prime_Numbers
; use Ada
.Containers
.Prime_Numbers
;
36 with System
; use type System
.Address
;
38 package body Ada
.Containers
.Formal_Hashed_Maps
with
42 -----------------------
43 -- Local Subprograms --
44 -----------------------
46 -- All local subprograms require comments ???
48 function Equivalent_Keys
50 Node
: Node_Type
) return Boolean;
51 pragma Inline
(Equivalent_Keys
);
58 with procedure Set_Element
(Node
: in out Node_Type
);
59 procedure Generic_Allocate
61 Node
: out Count_Type
);
63 function Hash_Node
(Node
: Node_Type
) return Hash_Type
;
64 pragma Inline
(Hash_Node
);
66 function Next
(Node
: Node_Type
) return Count_Type
;
69 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
);
70 pragma Inline
(Set_Next
);
72 function Vet
(Container
: Map
; Position
: Cursor
) return Boolean;
74 --------------------------
75 -- Local Instantiations --
76 --------------------------
79 new Hash_Tables
.Generic_Bounded_Operations
80 (HT_Types
=> HT_Types
,
81 Hash_Node
=> Hash_Node
,
83 Set_Next
=> Set_Next
);
86 new Hash_Tables
.Generic_Bounded_Keys
87 (HT_Types
=> HT_Types
,
92 Equivalent_Keys
=> Equivalent_Keys
);
98 function "=" (Left
, Right
: Map
) return Boolean is
100 if Length
(Left
) /= Length
(Right
) then
104 if Length
(Left
) = 0 then
113 Node
:= Left
.First
.Node
;
115 ENode
:= Find
(Container
=> Right
,
116 Key
=> Left
.Nodes
(Node
).Key
).Node
;
119 Right
.Nodes
(ENode
).Element
/= Left
.Nodes
(Node
).Element
124 Node
:= HT_Ops
.Next
(Left
, Node
);
135 procedure Assign
(Target
: in out Map
; Source
: Map
) is
136 procedure Insert_Element
(Source_Node
: Count_Type
);
137 pragma Inline
(Insert_Element
);
139 procedure Insert_Elements
is
140 new HT_Ops
.Generic_Iteration
(Insert_Element
);
146 procedure Insert_Element
(Source_Node
: Count_Type
) is
147 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
149 Insert
(Target
, N
.Key
, N
.Element
);
152 -- Start of processing for Assign
155 if Target
'Address = Source
'Address then
159 if Target
.Capacity
< Length
(Source
) then
160 raise Constraint_Error
with -- correct exception ???
161 "Source length exceeds Target capacity";
166 Insert_Elements
(Source
);
173 function Capacity
(Container
: Map
) return Count_Type
is
175 return Container
.Nodes
'Length;
182 procedure Clear
(Container
: in out Map
) is
184 HT_Ops
.Clear
(Container
);
191 function Contains
(Container
: Map
; Key
: Key_Type
) return Boolean is
193 return Find
(Container
, Key
) /= No_Element
;
202 Capacity
: Count_Type
:= 0) return Map
204 C
: constant Count_Type
:=
205 Count_Type
'Max (Capacity
, Source
.Capacity
);
208 Target
: Map
(C
, Source
.Modulus
);
212 if 0 < Capacity
and then Capacity
< Source
.Capacity
then
213 raise Capacity_Error
;
216 Target
.Length
:= Source
.Length
;
217 Target
.Free
:= Source
.Free
;
220 while H
<= Source
.Modulus
loop
221 Target
.Buckets
(H
) := Source
.Buckets
(H
);
226 while N
<= Source
.Capacity
loop
227 Target
.Nodes
(N
) := Source
.Nodes
(N
);
233 Free
(Target
, Cu
.Node
);
240 ---------------------
241 -- Current_To_Last --
242 ---------------------
244 function Current_To_Last
(Container
: Map
; Current
: Cursor
) return Map
is
245 Curs
: Cursor
:= First
(Container
);
246 C
: Map
(Container
.Capacity
, Container
.Modulus
) :=
247 Copy
(Container
, Container
.Capacity
);
251 if Curs
= No_Element
then
255 elsif Current
/= No_Element
and not Has_Element
(Container
, Current
) then
256 raise Constraint_Error
;
259 while Curs
.Node
/= Current
.Node
loop
262 Curs
:= Next
(Container
, (Node
=> Node
));
269 ---------------------
270 -- Default_Modulus --
271 ---------------------
273 function Default_Modulus
(Capacity
: Count_Type
) return Hash_Type
is
275 return To_Prime
(Capacity
);
282 procedure Delete
(Container
: in out Map
; Key
: Key_Type
) is
286 Key_Ops
.Delete_Key_Sans_Free
(Container
, Key
, X
);
289 raise Constraint_Error
with "attempt to delete key not in map";
295 procedure Delete
(Container
: in out Map
; Position
: in out Cursor
) is
297 if not Has_Element
(Container
, Position
) then
298 raise Constraint_Error
with
299 "Position cursor of Delete has no element";
302 pragma Assert
(Vet
(Container
, Position
), "bad cursor in Delete");
304 HT_Ops
.Delete_Node_Sans_Free
(Container
, Position
.Node
);
306 Free
(Container
, Position
.Node
);
313 function Element
(Container
: Map
; Key
: Key_Type
) return Element_Type
is
314 Node
: constant Count_Type
:= Find
(Container
, Key
).Node
;
318 raise Constraint_Error
with
319 "no element available because key not in map";
322 return Container
.Nodes
(Node
).Element
;
325 function Element
(Container
: Map
; Position
: Cursor
) return Element_Type
is
327 if not Has_Element
(Container
, Position
) then
328 raise Constraint_Error
with "Position cursor equals No_Element";
331 pragma Assert
(Vet
(Container
, Position
),
332 "bad cursor in function Element");
334 return Container
.Nodes
(Position
.Node
).Element
;
337 ---------------------
338 -- Equivalent_Keys --
339 ---------------------
341 function Equivalent_Keys
343 Node
: Node_Type
) return Boolean
346 return Equivalent_Keys
(Key
, Node
.Key
);
349 function Equivalent_Keys
353 CRight
: Cursor
) return Boolean
356 if not Has_Element
(Left
, CLeft
) then
357 raise Constraint_Error
with
358 "Left cursor of Equivalent_Keys has no element";
361 if not Has_Element
(Right
, CRight
) then
362 raise Constraint_Error
with
363 "Right cursor of Equivalent_Keys has no element";
366 pragma Assert
(Vet
(Left
, CLeft
),
367 "Left cursor of Equivalent_Keys is bad");
368 pragma Assert
(Vet
(Right
, CRight
),
369 "Right cursor of Equivalent_Keys is bad");
372 LN
: Node_Type
renames Left
.Nodes
(CLeft
.Node
);
373 RN
: Node_Type
renames Right
.Nodes
(CRight
.Node
);
375 return Equivalent_Keys
(LN
.Key
, RN
.Key
);
379 function Equivalent_Keys
382 Right
: Key_Type
) return Boolean
385 if not Has_Element
(Left
, CLeft
) then
386 raise Constraint_Error
with
387 "Left cursor of Equivalent_Keys has no element";
390 pragma Assert
(Vet
(Left
, CLeft
),
391 "Left cursor in Equivalent_Keys is bad");
394 LN
: Node_Type
renames Left
.Nodes
(CLeft
.Node
);
396 return Equivalent_Keys
(LN
.Key
, Right
);
400 function Equivalent_Keys
403 CRight
: Cursor
) return Boolean
406 if Has_Element
(Right
, CRight
) then
407 raise Constraint_Error
with
408 "Right cursor of Equivalent_Keys has no element";
411 pragma Assert
(Vet
(Right
, CRight
),
412 "Right cursor of Equivalent_Keys is bad");
415 RN
: Node_Type
renames Right
.Nodes
(CRight
.Node
);
418 return Equivalent_Keys
(Left
, RN
.Key
);
426 procedure Exclude
(Container
: in out Map
; Key
: Key_Type
) is
429 Key_Ops
.Delete_Key_Sans_Free
(Container
, Key
, X
);
437 function Find
(Container
: Map
; Key
: Key_Type
) return Cursor
is
438 Node
: constant Count_Type
:= Key_Ops
.Find
(Container
, Key
);
445 return (Node
=> Node
);
452 function First
(Container
: Map
) return Cursor
is
453 Node
: constant Count_Type
:= HT_Ops
.First
(Container
);
460 return (Node
=> Node
);
463 -----------------------
464 -- First_To_Previous --
465 -----------------------
467 function First_To_Previous
469 Current
: Cursor
) return Map
is
471 C
: Map
(Container
.Capacity
, Container
.Modulus
) :=
472 Copy
(Container
, Container
.Capacity
);
478 if Curs
= No_Element
then
481 elsif not Has_Element
(Container
, Curs
) then
482 raise Constraint_Error
;
485 while Curs
.Node
/= 0 loop
488 Curs
:= Next
(Container
, (Node
=> Node
));
493 end First_To_Previous
;
499 procedure Free
(HT
: in out Map
; X
: Count_Type
) is
501 HT
.Nodes
(X
).Has_Element
:= False;
505 ----------------------
506 -- Generic_Allocate --
507 ----------------------
509 procedure Generic_Allocate
(HT
: in out Map
; Node
: out Count_Type
) is
511 procedure Allocate
is
512 new HT_Ops
.Generic_Allocate
(Set_Element
);
516 HT
.Nodes
(Node
).Has_Element
:= True;
517 end Generic_Allocate
;
523 function Has_Element
(Container
: Map
; Position
: Cursor
) return Boolean is
526 or else not Container
.Nodes
(Position
.Node
).Has_Element
538 function Hash_Node
(Node
: Node_Type
) return Hash_Type
is
540 return Hash
(Node
.Key
);
548 (Container
: in out Map
;
550 New_Item
: Element_Type
)
556 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
560 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
563 N
.Element
:= New_Item
;
573 (Container
: in out Map
;
575 New_Item
: Element_Type
;
576 Position
: out Cursor
;
577 Inserted
: out Boolean)
579 procedure Assign_Key
(Node
: in out Node_Type
);
580 pragma Inline
(Assign_Key
);
582 function New_Node
return Count_Type
;
583 pragma Inline
(New_Node
);
585 procedure Local_Insert
is
586 new Key_Ops
.Generic_Conditional_Insert
(New_Node
);
588 procedure Allocate
is
589 new Generic_Allocate
(Assign_Key
);
595 procedure Assign_Key
(Node
: in out Node_Type
) is
598 Node
.Element
:= New_Item
;
605 function New_Node
return Count_Type
is
608 Allocate
(Container
, Result
);
612 -- Start of processing for Insert
615 Local_Insert
(Container
, Key
, Position
.Node
, Inserted
);
619 (Container
: in out Map
;
621 New_Item
: Element_Type
)
624 pragma Unreferenced
(Position
);
629 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
632 raise Constraint_Error
with
633 "attempt to insert key already in map";
641 function Is_Empty
(Container
: Map
) return Boolean is
643 return Length
(Container
) = 0;
650 function Key
(Container
: Map
; Position
: Cursor
) return Key_Type
is
652 if not Has_Element
(Container
, Position
) then
653 raise Constraint_Error
with
654 "Position cursor of function Key has no element";
657 pragma Assert
(Vet
(Container
, Position
), "bad cursor in function Key");
659 return Container
.Nodes
(Position
.Node
).Key
;
666 function Length
(Container
: Map
) return Count_Type
is
668 return Container
.Length
;
676 (Target
: in out Map
;
679 NN
: HT_Types
.Nodes_Type
renames Source
.Nodes
;
683 if Target
'Address = Source
'Address then
687 if Target
.Capacity
< Length
(Source
) then
688 raise Constraint_Error
with -- ???
689 "Source length exceeds Target capacity";
694 if Source
.Length
= 0 then
698 X
:= HT_Ops
.First
(Source
);
700 Insert
(Target
, NN
(X
).Key
, NN
(X
).Element
); -- optimize???
702 Y
:= HT_Ops
.Next
(Source
, X
);
704 HT_Ops
.Delete_Node_Sans_Free
(Source
, X
);
715 function Next
(Node
: Node_Type
) return Count_Type
is
720 function Next
(Container
: Map
; Position
: Cursor
) return Cursor
is
722 if Position
.Node
= 0 then
726 if not Has_Element
(Container
, Position
) then
727 raise Constraint_Error
728 with "Position has no element";
731 pragma Assert
(Vet
(Container
, Position
), "bad cursor in function Next");
734 Node
: constant Count_Type
:= HT_Ops
.Next
(Container
, Position
.Node
);
741 return (Node
=> Node
);
745 procedure Next
(Container
: Map
; Position
: in out Cursor
) is
747 Position
:= Next
(Container
, Position
);
754 function Overlap
(Left
, Right
: Map
) return Boolean is
755 Left_Node
: Count_Type
;
756 Left_Nodes
: Nodes_Type
renames Left
.Nodes
;
759 if Length
(Right
) = 0 or Length
(Left
) = 0 then
763 if Left
'Address = Right
'Address then
767 Left_Node
:= First
(Left
).Node
;
768 while Left_Node
/= 0 loop
770 N
: Node_Type
renames Left_Nodes
(Left_Node
);
771 E
: Key_Type
renames N
.Key
;
773 if Find
(Right
, E
).Node
/= 0 then
778 Left_Node
:= HT_Ops
.Next
(Left
, Left_Node
);
789 (Container
: in out Map
;
791 New_Item
: Element_Type
)
793 Node
: constant Count_Type
:= Key_Ops
.Find
(Container
, Key
);
797 raise Constraint_Error
with
798 "attempt to replace key not in map";
802 N
: Node_Type
renames Container
.Nodes
(Node
);
805 N
.Element
:= New_Item
;
809 ---------------------
810 -- Replace_Element --
811 ---------------------
813 procedure Replace_Element
814 (Container
: in out Map
;
816 New_Item
: Element_Type
)
819 if not Has_Element
(Container
, Position
) then
820 raise Constraint_Error
with
821 "Position cursor of Replace_Element has no element";
824 pragma Assert
(Vet
(Container
, Position
),
825 "bad cursor in Replace_Element");
827 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
830 ----------------------
831 -- Reserve_Capacity --
832 ----------------------
834 procedure Reserve_Capacity
835 (Container
: in out Map
;
836 Capacity
: Count_Type
)
839 if Capacity
> Container
.Capacity
then
840 raise Capacity_Error
with "requested capacity is too large";
842 end Reserve_Capacity
;
848 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
) is
857 function Strict_Equal
(Left
, Right
: Map
) return Boolean is
858 CuL
: Cursor
:= First
(Left
);
859 CuR
: Cursor
:= First
(Right
);
862 if Length
(Left
) /= Length
(Right
) then
866 while CuL
.Node
/= 0 or else CuR
.Node
/= 0 loop
867 if CuL
.Node
/= CuR
.Node
869 Left
.Nodes
(CuL
.Node
).Element
/= Right
.Nodes
(CuR
.Node
).Element
870 or else Left
.Nodes
(CuL
.Node
).Key
/= Right
.Nodes
(CuR
.Node
).Key
875 CuL
:= Next
(Left
, CuL
);
876 CuR
:= Next
(Right
, CuR
);
886 function Vet
(Container
: Map
; Position
: Cursor
) return Boolean is
888 if Position
.Node
= 0 then
896 if Container
.Length
= 0 then
900 if Container
.Capacity
= 0 then
904 if Container
.Buckets
'Length = 0 then
908 if Position
.Node
> Container
.Capacity
then
912 if Container
.Nodes
(Position
.Node
).Next
= Position
.Node
then
916 X
:= Container
.Buckets
917 (Key_Ops
.Index
(Container
, Container
.Nodes
(Position
.Node
).Key
));
919 for J
in 1 .. Container
.Length
loop
920 if X
= Position
.Node
then
928 if X
= Container
.Nodes
(X
).Next
then
930 -- Prevent unnecessary looping
935 X
:= Container
.Nodes
(X
).Next
;
942 end Ada
.Containers
.Formal_Hashed_Maps
;