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-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
.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
41 pragma Annotate
(CodePeer
, Skip_Analysis
);
43 -----------------------
44 -- Local Subprograms --
45 -----------------------
47 -- All local subprograms require comments ???
49 function Equivalent_Keys
51 Node
: Node_Type
) return Boolean;
52 pragma Inline
(Equivalent_Keys
);
59 with procedure Set_Element
(Node
: in out Node_Type
);
60 procedure Generic_Allocate
62 Node
: out Count_Type
);
64 function Hash_Node
(Node
: Node_Type
) return Hash_Type
;
65 pragma Inline
(Hash_Node
);
67 function Next
(Node
: Node_Type
) return Count_Type
;
70 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
);
71 pragma Inline
(Set_Next
);
73 function Vet
(Container
: Map
; Position
: Cursor
) return Boolean;
75 --------------------------
76 -- Local Instantiations --
77 --------------------------
80 new Hash_Tables
.Generic_Bounded_Operations
81 (HT_Types
=> HT_Types
,
82 Hash_Node
=> Hash_Node
,
84 Set_Next
=> Set_Next
);
87 new Hash_Tables
.Generic_Bounded_Keys
88 (HT_Types
=> HT_Types
,
93 Equivalent_Keys
=> Equivalent_Keys
);
99 function "=" (Left
, Right
: Map
) return Boolean is
101 if Length
(Left
) /= Length
(Right
) then
105 if Length
(Left
) = 0 then
114 Node
:= Left
.First
.Node
;
116 ENode
:= Find
(Container
=> Right
,
117 Key
=> Left
.Nodes
(Node
).Key
).Node
;
120 Right
.Nodes
(ENode
).Element
/= Left
.Nodes
(Node
).Element
125 Node
:= HT_Ops
.Next
(Left
, Node
);
136 procedure Assign
(Target
: in out Map
; Source
: Map
) is
137 procedure Insert_Element
(Source_Node
: Count_Type
);
138 pragma Inline
(Insert_Element
);
140 procedure Insert_Elements
is
141 new HT_Ops
.Generic_Iteration
(Insert_Element
);
147 procedure Insert_Element
(Source_Node
: Count_Type
) is
148 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
150 Insert
(Target
, N
.Key
, N
.Element
);
153 -- Start of processing for Assign
156 if Target
'Address = Source
'Address then
160 if Target
.Capacity
< Length
(Source
) then
161 raise Constraint_Error
with -- correct exception ???
162 "Source length exceeds Target capacity";
167 Insert_Elements
(Source
);
174 function Capacity
(Container
: Map
) return Count_Type
is
176 return Container
.Nodes
'Length;
183 procedure Clear
(Container
: in out Map
) is
185 HT_Ops
.Clear
(Container
);
192 function Contains
(Container
: Map
; Key
: Key_Type
) return Boolean is
194 return Find
(Container
, Key
) /= No_Element
;
203 Capacity
: Count_Type
:= 0) return Map
205 C
: constant Count_Type
:=
206 Count_Type
'Max (Capacity
, Source
.Capacity
);
209 Target
: Map
(C
, Source
.Modulus
);
213 if 0 < Capacity
and then Capacity
< Source
.Capacity
then
214 raise Capacity_Error
;
217 Target
.Length
:= Source
.Length
;
218 Target
.Free
:= Source
.Free
;
221 while H
<= Source
.Modulus
loop
222 Target
.Buckets
(H
) := Source
.Buckets
(H
);
227 while N
<= Source
.Capacity
loop
228 Target
.Nodes
(N
) := Source
.Nodes
(N
);
234 Free
(Target
, Cu
.Node
);
241 ---------------------
242 -- Current_To_Last --
243 ---------------------
245 function Current_To_Last
(Container
: Map
; Current
: Cursor
) return Map
is
246 Curs
: Cursor
:= First
(Container
);
247 C
: Map
(Container
.Capacity
, Container
.Modulus
) :=
248 Copy
(Container
, Container
.Capacity
);
252 if Curs
= No_Element
then
256 elsif Current
/= No_Element
and not Has_Element
(Container
, Current
) then
257 raise Constraint_Error
;
260 while Curs
.Node
/= Current
.Node
loop
263 Curs
:= Next
(Container
, (Node
=> Node
));
270 ---------------------
271 -- Default_Modulus --
272 ---------------------
274 function Default_Modulus
(Capacity
: Count_Type
) return Hash_Type
is
276 return To_Prime
(Capacity
);
283 procedure Delete
(Container
: in out Map
; Key
: Key_Type
) is
287 Key_Ops
.Delete_Key_Sans_Free
(Container
, Key
, X
);
290 raise Constraint_Error
with "attempt to delete key not in map";
296 procedure Delete
(Container
: in out Map
; Position
: in out Cursor
) is
298 if not Has_Element
(Container
, Position
) then
299 raise Constraint_Error
with
300 "Position cursor of Delete has no element";
303 pragma Assert
(Vet
(Container
, Position
), "bad cursor in Delete");
305 HT_Ops
.Delete_Node_Sans_Free
(Container
, Position
.Node
);
307 Free
(Container
, Position
.Node
);
314 function Element
(Container
: Map
; Key
: Key_Type
) return Element_Type
is
315 Node
: constant Count_Type
:= Find
(Container
, Key
).Node
;
319 raise Constraint_Error
with
320 "no element available because key not in map";
323 return Container
.Nodes
(Node
).Element
;
326 function Element
(Container
: Map
; Position
: Cursor
) return Element_Type
is
328 if not Has_Element
(Container
, Position
) then
329 raise Constraint_Error
with "Position cursor equals No_Element";
332 pragma Assert
(Vet
(Container
, Position
),
333 "bad cursor in function Element");
335 return Container
.Nodes
(Position
.Node
).Element
;
338 ---------------------
339 -- Equivalent_Keys --
340 ---------------------
342 function Equivalent_Keys
344 Node
: Node_Type
) return Boolean
347 return Equivalent_Keys
(Key
, Node
.Key
);
350 function Equivalent_Keys
354 CRight
: Cursor
) return Boolean
357 if not Has_Element
(Left
, CLeft
) then
358 raise Constraint_Error
with
359 "Left cursor of Equivalent_Keys has no element";
362 if not Has_Element
(Right
, CRight
) then
363 raise Constraint_Error
with
364 "Right cursor of Equivalent_Keys has no element";
367 pragma Assert
(Vet
(Left
, CLeft
),
368 "Left cursor of Equivalent_Keys is bad");
369 pragma Assert
(Vet
(Right
, CRight
),
370 "Right cursor of Equivalent_Keys is bad");
373 LN
: Node_Type
renames Left
.Nodes
(CLeft
.Node
);
374 RN
: Node_Type
renames Right
.Nodes
(CRight
.Node
);
376 return Equivalent_Keys
(LN
.Key
, RN
.Key
);
380 function Equivalent_Keys
383 Right
: Key_Type
) return Boolean
386 if not Has_Element
(Left
, CLeft
) then
387 raise Constraint_Error
with
388 "Left cursor of Equivalent_Keys has no element";
391 pragma Assert
(Vet
(Left
, CLeft
),
392 "Left cursor in Equivalent_Keys is bad");
395 LN
: Node_Type
renames Left
.Nodes
(CLeft
.Node
);
397 return Equivalent_Keys
(LN
.Key
, Right
);
401 function Equivalent_Keys
404 CRight
: Cursor
) return Boolean
407 if Has_Element
(Right
, CRight
) then
408 raise Constraint_Error
with
409 "Right cursor of Equivalent_Keys has no element";
412 pragma Assert
(Vet
(Right
, CRight
),
413 "Right cursor of Equivalent_Keys is bad");
416 RN
: Node_Type
renames Right
.Nodes
(CRight
.Node
);
419 return Equivalent_Keys
(Left
, RN
.Key
);
427 procedure Exclude
(Container
: in out Map
; Key
: Key_Type
) is
430 Key_Ops
.Delete_Key_Sans_Free
(Container
, Key
, X
);
438 function Find
(Container
: Map
; Key
: Key_Type
) return Cursor
is
439 Node
: constant Count_Type
:= Key_Ops
.Find
(Container
, Key
);
446 return (Node
=> Node
);
453 function First
(Container
: Map
) return Cursor
is
454 Node
: constant Count_Type
:= HT_Ops
.First
(Container
);
461 return (Node
=> Node
);
464 -----------------------
465 -- First_To_Previous --
466 -----------------------
468 function First_To_Previous
470 Current
: Cursor
) return Map
is
472 C
: Map
(Container
.Capacity
, Container
.Modulus
) :=
473 Copy
(Container
, Container
.Capacity
);
479 if Curs
= No_Element
then
482 elsif not Has_Element
(Container
, Curs
) then
483 raise Constraint_Error
;
486 while Curs
.Node
/= 0 loop
489 Curs
:= Next
(Container
, (Node
=> Node
));
494 end First_To_Previous
;
500 procedure Free
(HT
: in out Map
; X
: Count_Type
) is
502 HT
.Nodes
(X
).Has_Element
:= False;
506 ----------------------
507 -- Generic_Allocate --
508 ----------------------
510 procedure Generic_Allocate
(HT
: in out Map
; Node
: out Count_Type
) is
512 procedure Allocate
is
513 new HT_Ops
.Generic_Allocate
(Set_Element
);
517 HT
.Nodes
(Node
).Has_Element
:= True;
518 end Generic_Allocate
;
524 function Has_Element
(Container
: Map
; Position
: Cursor
) return Boolean is
527 or else not Container
.Nodes
(Position
.Node
).Has_Element
539 function Hash_Node
(Node
: Node_Type
) return Hash_Type
is
541 return Hash
(Node
.Key
);
549 (Container
: in out Map
;
551 New_Item
: Element_Type
)
557 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
561 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
564 N
.Element
:= New_Item
;
574 (Container
: in out Map
;
576 New_Item
: Element_Type
;
577 Position
: out Cursor
;
578 Inserted
: out Boolean)
580 procedure Assign_Key
(Node
: in out Node_Type
);
581 pragma Inline
(Assign_Key
);
583 function New_Node
return Count_Type
;
584 pragma Inline
(New_Node
);
586 procedure Local_Insert
is
587 new Key_Ops
.Generic_Conditional_Insert
(New_Node
);
589 procedure Allocate
is
590 new Generic_Allocate
(Assign_Key
);
596 procedure Assign_Key
(Node
: in out Node_Type
) is
599 Node
.Element
:= New_Item
;
606 function New_Node
return Count_Type
is
609 Allocate
(Container
, Result
);
613 -- Start of processing for Insert
616 Local_Insert
(Container
, Key
, Position
.Node
, Inserted
);
620 (Container
: in out Map
;
622 New_Item
: Element_Type
)
625 pragma Unreferenced
(Position
);
630 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
633 raise Constraint_Error
with
634 "attempt to insert key already in map";
642 function Is_Empty
(Container
: Map
) return Boolean is
644 return Length
(Container
) = 0;
651 function Key
(Container
: Map
; Position
: Cursor
) return Key_Type
is
653 if not Has_Element
(Container
, Position
) then
654 raise Constraint_Error
with
655 "Position cursor of function Key has no element";
658 pragma Assert
(Vet
(Container
, Position
), "bad cursor in function Key");
660 return Container
.Nodes
(Position
.Node
).Key
;
667 function Length
(Container
: Map
) return Count_Type
is
669 return Container
.Length
;
677 (Target
: in out Map
;
680 NN
: HT_Types
.Nodes_Type
renames Source
.Nodes
;
684 if Target
'Address = Source
'Address then
688 if Target
.Capacity
< Length
(Source
) then
689 raise Constraint_Error
with -- ???
690 "Source length exceeds Target capacity";
695 if Source
.Length
= 0 then
699 X
:= HT_Ops
.First
(Source
);
701 Insert
(Target
, NN
(X
).Key
, NN
(X
).Element
); -- optimize???
703 Y
:= HT_Ops
.Next
(Source
, X
);
705 HT_Ops
.Delete_Node_Sans_Free
(Source
, X
);
716 function Next
(Node
: Node_Type
) return Count_Type
is
721 function Next
(Container
: Map
; Position
: Cursor
) return Cursor
is
723 if Position
.Node
= 0 then
727 if not Has_Element
(Container
, Position
) then
728 raise Constraint_Error
729 with "Position has no element";
732 pragma Assert
(Vet
(Container
, Position
), "bad cursor in function Next");
735 Node
: constant Count_Type
:= HT_Ops
.Next
(Container
, Position
.Node
);
742 return (Node
=> Node
);
746 procedure Next
(Container
: Map
; Position
: in out Cursor
) is
748 Position
:= Next
(Container
, Position
);
755 function Overlap
(Left
, Right
: Map
) return Boolean is
756 Left_Node
: Count_Type
;
757 Left_Nodes
: Nodes_Type
renames Left
.Nodes
;
760 if Length
(Right
) = 0 or Length
(Left
) = 0 then
764 if Left
'Address = Right
'Address then
768 Left_Node
:= First
(Left
).Node
;
769 while Left_Node
/= 0 loop
771 N
: Node_Type
renames Left_Nodes
(Left_Node
);
772 E
: Key_Type
renames N
.Key
;
774 if Find
(Right
, E
).Node
/= 0 then
779 Left_Node
:= HT_Ops
.Next
(Left
, Left_Node
);
790 (Container
: in out Map
;
792 New_Item
: Element_Type
)
794 Node
: constant Count_Type
:= Key_Ops
.Find
(Container
, Key
);
798 raise Constraint_Error
with
799 "attempt to replace key not in map";
803 N
: Node_Type
renames Container
.Nodes
(Node
);
806 N
.Element
:= New_Item
;
810 ---------------------
811 -- Replace_Element --
812 ---------------------
814 procedure Replace_Element
815 (Container
: in out Map
;
817 New_Item
: Element_Type
)
820 if not Has_Element
(Container
, Position
) then
821 raise Constraint_Error
with
822 "Position cursor of Replace_Element has no element";
825 pragma Assert
(Vet
(Container
, Position
),
826 "bad cursor in Replace_Element");
828 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
831 ----------------------
832 -- Reserve_Capacity --
833 ----------------------
835 procedure Reserve_Capacity
836 (Container
: in out Map
;
837 Capacity
: Count_Type
)
840 if Capacity
> Container
.Capacity
then
841 raise Capacity_Error
with "requested capacity is too large";
843 end Reserve_Capacity
;
849 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
) is
858 function Strict_Equal
(Left
, Right
: Map
) return Boolean is
859 CuL
: Cursor
:= First
(Left
);
860 CuR
: Cursor
:= First
(Right
);
863 if Length
(Left
) /= Length
(Right
) then
867 while CuL
.Node
/= 0 or else CuR
.Node
/= 0 loop
868 if CuL
.Node
/= CuR
.Node
870 Left
.Nodes
(CuL
.Node
).Element
/= Right
.Nodes
(CuR
.Node
).Element
871 or else Left
.Nodes
(CuL
.Node
).Key
/= Right
.Nodes
(CuR
.Node
).Key
876 CuL
:= Next
(Left
, CuL
);
877 CuR
:= Next
(Right
, CuR
);
887 function Vet
(Container
: Map
; Position
: Cursor
) return Boolean is
889 if Position
.Node
= 0 then
897 if Container
.Length
= 0 then
901 if Container
.Capacity
= 0 then
905 if Container
.Buckets
'Length = 0 then
909 if Position
.Node
> Container
.Capacity
then
913 if Container
.Nodes
(Position
.Node
).Next
= Position
.Node
then
917 X
:= Container
.Buckets
918 (Key_Ops
.Index
(Container
, Container
.Nodes
(Position
.Node
).Key
));
920 for J
in 1 .. Container
.Length
loop
921 if X
= Position
.Node
then
929 if X
= Container
.Nodes
(X
).Next
then
931 -- Prevent unnecessary looping
936 X
:= Container
.Nodes
(X
).Next
;
943 end Ada
.Containers
.Formal_Hashed_Maps
;