1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . H A S H E D _ S E T S --
9 -- Copyright (C) 2004-2005, Free Software Foundation, Inc. --
11 -- This specification is derived from the Ada Reference Manual for use with --
12 -- GNAT. The copyright notice above, and the license provisions that follow --
13 -- apply solely to the contents of the part following the private keyword. --
15 -- GNAT is free software; you can redistribute it and/or modify it under --
16 -- terms of the GNU General Public License as published by the Free Soft- --
17 -- ware Foundation; either version 2, or (at your option) any later ver- --
18 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
19 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
20 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
21 -- for more details. You should have received a copy of the GNU General --
22 -- Public License distributed with GNAT; see file COPYING. If not, write --
23 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
24 -- Boston, MA 02110-1301, USA. --
26 -- As a special exception, if other files instantiate generics from this --
27 -- unit, or you link this unit with other files to produce an executable, --
28 -- this unit does not by itself cause the resulting executable to be --
29 -- covered by the GNU General Public License. This exception does not --
30 -- however invalidate any other reasons why the executable file might be --
31 -- covered by the GNU Public License. --
33 -- This unit has originally being developed by Matthew J Heaney. --
34 ------------------------------------------------------------------------------
36 with Ada
.Unchecked_Deallocation
;
38 with Ada
.Containers
.Hash_Tables
.Generic_Operations
;
39 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Operations
);
41 with Ada
.Containers
.Hash_Tables
.Generic_Keys
;
42 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Keys
);
44 with Ada
.Containers
.Prime_Numbers
;
46 with System
; use type System
.Address
;
48 package body Ada
.Containers
.Hashed_Sets
is
50 -----------------------
51 -- Local Subprograms --
52 -----------------------
54 function Copy_Node
(Source
: Node_Access
) return Node_Access
;
55 pragma Inline
(Copy_Node
);
57 function Equivalent_Keys
59 Node
: Node_Access
) return Boolean;
60 pragma Inline
(Equivalent_Keys
);
62 function Find_Equal_Key
63 (R_HT
: Hash_Table_Type
;
64 L_Node
: Node_Access
) return Boolean;
66 function Find_Equivalent_Key
67 (R_HT
: Hash_Table_Type
;
68 L_Node
: Node_Access
) return Boolean;
70 procedure Free
(X
: in out Node_Access
);
72 function Hash_Node
(Node
: Node_Access
) return Hash_Type
;
73 pragma Inline
(Hash_Node
);
76 (HT
: in out Hash_Table_Type
;
77 New_Item
: Element_Type
;
78 Node
: out Node_Access
;
79 Inserted
: out Boolean);
82 (HT
: Hash_Table_Type
;
83 Key
: Node_Access
) return Boolean;
84 pragma Inline
(Is_In
);
86 function Next
(Node
: Node_Access
) return Node_Access
;
89 function Read_Node
(Stream
: access Root_Stream_Type
'Class)
91 pragma Inline
(Read_Node
);
93 procedure Replace_Element
94 (HT
: in out Hash_Table_Type
;
96 New_Item
: Element_Type
);
98 procedure Set_Next
(Node
: Node_Access
; Next
: Node_Access
);
99 pragma Inline
(Set_Next
);
101 function Vet
(Position
: Cursor
) return Boolean;
104 (Stream
: access Root_Stream_Type
'Class;
106 pragma Inline
(Write_Node
);
108 --------------------------
109 -- Local Instantiations --
110 --------------------------
113 new Hash_Tables
.Generic_Operations
114 (HT_Types
=> HT_Types
,
115 Hash_Node
=> Hash_Node
,
117 Set_Next
=> Set_Next
,
118 Copy_Node
=> Copy_Node
,
121 package Element_Keys
is
122 new Hash_Tables
.Generic_Keys
123 (HT_Types
=> HT_Types
,
125 Set_Next
=> Set_Next
,
126 Key_Type
=> Element_Type
,
128 Equivalent_Keys
=> Equivalent_Keys
);
131 new HT_Ops
.Generic_Equal
(Find_Equal_Key
);
133 function Is_Equivalent
is
134 new HT_Ops
.Generic_Equal
(Find_Equivalent_Key
);
136 procedure Read_Nodes
is
137 new HT_Ops
.Generic_Read
(Read_Node
);
139 procedure Write_Nodes
is
140 new HT_Ops
.Generic_Write
(Write_Node
);
146 function "=" (Left
, Right
: Set
) return Boolean is
148 return Is_Equal
(Left
.HT
, Right
.HT
);
155 procedure Adjust
(Container
: in out Set
) is
157 HT_Ops
.Adjust
(Container
.HT
);
164 function Capacity
(Container
: Set
) return Count_Type
is
166 return HT_Ops
.Capacity
(Container
.HT
);
173 procedure Clear
(Container
: in out Set
) is
175 HT_Ops
.Clear
(Container
.HT
);
182 function Contains
(Container
: Set
; Item
: Element_Type
) return Boolean is
184 return Find
(Container
, Item
) /= No_Element
;
191 function Copy_Node
(Source
: Node_Access
) return Node_Access
is
193 return new Node_Type
'(Element => Source.Element, Next => null);
201 (Container : in out Set;
207 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
210 raise Constraint_Error;
217 (Container : in out Set;
218 Position : in out Cursor)
221 pragma Assert (Vet (Position), "bad cursor in Delete");
223 if Position.Node = null then
224 raise Constraint_Error;
227 if Position.Container /= Container'Unrestricted_Access then
231 if Container.HT.Busy > 0 then
235 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
237 Free (Position.Node);
238 Position.Container := null;
246 (Target : in out Set;
249 Tgt_Node : Node_Access;
252 if Target'Address = Source'Address then
257 if Source.Length = 0 then
261 if Target.HT.Busy > 0 then
265 -- TODO: This can be written in terms of a loop instead as
266 -- active-iterator style, sort of like a passive iterator.
268 Tgt_Node := HT_Ops.First (Target.HT);
269 while Tgt_Node /= null loop
270 if Is_In (Source.HT, Tgt_Node) then
272 X : Node_Access := Tgt_Node;
274 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
275 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
280 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
285 function Difference (Left, Right : Set) return Set is
286 Buckets : HT_Types.Buckets_Access;
290 if Left'Address = Right'Address then
294 if Left.Length = 0 then
298 if Right.Length = 0 then
303 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
305 Buckets := new Buckets_Type (0 .. Size - 1);
310 Iterate_Left : declare
311 procedure Process (L_Node : Node_Access);
314 new HT_Ops.Generic_Iteration (Process);
320 procedure Process (L_Node : Node_Access) is
322 if not Is_In (Right.HT, L_Node) then
324 J : constant Hash_Type :=
325 Hash (L_Node.Element) mod Buckets'Length;
327 Bucket : Node_Access renames Buckets (J);
330 Bucket := new Node_Type'(L_Node
.Element
, Bucket
);
333 Length
:= Length
+ 1;
337 -- Start of processing for Iterate_Left
343 HT_Ops
.Free_Hash_Table
(Buckets
);
347 return (Controlled
with HT
=> (Buckets
, Length
, 0, 0));
354 function Element
(Position
: Cursor
) return Element_Type
is
356 pragma Assert
(Vet
(Position
), "bad cursor in function Element");
358 if Position
.Node
= null then
359 raise Constraint_Error
;
362 return Position
.Node
.Element
;
365 ---------------------
366 -- Equivalent_Sets --
367 ---------------------
369 function Equivalent_Sets
(Left
, Right
: Set
) return Boolean is
371 return Is_Equivalent
(Left
.HT
, Right
.HT
);
374 -------------------------
375 -- Equivalent_Elements --
376 -------------------------
378 function Equivalent_Elements
(Left
, Right
: Cursor
)
381 pragma Assert
(Vet
(Left
), "bad Left cursor in Equivalent_Keys");
382 pragma Assert
(Vet
(Right
), "bad Right cursor in Equivalent_Keys");
385 or else Right
.Node
= null
387 raise Constraint_Error
;
390 return Equivalent_Elements
(Left
.Node
.Element
, Right
.Node
.Element
);
391 end Equivalent_Elements
;
393 function Equivalent_Elements
(Left
: Cursor
; Right
: Element_Type
)
396 pragma Assert
(Vet
(Left
), "bad Left cursor in Equivalent_Keys");
398 if Left
.Node
= null then
399 raise Constraint_Error
;
402 return Equivalent_Elements
(Left
.Node
.Element
, Right
);
403 end Equivalent_Elements
;
405 function Equivalent_Elements
(Left
: Element_Type
; Right
: Cursor
)
408 pragma Assert
(Vet
(Right
), "bad Right cursor in Equivalent_Keys");
410 if Right
.Node
= null then
411 raise Constraint_Error
;
414 return Equivalent_Elements
(Left
, Right
.Node
.Element
);
415 end Equivalent_Elements
;
417 ---------------------
418 -- Equivalent_Keys --
419 ---------------------
421 function Equivalent_Keys
(Key
: Element_Type
; Node
: Node_Access
)
424 return Equivalent_Elements
(Key
, Node
.Element
);
432 (Container
: in out Set
;
437 Element_Keys
.Delete_Key_Sans_Free
(Container
.HT
, Item
, X
);
445 procedure Finalize
(Container
: in out Set
) is
447 HT_Ops
.Finalize
(Container
.HT
);
456 Item
: Element_Type
) return Cursor
458 Node
: constant Node_Access
:= Element_Keys
.Find
(Container
.HT
, Item
);
465 return Cursor
'(Container'Unrestricted_Access, Node);
472 function Find_Equal_Key
473 (R_HT : Hash_Table_Type;
474 L_Node : Node_Access) return Boolean
476 R_Index : constant Hash_Type :=
477 Element_Keys.Index (R_HT, L_Node.Element);
479 R_Node : Node_Access := R_HT.Buckets (R_Index);
483 if R_Node = null then
487 if L_Node.Element = R_Node.Element then
491 R_Node := Next (R_Node);
495 -------------------------
496 -- Find_Equivalent_Key --
497 -------------------------
499 function Find_Equivalent_Key
500 (R_HT : Hash_Table_Type;
501 L_Node : Node_Access) return Boolean
503 R_Index : constant Hash_Type :=
504 Element_Keys.Index (R_HT, L_Node.Element);
506 R_Node : Node_Access := R_HT.Buckets (R_Index);
510 if R_Node = null then
514 if Equivalent_Elements (L_Node.Element, R_Node.Element) then
518 R_Node := Next (R_Node);
520 end Find_Equivalent_Key;
526 function First (Container : Set) return Cursor is
527 Node : constant Node_Access := HT_Ops.First (Container.HT);
534 return Cursor'(Container
'Unrestricted_Access, Node
);
541 procedure Free
(X
: in out Node_Access
) is
542 procedure Deallocate
is
543 new Ada
.Unchecked_Deallocation
(Node_Type
, Node_Access
);
547 X
.Next
:= X
; -- detect mischief (in Vet)
556 function Has_Element
(Position
: Cursor
) return Boolean is
558 pragma Assert
(Vet
(Position
), "bad cursor in Has_Element");
559 return Position
.Node
/= null;
566 function Hash_Node
(Node
: Node_Access
) return Hash_Type
is
568 return Hash
(Node
.Element
);
576 (Container
: in out Set
;
577 New_Item
: Element_Type
)
583 Insert
(Container
, New_Item
, Position
, Inserted
);
586 if Container
.HT
.Lock
> 0 then
590 Position
.Node
.Element
:= New_Item
;
599 (Container
: in out Set
;
600 New_Item
: Element_Type
;
601 Position
: out Cursor
;
602 Inserted
: out Boolean)
605 Insert
(Container
.HT
, New_Item
, Position
.Node
, Inserted
);
606 Position
.Container
:= Container
'Unchecked_Access;
610 (Container
: in out Set
;
611 New_Item
: Element_Type
)
617 Insert
(Container
, New_Item
, Position
, Inserted
);
620 raise Constraint_Error
;
625 (HT
: in out Hash_Table_Type
;
626 New_Item
: Element_Type
;
627 Node
: out Node_Access
;
628 Inserted
: out Boolean)
630 function New_Node
(Next
: Node_Access
) return Node_Access
;
631 pragma Inline
(New_Node
);
633 procedure Local_Insert
is
634 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
640 function New_Node
(Next
: Node_Access
) return Node_Access
is
642 return new Node_Type
'(New_Item, Next);
645 -- Start of processing for Insert
648 if HT_Ops.Capacity (HT) = 0 then
649 HT_Ops.Reserve_Capacity (HT, 1);
652 Local_Insert (HT, New_Item, Node, Inserted);
655 and then HT.Length > HT_Ops.Capacity (HT)
657 HT_Ops.Reserve_Capacity (HT, HT.Length);
665 procedure Intersection
666 (Target : in out Set;
669 Tgt_Node : Node_Access;
672 if Target'Address = Source'Address then
676 if Source.Length = 0 then
681 if Target.HT.Busy > 0 then
685 -- TODO: optimize this to use an explicit
686 -- loop instead of an active iterator
687 -- (similar to how a passive iterator is
690 -- Another possibility is to test which
691 -- set is smaller, and iterate over the
694 Tgt_Node := HT_Ops.First (Target.HT);
695 while Tgt_Node /= null loop
696 if Is_In (Source.HT, Tgt_Node) then
697 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
701 X : Node_Access := Tgt_Node;
703 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
704 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
711 function Intersection (Left, Right : Set) return Set is
712 Buckets : HT_Types.Buckets_Access;
716 if Left'Address = Right'Address then
720 Length := Count_Type'Min (Left.Length, Right.Length);
727 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length);
729 Buckets := new Buckets_Type (0 .. Size - 1);
734 Iterate_Left : declare
735 procedure Process (L_Node : Node_Access);
738 new HT_Ops.Generic_Iteration (Process);
744 procedure Process (L_Node : Node_Access) is
746 if Is_In (Right.HT, L_Node) then
748 J : constant Hash_Type :=
749 Hash (L_Node.Element) mod Buckets'Length;
751 Bucket : Node_Access renames Buckets (J);
754 Bucket := new Node_Type'(L_Node
.Element
, Bucket
);
757 Length
:= Length
+ 1;
761 -- Start of processing for Iterate_Left
767 HT_Ops
.Free_Hash_Table
(Buckets
);
771 return (Controlled
with HT
=> (Buckets
, Length
, 0, 0));
778 function Is_Empty
(Container
: Set
) return Boolean is
780 return Container
.HT
.Length
= 0;
787 function Is_In
(HT
: Hash_Table_Type
; Key
: Node_Access
) return Boolean is
789 return Element_Keys
.Find
(HT
, Key
.Element
) /= null;
796 function Is_Subset
(Subset
: Set
; Of_Set
: Set
) return Boolean is
797 Subset_Node
: Node_Access
;
800 if Subset
'Address = Of_Set
'Address then
804 if Subset
.Length
> Of_Set
.Length
then
808 -- TODO: rewrite this to loop in the
809 -- style of a passive iterator.
811 Subset_Node
:= HT_Ops
.First
(Subset
.HT
);
812 while Subset_Node
/= null loop
813 if not Is_In
(Of_Set
.HT
, Subset_Node
) then
816 Subset_Node
:= HT_Ops
.Next
(Subset
.HT
, Subset_Node
);
828 Process
: not null access procedure (Position
: Cursor
))
830 procedure Process_Node
(Node
: Node_Access
);
831 pragma Inline
(Process_Node
);
834 new HT_Ops
.Generic_Iteration
(Process_Node
);
840 procedure Process_Node
(Node
: Node_Access
) is
842 Process
(Cursor
'(Container'Unrestricted_Access, Node));
845 -- Start of processing for Iterate
848 -- TODO: resolve whether HT_Ops.Generic_Iteration should
849 -- manipulate busy bit.
851 Iterate (Container.HT);
858 function Length (Container : Set) return Count_Type is
860 return Container.HT.Length;
867 procedure Move (Target : in out Set; Source : in out Set) is
869 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
876 function Next (Node : Node_Access) return Node_Access is
881 function Next (Position : Cursor) return Cursor is
883 pragma Assert (Vet (Position), "bad cursor in function Next");
885 if Position.Node = null then
890 HT : Hash_Table_Type renames Position.Container.HT;
891 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
898 return Cursor'(Position
.Container
, Node
);
902 procedure Next
(Position
: in out Cursor
) is
904 Position
:= Next
(Position
);
911 function Overlap
(Left
, Right
: Set
) return Boolean is
912 Left_Node
: Node_Access
;
915 if Right
.Length
= 0 then
919 if Left
'Address = Right
'Address then
923 Left_Node
:= HT_Ops
.First
(Left
.HT
);
924 while Left_Node
/= null loop
925 if Is_In
(Right
.HT
, Left_Node
) then
928 Left_Node
:= HT_Ops
.Next
(Left
.HT
, Left_Node
);
938 procedure Query_Element
940 Process
: not null access procedure (Element
: Element_Type
))
943 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
945 if Position
.Node
= null then
946 raise Constraint_Error
;
950 HT
: Hash_Table_Type
renames Position
.Container
.HT
;
952 B
: Natural renames HT
.Busy
;
953 L
: Natural renames HT
.Lock
;
960 Process
(Position
.Node
.Element
);
978 (Stream
: access Root_Stream_Type
'Class;
982 Read_Nodes
(Stream
, Container
.HT
);
986 (Stream
: access Root_Stream_Type
'Class;
997 function Read_Node
(Stream
: access Root_Stream_Type
'Class)
1000 Node
: Node_Access
:= new Node_Type
;
1003 Element_Type
'Read (Stream
, Node
.Element
);
1016 (Container
: in out Set
;
1017 New_Item
: Element_Type
)
1019 Node
: constant Node_Access
:=
1020 Element_Keys
.Find
(Container
.HT
, New_Item
);
1024 raise Constraint_Error
;
1027 if Container
.HT
.Lock
> 0 then
1028 raise Program_Error
;
1031 Node
.Element
:= New_Item
;
1034 ---------------------
1035 -- Replace_Element --
1036 ---------------------
1038 procedure Replace_Element
1039 (HT
: in out Hash_Table_Type
;
1041 New_Item
: Element_Type
)
1044 if Equivalent_Elements
(Node
.Element
, New_Item
) then
1045 pragma Assert
(Hash
(Node
.Element
) = Hash
(New_Item
));
1048 raise Program_Error
;
1051 Node
.Element
:= New_Item
; -- Note that this assignment can fail
1056 raise Program_Error
;
1059 HT_Ops
.Delete_Node_Sans_Free
(HT
, Node
);
1061 Insert_New_Element
: declare
1062 function New_Node
(Next
: Node_Access
) return Node_Access
;
1063 pragma Inline
(New_Node
);
1065 procedure Local_Insert
is
1066 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
1072 function New_Node
(Next
: Node_Access
) return Node_Access
is
1074 Node
.Element
:= New_Item
; -- Note that this assignment can fail
1079 Result
: Node_Access
;
1082 -- Start of processing for Insert_New_Element
1089 Inserted
=> Inserted
);
1096 null; -- Assignment must have failed
1097 end Insert_New_Element
;
1099 Reinsert_Old_Element
: declare
1100 function New_Node
(Next
: Node_Access
) return Node_Access
;
1101 pragma Inline
(New_Node
);
1103 procedure Local_Insert
is
1104 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
1110 function New_Node
(Next
: Node_Access
) return Node_Access
is
1116 Result
: Node_Access
;
1119 -- Start of processing for Reinsert_Old_Element
1124 Key
=> Node
.Element
,
1126 Inserted
=> Inserted
);
1130 end Reinsert_Old_Element
;
1132 raise Program_Error
;
1133 end Replace_Element
;
1135 procedure Replace_Element
1136 (Container
: in out Set
;
1138 New_Item
: Element_Type
)
1141 pragma Assert
(Vet
(Position
), "bad cursor in Replace_Element");
1143 if Position
.Node
= null then
1144 raise Constraint_Error
;
1147 if Position
.Container
/= Container
'Unrestricted_Access then
1148 raise Program_Error
;
1151 Replace_Element
(Container
.HT
, Position
.Node
, New_Item
);
1152 end Replace_Element
;
1154 ----------------------
1155 -- Reserve_Capacity --
1156 ----------------------
1158 procedure Reserve_Capacity
1159 (Container
: in out Set
;
1160 Capacity
: Count_Type
)
1163 HT_Ops
.Reserve_Capacity
(Container
.HT
, Capacity
);
1164 end Reserve_Capacity
;
1170 procedure Set_Next
(Node
: Node_Access
; Next
: Node_Access
) is
1175 --------------------------
1176 -- Symmetric_Difference --
1177 --------------------------
1179 procedure Symmetric_Difference
1180 (Target
: in out Set
;
1184 if Target
'Address = Source
'Address then
1189 if Target
.HT
.Busy
> 0 then
1190 raise Program_Error
;
1194 N
: constant Count_Type
:= Target
.Length
+ Source
.Length
;
1196 if N
> HT_Ops
.Capacity
(Target
.HT
) then
1197 HT_Ops
.Reserve_Capacity
(Target
.HT
, N
);
1201 if Target
.Length
= 0 then
1202 Iterate_Source_When_Empty_Target
: declare
1203 procedure Process
(Src_Node
: Node_Access
);
1205 procedure Iterate
is
1206 new HT_Ops
.Generic_Iteration
(Process
);
1212 procedure Process
(Src_Node
: Node_Access
) is
1213 E
: Element_Type
renames Src_Node
.Element
;
1214 B
: Buckets_Type
renames Target
.HT
.Buckets
.all;
1215 J
: constant Hash_Type
:= Hash
(E
) mod B
'Length;
1216 N
: Count_Type
renames Target
.HT
.Length
;
1219 B
(J
) := new Node_Type
'(E, B (J));
1223 -- Start of processing for Iterate_Source_When_Empty_Target
1226 Iterate (Source.HT);
1227 end Iterate_Source_When_Empty_Target;
1230 Iterate_Source : declare
1231 procedure Process (Src_Node : Node_Access);
1233 procedure Iterate is
1234 new HT_Ops.Generic_Iteration (Process);
1240 procedure Process (Src_Node : Node_Access) is
1241 E : Element_Type renames Src_Node.Element;
1242 B : Buckets_Type renames Target.HT.Buckets.all;
1243 J : constant Hash_Type := Hash (E) mod B'Length;
1244 N : Count_Type renames Target.HT.Length;
1247 if B (J) = null then
1248 B (J) := new Node_Type'(E
, null);
1251 elsif Equivalent_Elements
(E
, B
(J
).Element
) then
1253 X
: Node_Access
:= B
(J
);
1255 B
(J
) := B
(J
).Next
;
1262 Prev
: Node_Access
:= B
(J
);
1263 Curr
: Node_Access
:= Prev
.Next
;
1266 while Curr
/= null loop
1267 if Equivalent_Elements
(E
, Curr
.Element
) then
1268 Prev
.Next
:= Curr
.Next
;
1278 B
(J
) := new Node_Type
'(E, B (J));
1284 -- Start of processing for Iterate_Source
1287 Iterate (Source.HT);
1290 end Symmetric_Difference;
1292 function Symmetric_Difference (Left, Right : Set) return Set is
1293 Buckets : HT_Types.Buckets_Access;
1294 Length : Count_Type;
1297 if Left'Address = Right'Address then
1301 if Right.Length = 0 then
1305 if Left.Length = 0 then
1310 Size : constant Hash_Type :=
1311 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1313 Buckets := new Buckets_Type (0 .. Size - 1);
1318 Iterate_Left : declare
1319 procedure Process (L_Node : Node_Access);
1321 procedure Iterate is
1322 new HT_Ops.Generic_Iteration (Process);
1328 procedure Process (L_Node : Node_Access) is
1330 if not Is_In (Right.HT, L_Node) then
1332 E : Element_Type renames L_Node.Element;
1333 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1336 Buckets (J) := new Node_Type'(E
, Buckets
(J
));
1337 Length
:= Length
+ 1;
1342 -- Start of processing for Iterate_Left
1348 HT_Ops
.Free_Hash_Table
(Buckets
);
1352 Iterate_Right
: declare
1353 procedure Process
(R_Node
: Node_Access
);
1355 procedure Iterate
is
1356 new HT_Ops
.Generic_Iteration
(Process
);
1362 procedure Process
(R_Node
: Node_Access
) is
1364 if not Is_In
(Left
.HT
, R_Node
) then
1366 E
: Element_Type
renames R_Node
.Element
;
1367 J
: constant Hash_Type
:= Hash
(E
) mod Buckets
'Length;
1370 Buckets
(J
) := new Node_Type
'(E, Buckets (J));
1371 Length := Length + 1;
1376 -- Start of processing for Iterate_Right
1382 HT_Ops.Free_Hash_Table (Buckets);
1386 return (Controlled with HT => (Buckets, Length, 0, 0));
1387 end Symmetric_Difference;
1393 function To_Set (New_Item : Element_Type) return Set is
1394 HT : Hash_Table_Type;
1399 Insert (HT, New_Item, Node, Inserted);
1400 return Set'(Controlled
with HT
);
1408 (Target
: in out Set
;
1411 procedure Process
(Src_Node
: Node_Access
);
1413 procedure Iterate
is
1414 new HT_Ops
.Generic_Iteration
(Process
);
1420 procedure Process
(Src_Node
: Node_Access
) is
1421 function New_Node
(Next
: Node_Access
) return Node_Access
;
1422 pragma Inline
(New_Node
);
1425 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
1431 function New_Node
(Next
: Node_Access
) return Node_Access
is
1432 Node
: constant Node_Access
:=
1433 new Node_Type
'(Src_Node.Element, Next);
1438 Tgt_Node : Node_Access;
1441 -- Start of processing for Process
1444 Insert (Target.HT, Src_Node.Element, Tgt_Node, Success);
1447 -- Start of processing for Union
1450 if Target'Address = Source'Address then
1454 if Target.HT.Busy > 0 then
1455 raise Program_Error;
1459 N : constant Count_Type := Target.Length + Source.Length;
1461 if N > HT_Ops.Capacity (Target.HT) then
1462 HT_Ops.Reserve_Capacity (Target.HT, N);
1466 Iterate (Source.HT);
1469 function Union (Left, Right : Set) return Set is
1470 Buckets : HT_Types.Buckets_Access;
1471 Length : Count_Type;
1474 if Left'Address = Right'Address then
1478 if Right.Length = 0 then
1482 if Left.Length = 0 then
1487 Size : constant Hash_Type :=
1488 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1490 Buckets := new Buckets_Type (0 .. Size - 1);
1493 Iterate_Left : declare
1494 procedure Process (L_Node : Node_Access);
1496 procedure Iterate is
1497 new HT_Ops.Generic_Iteration (Process);
1503 procedure Process (L_Node : Node_Access) is
1504 J : constant Hash_Type :=
1505 Hash (L_Node.Element) mod Buckets'Length;
1508 Buckets (J) := new Node_Type'(L_Node
.Element
, Buckets
(J
));
1511 -- Start of processing for Iterate_Left
1517 HT_Ops
.Free_Hash_Table
(Buckets
);
1521 Length
:= Left
.Length
;
1523 Iterate_Right
: declare
1524 procedure Process
(Src_Node
: Node_Access
);
1526 procedure Iterate
is
1527 new HT_Ops
.Generic_Iteration
(Process
);
1533 procedure Process
(Src_Node
: Node_Access
) is
1534 J
: constant Hash_Type
:=
1535 Hash
(Src_Node
.Element
) mod Buckets
'Length;
1537 Tgt_Node
: Node_Access
:= Buckets
(J
);
1540 while Tgt_Node
/= null loop
1541 if Equivalent_Elements
(Src_Node
.Element
, Tgt_Node
.Element
) then
1545 Tgt_Node
:= Next
(Tgt_Node
);
1548 Buckets
(J
) := new Node_Type
'(Src_Node.Element, Buckets (J));
1549 Length := Length + 1;
1552 -- Start of processing for Iterate_Right
1558 HT_Ops.Free_Hash_Table (Buckets);
1562 return (Controlled with HT => (Buckets, Length, 0, 0));
1569 function Vet (Position : Cursor) return Boolean is
1571 if Position.Node = null then
1572 return Position.Container = null;
1575 if Position.Container = null then
1579 if Position.Node.Next = Position.Node then
1584 HT : Hash_Table_Type renames Position.Container.HT;
1588 if HT.Length = 0 then
1592 if HT.Buckets = null
1593 or else HT.Buckets'Length = 0
1598 X := HT.Buckets (Element_Keys.Index (HT, Position.Node.Element));
1600 for J in 1 .. HT.Length loop
1601 if X = Position.Node then
1609 if X = X.Next then -- to prevent unnecessary looping
1625 (Stream : access Root_Stream_Type'Class;
1629 Write_Nodes (Stream, Container.HT);
1633 (Stream : access Root_Stream_Type'Class;
1637 raise Program_Error;
1644 procedure Write_Node
1645 (Stream : access Root_Stream_Type'Class;
1649 Element_Type'Write (Stream, Node.Element);
1652 package body Generic_Keys is
1654 -----------------------
1655 -- Local Subprograms --
1656 -----------------------
1658 function Equivalent_Key_Node
1660 Node : Node_Access) return Boolean;
1661 pragma Inline (Equivalent_Key_Node);
1663 --------------------------
1664 -- Local Instantiations --
1665 --------------------------
1668 new Hash_Tables.Generic_Keys
1669 (HT_Types => HT_Types,
1671 Set_Next => Set_Next,
1672 Key_Type => Key_Type,
1674 Equivalent_Keys => Equivalent_Key_Node);
1682 Key : Key_Type) return Boolean
1685 return Find (Container, Key) /= No_Element;
1693 (Container : in out Set;
1699 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1702 raise Constraint_Error;
1714 Key : Key_Type) return Element_Type
1716 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1719 return Node.Element;
1722 -------------------------
1723 -- Equivalent_Key_Node --
1724 -------------------------
1726 function Equivalent_Key_Node
1728 Node : Node_Access) return Boolean
1731 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1732 end Equivalent_Key_Node;
1739 (Container : in out Set;
1744 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1754 Key : Key_Type) return Cursor
1756 Node : constant Node_Access :=
1757 Key_Keys.Find (Container.HT, Key);
1764 return Cursor'(Container
'Unrestricted_Access, Node
);
1771 function Key
(Position
: Cursor
) return Key_Type
is
1773 pragma Assert
(Vet
(Position
), "bad cursor in function Key");
1775 if Position
.Node
= null then
1776 raise Constraint_Error
;
1779 return Key
(Position
.Node
.Element
);
1787 (Container
: in out Set
;
1789 New_Item
: Element_Type
)
1791 Node
: constant Node_Access
:=
1792 Key_Keys
.Find
(Container
.HT
, Key
);
1796 raise Constraint_Error
;
1799 Replace_Element
(Container
.HT
, Node
, New_Item
);
1802 -----------------------------------
1803 -- Update_Element_Preserving_Key --
1804 -----------------------------------
1806 procedure Update_Element_Preserving_Key
1807 (Container
: in out Set
;
1809 Process
: not null access
1810 procedure (Element
: in out Element_Type
))
1812 HT
: Hash_Table_Type
renames Container
.HT
;
1818 "bad cursor in Update_Element_Preserving_Key");
1820 if Position
.Node
= null then
1821 raise Constraint_Error
;
1824 if Position
.Container
/= Container
'Unrestricted_Access then
1825 raise Program_Error
;
1828 if HT
.Buckets
= null
1829 or else HT
.Buckets
'Length = 0
1830 or else HT
.Length
= 0
1831 or else Position
.Node
.Next
= Position
.Node
1833 raise Program_Error
;
1836 Indx
:= HT_Ops
.Index
(HT
, Position
.Node
);
1839 E
: Element_Type
renames Position
.Node
.Element
;
1840 K
: constant Key_Type
:= Key
(E
);
1842 B
: Natural renames HT
.Busy
;
1843 L
: Natural renames HT
.Lock
;
1861 if Equivalent_Keys
(K
, Key
(E
)) then
1862 pragma Assert
(Hash
(K
) = Hash
(E
));
1867 if HT
.Buckets
(Indx
) = Position
.Node
then
1868 HT
.Buckets
(Indx
) := Position
.Node
.Next
;
1872 Prev
: Node_Access
:= HT
.Buckets
(Indx
);
1875 while Prev
.Next
/= Position
.Node
loop
1879 raise Program_Error
;
1883 Prev
.Next
:= Position
.Node
.Next
;
1887 HT
.Length
:= HT
.Length
- 1;
1890 X
: Node_Access
:= Position
.Node
;
1896 raise Program_Error
;
1897 end Update_Element_Preserving_Key
;
1901 end Ada
.Containers
.Hashed_Sets
;