1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_HASHED_SETS --
9 -- Copyright (C) 2004-2008, 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 2, 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. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- This unit was originally developed by Matthew J Heaney. --
30 ------------------------------------------------------------------------------
32 with Ada.Unchecked_Deallocation;
34 with Ada.Containers.Hash_Tables.Generic_Operations;
35 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Operations);
37 with Ada.Containers.Hash_Tables.Generic_Keys;
38 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Keys);
40 with Ada.Containers.Prime_Numbers;
42 with System; use type System.Address;
44 package body Ada.Containers.Indefinite_Hashed_Sets is
46 -----------------------
47 -- Local Subprograms --
48 -----------------------
50 procedure Assign (Node : Node_Access; Item : Element_Type);
51 pragma Inline (Assign);
53 function Copy_Node (Source : Node_Access) return Node_Access;
54 pragma Inline (Copy_Node);
56 function Equivalent_Keys
58 Node : Node_Access) return Boolean;
59 pragma Inline (Equivalent_Keys);
61 function Find_Equal_Key
62 (R_HT : Hash_Table_Type;
63 L_Node : Node_Access) return Boolean;
65 function Find_Equivalent_Key
66 (R_HT : Hash_Table_Type;
67 L_Node : Node_Access) return Boolean;
69 procedure Free (X : in out Node_Access);
71 function Hash_Node (Node : Node_Access) return Hash_Type;
72 pragma Inline (Hash_Node);
75 (HT : in out Hash_Table_Type;
76 New_Item : Element_Type;
77 Node : out Node_Access;
78 Inserted : out Boolean);
80 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean;
81 pragma Inline (Is_In);
83 function Next (Node : Node_Access) return Node_Access;
86 function Read_Node (Stream : not null access Root_Stream_Type'Class)
88 pragma Inline (Read_Node);
90 procedure Set_Next (Node : Node_Access; Next : Node_Access);
91 pragma Inline (Set_Next);
93 function Vet (Position : Cursor) return Boolean;
96 (Stream : not null access Root_Stream_Type'Class;
98 pragma Inline (Write_Node);
100 --------------------------
101 -- Local Instantiations --
102 --------------------------
104 procedure Free_Element is
105 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
107 package HT_Ops is new Hash_Tables.Generic_Operations
108 (HT_Types => HT_Types,
109 Hash_Node => Hash_Node,
111 Set_Next => Set_Next,
112 Copy_Node => Copy_Node,
115 package Element_Keys is new Hash_Tables.Generic_Keys
116 (HT_Types => HT_Types,
118 Set_Next => Set_Next,
119 Key_Type => Element_Type,
121 Equivalent_Keys => Equivalent_Keys);
124 new HT_Ops.Generic_Equal (Find_Equal_Key);
126 function Is_Equivalent is
127 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
129 procedure Read_Nodes is
130 new HT_Ops.Generic_Read (Read_Node);
132 procedure Replace_Element is
133 new Element_Keys.Generic_Replace_Element (Hash_Node, Assign);
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 procedure Assign (Node : Node_Access; Item : Element_Type) is
161 X : Element_Access := Node.Element;
163 Node.Element := new Element_Type'(Item);
171 function Capacity (Container : Set) return Count_Type is
173 return HT_Ops.Capacity (Container.HT);
180 procedure Clear (Container : in out Set) is
182 HT_Ops.Clear (Container.HT);
189 function Contains (Container : Set; Item : Element_Type) return Boolean is
191 return Find (Container, Item) /= No_Element;
198 function Copy_Node (Source : Node_Access) return Node_Access is
199 E : Element_Access := new Element_Type'(Source.Element.all);
201 return new Node_Type'(Element => E, Next => null);
213 (Container : in out Set;
219 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
222 raise Constraint_Error with "attempt to delete element not in set";
229 (Container : in out Set;
230 Position : in out Cursor)
233 if Position.Node = null then
234 raise Constraint_Error with "Position cursor equals No_Element";
237 if Position.Node.Element = null then
238 raise Program_Error with "Position cursor is bad";
241 if Position.Container /= Container'Unrestricted_Access then
242 raise Program_Error with "Position cursor designates wrong set";
245 if Container.HT.Busy > 0 then
246 raise Program_Error with
247 "attempt to tamper with elements (set is busy)";
250 pragma Assert (Vet (Position), "Position cursor is bad");
252 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
254 Free (Position.Node);
255 Position.Container := null;
263 (Target : in out Set;
266 Tgt_Node : Node_Access;
269 if Target'Address = Source'Address then
274 if Source.HT.Length = 0 then
278 if Target.HT.Busy > 0 then
279 raise Program_Error with
280 "attempt to tamper with elements (set is busy)";
283 if Source.HT.Length < Target.HT.Length then
285 Src_Node : Node_Access;
288 Src_Node := HT_Ops.First (Source.HT);
289 while Src_Node /= null loop
290 Tgt_Node := Element_Keys.Find (Target.HT, Src_Node.Element.all);
292 if Tgt_Node /= null then
293 HT_Ops.Delete_Node_Sans_Free (Target.HT, Tgt_Node);
297 Src_Node := HT_Ops.Next (Source.HT, Src_Node);
302 Tgt_Node := HT_Ops.First (Target.HT);
303 while Tgt_Node /= null loop
304 if Is_In (Source.HT, Tgt_Node) then
306 X : Node_Access := Tgt_Node;
308 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
309 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
314 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
320 function Difference (Left, Right : Set) return Set is
321 Buckets : HT_Types.Buckets_Access;
325 if Left'Address = Right'Address then
329 if Left.Length = 0 then
333 if Right.Length = 0 then
338 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
340 Buckets := HT_Ops.New_Buckets (Length => Size);
345 Iterate_Left : declare
346 procedure Process (L_Node : Node_Access);
349 new HT_Ops.Generic_Iteration (Process);
355 procedure Process (L_Node : Node_Access) is
357 if not Is_In (Right.HT, L_Node) then
359 Src : Element_Type renames L_Node.Element.all;
360 Indx : constant Hash_Type := Hash (Src) mod Buckets'Length;
361 Bucket : Node_Access renames Buckets (Indx);
362 Tgt : Element_Access := new Element_Type'(Src);
364 Bucket := new Node_Type'(Tgt, Bucket);
371 Length := Length + 1;
375 -- Start of processing for Iterate_Left
381 HT_Ops.Free_Hash_Table (Buckets);
385 return (Controlled with HT => (Buckets, Length, 0, 0));
392 function Element (Position : Cursor) return Element_Type is
394 if Position.Node = null then
395 raise Constraint_Error with "Position cursor of equals No_Element";
398 if Position.Node.Element = null then -- handle dangling reference
399 raise Program_Error with "Position cursor is bad";
402 pragma Assert (Vet (Position), "bad cursor in function Element");
404 return Position.Node.Element.all;
407 ---------------------
408 -- Equivalent_Sets --
409 ---------------------
411 function Equivalent_Sets (Left, Right : Set) return Boolean is
413 return Is_Equivalent (Left.HT, Right.HT);
416 -------------------------
417 -- Equivalent_Elements --
418 -------------------------
420 function Equivalent_Elements (Left, Right : Cursor)
423 if Left.Node = null then
424 raise Constraint_Error with
425 "Left cursor of Equivalent_Elements equals No_Element";
428 if Right.Node = null then
429 raise Constraint_Error with
430 "Right cursor of Equivalent_Elements equals No_Element";
433 if Left.Node.Element = null then
434 raise Program_Error with
435 "Left cursor of Equivalent_Elements is bad";
438 if Right.Node.Element = null then
439 raise Program_Error with
440 "Right cursor of Equivalent_Elements is bad";
443 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
444 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
446 return Equivalent_Elements
447 (Left.Node.Element.all,
448 Right.Node.Element.all);
449 end Equivalent_Elements;
451 function Equivalent_Elements (Left : Cursor; Right : Element_Type)
454 if Left.Node = null then
455 raise Constraint_Error with
456 "Left cursor of Equivalent_Elements equals No_Element";
459 if Left.Node.Element = null then
460 raise Program_Error with
461 "Left cursor of Equivalent_Elements is bad";
464 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
466 return Equivalent_Elements (Left.Node.Element.all, Right);
467 end Equivalent_Elements;
469 function Equivalent_Elements (Left : Element_Type; Right : Cursor)
472 if Right.Node = null then
473 raise Constraint_Error with
474 "Right cursor of Equivalent_Elements equals No_Element";
477 if Right.Node.Element = null then
478 raise Program_Error with
479 "Right cursor of Equivalent_Elements is bad";
482 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
484 return Equivalent_Elements (Left, Right.Node.Element.all);
485 end Equivalent_Elements;
487 ---------------------
488 -- Equivalent_Keys --
489 ---------------------
491 function Equivalent_Keys (Key : Element_Type; Node : Node_Access)
494 return Equivalent_Elements (Key, Node.Element.all);
502 (Container : in out Set;
507 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
515 procedure Finalize (Container : in out Set) is
517 HT_Ops.Finalize (Container.HT);
526 Item : Element_Type) return Cursor
528 Node : constant Node_Access := Element_Keys.Find (Container.HT, Item);
535 return Cursor'(Container'Unrestricted_Access, Node);
542 function Find_Equal_Key
543 (R_HT : Hash_Table_Type;
544 L_Node : Node_Access) return Boolean
546 R_Index : constant Hash_Type :=
547 Element_Keys.Index (R_HT, L_Node.Element.all);
549 R_Node : Node_Access := R_HT.Buckets (R_Index);
553 if R_Node = null then
557 if L_Node.Element.all = R_Node.Element.all then
561 R_Node := Next (R_Node);
565 -------------------------
566 -- Find_Equivalent_Key --
567 -------------------------
569 function Find_Equivalent_Key
570 (R_HT : Hash_Table_Type;
571 L_Node : Node_Access) return Boolean
573 R_Index : constant Hash_Type :=
574 Element_Keys.Index (R_HT, L_Node.Element.all);
576 R_Node : Node_Access := R_HT.Buckets (R_Index);
580 if R_Node = null then
584 if Equivalent_Elements (L_Node.Element.all, R_Node.Element.all) then
588 R_Node := Next (R_Node);
590 end Find_Equivalent_Key;
596 function First (Container : Set) return Cursor is
597 Node : constant Node_Access := HT_Ops.First (Container.HT);
604 return Cursor'(Container'Unrestricted_Access, Node);
611 procedure Free (X : in out Node_Access) is
612 procedure Deallocate is
613 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
620 X.Next := X; -- detect mischief (in Vet)
623 Free_Element (X.Element);
638 function Has_Element (Position : Cursor) return Boolean is
640 pragma Assert (Vet (Position), "bad cursor in Has_Element");
641 return Position.Node /= null;
648 function Hash_Node (Node : Node_Access) return Hash_Type is
650 return Hash (Node.Element.all);
658 (Container : in out Set;
659 New_Item : Element_Type)
667 Insert (Container, New_Item, Position, Inserted);
670 if Container.HT.Lock > 0 then
671 raise Program_Error with
672 "attempt to tamper with cursors (set is locked)";
675 X := Position.Node.Element;
677 Position.Node.Element := new Element_Type'(New_Item);
688 (Container : in out Set;
689 New_Item : Element_Type;
690 Position : out Cursor;
691 Inserted : out Boolean)
694 Insert (Container.HT, New_Item, Position.Node, Inserted);
695 Position.Container := Container'Unchecked_Access;
699 (Container : in out Set;
700 New_Item : Element_Type)
703 pragma Unreferenced (Position);
708 Insert (Container, New_Item, Position, Inserted);
711 raise Constraint_Error with
712 "attempt to insert element already in set";
717 (HT : in out Hash_Table_Type;
718 New_Item : Element_Type;
719 Node : out Node_Access;
720 Inserted : out Boolean)
722 function New_Node (Next : Node_Access) return Node_Access;
723 pragma Inline (New_Node);
725 procedure Local_Insert is
726 new Element_Keys.Generic_Conditional_Insert (New_Node);
732 function New_Node (Next : Node_Access) return Node_Access is
733 Element : Element_Access := new Element_Type'(New_Item);
736 return new Node_Type'(Element, Next);
739 Free_Element (Element);
743 -- Start of processing for Insert
746 if HT_Ops.Capacity (HT) = 0 then
747 HT_Ops.Reserve_Capacity (HT, 1);
750 Local_Insert (HT, New_Item, Node, Inserted);
753 and then HT.Length > HT_Ops.Capacity (HT)
755 HT_Ops.Reserve_Capacity (HT, HT.Length);
763 procedure Intersection
764 (Target : in out Set;
767 Tgt_Node : Node_Access;
770 if Target'Address = Source'Address then
774 if Source.Length = 0 then
779 if Target.HT.Busy > 0 then
780 raise Program_Error with
781 "attempt to tamper with elements (set is busy)";
784 Tgt_Node := HT_Ops.First (Target.HT);
785 while Tgt_Node /= null loop
786 if Is_In (Source.HT, Tgt_Node) then
787 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
791 X : Node_Access := Tgt_Node;
793 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
794 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
801 function Intersection (Left, Right : Set) return Set is
802 Buckets : HT_Types.Buckets_Access;
806 if Left'Address = Right'Address then
810 Length := Count_Type'Min (Left.Length, Right.Length);
817 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length);
819 Buckets := HT_Ops.New_Buckets (Length => Size);
824 Iterate_Left : declare
825 procedure Process (L_Node : Node_Access);
828 new HT_Ops.Generic_Iteration (Process);
834 procedure Process (L_Node : Node_Access) is
836 if Is_In (Right.HT, L_Node) then
838 Src : Element_Type renames L_Node.Element.all;
840 Indx : constant Hash_Type := Hash (Src) mod Buckets'Length;
842 Bucket : Node_Access renames Buckets (Indx);
844 Tgt : Element_Access := new Element_Type'(Src);
847 Bucket := new Node_Type'(Tgt, Bucket);
854 Length := Length + 1;
858 -- Start of processing for Iterate_Left
864 HT_Ops.Free_Hash_Table (Buckets);
868 return (Controlled with HT => (Buckets, Length, 0, 0));
875 function Is_Empty (Container : Set) return Boolean is
877 return Container.HT.Length = 0;
884 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean is
886 return Element_Keys.Find (HT, Key.Element.all) /= null;
895 Of_Set : Set) return Boolean
897 Subset_Node : Node_Access;
900 if Subset'Address = Of_Set'Address then
904 if Subset.Length > Of_Set.Length then
908 Subset_Node := HT_Ops.First (Subset.HT);
909 while Subset_Node /= null loop
910 if not Is_In (Of_Set.HT, Subset_Node) then
914 Subset_Node := HT_Ops.Next (Subset.HT, Subset_Node);
926 Process : not null access procedure (Position : Cursor))
928 procedure Process_Node (Node : Node_Access);
929 pragma Inline (Process_Node);
932 new HT_Ops.Generic_Iteration (Process_Node);
938 procedure Process_Node (Node : Node_Access) is
940 Process (Cursor'(Container'Unrestricted_Access, Node));
943 B : Natural renames Container'Unrestricted_Access.HT.Busy;
945 -- Start of processing for Iterate
951 Iterate (Container.HT);
965 function Length (Container : Set) return Count_Type is
967 return Container.HT.Length;
974 procedure Move (Target : in out Set; Source : in out Set) is
976 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
983 function Next (Node : Node_Access) return Node_Access is
988 function Next (Position : Cursor) return Cursor is
990 if Position.Node = null then
994 if Position.Node.Element = null then
995 raise Program_Error with "bad cursor in Next";
998 pragma Assert (Vet (Position), "bad cursor in Next");
1001 HT : Hash_Table_Type renames Position.Container.HT;
1002 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
1009 return Cursor'(Position.Container, Node);
1013 procedure Next (Position : in out Cursor) is
1015 Position := Next (Position);
1022 function Overlap (Left, Right : Set) return Boolean is
1023 Left_Node : Node_Access;
1026 if Right.Length = 0 then
1030 if Left'Address = Right'Address then
1034 Left_Node := HT_Ops.First (Left.HT);
1035 while Left_Node /= null loop
1036 if Is_In (Right.HT, Left_Node) then
1040 Left_Node := HT_Ops.Next (Left.HT, Left_Node);
1050 procedure Query_Element
1052 Process : not null access procedure (Element : Element_Type))
1055 if Position.Node = null then
1056 raise Constraint_Error with
1057 "Position cursor of Query_Element equals No_Element";
1060 if Position.Node.Element = null then
1061 raise Program_Error with "bad cursor in Query_Element";
1064 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1067 HT : Hash_Table_Type renames
1068 Position.Container'Unrestricted_Access.all.HT;
1070 B : Natural renames HT.Busy;
1071 L : Natural renames HT.Lock;
1078 Process (Position.Node.Element.all);
1096 (Stream : not null access Root_Stream_Type'Class;
1097 Container : out Set)
1100 Read_Nodes (Stream, Container.HT);
1104 (Stream : not null access Root_Stream_Type'Class;
1108 raise Program_Error with "attempt to stream set cursor";
1116 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1118 X : Element_Access := new Element_Type'(Element_Type'Input (Stream));
1121 return new Node_Type'(X, null);
1133 (Container : in out Set;
1134 New_Item : Element_Type)
1136 Node : constant Node_Access :=
1137 Element_Keys.Find (Container.HT, New_Item);
1140 pragma Warnings (Off, X);
1144 raise Constraint_Error with
1145 "attempt to replace element not in set";
1148 if Container.HT.Lock > 0 then
1149 raise Program_Error with
1150 "attempt to tamper with cursors (set is locked)";
1155 Node.Element := new Element_Type'(New_Item);
1160 ---------------------
1161 -- Replace_Element --
1162 ---------------------
1164 procedure Replace_Element
1165 (Container : in out Set;
1167 New_Item : Element_Type)
1170 if Position.Node = null then
1171 raise Constraint_Error with "Position cursor equals No_Element";
1174 if Position.Node.Element = null then
1175 raise Program_Error with "bad cursor in Replace_Element";
1178 if Position.Container /= Container'Unrestricted_Access then
1179 raise Program_Error with
1180 "Position cursor designates wrong set";
1183 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1185 Replace_Element (Container.HT, Position.Node, New_Item);
1186 end Replace_Element;
1188 ----------------------
1189 -- Reserve_Capacity --
1190 ----------------------
1192 procedure Reserve_Capacity
1193 (Container : in out Set;
1194 Capacity : Count_Type)
1197 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1198 end Reserve_Capacity;
1204 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1209 --------------------------
1210 -- Symmetric_Difference --
1211 --------------------------
1213 procedure Symmetric_Difference
1214 (Target : in out Set;
1218 if Target'Address = Source'Address then
1223 if Target.HT.Busy > 0 then
1224 raise Program_Error with
1225 "attempt to tamper with elements (set is busy)";
1229 N : constant Count_Type := Target.Length + Source.Length;
1231 if N > HT_Ops.Capacity (Target.HT) then
1232 HT_Ops.Reserve_Capacity (Target.HT, N);
1236 if Target.Length = 0 then
1237 Iterate_Source_When_Empty_Target : declare
1238 procedure Process (Src_Node : Node_Access);
1240 procedure Iterate is
1241 new HT_Ops.Generic_Iteration (Process);
1247 procedure Process (Src_Node : Node_Access) is
1248 E : Element_Type renames Src_Node.Element.all;
1249 B : Buckets_Type renames Target.HT.Buckets.all;
1250 J : constant Hash_Type := Hash (E) mod B'Length;
1251 N : Count_Type renames Target.HT.Length;
1255 X : Element_Access := new Element_Type'(E);
1257 B (J) := new Node_Type'(X, B (J));
1267 -- Start of processing for Iterate_Source_When_Empty_Target
1270 Iterate (Source.HT);
1271 end Iterate_Source_When_Empty_Target;
1274 Iterate_Source : declare
1275 procedure Process (Src_Node : Node_Access);
1277 procedure Iterate is
1278 new HT_Ops.Generic_Iteration (Process);
1284 procedure Process (Src_Node : Node_Access) is
1285 E : Element_Type renames Src_Node.Element.all;
1286 B : Buckets_Type renames Target.HT.Buckets.all;
1287 J : constant Hash_Type := Hash (E) mod B'Length;
1288 N : Count_Type renames Target.HT.Length;
1291 if B (J) = null then
1293 X : Element_Access := new Element_Type'(E);
1295 B (J) := new Node_Type'(X, null);
1304 elsif Equivalent_Elements (E, B (J).Element.all) then
1306 X : Node_Access := B (J);
1308 B (J) := B (J).Next;
1315 Prev : Node_Access := B (J);
1316 Curr : Node_Access := Prev.Next;
1319 while Curr /= null loop
1320 if Equivalent_Elements (E, Curr.Element.all) then
1321 Prev.Next := Curr.Next;
1332 X : Element_Access := new Element_Type'(E);
1334 B (J) := new Node_Type'(X, B (J));
1346 -- Start of processing for Iterate_Source
1349 Iterate (Source.HT);
1352 end Symmetric_Difference;
1354 function Symmetric_Difference (Left, Right : Set) return Set is
1355 Buckets : HT_Types.Buckets_Access;
1356 Length : Count_Type;
1359 if Left'Address = Right'Address then
1363 if Right.Length = 0 then
1367 if Left.Length = 0 then
1372 Size : constant Hash_Type :=
1373 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1375 Buckets := HT_Ops.New_Buckets (Length => Size);
1380 Iterate_Left : declare
1381 procedure Process (L_Node : Node_Access);
1383 procedure Iterate is
1384 new HT_Ops.Generic_Iteration (Process);
1390 procedure Process (L_Node : Node_Access) is
1392 if not Is_In (Right.HT, L_Node) then
1394 E : Element_Type renames L_Node.Element.all;
1395 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1399 X : Element_Access := new Element_Type'(E);
1401 Buckets (J) := new Node_Type'(X, Buckets (J));
1408 Length := Length + 1;
1413 -- Start of processing for Iterate_Left
1419 HT_Ops.Free_Hash_Table (Buckets);
1423 Iterate_Right : declare
1424 procedure Process (R_Node : Node_Access);
1426 procedure Iterate is
1427 new HT_Ops.Generic_Iteration (Process);
1433 procedure Process (R_Node : Node_Access) is
1435 if not Is_In (Left.HT, R_Node) then
1437 E : Element_Type renames R_Node.Element.all;
1438 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1442 X : Element_Access := new Element_Type'(E);
1444 Buckets (J) := new Node_Type'(X, Buckets (J));
1451 Length := Length + 1;
1456 -- Start of processing for Iterate_Right
1462 HT_Ops.Free_Hash_Table (Buckets);
1466 return (Controlled with HT => (Buckets, Length, 0, 0));
1467 end Symmetric_Difference;
1473 function To_Set (New_Item : Element_Type) return Set is
1474 HT : Hash_Table_Type;
1478 pragma Unreferenced (Node, Inserted);
1481 Insert (HT, New_Item, Node, Inserted);
1482 return Set'(Controlled with HT);
1490 (Target : in out Set;
1493 procedure Process (Src_Node : Node_Access);
1495 procedure Iterate is
1496 new HT_Ops.Generic_Iteration (Process);
1502 procedure Process (Src_Node : Node_Access) is
1503 Src : Element_Type renames Src_Node.Element.all;
1505 function New_Node (Next : Node_Access) return Node_Access;
1506 pragma Inline (New_Node);
1509 new Element_Keys.Generic_Conditional_Insert (New_Node);
1515 function New_Node (Next : Node_Access) return Node_Access is
1516 Tgt : Element_Access := new Element_Type'(Src);
1519 return new Node_Type'(Tgt, Next);
1526 Tgt_Node : Node_Access;
1528 pragma Unreferenced (Tgt_Node, Success);
1530 -- Start of processing for Process
1533 Insert (Target.HT, Src, Tgt_Node, Success);
1536 -- Start of processing for Union
1539 if Target'Address = Source'Address then
1543 if Target.HT.Busy > 0 then
1544 raise Program_Error with
1545 "attempt to tamper with elements (set is busy)";
1549 N : constant Count_Type := Target.Length + Source.Length;
1551 if N > HT_Ops.Capacity (Target.HT) then
1552 HT_Ops.Reserve_Capacity (Target.HT, N);
1556 Iterate (Source.HT);
1559 function Union (Left, Right : Set) return Set is
1560 Buckets : HT_Types.Buckets_Access;
1561 Length : Count_Type;
1564 if Left'Address = Right'Address then
1568 if Right.Length = 0 then
1572 if Left.Length = 0 then
1577 Size : constant Hash_Type :=
1578 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1580 Buckets := HT_Ops.New_Buckets (Length => Size);
1583 Iterate_Left : declare
1584 procedure Process (L_Node : Node_Access);
1586 procedure Iterate is
1587 new HT_Ops.Generic_Iteration (Process);
1593 procedure Process (L_Node : Node_Access) is
1594 Src : Element_Type renames L_Node.Element.all;
1596 J : constant Hash_Type := Hash (Src) mod Buckets'Length;
1598 Bucket : Node_Access renames Buckets (J);
1600 Tgt : Element_Access := new Element_Type'(Src);
1603 Bucket := new Node_Type'(Tgt, Bucket);
1610 -- Start of processing for Process
1616 HT_Ops.Free_Hash_Table (Buckets);
1620 Length := Left.Length;
1622 Iterate_Right : declare
1623 procedure Process (Src_Node : Node_Access);
1625 procedure Iterate is
1626 new HT_Ops.Generic_Iteration (Process);
1632 procedure Process (Src_Node : Node_Access) is
1633 Src : Element_Type renames Src_Node.Element.all;
1634 Idx : constant Hash_Type := Hash (Src) mod Buckets'Length;
1636 Tgt_Node : Node_Access := Buckets (Idx);
1639 while Tgt_Node /= null loop
1640 if Equivalent_Elements (Src, Tgt_Node.Element.all) then
1643 Tgt_Node := Next (Tgt_Node);
1647 Tgt : Element_Access := new Element_Type'(Src);
1649 Buckets (Idx) := new Node_Type'(Tgt, Buckets (Idx));
1656 Length := Length + 1;
1659 -- Start of processing for Iterate_Right
1665 HT_Ops.Free_Hash_Table (Buckets);
1669 return (Controlled with HT => (Buckets, Length, 0, 0));
1676 function Vet (Position : Cursor) return Boolean is
1678 if Position.Node = null then
1679 return Position.Container = null;
1682 if Position.Container = null then
1686 if Position.Node.Next = Position.Node then
1690 if Position.Node.Element = null then
1695 HT : Hash_Table_Type renames Position.Container.HT;
1699 if HT.Length = 0 then
1703 if HT.Buckets = null
1704 or else HT.Buckets'Length = 0
1709 X := HT.Buckets (Element_Keys.Index (HT, Position.Node.Element.all));
1711 for J in 1 .. HT.Length loop
1712 if X = Position.Node then
1720 if X = X.Next then -- to prevent unnecessary looping
1736 (Stream : not null access Root_Stream_Type'Class;
1740 Write_Nodes (Stream, Container.HT);
1744 (Stream : not null access Root_Stream_Type'Class;
1748 raise Program_Error with "attempt to stream set cursor";
1755 procedure Write_Node
1756 (Stream : not null access Root_Stream_Type'Class;
1760 Element_Type'Output (Stream, Node.Element.all);
1763 package body Generic_Keys is
1765 -----------------------
1766 -- Local Subprograms --
1767 -----------------------
1769 function Equivalent_Key_Node
1771 Node : Node_Access) return Boolean;
1772 pragma Inline (Equivalent_Key_Node);
1774 --------------------------
1775 -- Local Instantiations --
1776 --------------------------
1779 new Hash_Tables.Generic_Keys
1780 (HT_Types => HT_Types,
1782 Set_Next => Set_Next,
1783 Key_Type => Key_Type,
1785 Equivalent_Keys => Equivalent_Key_Node);
1793 Key : Key_Type) return Boolean
1796 return Find (Container, Key) /= No_Element;
1804 (Container : in out Set;
1810 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1813 raise Constraint_Error with "key not in map";
1825 Key : Key_Type) return Element_Type
1827 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1831 raise Constraint_Error with "key not in map";
1834 return Node.Element.all;
1837 -------------------------
1838 -- Equivalent_Key_Node --
1839 -------------------------
1841 function Equivalent_Key_Node
1843 Node : Node_Access) return Boolean is
1845 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element.all));
1846 end Equivalent_Key_Node;
1853 (Container : in out Set;
1858 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1868 Key : Key_Type) return Cursor
1870 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1877 return Cursor'(Container'Unrestricted_Access, Node);
1884 function Key (Position : Cursor) return Key_Type is
1886 if Position.Node = null then
1887 raise Constraint_Error with
1888 "Position cursor equals No_Element";
1891 if Position.Node.Element = null then
1892 raise Program_Error with "Position cursor is bad";
1895 pragma Assert (Vet (Position), "bad cursor in function Key");
1897 return Key (Position.Node.Element.all);
1905 (Container : in out Set;
1907 New_Item : Element_Type)
1909 Node : constant Node_Access :=
1910 Key_Keys.Find (Container.HT, Key);
1914 raise Constraint_Error with
1915 "attempt to replace key not in set";
1918 Replace_Element (Container.HT, Node, New_Item);
1921 procedure Update_Element_Preserving_Key
1922 (Container : in out Set;
1924 Process : not null access
1925 procedure (Element : in out Element_Type))
1927 HT : Hash_Table_Type renames Container.HT;
1931 if Position.Node = null then
1932 raise Constraint_Error with
1933 "Position cursor equals No_Element";
1936 if Position.Node.Element = null
1937 or else Position.Node.Next = Position.Node
1939 raise Program_Error with "Position cursor is bad";
1942 if Position.Container /= Container'Unrestricted_Access then
1943 raise Program_Error with
1944 "Position cursor designates wrong set";
1947 if HT.Buckets = null
1948 or else HT.Buckets'Length = 0
1949 or else HT.Length = 0
1951 raise Program_Error with "Position cursor is bad (set is empty)";
1956 "bad cursor in Update_Element_Preserving_Key");
1958 Indx := HT_Ops.Index (HT, Position.Node);
1961 E : Element_Type renames Position.Node.Element.all;
1962 K : constant Key_Type := Key (E);
1964 B : Natural renames HT.Busy;
1965 L : Natural renames HT.Lock;
1983 if Equivalent_Keys (K, Key (E)) then
1984 pragma Assert (Hash (K) = Hash (E));
1989 if HT.Buckets (Indx) = Position.Node then
1990 HT.Buckets (Indx) := Position.Node.Next;
1994 Prev : Node_Access := HT.Buckets (Indx);
1997 while Prev.Next /= Position.Node loop
2001 raise Program_Error with
2002 "Position cursor is bad (node not found)";
2006 Prev.Next := Position.Node.Next;
2010 HT.Length := HT.Length - 1;
2013 X : Node_Access := Position.Node;
2019 raise Program_Error with "key was modified";
2020 end Update_Element_Preserving_Key;
2024 end Ada.Containers.Indefinite_Hashed_Sets;