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 Element : Element_Type);
91 procedure Set_Next (Node : Node_Access; Next : Node_Access);
92 pragma Inline (Set_Next);
95 (Stream : access Root_Stream_Type'Class;
97 pragma Inline (Write_Node);
99 --------------------------
100 -- Local Instantiations --
101 --------------------------
103 procedure Free_Element is
104 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
107 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
116 new Hash_Tables.Generic_Keys
117 (HT_Types => HT_Types,
119 Set_Next => Set_Next,
120 Key_Type => Element_Type,
122 Equivalent_Keys => Equivalent_Keys);
125 new HT_Ops.Generic_Equal (Find_Equal_Key);
127 function Is_Equivalent is
128 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
130 procedure Read_Nodes is
131 new HT_Ops.Generic_Read (Read_Node);
133 procedure Write_Nodes is
134 new HT_Ops.Generic_Write (Write_Node);
140 function "=" (Left, Right : Set) return Boolean is
142 return Is_Equal (Left.HT, Right.HT);
149 procedure Adjust (Container : in out Set) is
151 HT_Ops.Adjust (Container.HT);
158 function Capacity (Container : Set) return Count_Type is
160 return HT_Ops.Capacity (Container.HT);
167 procedure Clear (Container : in out Set) is
169 HT_Ops.Clear (Container.HT);
176 function Contains (Container : Set; Item : Element_Type) return Boolean is
178 return Find (Container, Item) /= No_Element;
185 function Copy_Node (Source : Node_Access) return Node_Access is
186 E : Element_Access := new Element_Type'(Source.Element.all);
188 return new Node_Type'(Element => E, Next => null);
200 (Container : in out Set;
206 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
209 raise Constraint_Error;
216 (Container : in out Set;
217 Position : in out Cursor)
220 if Position.Node = null then
221 raise Constraint_Error;
224 if Position.Container /= Set_Access'(Container'Unchecked_Access) then
228 if Container.HT.Busy > 0 then
232 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
234 Free (Position.Node);
236 Position.Container := null;
244 (Target : in out Set;
247 Tgt_Node : Node_Access;
250 if Target'Address = Source'Address then
255 if Source.Length = 0 then
259 if Target.HT.Busy > 0 then
263 -- TODO: This can be written in terms of a loop instead as
264 -- active-iterator style, sort of like a passive iterator.
266 Tgt_Node := HT_Ops.First (Target.HT);
267 while Tgt_Node /= null loop
268 if Is_In (Source.HT, Tgt_Node) then
270 X : Node_Access := Tgt_Node;
272 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
273 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
278 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
283 function Difference (Left, Right : Set) return Set is
284 Buckets : HT_Types.Buckets_Access;
288 if Left'Address = Right'Address then
292 if Left.Length = 0 then
296 if Right.Length = 0 then
301 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
303 Buckets := new Buckets_Type (0 .. Size - 1);
308 Iterate_Left : declare
309 procedure Process (L_Node : Node_Access);
312 new HT_Ops.Generic_Iteration (Process);
318 procedure Process (L_Node : Node_Access) is
320 if not Is_In (Right.HT, L_Node) then
322 Indx : constant Hash_Type :=
323 Hash (L_Node.Element.all) mod Buckets'Length;
325 Bucket : Node_Access renames Buckets (Indx);
328 Bucket := new Node_Type'(L_Node.Element, Bucket);
331 Length := Length + 1;
335 -- Start of processing for Iterate_Left
341 HT_Ops.Free_Hash_Table (Buckets);
345 return (Controlled with HT => (Buckets, Length, 0, 0));
352 function Element (Position : Cursor) return Element_Type is
354 return Position.Node.Element.all;
357 ---------------------
358 -- Equivalent_Sets --
359 ---------------------
361 function Equivalent_Sets (Left, Right : Set) return Boolean is
363 return Is_Equivalent (Left.HT, Right.HT);
366 -------------------------
367 -- Equivalent_Elements --
368 -------------------------
370 function Equivalent_Elements (Left, Right : Cursor)
373 return Equivalent_Elements
374 (Left.Node.Element.all,
375 Right.Node.Element.all);
376 end Equivalent_Elements;
378 function Equivalent_Elements (Left : Cursor; Right : Element_Type)
381 return Equivalent_Elements (Left.Node.Element.all, Right);
382 end Equivalent_Elements;
384 function Equivalent_Elements (Left : Element_Type; Right : Cursor)
387 return Equivalent_Elements (Left, Right.Node.Element.all);
388 end Equivalent_Elements;
390 ---------------------
391 -- Equivalent_Keys --
392 ---------------------
394 function Equivalent_Keys (Key : Element_Type; Node : Node_Access)
397 return Equivalent_Elements (Key, Node.Element.all);
405 (Container : in out Set;
410 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
418 procedure Finalize (Container : in out Set) is
420 HT_Ops.Finalize (Container.HT);
429 Item : Element_Type) return Cursor
431 Node : constant Node_Access := Element_Keys.Find (Container.HT, Item);
438 return Cursor'(Container'Unrestricted_Access, Node);
445 function Find_Equal_Key
446 (R_HT : Hash_Table_Type;
447 L_Node : Node_Access) return Boolean
449 R_Index : constant Hash_Type :=
450 Element_Keys.Index (R_HT, L_Node.Element.all);
452 R_Node : Node_Access := R_HT.Buckets (R_Index);
456 if R_Node = null then
460 if L_Node.Element.all = R_Node.Element.all then
464 R_Node := Next (R_Node);
468 -------------------------
469 -- Find_Equivalent_Key --
470 -------------------------
472 function Find_Equivalent_Key
473 (R_HT : Hash_Table_Type;
474 L_Node : Node_Access) return Boolean
476 R_Index : constant Hash_Type :=
477 Element_Keys.Index (R_HT, L_Node.Element.all);
479 R_Node : Node_Access := R_HT.Buckets (R_Index);
483 if R_Node = null then
487 if Equivalent_Elements (L_Node.Element.all, R_Node.Element.all) then
491 R_Node := Next (R_Node);
493 end Find_Equivalent_Key;
499 function First (Container : Set) return Cursor is
500 Node : constant Node_Access := HT_Ops.First (Container.HT);
507 return Cursor'(Container'Unrestricted_Access, Node);
514 procedure Free (X : in out Node_Access) is
515 procedure Deallocate is
516 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
524 Free_Element (X.Element);
539 function Has_Element (Position : Cursor) return Boolean is
541 if Position.Node = null then
542 pragma Assert (Position.Container = null);
553 function Hash_Node (Node : Node_Access) return Hash_Type is
555 return Hash (Node.Element.all);
563 (Container : in out Set;
564 New_Item : Element_Type)
572 Insert (Container, New_Item, Position, Inserted);
575 if Container.HT.Lock > 0 then
579 X := Position.Node.Element;
581 Position.Node.Element := new Element_Type'(New_Item);
592 (Container : in out Set;
593 New_Item : Element_Type;
594 Position : out Cursor;
595 Inserted : out Boolean)
597 function New_Node (Next : Node_Access) return Node_Access;
598 pragma Inline (New_Node);
601 new Element_Keys.Generic_Conditional_Insert (New_Node);
607 function New_Node (Next : Node_Access) return Node_Access is
608 Element : Element_Access := new Element_Type'(New_Item);
611 return new Node_Type'(Element, Next);
614 Free_Element (Element);
618 HT : Hash_Table_Type renames Container.HT;
620 -- Start of processing for Insert
623 if HT.Length >= HT_Ops.Capacity (HT) then
624 -- TODO: optimize this (see a-cohase.adb)
625 HT_Ops.Reserve_Capacity (HT, HT.Length + 1);
628 Insert (HT, New_Item, Position.Node, Inserted);
629 Position.Container := Container'Unchecked_Access;
633 (Container : in out Set;
634 New_Item : Element_Type)
640 Insert (Container, New_Item, Position, Inserted);
643 raise Constraint_Error;
651 procedure Intersection
652 (Target : in out Set;
655 Tgt_Node : Node_Access;
658 if Target'Address = Source'Address then
662 if Source.Length = 0 then
667 if Target.HT.Busy > 0 then
671 -- TODO: optimize this to use an explicit
672 -- loop instead of an active iterator
673 -- (similar to how a passive iterator is
676 -- Another possibility is to test which
677 -- set is smaller, and iterate over the
680 Tgt_Node := HT_Ops.First (Target.HT);
681 while Tgt_Node /= null loop
682 if Is_In (Source.HT, Tgt_Node) then
683 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
687 X : Node_Access := Tgt_Node;
689 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
690 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
697 function Intersection (Left, Right : Set) return Set is
698 Buckets : HT_Types.Buckets_Access;
702 if Left'Address = Right'Address then
706 Length := Count_Type'Min (Left.Length, Right.Length);
713 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length);
715 Buckets := new Buckets_Type (0 .. Size - 1);
720 Iterate_Left : declare
721 procedure Process (L_Node : Node_Access);
724 new HT_Ops.Generic_Iteration (Process);
730 procedure Process (L_Node : Node_Access) is
732 if Is_In (Right.HT, L_Node) then
734 Indx : constant Hash_Type :=
735 Hash (L_Node.Element.all) mod Buckets'Length;
737 Bucket : Node_Access renames Buckets (Indx);
740 Bucket := new Node_Type'(L_Node.Element, Bucket);
743 Length := Length + 1;
747 -- Start of processing for Iterate_Left
753 HT_Ops.Free_Hash_Table (Buckets);
757 return (Controlled with HT => (Buckets, Length, 0, 0));
764 function Is_Empty (Container : Set) return Boolean is
766 return Container.Length = 0;
773 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean is
775 return Element_Keys.Find (HT, Key.Element.all) /= null;
784 Of_Set : Set) return Boolean
786 Subset_Node : Node_Access;
789 if Subset'Address = Of_Set'Address then
793 if Subset.Length > Of_Set.Length then
797 -- TODO: rewrite this to loop in the
798 -- style of a passive iterator.
800 Subset_Node := HT_Ops.First (Subset.HT);
801 while Subset_Node /= null loop
802 if not Is_In (Of_Set.HT, Subset_Node) then
806 Subset_Node := HT_Ops.Next (Subset.HT, Subset_Node);
818 Process : not null access procedure (Position : Cursor))
820 procedure Process_Node (Node : Node_Access);
821 pragma Inline (Process_Node);
824 new HT_Ops.Generic_Iteration (Process_Node);
830 procedure Process_Node (Node : Node_Access) is
832 Process (Cursor'(Container'Unrestricted_Access, Node));
835 HT : Hash_Table_Type renames Container'Unrestricted_Access.all.HT;
836 B : Natural renames HT.Busy;
838 -- Start of processing for Iterate
858 function Length (Container : Set) return Count_Type is
860 return Container.HT.Length;
867 procedure Move (Target : in out Set; Source : in out Set) is
869 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
876 function Next (Node : Node_Access) return Node_Access is
881 function Next (Position : Cursor) return Cursor is
883 if Position.Node = null then
884 pragma Assert (Position.Container = null);
889 HT : Hash_Table_Type renames Position.Container.HT;
890 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
897 return Cursor'(Position.Container, Node);
901 procedure Next (Position : in out Cursor) is
903 Position := Next (Position);
910 function Overlap (Left, Right : Set) return Boolean is
911 Left_Node : Node_Access;
914 if Right.Length = 0 then
918 if Left'Address = Right'Address then
922 Left_Node := HT_Ops.First (Left.HT);
923 while Left_Node /= null loop
924 if Is_In (Right.HT, Left_Node) then
928 Left_Node := HT_Ops.Next (Left.HT, Left_Node);
938 procedure Query_Element
940 Process : not null access procedure (Element : Element_Type))
942 E : Element_Type renames Position.Node.Element.all;
944 HT : Hash_Table_Type renames
945 Position.Container'Unrestricted_Access.all.HT;
947 B : Natural renames HT.Busy;
948 L : Natural renames HT.Lock;
972 (Stream : access Root_Stream_Type'Class;
976 Read_Nodes (Stream, Container.HT);
984 (Stream : access Root_Stream_Type'Class) return Node_Access
986 X : Element_Access := new Element_Type'(Element_Type'Input (Stream));
989 return new Node_Type'(X, null);
1001 (Container : in out Set;
1002 New_Item : Element_Type)
1004 Node : constant Node_Access :=
1005 Element_Keys.Find (Container.HT, New_Item);
1011 raise Constraint_Error;
1014 if Container.HT.Lock > 0 then
1015 raise Program_Error;
1020 Node.Element := new Element_Type'(New_Item);
1025 ---------------------
1026 -- Replace_Element --
1027 ---------------------
1029 procedure Replace_Element
1030 (HT : in out Hash_Table_Type;
1032 Element : Element_Type)
1035 if Equivalent_Elements (Node.Element.all, Element) then
1036 pragma Assert (Hash (Node.Element.all) = Hash (Element));
1039 raise Program_Error;
1043 X : Element_Access := Node.Element;
1045 Node.Element := new Element_Type'(Element); -- OK if fails
1053 raise Program_Error;
1056 HT_Ops.Delete_Node_Sans_Free (HT, Node);
1058 Insert_New_Element : declare
1059 function New_Node (Next : Node_Access) return Node_Access;
1060 pragma Inline (New_Node);
1063 new Element_Keys.Generic_Conditional_Insert (New_Node);
1065 ------------------------
1066 -- Insert_New_Element --
1067 ------------------------
1069 function New_Node (Next : Node_Access) return Node_Access is
1071 Node.Element := new Element_Type'(Element); -- OK if fails
1076 Result : Node_Access;
1079 X : Element_Access := Node.Element;
1081 -- Start of processing for Insert_New_Element
1084 Attempt_Insert : begin
1089 Inserted => Inserted);
1092 Inserted := False; -- Assignment failed
1096 pragma Assert (Result = Node);
1097 Free_Element (X); -- Just propagate if fails
1100 end Insert_New_Element;
1102 Reinsert_Old_Element :
1104 function New_Node (Next : Node_Access) return Node_Access;
1105 pragma Inline (New_Node);
1108 new Element_Keys.Generic_Conditional_Insert (New_Node);
1114 function New_Node (Next : Node_Access) return Node_Access is
1120 Result : Node_Access;
1123 -- Start of processing for Reinsert_Old_Element
1128 Key => Node.Element.all,
1130 Inserted => Inserted);
1134 end Reinsert_Old_Element;
1136 raise Program_Error;
1137 end Replace_Element;
1139 procedure Replace_Element
1144 HT : Hash_Table_Type renames Container'Unrestricted_Access.all.HT;
1147 if Position.Node = null then
1148 raise Constraint_Error;
1151 if Position.Container /= Set_Access'(Container'Unrestricted_Access) then
1152 raise Program_Error;
1155 Replace_Element (HT, Position.Node, By);
1156 end Replace_Element;
1158 ----------------------
1159 -- Reserve_Capacity --
1160 ----------------------
1162 procedure Reserve_Capacity
1163 (Container : in out Set;
1164 Capacity : Count_Type)
1167 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1168 end Reserve_Capacity;
1174 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1179 --------------------------
1180 -- Symmetric_Difference --
1181 --------------------------
1183 procedure Symmetric_Difference
1184 (Target : in out Set;
1188 if Target'Address = Source'Address then
1193 if Target.HT.Busy > 0 then
1194 raise Program_Error;
1198 N : constant Count_Type := Target.Length + Source.Length;
1200 if N > HT_Ops.Capacity (Target.HT) then
1201 HT_Ops.Reserve_Capacity (Target.HT, N);
1205 if Target.Length = 0 then
1206 Iterate_Source_When_Empty_Target : declare
1207 procedure Process (Src_Node : Node_Access);
1209 procedure Iterate is
1210 new HT_Ops.Generic_Iteration (Process);
1216 procedure Process (Src_Node : Node_Access) is
1217 E : Element_Type renames Src_Node.Element.all;
1218 B : Buckets_Type renames Target.HT.Buckets.all;
1219 J : constant Hash_Type := Hash (E) mod B'Length;
1220 N : Count_Type renames Target.HT.Length;
1224 X : Element_Access := new Element_Type'(E);
1226 B (J) := new Node_Type'(X, B (J));
1236 -- Start of processing for Iterate_Source_When_Empty_Target
1239 Iterate (Source.HT);
1240 end Iterate_Source_When_Empty_Target;
1243 Iterate_Source : declare
1244 procedure Process (Src_Node : Node_Access);
1246 procedure Iterate is
1247 new HT_Ops.Generic_Iteration (Process);
1253 procedure Process (Src_Node : Node_Access) is
1254 E : Element_Type renames Src_Node.Element.all;
1255 B : Buckets_Type renames Target.HT.Buckets.all;
1256 J : constant Hash_Type := Hash (E) mod B'Length;
1257 N : Count_Type renames Target.HT.Length;
1260 if B (J) = null then
1262 X : Element_Access := new Element_Type'(E);
1264 B (J) := new Node_Type'(X, null);
1273 elsif Equivalent_Elements (E, B (J).Element.all) then
1275 X : Node_Access := B (J);
1277 B (J) := B (J).Next;
1284 Prev : Node_Access := B (J);
1285 Curr : Node_Access := Prev.Next;
1288 while Curr /= null loop
1289 if Equivalent_Elements (E, Curr.Element.all) then
1290 Prev.Next := Curr.Next;
1301 X : Element_Access := new Element_Type'(E);
1303 B (J) := new Node_Type'(X, B (J));
1315 -- Start of processing for Iterate_Source
1318 Iterate (Source.HT);
1321 end Symmetric_Difference;
1323 function Symmetric_Difference (Left, Right : Set) return Set is
1324 Buckets : HT_Types.Buckets_Access;
1325 Length : Count_Type;
1328 if Left'Address = Right'Address then
1332 if Right.Length = 0 then
1336 if Left.Length = 0 then
1341 Size : constant Hash_Type :=
1342 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1344 Buckets := new Buckets_Type (0 .. Size - 1);
1349 Iterate_Left : declare
1350 procedure Process (L_Node : Node_Access);
1352 procedure Iterate is
1353 new HT_Ops.Generic_Iteration (Process);
1359 procedure Process (L_Node : Node_Access) is
1361 if not Is_In (Right.HT, L_Node) then
1363 E : Element_Type renames L_Node.Element.all;
1364 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1368 X : Element_Access := new Element_Type'(E);
1370 Buckets (J) := new Node_Type'(X, Buckets (J));
1377 Length := Length + 1;
1382 -- Start of processing for Iterate_Left
1388 HT_Ops.Free_Hash_Table (Buckets);
1392 Iterate_Right : declare
1393 procedure Process (R_Node : Node_Access);
1395 procedure Iterate is
1396 new HT_Ops.Generic_Iteration (Process);
1402 procedure Process (R_Node : Node_Access) is
1404 if not Is_In (Left.HT, R_Node) then
1406 E : Element_Type renames R_Node.Element.all;
1407 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1411 X : Element_Access := new Element_Type'(E);
1413 Buckets (J) := new Node_Type'(X, Buckets (J));
1420 Length := Length + 1;
1425 -- Start of processing for Iterate_Right
1431 HT_Ops.Free_Hash_Table (Buckets);
1435 return (Controlled with HT => (Buckets, Length, 0, 0));
1436 end Symmetric_Difference;
1443 (Target : in out Set;
1446 procedure Process (Src_Node : Node_Access);
1448 procedure Iterate is
1449 new HT_Ops.Generic_Iteration (Process);
1455 procedure Process (Src_Node : Node_Access) is
1456 Src : Element_Type renames Src_Node.Element.all;
1458 function New_Node (Next : Node_Access) return Node_Access;
1459 pragma Inline (New_Node);
1462 new Element_Keys.Generic_Conditional_Insert (New_Node);
1468 function New_Node (Next : Node_Access) return Node_Access is
1469 Tgt : Element_Access := new Element_Type'(Src);
1472 return new Node_Type'(Tgt, Next);
1479 Tgt_Node : Node_Access;
1482 -- Start of processing for Process
1485 Insert (Target.HT, Src, Tgt_Node, Success);
1488 -- Start of processing for Union
1491 if Target'Address = Source'Address then
1495 if Target.HT.Busy > 0 then
1496 raise Program_Error;
1500 N : constant Count_Type := Target.Length + Source.Length;
1502 if N > HT_Ops.Capacity (Target.HT) then
1503 HT_Ops.Reserve_Capacity (Target.HT, N);
1507 Iterate (Source.HT);
1510 function Union (Left, Right : Set) return Set is
1511 Buckets : HT_Types.Buckets_Access;
1512 Length : Count_Type;
1515 if Left'Address = Right'Address then
1519 if Right.Length = 0 then
1523 if Left.Length = 0 then
1528 Size : constant Hash_Type :=
1529 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1531 Buckets := new Buckets_Type (0 .. Size - 1);
1534 Iterate_Left : declare
1535 procedure Process (L_Node : Node_Access);
1537 procedure Iterate is
1538 new HT_Ops.Generic_Iteration (Process);
1544 procedure Process (L_Node : Node_Access) is
1545 J : constant Hash_Type :=
1546 Hash (L_Node.Element.all) mod Buckets'Length;
1548 Bucket : Node_Access renames Buckets (J);
1551 Bucket := new Node_Type'(L_Node.Element, Bucket);
1554 -- Start of processing for Process
1560 HT_Ops.Free_Hash_Table (Buckets);
1564 Length := Left.Length;
1566 Iterate_Right : declare
1567 procedure Process (Src_Node : Node_Access);
1569 procedure Iterate is
1570 new HT_Ops.Generic_Iteration (Process);
1576 procedure Process (Src_Node : Node_Access) is
1577 Src : Element_Type renames Src_Node.Element.all;
1578 Idx : constant Hash_Type := Hash (Src) mod Buckets'Length;
1580 Tgt_Node : Node_Access := Buckets (Idx);
1583 while Tgt_Node /= null loop
1584 if Equivalent_Elements (Src, Tgt_Node.Element.all) then
1587 Tgt_Node := Next (Tgt_Node);
1591 Tgt : Element_Access := new Element_Type'(Src);
1593 Buckets (Idx) := new Node_Type'(Tgt, Buckets (Idx));
1600 Length := Length + 1;
1603 -- Start of processing for Iterate_Right
1609 HT_Ops.Free_Hash_Table (Buckets);
1613 return (Controlled with HT => (Buckets, Length, 0, 0));
1621 (Stream : access Root_Stream_Type'Class;
1625 Write_Nodes (Stream, Container.HT);
1632 procedure Write_Node
1633 (Stream : access Root_Stream_Type'Class;
1637 Element_Type'Output (Stream, Node.Element.all);
1640 package body Generic_Keys is
1642 -----------------------
1643 -- Local Subprograms --
1644 -----------------------
1646 function Equivalent_Key_Node
1648 Node : Node_Access) return Boolean;
1649 pragma Inline (Equivalent_Key_Node);
1651 --------------------------
1652 -- Local Instantiations --
1653 --------------------------
1656 new Hash_Tables.Generic_Keys
1657 (HT_Types => HT_Types,
1659 Set_Next => Set_Next,
1660 Key_Type => Key_Type,
1662 Equivalent_Keys => Equivalent_Key_Node);
1670 Key : Key_Type) return Boolean
1673 return Find (Container, Key) /= No_Element;
1681 (Container : in out Set;
1687 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1690 raise Constraint_Error;
1702 Key : Key_Type) return Element_Type
1704 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1706 return Node.Element.all;
1709 -------------------------
1710 -- Equivalent_Key_Node --
1711 -------------------------
1713 function Equivalent_Key_Node
1715 Node : Node_Access) return Boolean is
1717 return Equivalent_Keys (Key, Node.Element.all);
1718 end Equivalent_Key_Node;
1720 ---------------------
1721 -- Equivalent_Keys --
1722 ---------------------
1724 function Equivalent_Keys
1726 Right : Key_Type) return Boolean
1729 return Equivalent_Keys (Right, Left.Node.Element.all);
1730 end Equivalent_Keys;
1732 function Equivalent_Keys
1734 Right : Cursor) return Boolean
1737 return Equivalent_Keys (Left, Right.Node.Element.all);
1738 end Equivalent_Keys;
1745 (Container : in out Set;
1750 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1760 Key : Key_Type) return Cursor
1762 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1769 return Cursor'(Container'Unrestricted_Access, Node);
1776 function Key (Position : Cursor) return Key_Type is
1778 return Key (Position.Node.Element.all);
1786 (Container : in out Set;
1788 New_Item : Element_Type)
1790 Node : constant Node_Access :=
1791 Key_Keys.Find (Container.HT, Key);
1795 raise Constraint_Error;
1798 Replace_Element (Container.HT, Node, New_Item);
1801 procedure Update_Element_Preserving_Key
1802 (Container : in out Set;
1803 Position : in Cursor;
1804 Process : not null access
1805 procedure (Element : in out Element_Type))
1807 HT : Hash_Table_Type renames Container.HT;
1810 if Position.Node = null then
1811 raise Constraint_Error;
1814 if Position.Container /= Set_Access'(Container'Unchecked_Access) then
1815 raise Program_Error;
1819 E : Element_Type renames Position.Node.Element.all;
1820 K : Key_Type renames Key (E);
1822 B : Natural renames HT.Busy;
1823 L : Natural renames HT.Lock;
1841 if Equivalent_Keys (K, E) then
1842 pragma Assert (Hash (K) = Hash (E));
1848 X : Node_Access := Position.Node;
1850 HT_Ops.Delete_Node_Sans_Free (HT, X);
1854 raise Program_Error;
1855 end Update_Element_Preserving_Key;
1859 end Ada.Containers.Indefinite_Hashed_Sets;