1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . --
6 -- I N D E F I N I T E _ H A S H E D _ S E T S --
10 -- Copyright (C) 2004-2005 Free Software Foundation, Inc. --
12 -- This specification is derived from the Ada Reference Manual for use with --
13 -- GNAT. The copyright notice above, and the license provisions that follow --
14 -- apply solely to the contents of the part following the private keyword. --
16 -- GNAT is free software; you can redistribute it and/or modify it under --
17 -- terms of the GNU General Public License as published by the Free Soft- --
18 -- ware Foundation; either version 2, or (at your option) any later ver- --
19 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
20 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
21 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
22 -- for more details. You should have received a copy of the GNU General --
23 -- Public License distributed with GNAT; see file COPYING. If not, write --
24 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
25 -- Boston, MA 02110-1301, USA. --
27 -- As a special exception, if other files instantiate generics from this --
28 -- unit, or you link this unit with other files to produce an executable, --
29 -- this unit does not by itself cause the resulting executable to be --
30 -- covered by the GNU General Public License. This exception does not --
31 -- however invalidate any other reasons why the executable file might be --
32 -- covered by the GNU Public License. --
34 -- This unit has originally being developed by Matthew J Heaney. --
35 ------------------------------------------------------------------------------
37 with Ada.Unchecked_Deallocation;
39 with Ada.Containers.Hash_Tables.Generic_Operations;
40 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Operations);
42 with Ada.Containers.Hash_Tables.Generic_Keys;
43 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Keys);
45 with System; use type System.Address;
47 with Ada.Containers.Prime_Numbers;
49 package body Ada.Containers.Indefinite_Hashed_Sets is
51 -----------------------
52 -- Local Subprograms --
53 -----------------------
55 function Copy_Node (Source : Node_Access) return Node_Access;
56 pragma Inline (Copy_Node);
58 function Equivalent_Keys
60 Node : Node_Access) return Boolean;
61 pragma Inline (Equivalent_Keys);
63 function Find_Equal_Key
64 (R_HT : Hash_Table_Type;
65 L_Node : Node_Access) return Boolean;
67 function Find_Equivalent_Key
68 (R_HT : Hash_Table_Type;
69 L_Node : Node_Access) return Boolean;
71 procedure Free (X : in out Node_Access);
73 function Hash_Node (Node : Node_Access) return Hash_Type;
74 pragma Inline (Hash_Node);
76 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean;
77 pragma Inline (Is_In);
79 function Next (Node : Node_Access) return Node_Access;
82 function Read_Node (Stream : access Root_Stream_Type'Class)
84 pragma Inline (Read_Node);
86 procedure Replace_Element
87 (HT : in out Hash_Table_Type;
89 New_Item : Element_Type);
91 procedure Set_Next (Node : Node_Access; Next : Node_Access);
92 pragma Inline (Set_Next);
94 function Vet (Position : Cursor) return Boolean;
97 (Stream : access Root_Stream_Type'Class;
99 pragma Inline (Write_Node);
101 --------------------------
102 -- Local Instantiations --
103 --------------------------
105 procedure Free_Element is
106 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
109 new Hash_Tables.Generic_Operations
110 (HT_Types => HT_Types,
111 Hash_Node => Hash_Node,
113 Set_Next => Set_Next,
114 Copy_Node => Copy_Node,
117 package Element_Keys is
118 new Hash_Tables.Generic_Keys
119 (HT_Types => HT_Types,
121 Set_Next => Set_Next,
122 Key_Type => Element_Type,
124 Equivalent_Keys => Equivalent_Keys);
127 new HT_Ops.Generic_Equal (Find_Equal_Key);
129 function Is_Equivalent is
130 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
132 procedure Read_Nodes is
133 new HT_Ops.Generic_Read (Read_Node);
135 procedure Write_Nodes is
136 new HT_Ops.Generic_Write (Write_Node);
142 function "=" (Left, Right : Set) return Boolean is
144 return Is_Equal (Left.HT, Right.HT);
151 procedure Adjust (Container : in out Set) is
153 HT_Ops.Adjust (Container.HT);
160 function Capacity (Container : Set) return Count_Type is
162 return HT_Ops.Capacity (Container.HT);
169 procedure Clear (Container : in out Set) is
171 HT_Ops.Clear (Container.HT);
178 function Contains (Container : Set; Item : Element_Type) return Boolean is
180 return Find (Container, Item) /= No_Element;
187 function Copy_Node (Source : Node_Access) return Node_Access is
188 E : Element_Access := new Element_Type'(Source.Element.all);
190 return new Node_Type'(Element => E, Next => null);
202 (Container : in out Set;
208 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
211 raise Constraint_Error;
218 (Container : in out Set;
219 Position : in out Cursor)
222 pragma Assert (Vet (Position), "bad cursor in Delete");
224 if Position.Node = null then
225 raise Constraint_Error;
228 if Position.Node.Element = null then
232 if Position.Container /= Container'Unrestricted_Access then
236 if Container.HT.Busy > 0 then
240 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
242 Free (Position.Node);
243 Position.Container := null;
251 (Target : in out Set;
254 Tgt_Node : Node_Access;
257 if Target'Address = Source'Address then
262 if Source.Length = 0 then
266 if Target.HT.Busy > 0 then
270 -- TODO: This can be written in terms of a loop instead as
271 -- active-iterator style, sort of like a passive iterator.
273 Tgt_Node := HT_Ops.First (Target.HT);
274 while Tgt_Node /= null loop
275 if Is_In (Source.HT, Tgt_Node) then
277 X : Node_Access := Tgt_Node;
279 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
280 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
285 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
290 function Difference (Left, Right : Set) return Set is
291 Buckets : HT_Types.Buckets_Access;
295 if Left'Address = Right'Address then
299 if Left.Length = 0 then
303 if Right.Length = 0 then
308 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
310 Buckets := new Buckets_Type (0 .. Size - 1);
315 Iterate_Left : declare
316 procedure Process (L_Node : Node_Access);
319 new HT_Ops.Generic_Iteration (Process);
325 procedure Process (L_Node : Node_Access) is
327 if not Is_In (Right.HT, L_Node) then
329 Indx : constant Hash_Type :=
330 Hash (L_Node.Element.all) mod Buckets'Length;
332 Bucket : Node_Access renames Buckets (Indx);
335 Bucket := new Node_Type'(L_Node.Element, Bucket);
338 Length := Length + 1;
342 -- Start of processing for Iterate_Left
348 HT_Ops.Free_Hash_Table (Buckets);
352 return (Controlled with HT => (Buckets, Length, 0, 0));
359 function Element (Position : Cursor) return Element_Type is
361 pragma Assert (Vet (Position), "bad cursor in function Element");
363 if Position.Node = null then
364 raise Constraint_Error;
367 if Position.Node.Element = null then -- handle dangling reference
371 return Position.Node.Element.all;
374 ---------------------
375 -- Equivalent_Sets --
376 ---------------------
378 function Equivalent_Sets (Left, Right : Set) return Boolean is
380 return Is_Equivalent (Left.HT, Right.HT);
383 -------------------------
384 -- Equivalent_Elements --
385 -------------------------
387 function Equivalent_Elements (Left, Right : Cursor)
390 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Keys");
391 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Keys");
394 or else Right.Node = null
396 raise Constraint_Error;
399 if Left.Node.Element = null -- handle dangling cursor reference
400 or else Right.Node.Element = null
405 return Equivalent_Elements
406 (Left.Node.Element.all,
407 Right.Node.Element.all);
408 end Equivalent_Elements;
410 function Equivalent_Elements (Left : Cursor; Right : Element_Type)
413 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Keys");
415 if Left.Node = null then
416 raise Constraint_Error;
419 if Left.Node.Element = null then -- handling dangling reference
423 return Equivalent_Elements (Left.Node.Element.all, Right);
424 end Equivalent_Elements;
426 function Equivalent_Elements (Left : Element_Type; Right : Cursor)
429 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Keys");
431 if Right.Node = null then
432 raise Constraint_Error;
435 if Right.Node.Element = null then -- handle dangling cursor reference
439 return Equivalent_Elements (Left, Right.Node.Element.all);
440 end Equivalent_Elements;
442 ---------------------
443 -- Equivalent_Keys --
444 ---------------------
446 function Equivalent_Keys (Key : Element_Type; Node : Node_Access)
449 return Equivalent_Elements (Key, Node.Element.all);
457 (Container : in out Set;
462 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
470 procedure Finalize (Container : in out Set) is
472 HT_Ops.Finalize (Container.HT);
481 Item : Element_Type) return Cursor
483 Node : constant Node_Access := Element_Keys.Find (Container.HT, Item);
490 return Cursor'(Container'Unrestricted_Access, Node);
497 function Find_Equal_Key
498 (R_HT : Hash_Table_Type;
499 L_Node : Node_Access) return Boolean
501 R_Index : constant Hash_Type :=
502 Element_Keys.Index (R_HT, L_Node.Element.all);
504 R_Node : Node_Access := R_HT.Buckets (R_Index);
508 if R_Node = null then
512 if L_Node.Element.all = R_Node.Element.all then
516 R_Node := Next (R_Node);
520 -------------------------
521 -- Find_Equivalent_Key --
522 -------------------------
524 function Find_Equivalent_Key
525 (R_HT : Hash_Table_Type;
526 L_Node : Node_Access) return Boolean
528 R_Index : constant Hash_Type :=
529 Element_Keys.Index (R_HT, L_Node.Element.all);
531 R_Node : Node_Access := R_HT.Buckets (R_Index);
535 if R_Node = null then
539 if Equivalent_Elements (L_Node.Element.all, R_Node.Element.all) then
543 R_Node := Next (R_Node);
545 end Find_Equivalent_Key;
551 function First (Container : Set) return Cursor is
552 Node : constant Node_Access := HT_Ops.First (Container.HT);
559 return Cursor'(Container'Unrestricted_Access, Node);
566 procedure Free (X : in out Node_Access) is
567 procedure Deallocate is
568 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
575 X.Next := X; -- detect mischief (in Vet)
578 Free_Element (X.Element);
593 function Has_Element (Position : Cursor) return Boolean is
595 pragma Assert (Vet (Position), "bad cursor in Has_Element");
596 return Position.Node /= null;
603 function Hash_Node (Node : Node_Access) return Hash_Type is
605 return Hash (Node.Element.all);
613 (Container : in out Set;
614 New_Item : Element_Type)
622 Insert (Container, New_Item, Position, Inserted);
625 if Container.HT.Lock > 0 then
629 X := Position.Node.Element;
631 Position.Node.Element := new Element_Type'(New_Item);
642 (Container : in out Set;
643 New_Item : Element_Type;
644 Position : out Cursor;
645 Inserted : out Boolean)
647 function New_Node (Next : Node_Access) return Node_Access;
648 pragma Inline (New_Node);
650 procedure Local_Insert is
651 new Element_Keys.Generic_Conditional_Insert (New_Node);
657 function New_Node (Next : Node_Access) return Node_Access is
658 Element : Element_Access := new Element_Type'(New_Item);
661 return new Node_Type'(Element, Next);
664 Free_Element (Element);
668 HT : Hash_Table_Type renames Container.HT;
670 -- Start of processing for Insert
673 if HT_Ops.Capacity (HT) = 0 then
674 HT_Ops.Reserve_Capacity (HT, 1);
677 Local_Insert (HT, New_Item, Position.Node, Inserted);
680 and then HT.Length > HT_Ops.Capacity (HT)
682 HT_Ops.Reserve_Capacity (HT, HT.Length);
685 Position.Container := Container'Unchecked_Access;
689 (Container : in out Set;
690 New_Item : Element_Type)
696 Insert (Container, New_Item, Position, Inserted);
699 raise Constraint_Error;
707 procedure Intersection
708 (Target : in out Set;
711 Tgt_Node : Node_Access;
714 if Target'Address = Source'Address then
718 if Source.Length = 0 then
723 if Target.HT.Busy > 0 then
727 -- TODO: optimize this to use an explicit
728 -- loop instead of an active iterator
729 -- (similar to how a passive iterator is
732 -- Another possibility is to test which
733 -- set is smaller, and iterate over the
736 Tgt_Node := HT_Ops.First (Target.HT);
737 while Tgt_Node /= null loop
738 if Is_In (Source.HT, Tgt_Node) then
739 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
743 X : Node_Access := Tgt_Node;
745 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
746 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
753 function Intersection (Left, Right : Set) return Set is
754 Buckets : HT_Types.Buckets_Access;
758 if Left'Address = Right'Address then
762 Length := Count_Type'Min (Left.Length, Right.Length);
769 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length);
771 Buckets := new Buckets_Type (0 .. Size - 1);
776 Iterate_Left : declare
777 procedure Process (L_Node : Node_Access);
780 new HT_Ops.Generic_Iteration (Process);
786 procedure Process (L_Node : Node_Access) is
788 if Is_In (Right.HT, L_Node) then
790 Indx : constant Hash_Type :=
791 Hash (L_Node.Element.all) mod Buckets'Length;
793 Bucket : Node_Access renames Buckets (Indx);
796 Bucket := new Node_Type'(L_Node.Element, Bucket);
799 Length := Length + 1;
803 -- Start of processing for Iterate_Left
809 HT_Ops.Free_Hash_Table (Buckets);
813 return (Controlled with HT => (Buckets, Length, 0, 0));
820 function Is_Empty (Container : Set) return Boolean is
822 return Container.HT.Length = 0;
829 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean is
831 return Element_Keys.Find (HT, Key.Element.all) /= null;
840 Of_Set : Set) return Boolean
842 Subset_Node : Node_Access;
845 if Subset'Address = Of_Set'Address then
849 if Subset.Length > Of_Set.Length then
853 -- TODO: rewrite this to loop in the
854 -- style of a passive iterator.
856 Subset_Node := HT_Ops.First (Subset.HT);
857 while Subset_Node /= null loop
858 if not Is_In (Of_Set.HT, Subset_Node) then
862 Subset_Node := HT_Ops.Next (Subset.HT, Subset_Node);
874 Process : not null access procedure (Position : Cursor))
876 procedure Process_Node (Node : Node_Access);
877 pragma Inline (Process_Node);
880 new HT_Ops.Generic_Iteration (Process_Node);
886 procedure Process_Node (Node : Node_Access) is
888 Process (Cursor'(Container'Unrestricted_Access, Node));
891 HT : Hash_Table_Type renames Container'Unrestricted_Access.all.HT;
893 -- Start of processing for Iterate
896 -- TODO: resolve whether HT_Ops.Generic_Iteration should
897 -- manipulate busy bit.
906 function Length (Container : Set) return Count_Type is
908 return Container.HT.Length;
915 procedure Move (Target : in out Set; Source : in out Set) is
917 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
924 function Next (Node : Node_Access) return Node_Access is
929 function Next (Position : Cursor) return Cursor is
931 pragma Assert (Vet (Position), "bad cursor in function Next");
933 if Position.Node = null then
937 if Position.Node.Element = null then
942 HT : Hash_Table_Type renames Position.Container.HT;
943 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
950 return Cursor'(Position.Container, Node);
954 procedure Next (Position : in out Cursor) is
956 Position := Next (Position);
963 function Overlap (Left, Right : Set) return Boolean is
964 Left_Node : Node_Access;
967 if Right.Length = 0 then
971 if Left'Address = Right'Address then
975 Left_Node := HT_Ops.First (Left.HT);
976 while Left_Node /= null loop
977 if Is_In (Right.HT, Left_Node) then
981 Left_Node := HT_Ops.Next (Left.HT, Left_Node);
991 procedure Query_Element
993 Process : not null access procedure (Element : Element_Type))
996 pragma Assert (Vet (Position), "bad cursor in Query_Element");
998 if Position.Node = null then
999 raise Constraint_Error;
1002 if Position.Node.Element = null then
1003 raise Program_Error;
1007 HT : Hash_Table_Type renames
1008 Position.Container'Unrestricted_Access.all.HT;
1010 B : Natural renames HT.Busy;
1011 L : Natural renames HT.Lock;
1018 Process (Position.Node.Element.all);
1036 (Stream : access Root_Stream_Type'Class;
1037 Container : out Set)
1040 Read_Nodes (Stream, Container.HT);
1048 (Stream : access Root_Stream_Type'Class) return Node_Access
1050 X : Element_Access := new Element_Type'(Element_Type'Input (Stream));
1053 return new Node_Type'(X, null);
1065 (Container : in out Set;
1066 New_Item : Element_Type)
1068 Node : constant Node_Access :=
1069 Element_Keys.Find (Container.HT, New_Item);
1075 raise Constraint_Error;
1078 if Container.HT.Lock > 0 then
1079 raise Program_Error;
1084 Node.Element := new Element_Type'(New_Item);
1089 ---------------------
1090 -- Replace_Element --
1091 ---------------------
1093 procedure Replace_Element
1094 (HT : in out Hash_Table_Type;
1096 New_Item : Element_Type)
1099 if Equivalent_Elements (Node.Element.all, New_Item) then
1100 pragma Assert (Hash (Node.Element.all) = Hash (New_Item));
1103 raise Program_Error;
1107 X : Element_Access := Node.Element;
1109 Node.Element := new Element_Type'(New_Item); -- OK if fails
1117 raise Program_Error;
1120 HT_Ops.Delete_Node_Sans_Free (HT, Node);
1122 Insert_New_Element : declare
1123 function New_Node (Next : Node_Access) return Node_Access;
1124 pragma Inline (New_Node);
1127 new Element_Keys.Generic_Conditional_Insert (New_Node);
1129 ------------------------
1130 -- Insert_New_Element --
1131 ------------------------
1133 function New_Node (Next : Node_Access) return Node_Access is
1135 Node.Element := new Element_Type'(New_Item); -- OK if fails
1140 Result : Node_Access;
1143 X : Element_Access := Node.Element;
1145 -- Start of processing for Insert_New_Element
1148 Attempt_Insert : begin
1153 Inserted => Inserted);
1156 Inserted := False; -- Assignment failed
1160 Free_Element (X); -- Just propagate if fails
1163 end Insert_New_Element;
1165 Reinsert_Old_Element :
1167 function New_Node (Next : Node_Access) return Node_Access;
1168 pragma Inline (New_Node);
1171 new Element_Keys.Generic_Conditional_Insert (New_Node);
1177 function New_Node (Next : Node_Access) return Node_Access is
1183 Result : Node_Access;
1186 -- Start of processing for Reinsert_Old_Element
1191 Key => Node.Element.all,
1193 Inserted => Inserted);
1197 end Reinsert_Old_Element;
1199 raise Program_Error;
1200 end Replace_Element;
1202 procedure Replace_Element
1203 (Container : in out Set;
1205 New_Item : Element_Type)
1208 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1210 if Position.Node = null then
1211 raise Constraint_Error;
1214 if Position.Node.Element = null then
1215 raise Program_Error;
1218 if Position.Container /= Container'Unrestricted_Access then
1219 raise Program_Error;
1222 Replace_Element (Container.HT, Position.Node, New_Item);
1223 end Replace_Element;
1225 ----------------------
1226 -- Reserve_Capacity --
1227 ----------------------
1229 procedure Reserve_Capacity
1230 (Container : in out Set;
1231 Capacity : Count_Type)
1234 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1235 end Reserve_Capacity;
1241 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1246 --------------------------
1247 -- Symmetric_Difference --
1248 --------------------------
1250 procedure Symmetric_Difference
1251 (Target : in out Set;
1255 if Target'Address = Source'Address then
1260 if Target.HT.Busy > 0 then
1261 raise Program_Error;
1265 N : constant Count_Type := Target.Length + Source.Length;
1267 if N > HT_Ops.Capacity (Target.HT) then
1268 HT_Ops.Reserve_Capacity (Target.HT, N);
1272 if Target.Length = 0 then
1273 Iterate_Source_When_Empty_Target : declare
1274 procedure Process (Src_Node : Node_Access);
1276 procedure Iterate is
1277 new HT_Ops.Generic_Iteration (Process);
1283 procedure Process (Src_Node : Node_Access) is
1284 E : Element_Type renames Src_Node.Element.all;
1285 B : Buckets_Type renames Target.HT.Buckets.all;
1286 J : constant Hash_Type := Hash (E) mod B'Length;
1287 N : Count_Type renames Target.HT.Length;
1291 X : Element_Access := new Element_Type'(E);
1293 B (J) := new Node_Type'(X, B (J));
1303 -- Start of processing for Iterate_Source_When_Empty_Target
1306 Iterate (Source.HT);
1307 end Iterate_Source_When_Empty_Target;
1310 Iterate_Source : declare
1311 procedure Process (Src_Node : Node_Access);
1313 procedure Iterate is
1314 new HT_Ops.Generic_Iteration (Process);
1320 procedure Process (Src_Node : Node_Access) is
1321 E : Element_Type renames Src_Node.Element.all;
1322 B : Buckets_Type renames Target.HT.Buckets.all;
1323 J : constant Hash_Type := Hash (E) mod B'Length;
1324 N : Count_Type renames Target.HT.Length;
1327 if B (J) = null then
1329 X : Element_Access := new Element_Type'(E);
1331 B (J) := new Node_Type'(X, null);
1340 elsif Equivalent_Elements (E, B (J).Element.all) then
1342 X : Node_Access := B (J);
1344 B (J) := B (J).Next;
1351 Prev : Node_Access := B (J);
1352 Curr : Node_Access := Prev.Next;
1355 while Curr /= null loop
1356 if Equivalent_Elements (E, Curr.Element.all) then
1357 Prev.Next := Curr.Next;
1368 X : Element_Access := new Element_Type'(E);
1370 B (J) := new Node_Type'(X, B (J));
1382 -- Start of processing for Iterate_Source
1385 Iterate (Source.HT);
1388 end Symmetric_Difference;
1390 function Symmetric_Difference (Left, Right : Set) return Set is
1391 Buckets : HT_Types.Buckets_Access;
1392 Length : Count_Type;
1395 if Left'Address = Right'Address then
1399 if Right.Length = 0 then
1403 if Left.Length = 0 then
1408 Size : constant Hash_Type :=
1409 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1411 Buckets := new Buckets_Type (0 .. Size - 1);
1416 Iterate_Left : declare
1417 procedure Process (L_Node : Node_Access);
1419 procedure Iterate is
1420 new HT_Ops.Generic_Iteration (Process);
1426 procedure Process (L_Node : Node_Access) is
1428 if not Is_In (Right.HT, L_Node) then
1430 E : Element_Type renames L_Node.Element.all;
1431 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1435 X : Element_Access := new Element_Type'(E);
1437 Buckets (J) := new Node_Type'(X, Buckets (J));
1444 Length := Length + 1;
1449 -- Start of processing for Iterate_Left
1455 HT_Ops.Free_Hash_Table (Buckets);
1459 Iterate_Right : declare
1460 procedure Process (R_Node : Node_Access);
1462 procedure Iterate is
1463 new HT_Ops.Generic_Iteration (Process);
1469 procedure Process (R_Node : Node_Access) is
1471 if not Is_In (Left.HT, R_Node) then
1473 E : Element_Type renames R_Node.Element.all;
1474 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1478 X : Element_Access := new Element_Type'(E);
1480 Buckets (J) := new Node_Type'(X, Buckets (J));
1487 Length := Length + 1;
1492 -- Start of processing for Iterate_Right
1498 HT_Ops.Free_Hash_Table (Buckets);
1502 return (Controlled with HT => (Buckets, Length, 0, 0));
1503 end Symmetric_Difference;
1510 (Target : in out Set;
1513 procedure Process (Src_Node : Node_Access);
1515 procedure Iterate is
1516 new HT_Ops.Generic_Iteration (Process);
1522 procedure Process (Src_Node : Node_Access) is
1523 Src : Element_Type renames Src_Node.Element.all;
1525 function New_Node (Next : Node_Access) return Node_Access;
1526 pragma Inline (New_Node);
1529 new Element_Keys.Generic_Conditional_Insert (New_Node);
1535 function New_Node (Next : Node_Access) return Node_Access is
1536 Tgt : Element_Access := new Element_Type'(Src);
1539 return new Node_Type'(Tgt, Next);
1546 Tgt_Node : Node_Access;
1549 -- Start of processing for Process
1552 Insert (Target.HT, Src, Tgt_Node, Success);
1555 -- Start of processing for Union
1558 if Target'Address = Source'Address then
1562 if Target.HT.Busy > 0 then
1563 raise Program_Error;
1567 N : constant Count_Type := Target.Length + Source.Length;
1569 if N > HT_Ops.Capacity (Target.HT) then
1570 HT_Ops.Reserve_Capacity (Target.HT, N);
1574 Iterate (Source.HT);
1577 function Union (Left, Right : Set) return Set is
1578 Buckets : HT_Types.Buckets_Access;
1579 Length : Count_Type;
1582 if Left'Address = Right'Address then
1586 if Right.Length = 0 then
1590 if Left.Length = 0 then
1595 Size : constant Hash_Type :=
1596 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1598 Buckets := new Buckets_Type (0 .. Size - 1);
1601 Iterate_Left : declare
1602 procedure Process (L_Node : Node_Access);
1604 procedure Iterate is
1605 new HT_Ops.Generic_Iteration (Process);
1611 procedure Process (L_Node : Node_Access) is
1612 J : constant Hash_Type :=
1613 Hash (L_Node.Element.all) mod Buckets'Length;
1615 Bucket : Node_Access renames Buckets (J);
1618 Bucket := new Node_Type'(L_Node.Element, Bucket);
1621 -- Start of processing for Process
1627 HT_Ops.Free_Hash_Table (Buckets);
1631 Length := Left.Length;
1633 Iterate_Right : declare
1634 procedure Process (Src_Node : Node_Access);
1636 procedure Iterate is
1637 new HT_Ops.Generic_Iteration (Process);
1643 procedure Process (Src_Node : Node_Access) is
1644 Src : Element_Type renames Src_Node.Element.all;
1645 Idx : constant Hash_Type := Hash (Src) mod Buckets'Length;
1647 Tgt_Node : Node_Access := Buckets (Idx);
1650 while Tgt_Node /= null loop
1651 if Equivalent_Elements (Src, Tgt_Node.Element.all) then
1654 Tgt_Node := Next (Tgt_Node);
1658 Tgt : Element_Access := new Element_Type'(Src);
1660 Buckets (Idx) := new Node_Type'(Tgt, Buckets (Idx));
1667 Length := Length + 1;
1670 -- Start of processing for Iterate_Right
1676 HT_Ops.Free_Hash_Table (Buckets);
1680 return (Controlled with HT => (Buckets, Length, 0, 0));
1687 function Vet (Position : Cursor) return Boolean is
1689 if Position.Node = null then
1690 return Position.Container = null;
1693 if Position.Container = null then
1697 if Position.Node.Next = Position.Node then
1701 if Position.Node.Element = null then
1706 HT : Hash_Table_Type renames Position.Container.HT;
1710 if HT.Length = 0 then
1714 if HT.Buckets = null
1715 or else HT.Buckets'Length = 0
1720 X := HT.Buckets (Element_Keys.Index (HT, Position.Node.Element.all));
1722 for J in 1 .. HT.Length loop
1723 if X = Position.Node then
1731 if X = X.Next then -- to prevent unnecessary looping
1747 (Stream : access Root_Stream_Type'Class;
1751 Write_Nodes (Stream, Container.HT);
1758 procedure Write_Node
1759 (Stream : access Root_Stream_Type'Class;
1763 Element_Type'Output (Stream, Node.Element.all);
1766 package body Generic_Keys is
1768 -----------------------
1769 -- Local Subprograms --
1770 -----------------------
1772 function Equivalent_Key_Node
1774 Node : Node_Access) return Boolean;
1775 pragma Inline (Equivalent_Key_Node);
1777 --------------------------
1778 -- Local Instantiations --
1779 --------------------------
1782 new Hash_Tables.Generic_Keys
1783 (HT_Types => HT_Types,
1785 Set_Next => Set_Next,
1786 Key_Type => Key_Type,
1788 Equivalent_Keys => Equivalent_Key_Node);
1796 Key : Key_Type) return Boolean
1799 return Find (Container, Key) /= No_Element;
1807 (Container : in out Set;
1813 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1816 raise Constraint_Error;
1828 Key : Key_Type) return Element_Type
1830 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1832 return Node.Element.all;
1835 -------------------------
1836 -- Equivalent_Key_Node --
1837 -------------------------
1839 function Equivalent_Key_Node
1841 Node : Node_Access) return Boolean is
1843 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element.all));
1844 end Equivalent_Key_Node;
1851 (Container : in out Set;
1856 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1866 Key : Key_Type) return Cursor
1868 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1875 return Cursor'(Container'Unrestricted_Access, Node);
1882 function Key (Position : Cursor) return Key_Type is
1884 pragma Assert (Vet (Position), "bad cursor in function Key");
1886 if Position.Node = null then
1887 raise Constraint_Error;
1890 if Position.Node.Element = null then
1891 raise Program_Error;
1894 return Key (Position.Node.Element.all);
1902 (Container : in out Set;
1904 New_Item : Element_Type)
1906 Node : constant Node_Access :=
1907 Key_Keys.Find (Container.HT, Key);
1911 raise Constraint_Error;
1914 Replace_Element (Container.HT, Node, New_Item);
1917 procedure Update_Element_Preserving_Key
1918 (Container : in out Set;
1919 Position : in Cursor;
1920 Process : not null access
1921 procedure (Element : in out Element_Type))
1923 HT : Hash_Table_Type renames Container.HT;
1929 "bad cursor in Update_Element_Preserving_Key");
1931 if Position.Node = null then
1932 raise Constraint_Error;
1935 if Position.Node.Element = null
1936 or else Position.Node.Next = Position.Node
1938 raise Program_Error;
1941 if Position.Container /= Container'Unrestricted_Access then
1942 raise Program_Error;
1945 if HT.Buckets = null
1946 or else HT.Buckets'Length = 0
1947 or else HT.Length = 0
1949 raise Program_Error;
1952 Indx := HT_Ops.Index (HT, Position.Node);
1955 E : Element_Type renames Position.Node.Element.all;
1956 K : constant Key_Type := Key (E);
1958 B : Natural renames HT.Busy;
1959 L : Natural renames HT.Lock;
1977 if Equivalent_Keys (K, Key (E)) then
1978 pragma Assert (Hash (K) = Hash (E));
1983 if HT.Buckets (Indx) = Position.Node then
1984 HT.Buckets (Indx) := Position.Node.Next;
1988 Prev : Node_Access := HT.Buckets (Indx);
1991 while Prev.Next /= Position.Node loop
1995 raise Program_Error;
1999 Prev.Next := Position.Node.Next;
2003 HT.Length := HT.Length - 1;
2006 X : Node_Access := Position.Node;
2012 raise Program_Error;
2013 end Update_Element_Preserving_Key;
2017 end Ada.Containers.Indefinite_Hashed_Sets;