1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_HASHED_SETS --
9 -- Copyright (C) 2004-2011, 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/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Unchecked_Deallocation;
32 with Ada.Containers.Hash_Tables.Generic_Operations;
33 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Operations);
35 with Ada.Containers.Hash_Tables.Generic_Keys;
36 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Keys);
38 with Ada.Containers.Prime_Numbers;
40 with System; use type System.Address;
42 package body Ada.Containers.Indefinite_Hashed_Sets is
44 type Iterator is new Set_Iterator_Interfaces.Forward_Iterator with record
45 Container : Set_Access;
49 overriding function First (Object : Iterator) return Cursor;
51 overriding function Next
53 Position : Cursor) return Cursor;
55 -----------------------
56 -- Local Subprograms --
57 -----------------------
59 procedure Assign (Node : Node_Access; Item : Element_Type);
60 pragma Inline (Assign);
62 function Copy_Node (Source : Node_Access) return Node_Access;
63 pragma Inline (Copy_Node);
65 function Equivalent_Keys
67 Node : Node_Access) return Boolean;
68 pragma Inline (Equivalent_Keys);
70 function Find_Equal_Key
71 (R_HT : Hash_Table_Type;
72 L_Node : Node_Access) return Boolean;
74 function Find_Equivalent_Key
75 (R_HT : Hash_Table_Type;
76 L_Node : Node_Access) return Boolean;
78 procedure Free (X : in out Node_Access);
80 function Hash_Node (Node : Node_Access) return Hash_Type;
81 pragma Inline (Hash_Node);
84 (HT : in out Hash_Table_Type;
85 New_Item : Element_Type;
86 Node : out Node_Access;
87 Inserted : out Boolean);
89 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean;
90 pragma Inline (Is_In);
92 function Next (Node : Node_Access) return Node_Access;
95 function Read_Node (Stream : not null access Root_Stream_Type'Class)
97 pragma Inline (Read_Node);
99 procedure Set_Next (Node : Node_Access; Next : Node_Access);
100 pragma Inline (Set_Next);
102 function Vet (Position : Cursor) return Boolean;
105 (Stream : not null access Root_Stream_Type'Class;
107 pragma Inline (Write_Node);
109 --------------------------
110 -- Local Instantiations --
111 --------------------------
113 procedure Free_Element is
114 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
116 package HT_Ops is new Hash_Tables.Generic_Operations
117 (HT_Types => HT_Types,
118 Hash_Node => Hash_Node,
120 Set_Next => Set_Next,
121 Copy_Node => Copy_Node,
124 package Element_Keys is new Hash_Tables.Generic_Keys
125 (HT_Types => HT_Types,
127 Set_Next => Set_Next,
128 Key_Type => Element_Type,
130 Equivalent_Keys => Equivalent_Keys);
133 new HT_Ops.Generic_Equal (Find_Equal_Key);
135 function Is_Equivalent is
136 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
138 procedure Read_Nodes is
139 new HT_Ops.Generic_Read (Read_Node);
141 procedure Replace_Element is
142 new Element_Keys.Generic_Replace_Element (Hash_Node, Assign);
144 procedure Write_Nodes is
145 new HT_Ops.Generic_Write (Write_Node);
151 function "=" (Left, Right : Set) return Boolean is
153 return Is_Equal (Left.HT, Right.HT);
160 procedure Adjust (Container : in out Set) is
162 HT_Ops.Adjust (Container.HT);
169 procedure Assign (Node : Node_Access; Item : Element_Type) is
170 X : Element_Access := Node.Element;
172 Node.Element := new Element_Type'(Item);
180 function Capacity (Container : Set) return Count_Type is
182 return HT_Ops.Capacity (Container.HT);
189 procedure Clear (Container : in out Set) is
191 HT_Ops.Clear (Container.HT);
198 function Contains (Container : Set; Item : Element_Type) return Boolean is
200 return Find (Container, Item) /= No_Element;
207 function Copy_Node (Source : Node_Access) return Node_Access is
208 E : Element_Access := new Element_Type'(Source.Element.all);
210 return new Node_Type'(Element => E, Next => null);
222 (Container : in out Set;
228 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
231 raise Constraint_Error with "attempt to delete element not in set";
238 (Container : in out Set;
239 Position : in out Cursor)
242 if Position.Node = null then
243 raise Constraint_Error with "Position cursor equals No_Element";
246 if Position.Node.Element = null then
247 raise Program_Error with "Position cursor is bad";
250 if Position.Container /= Container'Unrestricted_Access then
251 raise Program_Error with "Position cursor designates wrong set";
254 if Container.HT.Busy > 0 then
255 raise Program_Error with
256 "attempt to tamper with cursors (set is busy)";
259 pragma Assert (Vet (Position), "Position cursor is bad");
261 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
263 Free (Position.Node);
264 Position.Container := null;
272 (Target : in out Set;
275 Tgt_Node : Node_Access;
278 if Target'Address = Source'Address then
283 if Source.HT.Length = 0 then
287 if Target.HT.Busy > 0 then
288 raise Program_Error with
289 "attempt to tamper with cursors (set is busy)";
292 if Source.HT.Length < Target.HT.Length then
294 Src_Node : Node_Access;
297 Src_Node := HT_Ops.First (Source.HT);
298 while Src_Node /= null loop
299 Tgt_Node := Element_Keys.Find (Target.HT, Src_Node.Element.all);
301 if Tgt_Node /= null then
302 HT_Ops.Delete_Node_Sans_Free (Target.HT, Tgt_Node);
306 Src_Node := HT_Ops.Next (Source.HT, Src_Node);
311 Tgt_Node := HT_Ops.First (Target.HT);
312 while Tgt_Node /= null loop
313 if Is_In (Source.HT, Tgt_Node) then
315 X : Node_Access := Tgt_Node;
317 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
318 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
323 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
329 function Difference (Left, Right : Set) return Set is
330 Buckets : HT_Types.Buckets_Access;
334 if Left'Address = Right'Address then
338 if Left.Length = 0 then
342 if Right.Length = 0 then
347 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
349 Buckets := HT_Ops.New_Buckets (Length => Size);
354 Iterate_Left : declare
355 procedure Process (L_Node : Node_Access);
358 new HT_Ops.Generic_Iteration (Process);
364 procedure Process (L_Node : Node_Access) is
366 if not Is_In (Right.HT, L_Node) then
368 Src : Element_Type renames L_Node.Element.all;
369 Indx : constant Hash_Type := Hash (Src) mod Buckets'Length;
370 Bucket : Node_Access renames Buckets (Indx);
371 Tgt : Element_Access := new Element_Type'(Src);
373 Bucket := new Node_Type'(Tgt, Bucket);
380 Length := Length + 1;
384 -- Start of processing for Iterate_Left
390 HT_Ops.Free_Hash_Table (Buckets);
394 return (Controlled with HT => (Buckets, Length, 0, 0));
401 function Element (Position : Cursor) return Element_Type is
403 if Position.Node = null then
404 raise Constraint_Error with "Position cursor of equals No_Element";
407 if Position.Node.Element = null then -- handle dangling reference
408 raise Program_Error with "Position cursor is bad";
411 pragma Assert (Vet (Position), "bad cursor in function Element");
413 return Position.Node.Element.all;
416 ---------------------
417 -- Equivalent_Sets --
418 ---------------------
420 function Equivalent_Sets (Left, Right : Set) return Boolean is
422 return Is_Equivalent (Left.HT, Right.HT);
425 -------------------------
426 -- Equivalent_Elements --
427 -------------------------
429 function Equivalent_Elements (Left, Right : Cursor) return Boolean is
431 if Left.Node = null then
432 raise Constraint_Error with
433 "Left cursor of Equivalent_Elements equals No_Element";
436 if Right.Node = null then
437 raise Constraint_Error with
438 "Right cursor of Equivalent_Elements equals No_Element";
441 if Left.Node.Element = null then
442 raise Program_Error with
443 "Left cursor of Equivalent_Elements is bad";
446 if Right.Node.Element = null then
447 raise Program_Error with
448 "Right cursor of Equivalent_Elements is bad";
451 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
452 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
454 return Equivalent_Elements
455 (Left.Node.Element.all,
456 Right.Node.Element.all);
457 end Equivalent_Elements;
459 function Equivalent_Elements
461 Right : Element_Type) return Boolean
464 if Left.Node = null then
465 raise Constraint_Error with
466 "Left cursor of Equivalent_Elements equals No_Element";
469 if Left.Node.Element = null then
470 raise Program_Error with
471 "Left cursor of Equivalent_Elements is bad";
474 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
476 return Equivalent_Elements (Left.Node.Element.all, Right);
477 end Equivalent_Elements;
479 function Equivalent_Elements
480 (Left : Element_Type;
481 Right : Cursor) return Boolean
484 if Right.Node = null then
485 raise Constraint_Error with
486 "Right cursor of Equivalent_Elements equals No_Element";
489 if Right.Node.Element = null then
490 raise Program_Error with
491 "Right cursor of Equivalent_Elements is bad";
494 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
496 return Equivalent_Elements (Left, Right.Node.Element.all);
497 end Equivalent_Elements;
499 ---------------------
500 -- Equivalent_Keys --
501 ---------------------
503 function Equivalent_Keys
505 Node : Node_Access) return Boolean
508 return Equivalent_Elements (Key, Node.Element.all);
516 (Container : in out Set;
521 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
529 procedure Finalize (Container : in out Set) is
531 HT_Ops.Finalize (Container.HT);
540 Item : Element_Type) return Cursor
542 Node : constant Node_Access := Element_Keys.Find (Container.HT, Item);
544 return (if Node = null then No_Element
545 else Cursor'(Container'Unrestricted_Access, Node));
552 function Find_Equal_Key
553 (R_HT : Hash_Table_Type;
554 L_Node : Node_Access) return Boolean
556 R_Index : constant Hash_Type :=
557 Element_Keys.Index (R_HT, L_Node.Element.all);
559 R_Node : Node_Access := R_HT.Buckets (R_Index);
563 if R_Node = null then
567 if L_Node.Element.all = R_Node.Element.all then
571 R_Node := Next (R_Node);
575 -------------------------
576 -- Find_Equivalent_Key --
577 -------------------------
579 function Find_Equivalent_Key
580 (R_HT : Hash_Table_Type;
581 L_Node : Node_Access) return Boolean
583 R_Index : constant Hash_Type :=
584 Element_Keys.Index (R_HT, L_Node.Element.all);
586 R_Node : Node_Access := R_HT.Buckets (R_Index);
590 if R_Node = null then
594 if Equivalent_Elements (L_Node.Element.all, R_Node.Element.all) then
598 R_Node := Next (R_Node);
600 end Find_Equivalent_Key;
606 function First (Container : Set) return Cursor is
607 Node : constant Node_Access := HT_Ops.First (Container.HT);
609 return (if Node = null then No_Element
610 else Cursor'(Container'Unrestricted_Access, Node));
613 function First (Object : Iterator) return Cursor is
614 Node : constant Node_Access := HT_Ops.First (Object.Container.HT);
616 return (if Node = null then No_Element
617 else Cursor'(Object.Container, Node));
624 procedure Free (X : in out Node_Access) is
625 procedure Deallocate is
626 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
633 X.Next := X; -- detect mischief (in Vet)
636 Free_Element (X.Element);
651 function Has_Element (Position : Cursor) return Boolean is
653 pragma Assert (Vet (Position), "bad cursor in Has_Element");
654 return Position.Node /= null;
661 function Hash_Node (Node : Node_Access) return Hash_Type is
663 return Hash (Node.Element.all);
671 (Container : in out Set;
672 New_Item : Element_Type)
680 Insert (Container, New_Item, Position, Inserted);
683 if Container.HT.Lock > 0 then
684 raise Program_Error with
685 "attempt to tamper with elements (set is locked)";
688 X := Position.Node.Element;
690 Position.Node.Element := new Element_Type'(New_Item);
701 (Container : in out Set;
702 New_Item : Element_Type;
703 Position : out Cursor;
704 Inserted : out Boolean)
707 Insert (Container.HT, New_Item, Position.Node, Inserted);
708 Position.Container := Container'Unchecked_Access;
712 (Container : in out Set;
713 New_Item : Element_Type)
716 pragma Unreferenced (Position);
721 Insert (Container, New_Item, Position, Inserted);
724 raise Constraint_Error with
725 "attempt to insert element already in set";
730 (HT : in out Hash_Table_Type;
731 New_Item : Element_Type;
732 Node : out Node_Access;
733 Inserted : out Boolean)
735 function New_Node (Next : Node_Access) return Node_Access;
736 pragma Inline (New_Node);
738 procedure Local_Insert is
739 new Element_Keys.Generic_Conditional_Insert (New_Node);
745 function New_Node (Next : Node_Access) return Node_Access is
746 Element : Element_Access := new Element_Type'(New_Item);
748 return new Node_Type'(Element, Next);
751 Free_Element (Element);
755 -- Start of processing for Insert
758 if HT_Ops.Capacity (HT) = 0 then
759 HT_Ops.Reserve_Capacity (HT, 1);
762 Local_Insert (HT, New_Item, Node, Inserted);
765 and then HT.Length > HT_Ops.Capacity (HT)
767 HT_Ops.Reserve_Capacity (HT, HT.Length);
775 procedure Intersection
776 (Target : in out Set;
779 Tgt_Node : Node_Access;
782 if Target'Address = Source'Address then
786 if Source.Length = 0 then
791 if Target.HT.Busy > 0 then
792 raise Program_Error with
793 "attempt to tamper with cursors (set is busy)";
796 Tgt_Node := HT_Ops.First (Target.HT);
797 while Tgt_Node /= null loop
798 if Is_In (Source.HT, Tgt_Node) then
799 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
803 X : Node_Access := Tgt_Node;
805 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
806 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
813 function Intersection (Left, Right : Set) return Set is
814 Buckets : HT_Types.Buckets_Access;
818 if Left'Address = Right'Address then
822 Length := Count_Type'Min (Left.Length, Right.Length);
829 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length);
831 Buckets := HT_Ops.New_Buckets (Length => Size);
836 Iterate_Left : declare
837 procedure Process (L_Node : Node_Access);
840 new HT_Ops.Generic_Iteration (Process);
846 procedure Process (L_Node : Node_Access) is
848 if Is_In (Right.HT, L_Node) then
850 Src : Element_Type renames L_Node.Element.all;
852 Indx : constant Hash_Type := Hash (Src) mod Buckets'Length;
854 Bucket : Node_Access renames Buckets (Indx);
856 Tgt : Element_Access := new Element_Type'(Src);
859 Bucket := new Node_Type'(Tgt, Bucket);
866 Length := Length + 1;
870 -- Start of processing for Iterate_Left
876 HT_Ops.Free_Hash_Table (Buckets);
880 return (Controlled with HT => (Buckets, Length, 0, 0));
887 function Is_Empty (Container : Set) return Boolean is
889 return Container.HT.Length = 0;
896 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean is
898 return Element_Keys.Find (HT, Key.Element.all) /= null;
907 Of_Set : Set) return Boolean
909 Subset_Node : Node_Access;
912 if Subset'Address = Of_Set'Address then
916 if Subset.Length > Of_Set.Length then
920 Subset_Node := HT_Ops.First (Subset.HT);
921 while Subset_Node /= null loop
922 if not Is_In (Of_Set.HT, Subset_Node) then
926 Subset_Node := HT_Ops.Next (Subset.HT, Subset_Node);
938 Process : not null access procedure (Position : Cursor))
940 procedure Process_Node (Node : Node_Access);
941 pragma Inline (Process_Node);
944 new HT_Ops.Generic_Iteration (Process_Node);
950 procedure Process_Node (Node : Node_Access) is
952 Process (Cursor'(Container'Unrestricted_Access, Node));
955 B : Natural renames Container'Unrestricted_Access.HT.Busy;
957 -- Start of processing for Iterate
963 Iterate (Container.HT);
973 function Iterate (Container : Set)
974 return Set_Iterator_Interfaces.Forward_Iterator'Class is
976 return Iterator'(Container'Unrestricted_Access, First (Container));
983 function Length (Container : Set) return Count_Type is
985 return Container.HT.Length;
992 procedure Move (Target : in out Set; Source : in out Set) is
994 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
1001 function Next (Node : Node_Access) return Node_Access is
1006 function Next (Position : Cursor) return Cursor is
1008 if Position.Node = null then
1012 if Position.Node.Element = null then
1013 raise Program_Error with "bad cursor in Next";
1016 pragma Assert (Vet (Position), "bad cursor in Next");
1019 HT : Hash_Table_Type renames Position.Container.HT;
1020 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
1022 return (if Node = null then No_Element
1023 else Cursor'(Position.Container, Node));
1027 procedure Next (Position : in out Cursor) is
1029 Position := Next (Position);
1034 Position : Cursor) return Cursor
1037 if Position.Container /= Object.Container then
1038 raise Program_Error with
1039 "Position cursor designates wrong set";
1042 return (if Position.Node = null then No_Element else Next (Position));
1049 function Overlap (Left, Right : Set) return Boolean is
1050 Left_Node : Node_Access;
1053 if Right.Length = 0 then
1057 if Left'Address = Right'Address then
1061 Left_Node := HT_Ops.First (Left.HT);
1062 while Left_Node /= null loop
1063 if Is_In (Right.HT, Left_Node) then
1067 Left_Node := HT_Ops.Next (Left.HT, Left_Node);
1077 procedure Query_Element
1079 Process : not null access procedure (Element : Element_Type))
1082 if Position.Node = null then
1083 raise Constraint_Error with
1084 "Position cursor of Query_Element equals No_Element";
1087 if Position.Node.Element = null then
1088 raise Program_Error with "bad cursor in Query_Element";
1091 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1094 HT : Hash_Table_Type renames
1095 Position.Container'Unrestricted_Access.all.HT;
1097 B : Natural renames HT.Busy;
1098 L : Natural renames HT.Lock;
1105 Process (Position.Node.Element.all);
1123 (Stream : not null access Root_Stream_Type'Class;
1124 Container : out Set)
1127 Read_Nodes (Stream, Container.HT);
1131 (Stream : not null access Root_Stream_Type'Class;
1135 raise Program_Error with "attempt to stream set cursor";
1139 (Stream : not null access Root_Stream_Type'Class;
1140 Item : out Constant_Reference_Type)
1143 raise Program_Error with "attempt to stream reference";
1151 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1153 X : Element_Access := new Element_Type'(Element_Type'Input (Stream));
1155 return new Node_Type'(X, null);
1166 function Constant_Reference
1167 (Container : aliased Set;
1168 Position : Cursor) return Constant_Reference_Type
1170 pragma Unreferenced (Container);
1172 return (Element => Position.Node.Element);
1173 end Constant_Reference;
1180 (Container : in out Set;
1181 New_Item : Element_Type)
1183 Node : constant Node_Access :=
1184 Element_Keys.Find (Container.HT, New_Item);
1187 pragma Warnings (Off, X);
1191 raise Constraint_Error with
1192 "attempt to replace element not in set";
1195 if Container.HT.Lock > 0 then
1196 raise Program_Error with
1197 "attempt to tamper with elements (set is locked)";
1202 Node.Element := new Element_Type'(New_Item);
1207 ---------------------
1208 -- Replace_Element --
1209 ---------------------
1211 procedure Replace_Element
1212 (Container : in out Set;
1214 New_Item : Element_Type)
1217 if Position.Node = null then
1218 raise Constraint_Error with "Position cursor equals No_Element";
1221 if Position.Node.Element = null then
1222 raise Program_Error with "bad cursor in Replace_Element";
1225 if Position.Container /= Container'Unrestricted_Access then
1226 raise Program_Error with
1227 "Position cursor designates wrong set";
1230 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1232 Replace_Element (Container.HT, Position.Node, New_Item);
1233 end Replace_Element;
1235 ----------------------
1236 -- Reserve_Capacity --
1237 ----------------------
1239 procedure Reserve_Capacity
1240 (Container : in out Set;
1241 Capacity : Count_Type)
1244 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1245 end Reserve_Capacity;
1251 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1256 --------------------------
1257 -- Symmetric_Difference --
1258 --------------------------
1260 procedure Symmetric_Difference
1261 (Target : in out Set;
1265 if Target'Address = Source'Address then
1270 if Target.HT.Busy > 0 then
1271 raise Program_Error with
1272 "attempt to tamper with cursors (set is busy)";
1276 N : constant Count_Type := Target.Length + Source.Length;
1278 if N > HT_Ops.Capacity (Target.HT) then
1279 HT_Ops.Reserve_Capacity (Target.HT, N);
1283 if Target.Length = 0 then
1284 Iterate_Source_When_Empty_Target : declare
1285 procedure Process (Src_Node : Node_Access);
1287 procedure Iterate is new HT_Ops.Generic_Iteration (Process);
1293 procedure Process (Src_Node : Node_Access) is
1294 E : Element_Type renames Src_Node.Element.all;
1295 B : Buckets_Type renames Target.HT.Buckets.all;
1296 J : constant Hash_Type := Hash (E) mod B'Length;
1297 N : Count_Type renames Target.HT.Length;
1301 X : Element_Access := new Element_Type'(E);
1303 B (J) := new Node_Type'(X, B (J));
1313 -- Start of processing for Iterate_Source_When_Empty_Target
1316 Iterate (Source.HT);
1317 end Iterate_Source_When_Empty_Target;
1320 Iterate_Source : declare
1321 procedure Process (Src_Node : Node_Access);
1323 procedure Iterate is
1324 new HT_Ops.Generic_Iteration (Process);
1330 procedure Process (Src_Node : Node_Access) is
1331 E : Element_Type renames Src_Node.Element.all;
1332 B : Buckets_Type renames Target.HT.Buckets.all;
1333 J : constant Hash_Type := Hash (E) mod B'Length;
1334 N : Count_Type renames Target.HT.Length;
1337 if B (J) = null then
1339 X : Element_Access := new Element_Type'(E);
1341 B (J) := new Node_Type'(X, null);
1350 elsif Equivalent_Elements (E, B (J).Element.all) then
1352 X : Node_Access := B (J);
1354 B (J) := B (J).Next;
1361 Prev : Node_Access := B (J);
1362 Curr : Node_Access := Prev.Next;
1365 while Curr /= null loop
1366 if Equivalent_Elements (E, Curr.Element.all) then
1367 Prev.Next := Curr.Next;
1378 X : Element_Access := new Element_Type'(E);
1380 B (J) := new Node_Type'(X, B (J));
1392 -- Start of processing for Iterate_Source
1395 Iterate (Source.HT);
1398 end Symmetric_Difference;
1400 function Symmetric_Difference (Left, Right : Set) return Set is
1401 Buckets : HT_Types.Buckets_Access;
1402 Length : Count_Type;
1405 if Left'Address = Right'Address then
1409 if Right.Length = 0 then
1413 if Left.Length = 0 then
1418 Size : constant Hash_Type :=
1419 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1421 Buckets := HT_Ops.New_Buckets (Length => Size);
1426 Iterate_Left : declare
1427 procedure Process (L_Node : Node_Access);
1429 procedure Iterate is
1430 new HT_Ops.Generic_Iteration (Process);
1436 procedure Process (L_Node : Node_Access) is
1438 if not Is_In (Right.HT, L_Node) then
1440 E : Element_Type renames L_Node.Element.all;
1441 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1445 X : Element_Access := new Element_Type'(E);
1447 Buckets (J) := new Node_Type'(X, Buckets (J));
1454 Length := Length + 1;
1459 -- Start of processing for Iterate_Left
1465 HT_Ops.Free_Hash_Table (Buckets);
1469 Iterate_Right : declare
1470 procedure Process (R_Node : Node_Access);
1472 procedure Iterate is
1473 new HT_Ops.Generic_Iteration (Process);
1479 procedure Process (R_Node : Node_Access) is
1481 if not Is_In (Left.HT, R_Node) then
1483 E : Element_Type renames R_Node.Element.all;
1484 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1488 X : Element_Access := new Element_Type'(E);
1490 Buckets (J) := new Node_Type'(X, Buckets (J));
1497 Length := Length + 1;
1502 -- Start of processing for Iterate_Right
1508 HT_Ops.Free_Hash_Table (Buckets);
1512 return (Controlled with HT => (Buckets, Length, 0, 0));
1513 end Symmetric_Difference;
1519 function To_Set (New_Item : Element_Type) return Set is
1520 HT : Hash_Table_Type;
1523 pragma Unreferenced (Node, Inserted);
1525 Insert (HT, New_Item, Node, Inserted);
1526 return Set'(Controlled with HT);
1534 (Target : in out Set;
1537 procedure Process (Src_Node : Node_Access);
1539 procedure Iterate is
1540 new HT_Ops.Generic_Iteration (Process);
1546 procedure Process (Src_Node : Node_Access) is
1547 Src : Element_Type renames Src_Node.Element.all;
1549 function New_Node (Next : Node_Access) return Node_Access;
1550 pragma Inline (New_Node);
1553 new Element_Keys.Generic_Conditional_Insert (New_Node);
1559 function New_Node (Next : Node_Access) return Node_Access is
1560 Tgt : Element_Access := new Element_Type'(Src);
1562 return new Node_Type'(Tgt, Next);
1569 Tgt_Node : Node_Access;
1571 pragma Unreferenced (Tgt_Node, Success);
1573 -- Start of processing for Process
1576 Insert (Target.HT, Src, Tgt_Node, Success);
1579 -- Start of processing for Union
1582 if Target'Address = Source'Address then
1586 if Target.HT.Busy > 0 then
1587 raise Program_Error with
1588 "attempt to tamper with cursors (set is busy)";
1592 N : constant Count_Type := Target.Length + Source.Length;
1594 if N > HT_Ops.Capacity (Target.HT) then
1595 HT_Ops.Reserve_Capacity (Target.HT, N);
1599 Iterate (Source.HT);
1602 function Union (Left, Right : Set) return Set is
1603 Buckets : HT_Types.Buckets_Access;
1604 Length : Count_Type;
1607 if Left'Address = Right'Address then
1611 if Right.Length = 0 then
1615 if Left.Length = 0 then
1620 Size : constant Hash_Type :=
1621 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1623 Buckets := HT_Ops.New_Buckets (Length => Size);
1626 Iterate_Left : declare
1627 procedure Process (L_Node : Node_Access);
1629 procedure Iterate is
1630 new HT_Ops.Generic_Iteration (Process);
1636 procedure Process (L_Node : Node_Access) is
1637 Src : Element_Type renames L_Node.Element.all;
1638 J : constant Hash_Type := Hash (Src) mod Buckets'Length;
1639 Bucket : Node_Access renames Buckets (J);
1640 Tgt : Element_Access := new Element_Type'(Src);
1642 Bucket := new Node_Type'(Tgt, Bucket);
1649 -- Start of processing for Process
1655 HT_Ops.Free_Hash_Table (Buckets);
1659 Length := Left.Length;
1661 Iterate_Right : declare
1662 procedure Process (Src_Node : Node_Access);
1664 procedure Iterate is
1665 new HT_Ops.Generic_Iteration (Process);
1671 procedure Process (Src_Node : Node_Access) is
1672 Src : Element_Type renames Src_Node.Element.all;
1673 Idx : constant Hash_Type := Hash (Src) mod Buckets'Length;
1675 Tgt_Node : Node_Access := Buckets (Idx);
1678 while Tgt_Node /= null loop
1679 if Equivalent_Elements (Src, Tgt_Node.Element.all) then
1682 Tgt_Node := Next (Tgt_Node);
1686 Tgt : Element_Access := new Element_Type'(Src);
1688 Buckets (Idx) := new Node_Type'(Tgt, Buckets (Idx));
1695 Length := Length + 1;
1698 -- Start of processing for Iterate_Right
1704 HT_Ops.Free_Hash_Table (Buckets);
1708 return (Controlled with HT => (Buckets, Length, 0, 0));
1715 function Vet (Position : Cursor) return Boolean is
1717 if Position.Node = null then
1718 return Position.Container = null;
1721 if Position.Container = null then
1725 if Position.Node.Next = Position.Node then
1729 if Position.Node.Element = null then
1734 HT : Hash_Table_Type renames Position.Container.HT;
1738 if HT.Length = 0 then
1742 if HT.Buckets = null
1743 or else HT.Buckets'Length = 0
1748 X := HT.Buckets (Element_Keys.Index (HT, Position.Node.Element.all));
1750 for J in 1 .. HT.Length loop
1751 if X = Position.Node then
1759 if X = X.Next then -- to prevent unnecessary looping
1775 (Stream : not null access Root_Stream_Type'Class;
1779 Write_Nodes (Stream, Container.HT);
1783 (Stream : not null access Root_Stream_Type'Class;
1787 raise Program_Error with "attempt to stream set cursor";
1791 (Stream : not null access Root_Stream_Type'Class;
1792 Item : Constant_Reference_Type)
1795 raise Program_Error with "attempt to stream reference";
1802 procedure Write_Node
1803 (Stream : not null access Root_Stream_Type'Class;
1807 Element_Type'Output (Stream, Node.Element.all);
1810 package body Generic_Keys is
1812 -----------------------
1813 -- Local Subprograms --
1814 -----------------------
1816 function Equivalent_Key_Node
1818 Node : Node_Access) return Boolean;
1819 pragma Inline (Equivalent_Key_Node);
1821 --------------------------
1822 -- Local Instantiations --
1823 --------------------------
1826 new Hash_Tables.Generic_Keys
1827 (HT_Types => HT_Types,
1829 Set_Next => Set_Next,
1830 Key_Type => Key_Type,
1832 Equivalent_Keys => Equivalent_Key_Node);
1840 Key : Key_Type) return Boolean
1843 return Find (Container, Key) /= No_Element;
1851 (Container : in out Set;
1857 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1860 raise Constraint_Error with "key not in map";
1872 Key : Key_Type) return Element_Type
1874 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1878 raise Constraint_Error with "key not in map";
1881 return Node.Element.all;
1884 -------------------------
1885 -- Equivalent_Key_Node --
1886 -------------------------
1888 function Equivalent_Key_Node
1890 Node : Node_Access) return Boolean is
1892 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element.all));
1893 end Equivalent_Key_Node;
1900 (Container : in out Set;
1905 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1915 Key : Key_Type) return Cursor
1917 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1919 return (if Node = null then No_Element
1920 else Cursor'(Container'Unrestricted_Access, Node));
1927 function Key (Position : Cursor) return Key_Type is
1929 if Position.Node = null then
1930 raise Constraint_Error with
1931 "Position cursor equals No_Element";
1934 if Position.Node.Element = null then
1935 raise Program_Error with "Position cursor is bad";
1938 pragma Assert (Vet (Position), "bad cursor in function Key");
1940 return Key (Position.Node.Element.all);
1948 (Container : in out Set;
1950 New_Item : Element_Type)
1952 Node : constant Node_Access :=
1953 Key_Keys.Find (Container.HT, Key);
1957 raise Constraint_Error with
1958 "attempt to replace key not in set";
1961 Replace_Element (Container.HT, Node, New_Item);
1964 procedure Update_Element_Preserving_Key
1965 (Container : in out Set;
1967 Process : not null access
1968 procedure (Element : in out Element_Type))
1970 HT : Hash_Table_Type renames Container.HT;
1974 if Position.Node = null then
1975 raise Constraint_Error with
1976 "Position cursor equals No_Element";
1979 if Position.Node.Element = null
1980 or else Position.Node.Next = Position.Node
1982 raise Program_Error with "Position cursor is bad";
1985 if Position.Container /= Container'Unrestricted_Access then
1986 raise Program_Error with
1987 "Position cursor designates wrong set";
1990 if HT.Buckets = null
1991 or else HT.Buckets'Length = 0
1992 or else HT.Length = 0
1994 raise Program_Error with "Position cursor is bad (set is empty)";
1999 "bad cursor in Update_Element_Preserving_Key");
2001 Indx := HT_Ops.Index (HT, Position.Node);
2004 E : Element_Type renames Position.Node.Element.all;
2005 K : constant Key_Type := Key (E);
2007 B : Natural renames HT.Busy;
2008 L : Natural renames HT.Lock;
2026 if Equivalent_Keys (K, Key (E)) then
2027 pragma Assert (Hash (K) = Hash (E));
2032 if HT.Buckets (Indx) = Position.Node then
2033 HT.Buckets (Indx) := Position.Node.Next;
2037 Prev : Node_Access := HT.Buckets (Indx);
2040 while Prev.Next /= Position.Node loop
2044 raise Program_Error with
2045 "Position cursor is bad (node not found)";
2049 Prev.Next := Position.Node.Next;
2053 HT.Length := HT.Length - 1;
2056 X : Node_Access := Position.Node;
2062 raise Program_Error with "key was modified";
2063 end Update_Element_Preserving_Key;
2065 ------------------------------
2066 -- Reference_Preserving_Key --
2067 ------------------------------
2069 function Reference_Preserving_Key
2070 (Container : aliased in out Set;
2071 Position : Cursor) return Reference_Type
2073 pragma Unreferenced (Container);
2075 return (Element => Position.Node.Element);
2076 end Reference_Preserving_Key;
2078 function Reference_Preserving_Key
2079 (Container : aliased in out Set;
2080 Key : Key_Type) return Reference_Type
2082 Position : constant Cursor := Find (Container, Key);
2084 return (Element => Position.Node.Element);
2085 end Reference_Preserving_Key;
2089 end Ada.Containers.Indefinite_Hashed_Sets;