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-2013, 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
is
40 -----------------------
41 -- Local Subprograms --
42 -----------------------
44 -- All local subprograms require comments ???
46 function Equivalent_Keys
48 Node
: Node_Type
) return Boolean;
49 pragma Inline
(Equivalent_Keys
);
56 with procedure Set_Element
(Node
: in out Node_Type
);
57 procedure Generic_Allocate
59 Node
: out Count_Type
);
61 function Hash_Node
(Node
: Node_Type
) return Hash_Type
;
62 pragma Inline
(Hash_Node
);
64 function Next
(Node
: Node_Type
) return Count_Type
;
67 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
);
68 pragma Inline
(Set_Next
);
70 function Vet
(Container
: Map
; Position
: Cursor
) return Boolean;
72 --------------------------
73 -- Local Instantiations --
74 --------------------------
77 new Hash_Tables
.Generic_Bounded_Operations
78 (HT_Types
=> HT_Types
,
79 Hash_Node
=> Hash_Node
,
81 Set_Next
=> Set_Next
);
84 new Hash_Tables
.Generic_Bounded_Keys
85 (HT_Types
=> HT_Types
,
90 Equivalent_Keys
=> Equivalent_Keys
);
96 function "=" (Left
, Right
: Map
) return Boolean is
98 if Length
(Left
) /= Length
(Right
) then
102 if Length
(Left
) = 0 then
111 Node
:= Left
.First
.Node
;
113 ENode
:= Find
(Container
=> Right
,
114 Key
=> Left
.Nodes
(Node
).Key
).Node
;
117 Right
.Nodes
(ENode
).Element
/= Left
.Nodes
(Node
).Element
122 Node
:= HT_Ops
.Next
(Left
, Node
);
133 procedure Assign
(Target
: in out Map
; Source
: Map
) is
134 procedure Insert_Element
(Source_Node
: Count_Type
);
135 pragma Inline
(Insert_Element
);
137 procedure Insert_Elements
is
138 new HT_Ops
.Generic_Iteration
(Insert_Element
);
144 procedure Insert_Element
(Source_Node
: Count_Type
) is
145 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
147 Target
.Insert
(N
.Key
, N
.Element
);
150 -- Start of processing for Assign
153 if Target
'Address = Source
'Address then
157 if Target
.Capacity
< Length
(Source
) then
158 raise Constraint_Error
with -- correct exception ???
159 "Source length exceeds Target capacity";
164 Insert_Elements
(Source
);
171 function Capacity
(Container
: Map
) return Count_Type
is
173 return Container
.Nodes
'Length;
180 procedure Clear
(Container
: in out Map
) is
182 HT_Ops
.Clear
(Container
);
189 function Contains
(Container
: Map
; Key
: Key_Type
) return Boolean is
191 return Find
(Container
, Key
) /= No_Element
;
200 Capacity
: Count_Type
:= 0) return Map
202 C
: constant Count_Type
:=
203 Count_Type
'Max (Capacity
, Source
.Capacity
);
206 Target
: Map
(C
, Source
.Modulus
);
210 Target
.Length
:= Source
.Length
;
211 Target
.Free
:= Source
.Free
;
214 while H
<= Source
.Modulus
loop
215 Target
.Buckets
(H
) := Source
.Buckets
(H
);
220 while N
<= Source
.Capacity
loop
221 Target
.Nodes
(N
) := Source
.Nodes
(N
);
227 Free
(Target
, Cu
.Node
);
234 ---------------------
235 -- Default_Modulus --
236 ---------------------
238 function Default_Modulus
(Capacity
: Count_Type
) return Hash_Type
is
240 return To_Prime
(Capacity
);
247 procedure Delete
(Container
: in out Map
; Key
: Key_Type
) is
251 Key_Ops
.Delete_Key_Sans_Free
(Container
, Key
, X
);
254 raise Constraint_Error
with "attempt to delete key not in map";
260 procedure Delete
(Container
: in out Map
; Position
: in out Cursor
) is
262 if not Has_Element
(Container
, Position
) then
263 raise Constraint_Error
with
264 "Position cursor of Delete has no element";
267 pragma Assert
(Vet
(Container
, Position
), "bad cursor in Delete");
269 HT_Ops
.Delete_Node_Sans_Free
(Container
, Position
.Node
);
271 Free
(Container
, Position
.Node
);
278 function Element
(Container
: Map
; Key
: Key_Type
) return Element_Type
is
279 Node
: constant Count_Type
:= Find
(Container
, Key
).Node
;
283 raise Constraint_Error
with
284 "no element available because key not in map";
287 return Container
.Nodes
(Node
).Element
;
290 function Element
(Container
: Map
; Position
: Cursor
) return Element_Type
is
292 if not Has_Element
(Container
, Position
) then
293 raise Constraint_Error
with "Position cursor equals No_Element";
296 pragma Assert
(Vet
(Container
, Position
),
297 "bad cursor in function Element");
299 return Container
.Nodes
(Position
.Node
).Element
;
302 ---------------------
303 -- Equivalent_Keys --
304 ---------------------
306 function Equivalent_Keys
308 Node
: Node_Type
) return Boolean
311 return Equivalent_Keys
(Key
, Node
.Key
);
314 function Equivalent_Keys
318 CRight
: Cursor
) return Boolean
321 if not Has_Element
(Left
, CLeft
) then
322 raise Constraint_Error
with
323 "Left cursor of Equivalent_Keys has no element";
326 if not Has_Element
(Right
, CRight
) then
327 raise Constraint_Error
with
328 "Right cursor of Equivalent_Keys has no element";
331 pragma Assert
(Vet
(Left
, CLeft
),
332 "Left cursor of Equivalent_Keys is bad");
333 pragma Assert
(Vet
(Right
, CRight
),
334 "Right cursor of Equivalent_Keys is bad");
337 LN
: Node_Type
renames Left
.Nodes
(CLeft
.Node
);
338 RN
: Node_Type
renames Right
.Nodes
(CRight
.Node
);
340 return Equivalent_Keys
(LN
.Key
, RN
.Key
);
344 function Equivalent_Keys
347 Right
: Key_Type
) return Boolean
350 if not Has_Element
(Left
, CLeft
) then
351 raise Constraint_Error
with
352 "Left cursor of Equivalent_Keys has no element";
355 pragma Assert
(Vet
(Left
, CLeft
),
356 "Left cursor in Equivalent_Keys is bad");
359 LN
: Node_Type
renames Left
.Nodes
(CLeft
.Node
);
361 return Equivalent_Keys
(LN
.Key
, Right
);
365 function Equivalent_Keys
368 CRight
: Cursor
) return Boolean
371 if Has_Element
(Right
, CRight
) then
372 raise Constraint_Error
with
373 "Right cursor of Equivalent_Keys has no element";
376 pragma Assert
(Vet
(Right
, CRight
),
377 "Right cursor of Equivalent_Keys is bad");
380 RN
: Node_Type
renames Right
.Nodes
(CRight
.Node
);
383 return Equivalent_Keys
(Left
, RN
.Key
);
391 procedure Exclude
(Container
: in out Map
; Key
: Key_Type
) is
394 Key_Ops
.Delete_Key_Sans_Free
(Container
, Key
, X
);
402 function Find
(Container
: Map
; Key
: Key_Type
) return Cursor
is
403 Node
: constant Count_Type
:= Key_Ops
.Find
(Container
, Key
);
410 return (Node
=> Node
);
417 function First
(Container
: Map
) return Cursor
is
418 Node
: constant Count_Type
:= HT_Ops
.First
(Container
);
425 return (Node
=> Node
);
432 procedure Free
(HT
: in out Map
; X
: Count_Type
) is
434 HT
.Nodes
(X
).Has_Element
:= False;
438 ----------------------
439 -- Generic_Allocate --
440 ----------------------
442 procedure Generic_Allocate
(HT
: in out Map
; Node
: out Count_Type
) is
444 procedure Allocate
is
445 new HT_Ops
.Generic_Allocate
(Set_Element
);
449 HT
.Nodes
(Node
).Has_Element
:= True;
450 end Generic_Allocate
;
456 function Has_Element
(Container
: Map
; Position
: Cursor
) return Boolean is
458 if Position
.Node
= 0 or else
459 not Container
.Nodes
(Position
.Node
).Has_Element
then
470 function Hash_Node
(Node
: Node_Type
) return Hash_Type
is
472 return Hash
(Node
.Key
);
480 (Container
: in out Map
;
482 New_Item
: Element_Type
)
488 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
493 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
496 N
.Element
:= New_Item
;
506 (Container
: in out Map
;
508 New_Item
: Element_Type
;
509 Position
: out Cursor
;
510 Inserted
: out Boolean)
512 procedure Assign_Key
(Node
: in out Node_Type
);
513 pragma Inline
(Assign_Key
);
515 function New_Node
return Count_Type
;
516 pragma Inline
(New_Node
);
518 procedure Local_Insert
is
519 new Key_Ops
.Generic_Conditional_Insert
(New_Node
);
521 procedure Allocate
is
522 new Generic_Allocate
(Assign_Key
);
528 procedure Assign_Key
(Node
: in out Node_Type
) is
531 Node
.Element
:= New_Item
;
538 function New_Node
return Count_Type
is
541 Allocate
(Container
, Result
);
545 -- Start of processing for Insert
548 Local_Insert
(Container
, Key
, Position
.Node
, Inserted
);
552 (Container
: in out Map
;
554 New_Item
: Element_Type
)
557 pragma Unreferenced
(Position
);
562 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
565 raise Constraint_Error
with
566 "attempt to insert key already in map";
574 function Is_Empty
(Container
: Map
) return Boolean is
576 return Length
(Container
) = 0;
583 function Key
(Container
: Map
; Position
: Cursor
) return Key_Type
is
585 if not Has_Element
(Container
, Position
) then
586 raise Constraint_Error
with
587 "Position cursor of function Key has no element";
590 pragma Assert
(Vet
(Container
, Position
), "bad cursor in function Key");
592 return Container
.Nodes
(Position
.Node
).Key
;
599 function Left
(Container
: Map
; Position
: Cursor
) return Map
is
601 C
: Map
(Container
.Capacity
, Container
.Modulus
) :=
602 Copy
(Container
, Container
.Capacity
);
608 if Curs
= No_Element
then
612 if not Has_Element
(Container
, Curs
) then
613 raise Constraint_Error
;
616 while Curs
.Node
/= 0 loop
619 Curs
:= Next
(Container
, (Node
=> Node
));
629 function Length
(Container
: Map
) return Count_Type
is
631 return Container
.Length
;
639 (Target
: in out Map
;
642 NN
: HT_Types
.Nodes_Type
renames Source
.Nodes
;
646 if Target
'Address = Source
'Address then
650 if Target
.Capacity
< Length
(Source
) then
651 raise Constraint_Error
with -- ???
652 "Source length exceeds Target capacity";
657 if Source
.Length
= 0 then
661 X
:= HT_Ops
.First
(Source
);
663 Insert
(Target
, NN
(X
).Key
, NN
(X
).Element
); -- optimize???
665 Y
:= HT_Ops
.Next
(Source
, X
);
667 HT_Ops
.Delete_Node_Sans_Free
(Source
, X
);
678 function Next
(Node
: Node_Type
) return Count_Type
is
683 function Next
(Container
: Map
; Position
: Cursor
) return Cursor
is
685 if Position
.Node
= 0 then
689 if not Has_Element
(Container
, Position
) then
690 raise Constraint_Error
691 with "Position has no element";
694 pragma Assert
(Vet
(Container
, Position
), "bad cursor in function Next");
697 Node
: constant Count_Type
:= HT_Ops
.Next
(Container
, Position
.Node
);
704 return (Node
=> Node
);
708 procedure Next
(Container
: Map
; Position
: in out Cursor
) is
710 Position
:= Next
(Container
, Position
);
717 function Overlap
(Left
, Right
: Map
) return Boolean is
718 Left_Node
: Count_Type
;
719 Left_Nodes
: Nodes_Type
renames Left
.Nodes
;
722 if Length
(Right
) = 0 or Length
(Left
) = 0 then
726 if Left
'Address = Right
'Address then
730 Left_Node
:= First
(Left
).Node
;
731 while Left_Node
/= 0 loop
733 N
: Node_Type
renames Left_Nodes
(Left_Node
);
734 E
: Key_Type
renames N
.Key
;
736 if Find
(Right
, E
).Node
/= 0 then
741 Left_Node
:= HT_Ops
.Next
(Left
, Left_Node
);
752 (Container
: in out Map
;
754 New_Item
: Element_Type
)
756 Node
: constant Count_Type
:= Key_Ops
.Find
(Container
, Key
);
760 raise Constraint_Error
with
761 "attempt to replace key not in map";
765 N
: Node_Type
renames Container
.Nodes
(Node
);
768 N
.Element
:= New_Item
;
772 ---------------------
773 -- Replace_Element --
774 ---------------------
776 procedure Replace_Element
777 (Container
: in out Map
;
779 New_Item
: Element_Type
)
782 if not Has_Element
(Container
, Position
) then
783 raise Constraint_Error
with
784 "Position cursor of Replace_Element has no element";
787 pragma Assert
(Vet
(Container
, Position
),
788 "bad cursor in Replace_Element");
790 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
793 ----------------------
794 -- Reserve_Capacity --
795 ----------------------
797 procedure Reserve_Capacity
798 (Container
: in out Map
;
799 Capacity
: Count_Type
)
802 if Capacity
> Container
.Capacity
then
803 raise Capacity_Error
with "requested capacity is too large";
805 end Reserve_Capacity
;
811 function Right
(Container
: Map
; Position
: Cursor
) return Map
is
812 Curs
: Cursor
:= First
(Container
);
813 C
: Map
(Container
.Capacity
, Container
.Modulus
) :=
814 Copy
(Container
, Container
.Capacity
);
818 if Curs
= No_Element
then
823 if Position
/= No_Element
and not Has_Element
(Container
, Position
) then
824 raise Constraint_Error
;
827 while Curs
.Node
/= Position
.Node
loop
830 Curs
:= Next
(Container
, (Node
=> Node
));
840 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
) is
849 function Strict_Equal
(Left
, Right
: Map
) return Boolean is
850 CuL
: Cursor
:= First
(Left
);
851 CuR
: Cursor
:= First
(Right
);
854 if Length
(Left
) /= Length
(Right
) then
858 while CuL
.Node
/= 0 or CuR
.Node
/= 0 loop
859 if CuL
.Node
/= CuR
.Node
or else
860 (Left
.Nodes
(CuL
.Node
).Element
/=
861 Right
.Nodes
(CuR
.Node
).Element
or
862 Left
.Nodes
(CuL
.Node
).Key
/=
863 Right
.Nodes
(CuR
.Node
).Key
) then
867 CuL
:= Next
(Left
, CuL
);
868 CuR
:= Next
(Right
, CuR
);
878 function Vet
(Container
: Map
; Position
: Cursor
) return Boolean is
880 if Position
.Node
= 0 then
888 if Container
.Length
= 0 then
892 if Container
.Capacity
= 0 then
896 if Container
.Buckets
'Length = 0 then
900 if Position
.Node
> Container
.Capacity
then
904 if Container
.Nodes
(Position
.Node
).Next
= Position
.Node
then
908 X
:= Container
.Buckets
909 (Key_Ops
.Index
(Container
, Container
.Nodes
(Position
.Node
).Key
));
911 for J
in 1 .. Container
.Length
loop
912 if X
= Position
.Node
then
920 if X
= Container
.Nodes
(X
).Next
then
922 -- Prevent unnecessary looping
927 X
:= Container
.Nodes
(X
).Next
;
934 end Ada
.Containers
.Formal_Hashed_Maps
;