1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . H A S H E D _ S E T S --
9 -- Copyright (C) 2004-2005 Free Software Foundation, Inc. --
11 -- This specification is derived from the Ada Reference Manual for use with --
12 -- GNAT. The copyright notice above, and the license provisions that follow --
13 -- apply solely to the contents of the part following the private keyword. --
15 -- GNAT is free software; you can redistribute it and/or modify it under --
16 -- terms of the GNU General Public License as published by the Free Soft- --
17 -- ware Foundation; either version 2, or (at your option) any later ver- --
18 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
19 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
20 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
21 -- for more details. You should have received a copy of the GNU General --
22 -- Public License distributed with GNAT; see file COPYING. If not, write --
23 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
24 -- Boston, MA 02110-1301, USA. --
26 -- As a special exception, if other files instantiate generics from this --
27 -- unit, or you link this unit with other files to produce an executable, --
28 -- this unit does not by itself cause the resulting executable to be --
29 -- covered by the GNU General Public License. This exception does not --
30 -- however invalidate any other reasons why the executable file might be --
31 -- covered by the GNU Public License. --
33 -- This unit has originally being developed by Matthew J Heaney. --
34 ------------------------------------------------------------------------------
36 with Ada.Unchecked_Deallocation;
38 with Ada.Containers.Hash_Tables.Generic_Operations;
39 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Operations);
41 with Ada.Containers.Hash_Tables.Generic_Keys;
42 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Keys);
44 with Ada.Containers.Prime_Numbers;
46 with System; use type System.Address;
48 package body Ada.Containers.Hashed_Sets is
50 -----------------------
51 -- Local Subprograms --
52 -----------------------
54 function Copy_Node (Source : Node_Access) return Node_Access;
55 pragma Inline (Copy_Node);
57 function Equivalent_Keys
59 Node : Node_Access) return Boolean;
60 pragma Inline (Equivalent_Keys);
62 function Find_Equal_Key
63 (R_HT : Hash_Table_Type;
64 L_Node : Node_Access) return Boolean;
66 function Find_Equivalent_Key
67 (R_HT : Hash_Table_Type;
68 L_Node : Node_Access) return Boolean;
70 function Hash_Node (Node : Node_Access) return Hash_Type;
71 pragma Inline (Hash_Node);
74 (HT : Hash_Table_Type;
75 Key : Node_Access) return Boolean;
76 pragma Inline (Is_In);
78 function Next (Node : Node_Access) return Node_Access;
81 function Read_Node (Stream : access Root_Stream_Type'Class)
83 pragma Inline (Read_Node);
85 procedure Replace_Element
86 (HT : in out Hash_Table_Type;
88 Element : Element_Type);
90 procedure Set_Next (Node : Node_Access; Next : Node_Access);
91 pragma Inline (Set_Next);
94 (Stream : access Root_Stream_Type'Class;
96 pragma Inline (Write_Node);
98 --------------------------
99 -- Local Instantiations --
100 --------------------------
103 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
106 new Hash_Tables.Generic_Operations
107 (HT_Types => HT_Types,
108 Hash_Node => Hash_Node,
110 Set_Next => Set_Next,
111 Copy_Node => Copy_Node,
114 package Element_Keys is
115 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 Write_Nodes is
133 new HT_Ops.Generic_Write (Write_Node);
139 function "=" (Left, Right : Set) return Boolean is
141 return Is_Equal (Left.HT, Right.HT);
148 procedure Adjust (Container : in out Set) is
150 HT_Ops.Adjust (Container.HT);
157 function Capacity (Container : Set) return Count_Type is
159 return HT_Ops.Capacity (Container.HT);
166 procedure Clear (Container : in out Set) is
168 HT_Ops.Clear (Container.HT);
175 function Contains (Container : Set; Item : Element_Type) return Boolean is
177 return Find (Container, Item) /= No_Element;
184 function Copy_Node (Source : Node_Access) return Node_Access is
186 return new Node_Type'(Element => Source.Element, Next => null);
194 (Container : in out Set;
200 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
203 raise Constraint_Error;
210 (Container : in out Set;
211 Position : in out Cursor)
214 if Position.Node = null then
215 raise Constraint_Error;
218 if Position.Container /= Set_Access'(Container'Unchecked_Access) then
222 if Container.HT.Busy > 0 then
226 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
228 Free (Position.Node);
230 Position.Container := null;
238 (Target : in out Set;
241 Tgt_Node : Node_Access;
244 if Target'Address = Source'Address then
249 if Source.Length = 0 then
253 if Target.HT.Busy > 0 then
257 -- TODO: This can be written in terms of a loop instead as
258 -- active-iterator style, sort of like a passive iterator.
260 Tgt_Node := HT_Ops.First (Target.HT);
261 while Tgt_Node /= null loop
262 if Is_In (Source.HT, Tgt_Node) then
264 X : Node_Access := Tgt_Node;
266 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
267 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
272 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
277 function Difference (Left, Right : Set) return Set is
278 Buckets : HT_Types.Buckets_Access;
282 if Left'Address = Right'Address then
286 if Left.Length = 0 then
290 if Right.Length = 0 then
295 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
297 Buckets := new Buckets_Type (0 .. Size - 1);
302 Iterate_Left : declare
303 procedure Process (L_Node : Node_Access);
306 new HT_Ops.Generic_Iteration (Process);
312 procedure Process (L_Node : Node_Access) is
314 if not Is_In (Right.HT, L_Node) then
316 J : constant Hash_Type :=
317 Hash (L_Node.Element) mod Buckets'Length;
319 Bucket : Node_Access renames Buckets (J);
322 Bucket := new Node_Type'(L_Node.Element, Bucket);
325 Length := Length + 1;
329 -- Start of processing for Iterate_Left
335 HT_Ops.Free_Hash_Table (Buckets);
339 return (Controlled with HT => (Buckets, Length, 0, 0));
346 function Element (Position : Cursor) return Element_Type is
348 return Position.Node.Element;
351 ---------------------
352 -- Equivalent_Sets --
353 ---------------------
355 function Equivalent_Sets (Left, Right : Set) return Boolean is
357 return Is_Equivalent (Left.HT, Right.HT);
360 -------------------------
361 -- Equivalent_Elements --
362 -------------------------
364 function Equivalent_Elements (Left, Right : Cursor)
367 return Equivalent_Elements (Left.Node.Element, Right.Node.Element);
368 end Equivalent_Elements;
370 function Equivalent_Elements (Left : Cursor; Right : Element_Type)
373 return Equivalent_Elements (Left.Node.Element, Right);
374 end Equivalent_Elements;
376 function Equivalent_Elements (Left : Element_Type; Right : Cursor)
379 return Equivalent_Elements (Left, Right.Node.Element);
380 end Equivalent_Elements;
382 ---------------------
383 -- Equivalent_Keys --
384 ---------------------
386 function Equivalent_Keys (Key : Element_Type; Node : Node_Access)
389 return Equivalent_Elements (Key, Node.Element);
397 (Container : in out Set;
402 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
410 procedure Finalize (Container : in out Set) is
412 HT_Ops.Finalize (Container.HT);
421 Item : Element_Type) return Cursor
423 Node : constant Node_Access := Element_Keys.Find (Container.HT, Item);
430 return Cursor'(Container'Unrestricted_Access, Node);
437 function Find_Equal_Key
438 (R_HT : Hash_Table_Type;
439 L_Node : Node_Access) return Boolean
441 R_Index : constant Hash_Type :=
442 Element_Keys.Index (R_HT, L_Node.Element);
444 R_Node : Node_Access := R_HT.Buckets (R_Index);
448 if R_Node = null then
452 if L_Node.Element = R_Node.Element then
456 R_Node := Next (R_Node);
460 -------------------------
461 -- Find_Equivalent_Key --
462 -------------------------
464 function Find_Equivalent_Key
465 (R_HT : Hash_Table_Type;
466 L_Node : Node_Access) return Boolean
468 R_Index : constant Hash_Type :=
469 Element_Keys.Index (R_HT, L_Node.Element);
471 R_Node : Node_Access := R_HT.Buckets (R_Index);
475 if R_Node = null then
479 if Equivalent_Elements (L_Node.Element, R_Node.Element) then
483 R_Node := Next (R_Node);
485 end Find_Equivalent_Key;
491 function First (Container : Set) return Cursor is
492 Node : constant Node_Access := HT_Ops.First (Container.HT);
499 return Cursor'(Container'Unrestricted_Access, Node);
506 function Has_Element (Position : Cursor) return Boolean is
508 if Position.Node = null then
509 pragma Assert (Position.Container = null);
520 function Hash_Node (Node : Node_Access) return Hash_Type is
522 return Hash (Node.Element);
530 (Container : in out Set;
531 New_Item : Element_Type)
537 Insert (Container, New_Item, Position, Inserted);
540 if Container.HT.Lock > 0 then
544 Position.Node.Element := New_Item;
553 (Container : in out Set;
554 New_Item : Element_Type;
555 Position : out Cursor;
556 Inserted : out Boolean)
558 function New_Node (Next : Node_Access) return Node_Access;
559 pragma Inline (New_Node);
561 procedure Local_Insert is
562 new Element_Keys.Generic_Conditional_Insert (New_Node);
568 function New_Node (Next : Node_Access) return Node_Access is
569 Node : constant Node_Access := new Node_Type'(New_Item, Next);
574 HT : Hash_Table_Type renames Container.HT;
576 -- Start of processing for Insert
579 if HT.Length >= HT_Ops.Capacity (HT) then
582 -- Perform the insertion first, and then reserve
583 -- capacity, but only if the insertion succeeds and
584 -- the (new) length is greater then current capacity.
587 HT_Ops.Reserve_Capacity (HT, HT.Length + 1);
590 Local_Insert (HT, New_Item, Position.Node, Inserted);
591 Position.Container := Container'Unchecked_Access;
595 (Container : in out Set;
596 New_Item : Element_Type)
602 Insert (Container, New_Item, Position, Inserted);
605 raise Constraint_Error;
613 procedure Intersection
614 (Target : in out Set;
617 Tgt_Node : Node_Access;
620 if Target'Address = Source'Address then
624 if Source.Length = 0 then
629 if Target.HT.Busy > 0 then
633 -- TODO: optimize this to use an explicit
634 -- loop instead of an active iterator
635 -- (similar to how a passive iterator is
638 -- Another possibility is to test which
639 -- set is smaller, and iterate over the
642 Tgt_Node := HT_Ops.First (Target.HT);
643 while Tgt_Node /= null loop
644 if Is_In (Source.HT, Tgt_Node) then
645 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
649 X : Node_Access := Tgt_Node;
651 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
652 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
659 function Intersection (Left, Right : Set) return Set is
660 Buckets : HT_Types.Buckets_Access;
664 if Left'Address = Right'Address then
668 Length := Count_Type'Min (Left.Length, Right.Length);
675 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length);
677 Buckets := new Buckets_Type (0 .. Size - 1);
682 Iterate_Left : declare
683 procedure Process (L_Node : Node_Access);
686 new HT_Ops.Generic_Iteration (Process);
692 procedure Process (L_Node : Node_Access) is
694 if Is_In (Right.HT, L_Node) then
696 J : constant Hash_Type :=
697 Hash (L_Node.Element) mod Buckets'Length;
699 Bucket : Node_Access renames Buckets (J);
702 Bucket := new Node_Type'(L_Node.Element, Bucket);
705 Length := Length + 1;
709 -- Start of processing for Iterate_Left
715 HT_Ops.Free_Hash_Table (Buckets);
719 return (Controlled with HT => (Buckets, Length, 0, 0));
726 function Is_Empty (Container : Set) return Boolean is
728 return Container.Length = 0;
735 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean is
737 return Element_Keys.Find (HT, Key.Element) /= null;
744 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
745 Subset_Node : Node_Access;
748 if Subset'Address = Of_Set'Address then
752 if Subset.Length > Of_Set.Length then
756 -- TODO: rewrite this to loop in the
757 -- style of a passive iterator.
759 Subset_Node := HT_Ops.First (Subset.HT);
760 while Subset_Node /= null loop
761 if not Is_In (Of_Set.HT, Subset_Node) then
764 Subset_Node := HT_Ops.Next (Subset.HT, Subset_Node);
776 Process : not null access procedure (Position : Cursor))
778 procedure Process_Node (Node : Node_Access);
779 pragma Inline (Process_Node);
782 new HT_Ops.Generic_Iteration (Process_Node);
788 procedure Process_Node (Node : Node_Access) is
790 Process (Cursor'(Container'Unrestricted_Access, Node));
793 HT : Hash_Table_Type renames Container'Unrestricted_Access.all.HT;
794 B : Natural renames HT.Busy;
796 -- Start of processing for Iterate
816 function Length (Container : Set) return Count_Type is
818 return Container.HT.Length;
825 procedure Move (Target : in out Set; Source : in out Set) is
827 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
834 function Next (Node : Node_Access) return Node_Access is
839 function Next (Position : Cursor) return Cursor is
841 if Position.Node = null then
842 pragma Assert (Position.Container = null);
847 HT : Hash_Table_Type renames Position.Container.HT;
848 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
855 return Cursor'(Position.Container, Node);
859 procedure Next (Position : in out Cursor) is
861 Position := Next (Position);
868 function Overlap (Left, Right : Set) return Boolean is
869 Left_Node : Node_Access;
872 if Right.Length = 0 then
876 if Left'Address = Right'Address then
880 Left_Node := HT_Ops.First (Left.HT);
881 while Left_Node /= null loop
882 if Is_In (Right.HT, Left_Node) then
885 Left_Node := HT_Ops.Next (Left.HT, Left_Node);
895 procedure Query_Element
897 Process : not null access procedure (Element : Element_Type))
899 E : Element_Type renames Position.Node.Element;
901 HT : Hash_Table_Type renames Position.Container.HT;
903 B : Natural renames HT.Busy;
904 L : Natural renames HT.Lock;
928 (Stream : access Root_Stream_Type'Class;
932 Read_Nodes (Stream, Container.HT);
939 function Read_Node (Stream : access Root_Stream_Type'Class)
942 Node : Node_Access := new Node_Type;
945 Element_Type'Read (Stream, Node.Element);
958 (Container : in out Set; -- TODO: need ruling from ARG
959 New_Item : Element_Type)
961 Node : constant Node_Access :=
962 Element_Keys.Find (Container.HT, New_Item);
966 raise Constraint_Error;
969 if Container.HT.Lock > 0 then
973 Node.Element := New_Item;
976 ---------------------
977 -- Replace_Element --
978 ---------------------
980 procedure Replace_Element
981 (HT : in out Hash_Table_Type;
983 Element : Element_Type)
986 if Equivalent_Elements (Node.Element, Element) then
987 pragma Assert (Hash (Node.Element) = Hash (Element));
993 Node.Element := Element; -- Note that this assignment can fail
1001 HT_Ops.Delete_Node_Sans_Free (HT, Node);
1003 Insert_New_Element : declare
1004 function New_Node (Next : Node_Access) return Node_Access;
1005 pragma Inline (New_Node);
1007 procedure Local_Insert is
1008 new Element_Keys.Generic_Conditional_Insert (New_Node);
1014 function New_Node (Next : Node_Access) return Node_Access is
1016 Node.Element := Element; -- Note that this assignment can fail
1021 Result : Node_Access;
1024 -- Start of processing for Insert_New_Element
1031 Inserted => Inserted);
1034 pragma Assert (Result = Node);
1039 null; -- Assignment must have failed
1040 end Insert_New_Element;
1042 Reinsert_Old_Element : declare
1043 function New_Node (Next : Node_Access) return Node_Access;
1044 pragma Inline (New_Node);
1046 procedure Local_Insert is
1047 new Element_Keys.Generic_Conditional_Insert (New_Node);
1053 function New_Node (Next : Node_Access) return Node_Access is
1059 Result : Node_Access;
1062 -- Start of processing for Reinsert_Old_Element
1067 Key => Node.Element,
1069 Inserted => Inserted);
1073 end Reinsert_Old_Element;
1075 raise Program_Error;
1076 end Replace_Element;
1078 procedure Replace_Element
1083 HT : Hash_Table_Type renames Container'Unrestricted_Access.all.HT;
1086 if Position.Node = null then
1087 raise Constraint_Error;
1090 if Position.Container /= Set_Access'(Container'Unrestricted_Access) then
1091 raise Program_Error;
1094 Replace_Element (HT, Position.Node, By);
1095 end Replace_Element;
1097 ----------------------
1098 -- Reserve_Capacity --
1099 ----------------------
1101 procedure Reserve_Capacity
1102 (Container : in out Set;
1103 Capacity : Count_Type)
1106 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1107 end Reserve_Capacity;
1113 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1118 --------------------------
1119 -- Symmetric_Difference --
1120 --------------------------
1122 procedure Symmetric_Difference
1123 (Target : in out Set;
1127 if Target'Address = Source'Address then
1132 if Target.HT.Busy > 0 then
1133 raise Program_Error;
1137 N : constant Count_Type := Target.Length + Source.Length;
1139 if N > HT_Ops.Capacity (Target.HT) then
1140 HT_Ops.Reserve_Capacity (Target.HT, N);
1144 if Target.Length = 0 then
1145 Iterate_Source_When_Empty_Target : declare
1146 procedure Process (Src_Node : Node_Access);
1148 procedure Iterate is
1149 new HT_Ops.Generic_Iteration (Process);
1155 procedure Process (Src_Node : Node_Access) is
1156 E : Element_Type renames Src_Node.Element;
1157 B : Buckets_Type renames Target.HT.Buckets.all;
1158 J : constant Hash_Type := Hash (E) mod B'Length;
1159 N : Count_Type renames Target.HT.Length;
1162 B (J) := new Node_Type'(E, B (J));
1166 -- Start of processing for Iterate_Source_When_Empty_Target
1169 Iterate (Source.HT);
1170 end Iterate_Source_When_Empty_Target;
1173 Iterate_Source : declare
1174 procedure Process (Src_Node : Node_Access);
1176 procedure Iterate is
1177 new HT_Ops.Generic_Iteration (Process);
1183 procedure Process (Src_Node : Node_Access) is
1184 E : Element_Type renames Src_Node.Element;
1185 B : Buckets_Type renames Target.HT.Buckets.all;
1186 J : constant Hash_Type := Hash (E) mod B'Length;
1187 N : Count_Type renames Target.HT.Length;
1190 if B (J) = null then
1191 B (J) := new Node_Type'(E, null);
1194 elsif Equivalent_Elements (E, B (J).Element) then
1196 X : Node_Access := B (J);
1198 B (J) := B (J).Next;
1205 Prev : Node_Access := B (J);
1206 Curr : Node_Access := Prev.Next;
1209 while Curr /= null loop
1210 if Equivalent_Elements (E, Curr.Element) then
1211 Prev.Next := Curr.Next;
1221 B (J) := new Node_Type'(E, B (J));
1227 -- Start of processing for Iterate_Source
1230 Iterate (Source.HT);
1233 end Symmetric_Difference;
1235 function Symmetric_Difference (Left, Right : Set) return Set is
1236 Buckets : HT_Types.Buckets_Access;
1237 Length : Count_Type;
1240 if Left'Address = Right'Address then
1244 if Right.Length = 0 then
1248 if Left.Length = 0 then
1253 Size : constant Hash_Type :=
1254 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1256 Buckets := new Buckets_Type (0 .. Size - 1);
1261 Iterate_Left : declare
1262 procedure Process (L_Node : Node_Access);
1264 procedure Iterate is
1265 new HT_Ops.Generic_Iteration (Process);
1271 procedure Process (L_Node : Node_Access) is
1273 if not Is_In (Right.HT, L_Node) then
1275 E : Element_Type renames L_Node.Element;
1276 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1279 Buckets (J) := new Node_Type'(E, Buckets (J));
1280 Length := Length + 1;
1285 -- Start of processing for Iterate_Left
1291 HT_Ops.Free_Hash_Table (Buckets);
1295 Iterate_Right : declare
1296 procedure Process (R_Node : Node_Access);
1298 procedure Iterate is
1299 new HT_Ops.Generic_Iteration (Process);
1305 procedure Process (R_Node : Node_Access) is
1307 if not Is_In (Left.HT, R_Node) then
1309 E : Element_Type renames R_Node.Element;
1310 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1313 Buckets (J) := new Node_Type'(E, Buckets (J));
1314 Length := Length + 1;
1319 -- Start of processing for Iterate_Right
1325 HT_Ops.Free_Hash_Table (Buckets);
1329 return (Controlled with HT => (Buckets, Length, 0, 0));
1330 end Symmetric_Difference;
1337 (Target : in out Set;
1340 procedure Process (Src_Node : Node_Access);
1342 procedure Iterate is
1343 new HT_Ops.Generic_Iteration (Process);
1349 procedure Process (Src_Node : Node_Access) is
1350 function New_Node (Next : Node_Access) return Node_Access;
1351 pragma Inline (New_Node);
1354 new Element_Keys.Generic_Conditional_Insert (New_Node);
1360 function New_Node (Next : Node_Access) return Node_Access is
1361 Node : constant Node_Access :=
1362 new Node_Type'(Src_Node.Element, Next);
1367 Tgt_Node : Node_Access;
1370 -- Start of processing for Process
1373 Insert (Target.HT, Src_Node.Element, Tgt_Node, Success);
1376 -- Start of processing for Union
1379 if Target'Address = Source'Address then
1383 if Target.HT.Busy > 0 then
1384 raise Program_Error;
1388 N : constant Count_Type := Target.Length + Source.Length;
1390 if N > HT_Ops.Capacity (Target.HT) then
1391 HT_Ops.Reserve_Capacity (Target.HT, N);
1395 Iterate (Source.HT);
1398 function Union (Left, Right : Set) return Set is
1399 Buckets : HT_Types.Buckets_Access;
1400 Length : Count_Type;
1403 if Left'Address = Right'Address then
1407 if Right.Length = 0 then
1411 if Left.Length = 0 then
1416 Size : constant Hash_Type :=
1417 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1419 Buckets := new Buckets_Type (0 .. Size - 1);
1422 Iterate_Left : declare
1423 procedure Process (L_Node : Node_Access);
1425 procedure Iterate is
1426 new HT_Ops.Generic_Iteration (Process);
1432 procedure Process (L_Node : Node_Access) is
1433 J : constant Hash_Type :=
1434 Hash (L_Node.Element) mod Buckets'Length;
1437 Buckets (J) := new Node_Type'(L_Node.Element, Buckets (J));
1440 -- Start of processing for Iterate_Left
1446 HT_Ops.Free_Hash_Table (Buckets);
1450 Length := Left.Length;
1452 Iterate_Right : declare
1453 procedure Process (Src_Node : Node_Access);
1455 procedure Iterate is
1456 new HT_Ops.Generic_Iteration (Process);
1462 procedure Process (Src_Node : Node_Access) is
1463 J : constant Hash_Type :=
1464 Hash (Src_Node.Element) mod Buckets'Length;
1466 Tgt_Node : Node_Access := Buckets (J);
1469 while Tgt_Node /= null loop
1470 if Equivalent_Elements (Src_Node.Element, Tgt_Node.Element) then
1474 Tgt_Node := Next (Tgt_Node);
1477 Buckets (J) := new Node_Type'(Src_Node.Element, Buckets (J));
1478 Length := Length + 1;
1481 -- Start of processing for Iterate_Right
1487 HT_Ops.Free_Hash_Table (Buckets);
1491 return (Controlled with HT => (Buckets, Length, 0, 0));
1499 (Stream : access Root_Stream_Type'Class;
1503 Write_Nodes (Stream, Container.HT);
1510 procedure Write_Node
1511 (Stream : access Root_Stream_Type'Class;
1515 Element_Type'Write (Stream, Node.Element);
1518 package body Generic_Keys is
1520 -----------------------
1521 -- Local Subprograms --
1522 -----------------------
1524 function Equivalent_Key_Node
1526 Node : Node_Access) return Boolean;
1527 pragma Inline (Equivalent_Key_Node);
1529 --------------------------
1530 -- Local Instantiations --
1531 --------------------------
1534 new Hash_Tables.Generic_Keys
1535 (HT_Types => HT_Types,
1537 Set_Next => Set_Next,
1538 Key_Type => Key_Type,
1540 Equivalent_Keys => Equivalent_Key_Node);
1548 Key : Key_Type) return Boolean
1551 return Find (Container, Key) /= No_Element;
1559 (Container : in out Set;
1565 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1568 raise Constraint_Error;
1580 Key : Key_Type) return Element_Type
1582 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1585 return Node.Element;
1588 -------------------------
1589 -- Equivalent_Key_Node --
1590 -------------------------
1592 function Equivalent_Key_Node
1594 Node : Node_Access) return Boolean
1597 return Equivalent_Keys (Key, Node.Element);
1598 end Equivalent_Key_Node;
1600 ---------------------
1601 -- Equivalent_Keys --
1602 ---------------------
1604 function Equivalent_Keys
1606 Right : Key_Type) return Boolean is
1608 return Equivalent_Keys (Right, Left.Node.Element);
1609 end Equivalent_Keys;
1611 function Equivalent_Keys
1613 Right : Cursor) return Boolean is
1615 return Equivalent_Keys (Left, Right.Node.Element);
1616 end Equivalent_Keys;
1623 (Container : in out Set;
1628 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1638 Key : Key_Type) return Cursor
1640 Node : constant Node_Access :=
1641 Key_Keys.Find (Container.HT, Key);
1648 return Cursor'(Container'Unrestricted_Access, Node);
1655 function Key (Position : Cursor) return Key_Type is
1657 return Key (Position.Node.Element);
1665 (Container : in out Set;
1667 New_Item : Element_Type)
1669 Node : constant Node_Access :=
1670 Key_Keys.Find (Container.HT, Key);
1674 raise Constraint_Error;
1677 Replace_Element (Container.HT, Node, New_Item);
1680 -----------------------------------
1681 -- Update_Element_Preserving_Key --
1682 -----------------------------------
1684 procedure Update_Element_Preserving_Key
1685 (Container : in out Set;
1687 Process : not null access
1688 procedure (Element : in out Element_Type))
1690 HT : Hash_Table_Type renames Container.HT;
1693 if Position.Node = null then
1694 raise Constraint_Error;
1697 if Position.Container /= Set_Access'(Container'Unchecked_Access) then
1698 raise Program_Error;
1702 E : Element_Type renames Position.Node.Element;
1703 K : Key_Type renames Key (E);
1705 B : Natural renames HT.Busy;
1706 L : Natural renames HT.Lock;
1724 if Equivalent_Keys (K, E) then
1725 pragma Assert (Hash (K) = Hash (E));
1731 X : Node_Access := Position.Node;
1733 HT_Ops.Delete_Node_Sans_Free (HT, X);
1737 raise Program_Error;
1738 end Update_Element_Preserving_Key;
1742 end Ada.Containers.Hashed_Sets;