1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . B O U N D E D _ H A S H E D _ S E T S --
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.Containers.Hash_Tables.Generic_Bounded_Operations;
31 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Operations);
33 with Ada.Containers.Hash_Tables.Generic_Bounded_Keys;
34 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Keys);
36 with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
37 with Ada.Finalization; use Ada.Finalization;
39 with System; use type System.Address;
41 package body Ada.Containers.Bounded_Hashed_Sets is
43 type Iterator is new Limited_Controlled and
44 Set_Iterator_Interfaces.Forward_Iterator with
46 Container : Set_Access;
49 overriding procedure Finalize (Object : in out Iterator);
51 overriding function First (Object : Iterator) return Cursor;
53 overriding function Next
55 Position : Cursor) return Cursor;
57 -----------------------
58 -- Local Subprograms --
59 -----------------------
61 function Equivalent_Keys
63 Node : Node_Type) return Boolean;
64 pragma Inline (Equivalent_Keys);
66 function Hash_Node (Node : Node_Type) return Hash_Type;
67 pragma Inline (Hash_Node);
70 (Container : in out Set;
71 New_Item : Element_Type;
72 Node : out Count_Type;
73 Inserted : out Boolean);
75 function Is_In (HT : Set; Key : Node_Type) return Boolean;
76 pragma Inline (Is_In);
78 procedure Set_Element (Node : in out Node_Type; Item : Element_Type);
79 pragma Inline (Set_Element);
81 function Next (Node : Node_Type) return Count_Type;
84 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
85 pragma Inline (Set_Next);
87 function Vet (Position : Cursor) return Boolean;
89 --------------------------
90 -- Local Instantiations --
91 --------------------------
93 package HT_Ops is new Hash_Tables.Generic_Bounded_Operations
94 (HT_Types => HT_Types,
95 Hash_Node => Hash_Node,
97 Set_Next => Set_Next);
99 package Element_Keys is new Hash_Tables.Generic_Bounded_Keys
100 (HT_Types => HT_Types,
102 Set_Next => Set_Next,
103 Key_Type => Element_Type,
105 Equivalent_Keys => Equivalent_Keys);
107 procedure Replace_Element is
108 new Element_Keys.Generic_Replace_Element (Hash_Node, Set_Element);
114 function "=" (Left, Right : Set) return Boolean is
115 function Find_Equal_Key
116 (R_HT : Hash_Table_Type'Class;
117 L_Node : Node_Type) return Boolean;
118 pragma Inline (Find_Equal_Key);
121 new HT_Ops.Generic_Equal (Find_Equal_Key);
127 function Find_Equal_Key
128 (R_HT : Hash_Table_Type'Class;
129 L_Node : Node_Type) return Boolean
131 R_Index : constant Hash_Type :=
132 Element_Keys.Index (R_HT, L_Node.Element);
134 R_Node : Count_Type := R_HT.Buckets (R_Index);
142 if L_Node.Element = R_HT.Nodes (R_Node).Element then
146 R_Node := Next (R_HT.Nodes (R_Node));
150 -- Start of processing for "="
153 return Is_Equal (Left, Right);
160 procedure Assign (Target : in out Set; Source : Set) is
161 procedure Insert_Element (Source_Node : Count_Type);
163 procedure Insert_Elements is
164 new HT_Ops.Generic_Iteration (Insert_Element);
170 procedure Insert_Element (Source_Node : Count_Type) is
171 N : Node_Type renames Source.Nodes (Source_Node);
175 Insert (Target, N.Element, X, B);
179 -- Start of processing for Assign
182 if Target'Address = Source'Address then
186 if Target.Capacity < Source.Length then
188 with "Target capacity is less than Source length";
191 HT_Ops.Clear (Target);
192 Insert_Elements (Source);
199 function Capacity (Container : Set) return Count_Type is
201 return Container.Capacity;
208 procedure Clear (Container : in out Set) is
210 HT_Ops.Clear (Container);
213 ------------------------
214 -- Constant_Reference --
215 ------------------------
217 function Constant_Reference
218 (Container : aliased Set;
219 Position : Cursor) return Constant_Reference_Type
222 if Position.Container = null then
223 raise Constraint_Error with "Position cursor has no element";
226 if Position.Container /= Container'Unrestricted_Access then
227 raise Program_Error with
228 "Position cursor designates wrong container";
231 pragma Assert (Vet (Position), "bad cursor in Constant_Reference");
234 N : Node_Type renames Container.Nodes (Position.Node);
236 return (Element => N.Element'Access);
238 end Constant_Reference;
244 function Contains (Container : Set; Item : Element_Type) return Boolean is
246 return Find (Container, Item) /= No_Element;
255 Capacity : Count_Type := 0;
256 Modulus : Hash_Type := 0) return Set
264 elsif Capacity >= Source.Length then
267 raise Capacity_Error with "Capacity value too small";
271 M := Default_Modulus (C);
276 return Target : Set (Capacity => C, Modulus => M) do
277 Assign (Target => Target, Source => Source);
281 ---------------------
282 -- Default_Modulus --
283 ---------------------
285 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
287 return To_Prime (Capacity);
295 (Container : in out Set;
301 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
304 raise Constraint_Error with "attempt to delete element not in set";
307 HT_Ops.Free (Container, X);
311 (Container : in out Set;
312 Position : in out Cursor)
315 if Position.Node = 0 then
316 raise Constraint_Error with "Position cursor equals No_Element";
319 if Position.Container /= Container'Unrestricted_Access then
320 raise Program_Error with "Position cursor designates wrong set";
323 if Container.Busy > 0 then
324 raise Program_Error with
325 "attempt to tamper with cursors (set is busy)";
328 pragma Assert (Vet (Position), "bad cursor in Delete");
330 HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
331 HT_Ops.Free (Container, Position.Node);
333 Position := No_Element;
341 (Target : in out Set;
344 Tgt_Node, Src_Node : Count_Type;
346 TN : Nodes_Type renames Target.Nodes;
347 SN : Nodes_Type renames Source.Nodes;
350 if Target'Address = Source'Address then
351 HT_Ops.Clear (Target);
355 if Source.Length = 0 then
359 if Target.Busy > 0 then
360 raise Program_Error with
361 "attempt to tamper with cursors (set is busy)";
364 if Source.Length < Target.Length then
365 Src_Node := HT_Ops.First (Source);
366 while Src_Node /= 0 loop
367 Tgt_Node := Element_Keys.Find (Target, SN (Src_Node).Element);
369 if Tgt_Node /= 0 then
370 HT_Ops.Delete_Node_Sans_Free (Target, Tgt_Node);
371 HT_Ops.Free (Target, Tgt_Node);
374 Src_Node := HT_Ops.Next (Source, Src_Node);
378 Tgt_Node := HT_Ops.First (Target);
379 while Tgt_Node /= 0 loop
380 if Is_In (Source, TN (Tgt_Node)) then
382 X : constant Count_Type := Tgt_Node;
384 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
385 HT_Ops.Delete_Node_Sans_Free (Target, X);
386 HT_Ops.Free (Target, X);
390 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
396 function Difference (Left, Right : Set) return Set is
398 if Left'Address = Right'Address then
402 if Left.Length = 0 then
406 if Right.Length = 0 then
410 return Result : Set (Left.Length, To_Prime (Left.Length)) do
411 Iterate_Left : declare
412 procedure Process (L_Node : Count_Type);
415 new HT_Ops.Generic_Iteration (Process);
421 procedure Process (L_Node : Count_Type) is
422 N : Node_Type renames Left.Nodes (L_Node);
426 if not Is_In (Right, N) then
427 Insert (Result, N.Element, X, B); -- optimize this ???
429 pragma Assert (X > 0);
433 -- Start of processing for Iterate_Left
445 function Element (Position : Cursor) return Element_Type is
447 if Position.Node = 0 then
448 raise Constraint_Error with "Position cursor equals No_Element";
451 pragma Assert (Vet (Position), "bad cursor in function Element");
454 S : Set renames Position.Container.all;
455 N : Node_Type renames S.Nodes (Position.Node);
461 ---------------------
462 -- Equivalent_Sets --
463 ---------------------
465 function Equivalent_Sets (Left, Right : Set) return Boolean is
466 function Find_Equivalent_Key
467 (R_HT : Hash_Table_Type'Class;
468 L_Node : Node_Type) return Boolean;
469 pragma Inline (Find_Equivalent_Key);
471 function Is_Equivalent is
472 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
474 -------------------------
475 -- Find_Equivalent_Key --
476 -------------------------
478 function Find_Equivalent_Key
479 (R_HT : Hash_Table_Type'Class;
480 L_Node : Node_Type) return Boolean
482 R_Index : constant Hash_Type :=
483 Element_Keys.Index (R_HT, L_Node.Element);
485 R_Node : Count_Type := R_HT.Buckets (R_Index);
487 RN : Nodes_Type renames R_HT.Nodes;
495 if Equivalent_Elements (L_Node.Element, RN (R_Node).Element) then
499 R_Node := HT_Ops.Next (R_HT, R_Node);
501 end Find_Equivalent_Key;
503 -- Start of processing for Equivalent_Sets
506 return Is_Equivalent (Left, Right);
509 -------------------------
510 -- Equivalent_Elements --
511 -------------------------
513 function Equivalent_Elements (Left, Right : Cursor)
517 if Left.Node = 0 then
518 raise Constraint_Error with
519 "Left cursor of Equivalent_Elements equals No_Element";
522 if Right.Node = 0 then
523 raise Constraint_Error with
524 "Right cursor of Equivalent_Elements equals No_Element";
527 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
528 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
531 LN : Node_Type renames Left.Container.Nodes (Left.Node);
532 RN : Node_Type renames Right.Container.Nodes (Right.Node);
534 return Equivalent_Elements (LN.Element, RN.Element);
536 end Equivalent_Elements;
538 function Equivalent_Elements
540 Right : Element_Type) return Boolean
543 if Left.Node = 0 then
544 raise Constraint_Error with
545 "Left cursor of Equivalent_Elements equals No_Element";
548 pragma Assert (Vet (Left), "Left cursor in Equivalent_Elements is bad");
551 LN : Node_Type renames Left.Container.Nodes (Left.Node);
553 return Equivalent_Elements (LN.Element, Right);
555 end Equivalent_Elements;
557 function Equivalent_Elements
558 (Left : Element_Type;
559 Right : Cursor) return Boolean
562 if Right.Node = 0 then
563 raise Constraint_Error with
564 "Right cursor of Equivalent_Elements equals No_Element";
569 "Right cursor of Equivalent_Elements is bad");
572 RN : Node_Type renames Right.Container.Nodes (Right.Node);
574 return Equivalent_Elements (Left, RN.Element);
576 end Equivalent_Elements;
578 ---------------------
579 -- Equivalent_Keys --
580 ---------------------
582 function Equivalent_Keys
584 Node : Node_Type) return Boolean
587 return Equivalent_Elements (Key, Node.Element);
595 (Container : in out Set;
600 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
601 HT_Ops.Free (Container, X);
608 procedure Finalize (Object : in out Iterator) is
610 if Object.Container /= null then
612 B : Natural renames Object.Container.all.Busy;
625 Item : Element_Type) return Cursor
627 Node : constant Count_Type := Element_Keys.Find (Container, Item);
629 return (if Node = 0 then No_Element
630 else Cursor'(Container'Unrestricted_Access, Node));
637 function First (Container : Set) return Cursor is
638 Node : constant Count_Type := HT_Ops.First (Container);
640 return (if Node = 0 then No_Element
641 else Cursor'(Container'Unrestricted_Access, Node));
644 overriding function First (Object : Iterator) return Cursor is
646 return Object.Container.First;
653 function Has_Element (Position : Cursor) return Boolean is
655 pragma Assert (Vet (Position), "bad cursor in Has_Element");
656 return Position.Node /= 0;
663 function Hash_Node (Node : Node_Type) return Hash_Type is
665 return Hash (Node.Element);
673 (Container : in out Set;
674 New_Item : Element_Type)
680 Insert (Container, New_Item, Position, Inserted);
683 if Container.Lock > 0 then
684 raise Program_Error with
685 "attempt to tamper with elements (set is locked)";
688 Container.Nodes (Position.Node).Element := New_Item;
697 (Container : in out Set;
698 New_Item : Element_Type;
699 Position : out Cursor;
700 Inserted : out Boolean)
703 Insert (Container, New_Item, Position.Node, Inserted);
704 Position.Container := Container'Unchecked_Access;
708 (Container : in out Set;
709 New_Item : Element_Type)
712 pragma Unreferenced (Position);
717 Insert (Container, New_Item, Position, Inserted);
720 raise Constraint_Error with
721 "attempt to insert element already in set";
726 (Container : in out Set;
727 New_Item : Element_Type;
728 Node : out Count_Type;
729 Inserted : out Boolean)
731 procedure Allocate_Set_Element (Node : in out Node_Type);
732 pragma Inline (Allocate_Set_Element);
734 function New_Node return Count_Type;
735 pragma Inline (New_Node);
737 procedure Local_Insert is
738 new Element_Keys.Generic_Conditional_Insert (New_Node);
740 procedure Allocate is
741 new HT_Ops.Generic_Allocate (Allocate_Set_Element);
743 ---------------------------
744 -- Allocate_Set_Element --
745 ---------------------------
747 procedure Allocate_Set_Element (Node : in out Node_Type) is
749 Node.Element := New_Item;
750 end Allocate_Set_Element;
756 function New_Node return Count_Type is
759 Allocate (Container, Result);
763 -- Start of processing for Insert
766 -- The buckets array length is specified by the user as a discriminant
767 -- of the container type, so it is possible for the buckets array to
768 -- have a length of zero. We must check for this case specifically, in
769 -- order to prevent divide-by-zero errors later, when we compute the
770 -- buckets array index value for an element, given its hash value.
772 if Container.Buckets'Length = 0 then
773 raise Capacity_Error with "No capacity for insertion";
776 Local_Insert (Container, New_Item, Node, Inserted);
783 procedure Intersection
784 (Target : in out Set;
787 Tgt_Node : Count_Type;
788 TN : Nodes_Type renames Target.Nodes;
791 if Target'Address = Source'Address then
795 if Source.Length = 0 then
796 HT_Ops.Clear (Target);
800 if Target.Busy > 0 then
801 raise Program_Error with
802 "attempt to tamper with cursors (set is busy)";
805 Tgt_Node := HT_Ops.First (Target);
806 while Tgt_Node /= 0 loop
807 if Is_In (Source, TN (Tgt_Node)) then
808 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
812 X : constant Count_Type := Tgt_Node;
814 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
815 HT_Ops.Delete_Node_Sans_Free (Target, X);
816 HT_Ops.Free (Target, X);
822 function Intersection (Left, Right : Set) return Set is
826 if Left'Address = Right'Address then
830 C := Count_Type'Min (Left.Length, Right.Length);
836 return Result : Set (C, To_Prime (C)) do
837 Iterate_Left : declare
838 procedure Process (L_Node : Count_Type);
841 new HT_Ops.Generic_Iteration (Process);
847 procedure Process (L_Node : Count_Type) is
848 N : Node_Type renames Left.Nodes (L_Node);
853 if Is_In (Right, N) then
854 Insert (Result, N.Element, X, B); -- optimize ???
856 pragma Assert (X > 0);
860 -- Start of processing for Iterate_Left
872 function Is_Empty (Container : Set) return Boolean is
874 return Container.Length = 0;
881 function Is_In (HT : Set; Key : Node_Type) return Boolean is
883 return Element_Keys.Find (HT, Key.Element) /= 0;
890 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
891 Subset_Node : Count_Type;
892 SN : Nodes_Type renames Subset.Nodes;
895 if Subset'Address = Of_Set'Address then
899 if Subset.Length > Of_Set.Length then
903 Subset_Node := HT_Ops.First (Subset);
904 while Subset_Node /= 0 loop
905 if not Is_In (Of_Set, SN (Subset_Node)) then
908 Subset_Node := HT_Ops.Next (Subset, Subset_Node);
920 Process : not null access procedure (Position : Cursor))
922 procedure Process_Node (Node : Count_Type);
923 pragma Inline (Process_Node);
926 new HT_Ops.Generic_Iteration (Process_Node);
932 procedure Process_Node (Node : Count_Type) is
934 Process (Cursor'(Container'Unrestricted_Access, Node));
937 B : Natural renames Container'Unrestricted_Access.all.Busy;
939 -- Start of processing for Iterate
955 function Iterate (Container : Set)
956 return Set_Iterator_Interfaces.Forward_Iterator'Class
958 B : Natural renames Container'Unrestricted_Access.all.Busy;
961 return It : constant Iterator :=
962 Iterator'(Limited_Controlled with
963 Container => Container'Unrestricted_Access);
970 function Length (Container : Set) return Count_Type is
972 return Container.Length;
979 procedure Move (Target : in out Set; Source : in out Set) is
981 if Target'Address = Source'Address then
985 if Source.Busy > 0 then
986 raise Program_Error with
987 "attempt to tamper with cursors (container is busy)";
990 Target.Assign (Source);
998 function Next (Node : Node_Type) return Count_Type is
1003 function Next (Position : Cursor) return Cursor is
1005 if Position.Node = 0 then
1009 pragma Assert (Vet (Position), "bad cursor in Next");
1012 HT : Set renames Position.Container.all;
1013 Node : constant Count_Type := HT_Ops.Next (HT, Position.Node);
1020 return Cursor'(Position.Container, Node);
1024 procedure Next (Position : in out Cursor) is
1026 Position := Next (Position);
1031 Position : Cursor) return Cursor
1034 if Position.Container = null then
1038 if Position.Container /= Object.Container then
1039 raise Program_Error with
1040 "Position cursor of Next designates wrong set";
1043 return Next (Position);
1050 function Overlap (Left, Right : Set) return Boolean is
1051 Left_Node : Count_Type;
1054 if Right.Length = 0 then
1058 if Left'Address = Right'Address then
1062 Left_Node := HT_Ops.First (Left);
1063 while Left_Node /= 0 loop
1064 if Is_In (Right, Left.Nodes (Left_Node)) then
1067 Left_Node := HT_Ops.Next (Left, Left_Node);
1077 procedure Query_Element
1079 Process : not null access procedure (Element : Element_Type))
1082 if Position.Node = 0 then
1083 raise Constraint_Error with
1084 "Position cursor of Query_Element equals No_Element";
1087 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1090 S : Set renames Position.Container.all;
1091 B : Natural renames S.Busy;
1092 L : Natural renames S.Lock;
1099 Process (S.Nodes (Position.Node).Element);
1117 (Stream : not null access Root_Stream_Type'Class;
1118 Container : out Set)
1120 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1123 procedure Read_Nodes is
1124 new HT_Ops.Generic_Read (Read_Node);
1130 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1133 procedure Read_Element (Node : in out Node_Type);
1134 pragma Inline (Read_Element);
1136 procedure Allocate is
1137 new HT_Ops.Generic_Allocate (Read_Element);
1139 procedure Read_Element (Node : in out Node_Type) is
1141 Element_Type'Read (Stream, Node.Element);
1146 -- Start of processing for Read_Node
1149 Allocate (Container, Node);
1153 -- Start of processing for Read
1156 Read_Nodes (Stream, Container);
1160 (Stream : not null access Root_Stream_Type'Class;
1164 raise Program_Error with "attempt to stream set cursor";
1168 (Stream : not null access Root_Stream_Type'Class;
1169 Item : out Constant_Reference_Type)
1172 raise Program_Error with "attempt to stream reference";
1180 (Container : in out Set;
1181 New_Item : Element_Type)
1183 Node : constant Count_Type :=
1184 Element_Keys.Find (Container, New_Item);
1188 raise Constraint_Error with
1189 "attempt to replace element not in set";
1192 if Container.Lock > 0 then
1193 raise Program_Error with
1194 "attempt to tamper with elements (set is locked)";
1197 Container.Nodes (Node).Element := New_Item;
1200 procedure Replace_Element
1201 (Container : in out Set;
1203 New_Item : Element_Type)
1206 if Position.Node = 0 then
1207 raise Constraint_Error with
1208 "Position cursor equals No_Element";
1211 if Position.Container /= Container'Unrestricted_Access then
1212 raise Program_Error with
1213 "Position cursor designates wrong set";
1216 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1218 Replace_Element (Container, Position.Node, New_Item);
1219 end Replace_Element;
1221 ----------------------
1222 -- Reserve_Capacity --
1223 ----------------------
1225 procedure Reserve_Capacity
1226 (Container : in out Set;
1227 Capacity : Count_Type)
1230 if Capacity > Container.Capacity then
1231 raise Capacity_Error with "requested capacity is too large";
1233 end Reserve_Capacity;
1239 procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1241 Node.Element := Item;
1248 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1253 --------------------------
1254 -- Symmetric_Difference --
1255 --------------------------
1257 procedure Symmetric_Difference
1258 (Target : in out Set;
1261 procedure Process (Source_Node : Count_Type);
1262 pragma Inline (Process);
1264 procedure Iterate is
1265 new HT_Ops.Generic_Iteration (Process);
1271 procedure Process (Source_Node : Count_Type) is
1272 N : Node_Type renames Source.Nodes (Source_Node);
1277 if Is_In (Target, N) then
1278 Delete (Target, N.Element);
1280 Insert (Target, N.Element, X, B);
1285 -- Start of processing for Symmetric_Difference
1288 if Target'Address = Source'Address then
1289 HT_Ops.Clear (Target);
1293 if Target.Length = 0 then
1294 Assign (Target => Target, Source => Source);
1298 if Target.Busy > 0 then
1299 raise Program_Error with
1300 "attempt to tamper with cursors (set is busy)";
1304 end Symmetric_Difference;
1306 function Symmetric_Difference (Left, Right : Set) return Set is
1310 if Left'Address = Right'Address then
1314 if Right.Length = 0 then
1318 if Left.Length = 0 then
1322 C := Left.Length + Right.Length;
1324 return Result : Set (C, To_Prime (C)) do
1325 Iterate_Left : declare
1326 procedure Process (L_Node : Count_Type);
1328 procedure Iterate is
1329 new HT_Ops.Generic_Iteration (Process);
1335 procedure Process (L_Node : Count_Type) is
1336 N : Node_Type renames Left.Nodes (L_Node);
1340 if not Is_In (Right, N) then
1341 Insert (Result, N.Element, X, B);
1346 -- Start of processing for Iterate_Left
1352 Iterate_Right : declare
1353 procedure Process (R_Node : Count_Type);
1355 procedure Iterate is
1356 new HT_Ops.Generic_Iteration (Process);
1362 procedure Process (R_Node : Count_Type) is
1363 N : Node_Type renames Right.Nodes (R_Node);
1367 if not Is_In (Left, N) then
1368 Insert (Result, N.Element, X, B);
1373 -- Start of processing for Iterate_Right
1379 end Symmetric_Difference;
1385 function To_Set (New_Item : Element_Type) return Set is
1389 return Result : Set (1, 1) do
1390 Insert (Result, New_Item, X, B);
1400 (Target : in out Set;
1403 procedure Process (Src_Node : Count_Type);
1405 procedure Iterate is
1406 new HT_Ops.Generic_Iteration (Process);
1412 procedure Process (Src_Node : Count_Type) is
1413 N : Node_Type renames Source.Nodes (Src_Node);
1417 Insert (Target, N.Element, X, B);
1420 -- Start of processing for Union
1423 if Target'Address = Source'Address then
1427 if Target.Busy > 0 then
1428 raise Program_Error with
1429 "attempt to tamper with cursors (set is busy)";
1432 -- ??? why is this code commented out ???
1434 -- N : constant Count_Type := Target.Length + Source.Length;
1436 -- if N > HT_Ops.Capacity (Target.HT) then
1437 -- HT_Ops.Reserve_Capacity (Target.HT, N);
1444 function Union (Left, Right : Set) return Set is
1448 if Left'Address = Right'Address then
1452 if Right.Length = 0 then
1456 if Left.Length = 0 then
1460 C := Left.Length + Right.Length;
1462 return Result : Set (C, To_Prime (C)) do
1463 Assign (Target => Result, Source => Left);
1464 Union (Target => Result, Source => Right);
1472 function Vet (Position : Cursor) return Boolean is
1474 if Position.Node = 0 then
1475 return Position.Container = null;
1478 if Position.Container = null then
1483 S : Set renames Position.Container.all;
1484 N : Nodes_Type renames S.Nodes;
1488 if S.Length = 0 then
1492 if Position.Node > N'Last then
1496 if N (Position.Node).Next = Position.Node then
1500 X := S.Buckets (Element_Keys.Index (S, N (Position.Node).Element));
1502 for J in 1 .. S.Length loop
1503 if X = Position.Node then
1511 if X = N (X).Next then -- to prevent unnecessary looping
1527 (Stream : not null access Root_Stream_Type'Class;
1530 procedure Write_Node
1531 (Stream : not null access Root_Stream_Type'Class;
1533 pragma Inline (Write_Node);
1535 procedure Write_Nodes is
1536 new HT_Ops.Generic_Write (Write_Node);
1542 procedure Write_Node
1543 (Stream : not null access Root_Stream_Type'Class;
1547 Element_Type'Write (Stream, Node.Element);
1550 -- Start of processing for Write
1553 Write_Nodes (Stream, Container);
1557 (Stream : not null access Root_Stream_Type'Class;
1561 raise Program_Error with "attempt to stream set cursor";
1565 (Stream : not null access Root_Stream_Type'Class;
1566 Item : Constant_Reference_Type)
1569 raise Program_Error with "attempt to stream reference";
1572 package body Generic_Keys is
1574 -----------------------
1575 -- Local Subprograms --
1576 -----------------------
1578 function Equivalent_Key_Node
1580 Node : Node_Type) return Boolean;
1581 pragma Inline (Equivalent_Key_Node);
1583 --------------------------
1584 -- Local Instantiations --
1585 --------------------------
1588 new Hash_Tables.Generic_Bounded_Keys
1589 (HT_Types => HT_Types,
1591 Set_Next => Set_Next,
1592 Key_Type => Key_Type,
1594 Equivalent_Keys => Equivalent_Key_Node);
1596 ------------------------
1597 -- Constant_Reference --
1598 ------------------------
1600 function Constant_Reference
1601 (Container : aliased Set;
1602 Key : Key_Type) return Constant_Reference_Type
1604 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1608 raise Constraint_Error with "key not in set";
1612 N : Node_Type renames Container.Nodes (Node);
1614 return (Element => N.Element'Access);
1616 end Constant_Reference;
1624 Key : Key_Type) return Boolean
1627 return Find (Container, Key) /= No_Element;
1635 (Container : in out Set;
1641 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1644 raise Constraint_Error with "attempt to delete key not in set";
1647 HT_Ops.Free (Container, X);
1656 Key : Key_Type) return Element_Type
1658 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1662 raise Constraint_Error with "key not in map"; -- ??? "set"
1665 return Container.Nodes (Node).Element;
1668 -------------------------
1669 -- Equivalent_Key_Node --
1670 -------------------------
1672 function Equivalent_Key_Node
1674 Node : Node_Type) return Boolean
1677 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1678 end Equivalent_Key_Node;
1685 (Container : in out Set;
1690 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1691 HT_Ops.Free (Container, X);
1700 Key : Key_Type) return Cursor
1702 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1704 return (if Node = 0 then No_Element
1705 else Cursor'(Container'Unrestricted_Access, Node));
1712 function Key (Position : Cursor) return Key_Type is
1714 if Position.Node = 0 then
1715 raise Constraint_Error with
1716 "Position cursor equals No_Element";
1719 pragma Assert (Vet (Position), "bad cursor in function Key");
1720 return Key (Position.Container.Nodes (Position.Node).Element);
1728 (Stream : not null access Root_Stream_Type'Class;
1729 Item : out Reference_Type)
1732 raise Program_Error with "attempt to stream reference";
1735 ------------------------------
1736 -- Reference_Preserving_Key --
1737 ------------------------------
1739 function Reference_Preserving_Key
1740 (Container : aliased in out Set;
1741 Position : Cursor) return Reference_Type
1744 if Position.Container = null then
1745 raise Constraint_Error with "Position cursor has no element";
1748 if Position.Container /= Container'Unrestricted_Access then
1749 raise Program_Error with
1750 "Position cursor designates wrong container";
1755 "bad cursor in function Reference_Preserving_Key");
1757 -- Some form of finalization will be required in order to actually
1758 -- check that the key-part of the element designated by Position has
1762 N : Node_Type renames Container.Nodes (Position.Node);
1764 return (Element => N.Element'Access);
1766 end Reference_Preserving_Key;
1768 function Reference_Preserving_Key
1769 (Container : aliased in out Set;
1770 Key : Key_Type) return Reference_Type
1772 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1776 raise Constraint_Error with "key not in set";
1780 N : Node_Type renames Container.Nodes (Node);
1782 return (Element => N.Element'Access);
1784 end Reference_Preserving_Key;
1791 (Container : in out Set;
1793 New_Item : Element_Type)
1795 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1799 raise Constraint_Error with
1800 "attempt to replace key not in set";
1803 Replace_Element (Container, Node, New_Item);
1806 -----------------------------------
1807 -- Update_Element_Preserving_Key --
1808 -----------------------------------
1810 procedure Update_Element_Preserving_Key
1811 (Container : in out Set;
1813 Process : not null access
1814 procedure (Element : in out Element_Type))
1817 N : Nodes_Type renames Container.Nodes;
1820 if Position.Node = 0 then
1821 raise Constraint_Error with
1822 "Position cursor equals No_Element";
1825 if Position.Container /= Container'Unrestricted_Access then
1826 raise Program_Error with
1827 "Position cursor designates wrong set";
1830 -- ??? why is this code commented out ???
1831 -- if HT.Buckets = null
1832 -- or else HT.Buckets'Length = 0
1833 -- or else HT.Length = 0
1834 -- or else Position.Node.Next = Position.Node
1836 -- raise Program_Error with
1837 -- "Position cursor is bad (set is empty)";
1842 "bad cursor in Update_Element_Preserving_Key");
1844 -- Record bucket now, in case key is changed
1846 Indx := HT_Ops.Index (Container.Buckets, N (Position.Node));
1849 E : Element_Type renames N (Position.Node).Element;
1850 K : constant Key_Type := Key (E);
1852 B : Natural renames Container.Busy;
1853 L : Natural renames Container.Lock;
1871 if Equivalent_Keys (K, Key (E)) then
1872 pragma Assert (Hash (K) = Hash (E));
1877 -- Key was modified, so remove this node from set.
1879 if Container.Buckets (Indx) = Position.Node then
1880 Container.Buckets (Indx) := N (Position.Node).Next;
1884 Prev : Count_Type := Container.Buckets (Indx);
1887 while N (Prev).Next /= Position.Node loop
1888 Prev := N (Prev).Next;
1891 raise Program_Error with
1892 "Position cursor is bad (node not found)";
1896 N (Prev).Next := N (Position.Node).Next;
1900 Container.Length := Container.Length - 1;
1901 HT_Ops.Free (Container, Position.Node);
1903 raise Program_Error with "key was modified";
1904 end Update_Element_Preserving_Key;
1911 (Stream : not null access Root_Stream_Type'Class;
1912 Item : Reference_Type)
1915 raise Program_Error with "attempt to stream reference";
1920 end Ada.Containers.Bounded_Hashed_Sets;