1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . F O R M A L _ H A S H E D _ S E T S --
9 -- Copyright (C) 2010, 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 3, 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. --
22 -- As a special exception under Section 7 of GPL version 3, you are granted --
23 -- additional permissions described in the GCC Runtime Library Exception, --
24 -- version 3.1, as published by the Free Software Foundation. --
26 -- You should have received a copy of the GNU General Public License and --
27 -- a copy of the GCC Runtime Library Exception along with this program; --
28 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
29 -- <http://www.gnu.org/licenses/>. --
30 ------------------------------------------------------------------------------
32 with Ada.Containers.Hash_Tables.Generic_Bounded_Operations;
33 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Operations);
35 with Ada.Containers.Hash_Tables.Generic_Bounded_Keys;
36 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Keys);
38 with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
40 with System; use type System.Address;
42 package body Ada.Containers.Formal_Hashed_Sets is
44 -----------------------
45 -- Local Subprograms --
46 -----------------------
50 Target : in out Hash_Table_Type);
52 function Equivalent_Keys
54 Node : Node_Type) return Boolean;
55 pragma Inline (Equivalent_Keys);
58 (HT : in out Hash_Table_Type;
62 with procedure Set_Element (Node : in out Node_Type);
63 procedure Generic_Allocate
64 (HT : in out Hash_Table_Type;
65 Node : out Count_Type);
67 function Hash_Node (Node : Node_Type) return Hash_Type;
68 pragma Inline (Hash_Node);
71 (Container : in out Hash_Table_Type;
72 New_Item : Element_Type;
73 Node : out Count_Type;
74 Inserted : out Boolean);
76 procedure Intersection
77 (Left : Hash_Table_Type;
79 Target : in out Hash_Table_Type);
82 (HT : HT_Types.Hash_Table_Type;
83 Key : Node_Type) return Boolean;
84 pragma Inline (Is_In);
86 procedure Set_Element (Node : in out Node_Type; Item : Element_Type);
87 pragma Inline (Set_Element);
89 function Next_Unchecked
91 Position : Cursor) return Cursor;
93 function Next (Node : Node_Type) return Count_Type;
96 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
97 pragma Inline (Set_Next);
99 function Vet (Container : Set; Position : Cursor) return Boolean;
101 --------------------------
102 -- Local Instantiations --
103 --------------------------
105 package HT_Ops is new Hash_Tables.Generic_Bounded_Operations
106 (HT_Types => HT_Types,
107 Hash_Node => Hash_Node,
109 Set_Next => Set_Next);
111 package Element_Keys is new Hash_Tables.Generic_Bounded_Keys
112 (HT_Types => HT_Types,
114 Set_Next => Set_Next,
115 Key_Type => Element_Type,
117 Equivalent_Keys => Equivalent_Keys);
119 procedure Replace_Element is
120 new Element_Keys.Generic_Replace_Element (Hash_Node, Set_Element);
126 function "=" (Left, Right : Set) return Boolean is
129 if Length (Left) /= Length (Right) then
133 if Length (Left) = 0 then
138 Node : Count_Type := First (Left).Node;
143 if Left.K = Plain then
146 Last := HT_Ops.Next (Left.HT.all, Left.Last);
149 while Node /= Last loop
150 ENode := Find (Container => Right,
151 Item => Left.HT.Nodes (Node).Element).Node;
153 Right.HT.Nodes (ENode).Element /= Left.HT.Nodes (Node).Element
158 Node := HT_Ops.Next (Left.HT.all, Node);
171 procedure Assign (Target : in out Set; Source : Set) is
172 procedure Insert_Element (Source_Node : Count_Type);
174 procedure Insert_Elements is
175 new HT_Ops.Generic_Iteration (Insert_Element);
181 procedure Insert_Element (Source_Node : Count_Type) is
182 N : Node_Type renames Source.HT.Nodes (Source_Node);
187 Insert (Target.HT.all, N.Element, X, B);
191 -- Start of processing for Assign
194 if Target.K /= Plain then
195 raise Constraint_Error
196 with "Can't modify part of container";
199 if Target'Address = Source'Address then
203 if Target.Capacity < Length (Source) then
204 raise Storage_Error with "not enough capacity"; -- SE or CE? ???
207 HT_Ops.Clear (Target.HT.all);
211 Insert_Elements (Source.HT.all);
214 N : Count_Type := Source.First;
216 while N /= HT_Ops.Next (Source.HT.all, Source.Last) loop
218 N := HT_Ops.Next (Source.HT.all, N);
228 function Capacity (Container : Set) return Count_Type is
230 return Container.HT.Nodes'Length;
237 procedure Clear (Container : in out Set) is
240 if Container.K /= Plain then
241 raise Constraint_Error
242 with "Can't modify part of container";
245 HT_Ops.Clear (Container.HT.all);
252 function Contains (Container : Set; Item : Element_Type) return Boolean is
254 return Find (Container, Item) /= No_Element;
263 Capacity : Count_Type := 0) return Set
265 C : constant Count_Type :=
266 Count_Type'Max (Capacity, Source.Capacity);
269 Target : Set (C, Source.Modulus);
272 if (Source.K = Part and Source.Length = 0) or
273 Source.HT.Length = 0 then
277 Target.HT.Length := Source.HT.Length;
278 Target.HT.Free := Source.HT.Free;
279 while H <= Source.Modulus loop
280 Target.HT.Buckets (H) := Source.HT.Buckets (H);
283 while N <= Source.Capacity loop
284 Target.HT.Nodes (N) := Source.HT.Nodes (N);
289 Free (Target.HT.all, Cu.Node);
292 if Source.K = Part then
293 N := HT_Ops.First (Target.HT.all);
294 while N /= Source.First loop
296 N := HT_Ops.Next (Target.HT.all, N);
299 N := HT_Ops.Next (Target.HT.all, Source.Last);
302 N := HT_Ops.Next (Target.HT.all, N);
309 ---------------------
310 -- Default_Modulus --
311 ---------------------
313 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
315 return To_Prime (Capacity);
323 (Container : in out Set;
330 if Container.K /= Plain then
331 raise Constraint_Error
332 with "Can't modify part of container";
335 Element_Keys.Delete_Key_Sans_Free (Container.HT.all, Item, X);
338 raise Constraint_Error with "attempt to delete element not in set";
340 Free (Container.HT.all, X);
344 (Container : in out Set;
345 Position : in out Cursor)
349 if Container.K /= Plain then
350 raise Constraint_Error
351 with "Can't modify part of container";
354 if not Has_Element (Container, Position) then
355 raise Constraint_Error with "Position cursor has no element";
358 if Container.HT.Busy > 0 then
359 raise Program_Error with
360 "attempt to tamper with elements (set is busy)";
363 pragma Assert (Vet (Container, Position), "bad cursor in Delete");
365 HT_Ops.Delete_Node_Sans_Free (Container.HT.all, Position.Node);
366 Free (Container.HT.all, Position.Node);
368 Position := No_Element;
376 (Target : in out Set;
379 Tgt_Node, Src_Node, Src_Last, Src_Length : Count_Type;
381 TN : Nodes_Type renames Target.HT.Nodes;
382 SN : Nodes_Type renames Source.HT.Nodes;
386 if Target.K /= Plain then
387 raise Constraint_Error
388 with "Can't modify part of container";
391 if Target'Address = Source'Address then
398 Src_Length := Source.HT.Length;
400 Src_Length := Source.Length;
403 if Src_Length = 0 then
407 if Target.HT.Busy > 0 then
408 raise Program_Error with
409 "attempt to tamper with elements (set is busy)";
414 if Src_Length >= Target.HT.Length then
415 Tgt_Node := HT_Ops.First (Target.HT.all);
416 while Tgt_Node /= 0 loop
417 if Element_Keys.Find (Source.HT.all,
418 TN (Tgt_Node).Element) /= 0 then
420 X : constant Count_Type := Tgt_Node;
422 Tgt_Node := HT_Ops.Next (Target.HT.all, Tgt_Node);
423 HT_Ops.Delete_Node_Sans_Free (Target.HT.all, X);
424 Free (Target.HT.all, X);
427 Tgt_Node := HT_Ops.Next (Target.HT.all, Tgt_Node);
432 Src_Node := HT_Ops.First (Source.HT.all);
436 Src_Node := Source.First;
437 Src_Last := HT_Ops.Next (Source.HT.all, Source.Last);
439 while Src_Node /= Src_Last loop
440 Tgt_Node := Element_Keys.Find
441 (Target.HT.all, SN (Src_Node).Element);
443 if Tgt_Node /= 0 then
444 HT_Ops.Delete_Node_Sans_Free (Target.HT.all, Tgt_Node);
445 Free (Target.HT.all, Tgt_Node);
448 Src_Node := HT_Ops.Next (Source.HT.all, Src_Node);
454 Target : in out Hash_Table_Type)
456 procedure Process (L_Node : Count_Type);
459 new HT_Ops.Generic_Iteration (Process);
465 procedure Process (L_Node : Count_Type) is
466 E : Element_Type renames Left.HT.Nodes (L_Node).Element;
471 if Find (Right, E).Node = 0 then
472 Insert (Target, E, X, B);
477 -- Start of processing for Difference
480 if Left.K = Plain then
481 Iterate (Left.HT.all);
484 if Left.Length = 0 then
489 Node : Count_Type := Left.First;
491 while Node /= Left.HT.Nodes (Left.Last).Next loop
493 Node := HT_Ops.Next (Left.HT.all, Node);
499 function Difference (Left, Right : Set) return Set is
504 if Left'Address = Right'Address then
508 if Length (Left) = 0 then
512 if Length (Right) = 0 then
517 H := Default_Modulus (C);
518 Difference (Left, Right, Target => S.HT.all);
528 Position : Cursor) return Element_Type is
530 if not Has_Element (Container, Position) then
531 raise Constraint_Error with "Position cursor equals No_Element";
534 pragma Assert (Vet (Container, Position),
535 "bad cursor in function Element");
538 HT : Hash_Table_Type renames Container.HT.all;
540 return HT.Nodes (Position.Node).Element;
544 ---------------------
545 -- Equivalent_Sets --
546 ---------------------
548 function Equivalent_Sets (Left, Right : Set) return Boolean is
550 if Left.K = Plain and Right.K = Plain then
553 function Find_Equivalent_Key
554 (R_HT : Hash_Table_Type'Class;
555 L_Node : Node_Type) return Boolean;
556 pragma Inline (Find_Equivalent_Key);
558 function Is_Equivalent is
559 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
561 -------------------------
562 -- Find_Equivalent_Key --
563 -------------------------
565 function Find_Equivalent_Key
566 (R_HT : Hash_Table_Type'Class;
567 L_Node : Node_Type) return Boolean
569 R_Index : constant Hash_Type :=
570 Element_Keys.Index (R_HT, L_Node.Element);
572 R_Node : Count_Type := R_HT.Buckets (R_Index);
574 RN : Nodes_Type renames R_HT.Nodes;
582 if Equivalent_Elements (L_Node.Element,
583 RN (R_Node).Element) then
587 R_Node := HT_Ops.Next (R_HT, R_Node);
589 end Find_Equivalent_Key;
591 -- Start of processing of Equivalent_Sets
594 return Is_Equivalent (Left.HT.all, Right.HT.all);
599 function Equal_Between
600 (L : Hash_Table_Type; R : Set;
601 From : Count_Type; To : Count_Type) return Boolean;
603 -- To and From are valid and Length are equal
604 function Equal_Between
605 (L : Hash_Table_Type; R : Set;
606 From : Count_Type; To : Count_Type) return Boolean
609 To_Index : constant Hash_Type :=
610 Element_Keys.Index (L, L.Nodes (To).Element);
611 L_Node : Count_Type := From;
615 L_Index := Element_Keys.Index (L, L.Nodes (From).Element);
617 -- For each node of hash table L, search for an equivalent
618 -- node in hash table R.
620 while L_Index /= To_Index or else
621 L_Node /= HT_Ops.Next (L, To) loop
622 pragma Assert (L_Node /= 0);
624 if Find (R, L.Nodes (L_Node).Element).Node = 0 then
628 L_Node := L.Nodes (L_Node).Next;
631 -- We have exhausted the nodes in this bucket
632 -- Find the next bucket
635 L_Index := L_Index + 1;
636 L_Node := L.Buckets (L_Index);
637 exit when L_Node /= 0;
646 if Length (Left) /= Length (Right) then
649 if Length (Left) = 0 then
652 if Left.K = Part then
653 return Equal_Between (Left.HT.all, Right,
654 Left.First, Left.Last);
656 return Equal_Between (Right.HT.all, Left,
657 Right.First, Right.Last);
663 -------------------------
664 -- Equivalent_Elements --
665 -------------------------
667 function Equivalent_Elements (Left : Set; CLeft : Cursor;
668 Right : Set; CRight : Cursor)
671 if not Has_Element (Left, CLeft) then
672 raise Constraint_Error with
673 "Left cursor of Equivalent_Elements has no element";
676 if not Has_Element (Right, CRight) then
677 raise Constraint_Error with
678 "Right cursor of Equivalent_Elements has no element";
681 pragma Assert (Vet (Left, CLeft),
682 "bad Left cursor in Equivalent_Elements");
683 pragma Assert (Vet (Right, CRight),
684 "bad Right cursor in Equivalent_Elements");
687 LN : Node_Type renames Left.HT.Nodes (CLeft.Node);
688 RN : Node_Type renames Right.HT.Nodes (CRight.Node);
690 return Equivalent_Elements (LN.Element, RN.Element);
692 end Equivalent_Elements;
694 function Equivalent_Elements
697 Right : Element_Type) return Boolean is
699 if not Has_Element (Left, CLeft) then
700 raise Constraint_Error with
701 "Left cursor of Equivalent_Elements has no element";
704 pragma Assert (Vet (Left, CLeft),
705 "Left cursor in Equivalent_Elements is bad");
708 LN : Node_Type renames Left.HT.Nodes (CLeft.Node);
710 return Equivalent_Elements (LN.Element, Right);
712 end Equivalent_Elements;
714 function Equivalent_Elements
715 (Left : Element_Type;
717 CRight : Cursor) return Boolean is
719 if not Has_Element (Right, CRight) then
720 raise Constraint_Error with
721 "Right cursor of Equivalent_Elements has no element";
725 (Vet (Right, CRight),
726 "Right cursor of Equivalent_Elements is bad");
729 RN : Node_Type renames Right.HT.Nodes (CRight.Node);
731 return Equivalent_Elements (Left, RN.Element);
733 end Equivalent_Elements;
737 ---------------------
738 -- Equivalent_Keys --
739 ---------------------
741 function Equivalent_Keys (Key : Element_Type; Node : Node_Type)
744 return Equivalent_Elements (Key, Node.Element);
752 (Container : in out Set;
757 if Container.K /= Plain then
758 raise Constraint_Error
759 with "Can't modify part of container";
761 Element_Keys.Delete_Key_Sans_Free (Container.HT.all, Item, X);
762 Free (Container.HT.all, X);
771 Item : Element_Type) return Cursor
777 Node : constant Count_Type :=
778 Element_Keys.Find (Container.HT.all, Item);
784 return (Node => Node);
788 function Find_Between
789 (HT : Hash_Table_Type;
792 To : Count_Type) return Count_Type;
794 function Find_Between
795 (HT : Hash_Table_Type;
798 To : Count_Type) return Count_Type is
801 Indx_From : constant Hash_Type :=
802 Element_Keys.Index (HT,
803 HT.Nodes (From).Element);
804 Indx_To : constant Hash_Type :=
805 Element_Keys.Index (HT,
806 HT.Nodes (To).Element);
808 To_Node : Count_Type;
812 Indx := Element_Keys.Index (HT, Key);
814 if Indx < Indx_From or Indx > Indx_To then
818 if Indx = Indx_From then
821 Node := HT.Buckets (Indx);
824 if Indx = Indx_To then
825 To_Node := HT.Nodes (To).Next;
830 while Node /= To_Node loop
831 if Equivalent_Keys (Key, HT.Nodes (Node)) then
834 Node := HT.Nodes (Node).Next;
840 if Container.Length = 0 then
844 return (Node => Find_Between (Container.HT.all, Item,
845 Container.First, Container.Last));
854 function First (Container : Set) return Cursor is
859 Node : constant Count_Type := HT_Ops.First (Container.HT.all);
866 return (Node => Node);
870 Node : constant Count_Type := Container.First;
877 return (Node => Node);
887 (HT : in out Hash_Table_Type;
891 HT.Nodes (X).Has_Element := False;
895 ----------------------
896 -- Generic_Allocate --
897 ----------------------
899 procedure Generic_Allocate
900 (HT : in out Hash_Table_Type;
901 Node : out Count_Type)
904 procedure Allocate is
905 new HT_Ops.Generic_Allocate (Set_Element);
909 HT.Nodes (Node).Has_Element := True;
910 end Generic_Allocate;
916 function Has_Element (Container : Set; Position : Cursor) return Boolean is
918 if Position.Node = 0 or else
919 not Container.HT.Nodes (Position.Node).Has_Element then
923 if Container.K = Plain then
928 Lst_Index : constant Hash_Type :=
929 Element_Keys.Index (Container.HT.all,
931 (Container.Last).Element);
932 Fst_Index : constant Hash_Type :=
933 Element_Keys.Index (Container.HT.all,
935 (Container.First).Element);
936 Index : constant Hash_Type :=
937 Element_Keys.Index (Container.HT.all,
939 (Position.Node).Element);
940 Lst_Node : Count_Type;
944 if Index < Fst_Index or Index > Lst_Index then
948 if Index > Fst_Index and Index < Lst_Index then
952 if Index = Fst_Index then
953 Node := Container.First;
955 Node := Container.HT.Buckets (Index);
958 if Index = Lst_Index then
959 Lst_Node := Container.HT.Nodes (Container.Last).Next;
964 while Node /= Lst_Node loop
965 if Position.Node = Node then
968 Node := HT_Ops.Next (Container.HT.all, Node);
979 function Hash_Node (Node : Node_Type) return Hash_Type is
981 return Hash (Node.Element);
989 (Container : in out Set;
990 New_Item : Element_Type)
996 Insert (Container, New_Item, Position, Inserted);
999 if Container.HT.Lock > 0 then
1000 raise Program_Error with
1001 "attempt to tamper with cursors (set is locked)";
1004 Container.HT.Nodes (Position.Node).Element := New_Item;
1013 (Container : in out Set;
1014 New_Item : Element_Type;
1015 Position : out Cursor;
1016 Inserted : out Boolean)
1019 if Container.K /= Plain then
1020 raise Constraint_Error
1021 with "Can't modify part of container";
1024 Insert (Container.HT.all, New_Item, Position.Node, Inserted);
1028 (Container : in out Set;
1029 New_Item : Element_Type)
1035 Insert (Container, New_Item, Position, Inserted);
1037 if not Inserted then
1038 raise Constraint_Error with
1039 "attempt to insert element already in set";
1044 (Container : in out Hash_Table_Type;
1045 New_Item : Element_Type;
1046 Node : out Count_Type;
1047 Inserted : out Boolean)
1049 procedure Allocate_Set_Element (Node : in out Node_Type);
1050 pragma Inline (Allocate_Set_Element);
1052 function New_Node return Count_Type;
1053 pragma Inline (New_Node);
1055 procedure Local_Insert is
1056 new Element_Keys.Generic_Conditional_Insert (New_Node);
1058 procedure Allocate is
1059 new Generic_Allocate (Allocate_Set_Element);
1061 ---------------------------
1062 -- Allocate_Set_Element --
1063 ---------------------------
1065 procedure Allocate_Set_Element (Node : in out Node_Type) is
1067 Node.Element := New_Item;
1068 end Allocate_Set_Element;
1074 function New_Node return Count_Type is
1075 Result : Count_Type;
1077 Allocate (Container, Result);
1081 -- Start of processing for Insert
1085 Local_Insert (Container, New_Item, Node, Inserted);
1093 procedure Intersection
1094 (Target : in out Set;
1097 Tgt_Node : Count_Type;
1098 TN : Nodes_Type renames Target.HT.Nodes;
1101 if Target.K /= Plain then
1102 raise Constraint_Error
1103 with "Can't modify part of container";
1106 if Target'Address = Source'Address then
1110 if Source.HT.Length = 0 then
1115 if Target.HT.Busy > 0 then
1116 raise Program_Error with
1117 "attempt to tamper with elements (set is busy)";
1120 Tgt_Node := HT_Ops.First (Target.HT.all);
1121 while Tgt_Node /= 0 loop
1122 if Find (Source, TN (Tgt_Node).Element).Node /= 0 then
1123 Tgt_Node := HT_Ops.Next (Target.HT.all, Tgt_Node);
1127 X : constant Count_Type := Tgt_Node;
1129 Tgt_Node := HT_Ops.Next (Target.HT.all, Tgt_Node);
1130 HT_Ops.Delete_Node_Sans_Free (Target.HT.all, X);
1131 Free (Target.HT.all, X);
1137 procedure Intersection
1138 (Left : Hash_Table_Type;
1140 Target : in out Hash_Table_Type)
1142 procedure Process (L_Node : Count_Type);
1144 procedure Iterate is
1145 new HT_Ops.Generic_Iteration (Process);
1151 procedure Process (L_Node : Count_Type) is
1152 E : Element_Type renames Left.Nodes (L_Node).Element;
1157 if Find (Right, E).Node /= 0 then
1158 Insert (Target, E, X, B);
1163 -- Start of processing for Intersection
1169 function Intersection (Left, Right : Set) return Set is
1176 if Left'Address = Right'Address then
1180 C := Count_Type'Min (Length (Left), Length (Right)); -- ???
1181 H := Default_Modulus (C);
1182 return S : Set (C, H) do
1183 if Length (Left) /= 0 and Length (Right) /= 0 then
1184 if Left.K = Plain then
1185 Intersection (Left.HT.all, Right, Target => S.HT.all);
1188 while C /= Left.HT.Nodes (Left.Last).Next loop
1189 pragma Assert (C /= 0);
1190 if Find (Right, Left.HT.Nodes (C).Element).Node /= 0 then
1191 Insert (S.HT.all, Left.HT.Nodes (C).Element, X, B);
1194 C := Left.HT.Nodes (C).Next;
1205 function Is_Empty (Container : Set) return Boolean is
1207 return Length (Container) = 0;
1214 function Is_In (HT : HT_Types.Hash_Table_Type;
1215 Key : Node_Type) return Boolean is
1217 return Element_Keys.Find (HT, Key.Element) /= 0;
1224 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
1225 Subset_Node : Count_Type;
1226 Subset_Nodes : Nodes_Type renames Subset.HT.Nodes;
1227 To_Node : Count_Type;
1229 if Subset'Address = Of_Set'Address then
1233 if Length (Subset) > Length (Of_Set) then
1237 Subset_Node := First (Subset).Node;
1239 if Subset.K = Plain then
1242 To_Node := Subset.HT.Nodes (Subset.Last).Next;
1245 while Subset_Node /= To_Node loop
1247 N : Node_Type renames Subset_Nodes (Subset_Node);
1248 E : Element_Type renames N.Element;
1251 if Find (Of_Set, E).Node = 0 then
1256 Subset_Node := HT_Ops.Next (Subset.HT.all, Subset_Node);
1269 not null access procedure (Container : Set; Position : Cursor))
1271 procedure Process_Node (Node : Count_Type);
1272 pragma Inline (Process_Node);
1274 procedure Iterate is
1275 new HT_Ops.Generic_Iteration (Process_Node);
1281 procedure Process_Node (Node : Count_Type) is
1283 Process (Container, (Node => Node));
1286 B : Natural renames Container'Unrestricted_Access.HT.Busy;
1288 -- Start of processing for Iterate
1296 Iterate (Container.HT.all);
1299 if Container.Length = 0 then
1304 Node : Count_Type := Container.First;
1306 while Node /= Container.HT.Nodes (Container.Last).Next loop
1307 Process_Node (Node);
1308 Node := HT_Ops.Next (Container.HT.all, Node);
1325 function Left (Container : Set; Position : Cursor) return Set is
1327 Fst : constant Count_Type := First (Container).Node;
1328 L : Count_Type := 0;
1329 C : Count_Type := Fst;
1331 while C /= Position.Node loop
1332 if C = 0 or C = Container.Last then
1333 raise Constraint_Error with
1334 "Position cursor has no element";
1337 C := HT_Ops.Next (Container.HT.all, C);
1341 return (Capacity => Container.Capacity,
1342 Modulus => Container.Modulus,
1349 return (Capacity => Container.Capacity,
1350 Modulus => Container.Modulus,
1363 function Length (Container : Set) return Count_Type is
1367 return Container.HT.Length;
1369 return Container.Length;
1377 procedure Move (Target : in out Set; Source : in out Set) is
1378 HT : HT_Types.Hash_Table_Type renames Source.HT.all;
1379 NN : HT_Types.Nodes_Type renames HT.Nodes;
1384 if Target.K /= Plain or Source.K /= Plain then
1385 raise Constraint_Error
1386 with "Can't modify part of container";
1389 if Target'Address = Source'Address then
1393 if Target.Capacity < Length (Source) then
1394 raise Constraint_Error with -- ???
1395 "Source length exceeds Target capacity";
1399 raise Program_Error with
1400 "attempt to tamper with cursors of Source (list is busy)";
1405 if HT.Length = 0 then
1409 X := HT_Ops.First (HT);
1411 Insert (Target, NN (X).Element); -- optimize???
1413 Y := HT_Ops.Next (HT, X);
1415 HT_Ops.Delete_Node_Sans_Free (HT, X);
1426 function Next (Node : Node_Type) return Count_Type is
1431 function Next_Unchecked
1433 Position : Cursor) return Cursor
1435 HT : Hash_Table_Type renames Container.HT.all;
1436 Node : constant Count_Type := HT_Ops.Next (HT, Position.Node);
1443 if Container.K = Part and then Container.Last = Position.Node then
1447 return (Node => Node);
1450 function Next (Container : Set; Position : Cursor) return Cursor is
1452 if Position.Node = 0 then
1456 if not Has_Element (Container, Position) then
1457 raise Constraint_Error
1458 with "Position has no element";
1461 pragma Assert (Vet (Container, Position), "bad cursor in Next");
1463 return Next_Unchecked (Container, Position);
1466 procedure Next (Container : Set; Position : in out Cursor) is
1468 Position := Next (Container, Position);
1475 function Overlap (Left, Right : Set) return Boolean is
1476 Left_Node : Count_Type;
1477 Left_Nodes : Nodes_Type renames Left.HT.Nodes;
1478 To_Node : Count_Type;
1480 if Length (Right) = 0 or Length (Left) = 0 then
1484 if Left'Address = Right'Address then
1488 Left_Node := First (Left).Node;
1490 if Left.K = Plain then
1493 To_Node := Left.HT.Nodes (Left.Last).Next;
1496 while Left_Node /= To_Node loop
1498 N : Node_Type renames Left_Nodes (Left_Node);
1499 E : Element_Type renames N.Element;
1502 if Find (Right, E).Node /= 0 then
1507 Left_Node := HT_Ops.Next (Left.HT.all, Left_Node);
1517 procedure Query_Element
1518 (Container : in out Set;
1520 Process : not null access procedure (Element : Element_Type))
1523 if Container.K /= Plain then
1524 raise Constraint_Error
1525 with "Can't modify part of container";
1528 if not Has_Element (Container, Position) then
1529 raise Constraint_Error with
1530 "Position cursor of Query_Element has no element";
1533 pragma Assert (Vet (Container, Position), "bad cursor in Query_Element");
1536 HT : Hash_Table_Type renames Container.HT.all;
1538 B : Natural renames HT.Busy;
1539 L : Natural renames HT.Lock;
1546 Process (HT.Nodes (Position.Node).Element);
1564 (Stream : not null access Root_Stream_Type'Class;
1565 Container : out Set)
1567 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1570 procedure Read_Nodes is
1571 new HT_Ops.Generic_Read (Read_Node);
1577 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1580 procedure Read_Element (Node : in out Node_Type);
1581 pragma Inline (Read_Element);
1583 procedure Allocate is
1584 new Generic_Allocate (Read_Element);
1586 procedure Read_Element (Node : in out Node_Type) is
1588 Element_Type'Read (Stream, Node.Element);
1593 -- Start of processing for Read_Node
1596 Allocate (Container.HT.all, Node);
1600 -- Start of processing for Read
1603 if Container.K /= Plain then
1604 raise Constraint_Error;
1607 if Container.HT = null then
1608 Result := new HT_Types.Hash_Table_Type (Container.Capacity,
1611 Result := Container.HT;
1614 Read_Nodes (Stream, Result.all);
1615 Container.HT := Result;
1619 (Stream : not null access Root_Stream_Type'Class;
1623 raise Program_Error with "attempt to stream set cursor";
1631 (Container : in out Set;
1632 New_Item : Element_Type)
1634 Node : constant Count_Type :=
1635 Element_Keys.Find (Container.HT.all, New_Item);
1638 if Container.K /= Plain then
1639 raise Constraint_Error
1640 with "Can't modify part of container";
1644 raise Constraint_Error with
1645 "attempt to replace element not in set";
1648 if Container.HT.Lock > 0 then
1649 raise Program_Error with
1650 "attempt to tamper with cursors (set is locked)";
1653 Container.HT.Nodes (Node).Element := New_Item;
1656 ---------------------
1657 -- Replace_Element --
1658 ---------------------
1660 procedure Replace_Element
1661 (Container : in out Set;
1663 New_Item : Element_Type)
1666 if Container.K /= Plain then
1667 raise Constraint_Error
1668 with "Can't modify part of container";
1671 if not Has_Element (Container, Position) then
1672 raise Constraint_Error with
1673 "Position cursor equals No_Element";
1676 pragma Assert (Vet (Container, Position),
1677 "bad cursor in Replace_Element");
1679 Replace_Element (Container.HT.all, Position.Node, New_Item);
1680 end Replace_Element;
1682 ----------------------
1683 -- Reserve_Capacity --
1684 ----------------------
1686 procedure Reserve_Capacity
1687 (Container : in out Set;
1688 Capacity : Count_Type)
1691 if Container.K /= Plain then
1692 raise Constraint_Error
1693 with "Can't modify part of container";
1695 if Capacity > Container.Capacity then
1696 raise Constraint_Error with "requested capacity is too large";
1698 end Reserve_Capacity;
1704 function Right (Container : Set; Position : Cursor) return Set is
1707 L : Count_Type := 0;
1708 C : Count_Type := Position.Node;
1712 return (Capacity => Container.Capacity,
1713 Modulus => Container.Modulus,
1721 if Container.K = Plain then
1724 Lst := HT_Ops.Next (Container.HT.all, Container.Last);
1728 raise Constraint_Error with
1729 "Position cursor has no element";
1734 raise Constraint_Error with
1735 "Position cursor has no element";
1738 C := HT_Ops.Next (Container.HT.all, C);
1742 return (Capacity => Container.Capacity,
1743 Modulus => Container.Modulus,
1747 First => Position.Node,
1755 procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1757 Node.Element := Item;
1764 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1773 function Strict_Equal (Left, Right : Set) return Boolean is
1774 CuL : Cursor := First (Left);
1775 CuR : Cursor := First (Right);
1777 if Length (Left) /= Length (Right) then
1781 while CuL.Node /= 0 or CuR.Node /= 0 loop
1782 if CuL.Node /= CuR.Node or else
1783 Left.HT.Nodes (CuL.Node).Element /=
1784 Right.HT.Nodes (CuR.Node).Element then
1787 CuL := Next_Unchecked (Left, CuL);
1788 CuR := Next_Unchecked (Right, CuR);
1794 --------------------------
1795 -- Symmetric_Difference --
1796 --------------------------
1798 procedure Symmetric_Difference
1799 (Target : in out Set;
1802 procedure Process (Source_Node : Count_Type);
1803 pragma Inline (Process);
1805 procedure Iterate is
1806 new HT_Ops.Generic_Iteration (Process);
1812 procedure Process (Source_Node : Count_Type) is
1813 N : Node_Type renames Source.HT.Nodes (Source_Node);
1818 if Is_In (Target.HT.all, N) then
1819 Delete (Target, N.Element);
1821 Insert (Target.HT.all, N.Element, X, B);
1826 -- Start of processing for Symmetric_Difference
1829 if Target.K /= Plain then
1830 raise Constraint_Error
1831 with "Can't modify part of container";
1834 if Target'Address = Source'Address then
1839 if Length (Target) = 0 then
1840 Assign (Target, Source);
1844 if Target.HT.Busy > 0 then
1845 raise Program_Error with
1846 "attempt to tamper with elements (set is busy)";
1849 if Source.K = Plain then
1850 Iterate (Source.HT.all);
1853 if Source.Length = 0 then
1858 Node : Count_Type := Source.First;
1860 while Node /= Source.HT.Nodes (Source.Last).Next loop
1862 Node := HT_Ops.Next (Source.HT.all, Node);
1867 end Symmetric_Difference;
1869 function Symmetric_Difference (Left, Right : Set) return Set is
1874 if Left'Address = Right'Address then
1878 if Length (Right) = 0 then
1882 if Length (Left) = 0 then
1886 C := Length (Left) + Length (Right);
1887 H := Default_Modulus (C);
1888 return S : Set (C, H) do
1889 Difference (Left, Right, S.HT.all);
1890 Difference (Right, Left, S.HT.all);
1892 end Symmetric_Difference;
1898 function To_Set (New_Item : Element_Type) return Set is
1903 return S : Set (Capacity => 1, Modulus => 1) do
1904 Insert (S.HT.all, New_Item, X, B);
1914 (Target : in out Set;
1917 procedure Process (Src_Node : Count_Type);
1919 procedure Iterate is
1920 new HT_Ops.Generic_Iteration (Process);
1926 procedure Process (Src_Node : Count_Type) is
1927 N : Node_Type renames Source.HT.Nodes (Src_Node);
1928 E : Element_Type renames N.Element;
1934 Insert (Target.HT.all, E, X, B);
1937 -- Start of processing for Union
1941 if Target.K /= Plain then
1942 raise Constraint_Error
1943 with "Can't modify part of container";
1946 if Target'Address = Source'Address then
1950 if Target.HT.Busy > 0 then
1951 raise Program_Error with
1952 "attempt to tamper with elements (set is busy)";
1955 if Source.K = Plain then
1956 Iterate (Source.HT.all);
1959 if Source.Length = 0 then
1964 Node : Count_Type := Source.First;
1966 while Node /= Source.HT.Nodes (Source.Last).Next loop
1968 Node := HT_Ops.Next (Source.HT.all, Node);
1974 function Union (Left, Right : Set) return Set is
1979 if Left'Address = Right'Address then
1983 if Length (Right) = 0 then
1987 if Length (Left) = 0 then
1991 C := Length (Left) + Length (Right);
1992 H := Default_Modulus (C);
1993 return S : Set (C, H) do
1994 Assign (Target => S, Source => Left);
1995 Union (Target => S, Source => Right);
2003 function Vet (Container : Set; Position : Cursor) return Boolean is
2005 if Position.Node = 0 then
2010 S : Set renames Container;
2011 N : Nodes_Type renames S.HT.Nodes;
2015 if S.Length = 0 then
2019 if Position.Node > N'Last then
2023 if N (Position.Node).Next = Position.Node then
2027 X := S.HT.Buckets (Element_Keys.Index (S.HT.all,
2028 N (Position.Node).Element));
2030 for J in 1 .. S.Length loop
2031 if X = Position.Node then
2039 if X = N (X).Next then -- to prevent unnecessary looping
2055 (Stream : not null access Root_Stream_Type'Class;
2058 procedure Write_Node
2059 (Stream : not null access Root_Stream_Type'Class;
2061 pragma Inline (Write_Node);
2063 procedure Write_Nodes is
2064 new HT_Ops.Generic_Write (Write_Node);
2070 procedure Write_Node
2071 (Stream : not null access Root_Stream_Type'Class;
2075 Element_Type'Write (Stream, Node.Element);
2078 -- Start of processing for Write
2081 Write_Nodes (Stream, Container.HT.all);
2085 (Stream : not null access Root_Stream_Type'Class;
2089 raise Program_Error with "attempt to stream set cursor";
2091 package body Generic_Keys is
2093 -----------------------
2094 -- Local Subprograms --
2095 -----------------------
2097 function Equivalent_Key_Node
2099 Node : Node_Type) return Boolean;
2100 pragma Inline (Equivalent_Key_Node);
2102 --------------------------
2103 -- Local Instantiations --
2104 --------------------------
2107 new Hash_Tables.Generic_Bounded_Keys
2108 (HT_Types => HT_Types,
2110 Set_Next => Set_Next,
2111 Key_Type => Key_Type,
2113 Equivalent_Keys => Equivalent_Key_Node);
2121 Key : Key_Type) return Boolean
2124 return Find (Container, Key) /= No_Element;
2132 (Container : in out Set;
2138 if Container.K /= Plain then
2139 raise Constraint_Error
2140 with "Can't modify part of container";
2143 Key_Keys.Delete_Key_Sans_Free (Container.HT.all, Key, X);
2146 raise Constraint_Error with "attempt to delete key not in set";
2149 Free (Container.HT.all, X);
2158 Key : Key_Type) return Element_Type
2160 Node : constant Count_Type := Find (Container, Key).Node;
2164 raise Constraint_Error with "key not in map";
2167 return Container.HT.Nodes (Node).Element;
2170 -------------------------
2171 -- Equivalent_Key_Node --
2172 -------------------------
2174 function Equivalent_Key_Node
2176 Node : Node_Type) return Boolean
2179 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
2180 end Equivalent_Key_Node;
2187 (Container : in out Set;
2192 if Container.K /= Plain then
2193 raise Constraint_Error
2194 with "Can't modify part of container";
2197 Key_Keys.Delete_Key_Sans_Free (Container.HT.all, Key, X);
2198 Free (Container.HT.all, X);
2207 Key : Key_Type) return Cursor
2210 if Container.K = Plain then
2212 Node : constant Count_Type :=
2213 Key_Keys.Find (Container.HT.all, Key);
2220 return (Node => Node);
2224 function Find_Between
2225 (HT : Hash_Table_Type;
2228 To : Count_Type) return Count_Type;
2230 function Find_Between
2231 (HT : Hash_Table_Type;
2234 To : Count_Type) return Count_Type is
2237 Indx_From : constant Hash_Type :=
2238 Key_Keys.Index (HT, Generic_Keys.Key
2239 (HT.Nodes (From).Element));
2240 Indx_To : constant Hash_Type :=
2241 Key_Keys.Index (HT, Generic_Keys.Key
2242 (HT.Nodes (To).Element));
2244 To_Node : Count_Type;
2248 Indx := Key_Keys.Index (HT, Key);
2250 if Indx < Indx_From or Indx > Indx_To then
2254 if Indx = Indx_From then
2257 Node := HT.Buckets (Indx);
2260 if Indx = Indx_To then
2261 To_Node := HT.Nodes (To).Next;
2266 while Node /= To_Node loop
2267 if Equivalent_Key_Node (Key, HT.Nodes (Node)) then
2270 Node := HT.Nodes (Node).Next;
2277 if Container.Length = 0 then
2281 return (Node => Find_Between (Container.HT.all, Key,
2282 Container.First, Container.Last));
2291 function Key (Container : Set; Position : Cursor) return Key_Type is
2293 if not Has_Element (Container, Position) then
2294 raise Constraint_Error with
2295 "Position cursor has no element";
2298 pragma Assert (Vet (Container, Position),
2299 "bad cursor in function Key");
2302 HT : Hash_Table_Type renames Container.HT.all;
2303 N : Node_Type renames HT.Nodes (Position.Node);
2305 return Key (N.Element);
2314 (Container : in out Set;
2316 New_Item : Element_Type)
2319 if Container.K /= Plain then
2320 raise Constraint_Error
2321 with "Can't modify part of container";
2325 Node : constant Count_Type :=
2326 Key_Keys.Find (Container.HT.all, Key);
2330 raise Constraint_Error with
2331 "attempt to replace key not in set";
2334 Replace_Element (Container.HT.all, Node, New_Item);
2338 -----------------------------------
2339 -- Update_Element_Preserving_Key --
2340 -----------------------------------
2342 procedure Update_Element_Preserving_Key
2343 (Container : in out Set;
2345 Process : not null access
2346 procedure (Element : in out Element_Type))
2349 N : Nodes_Type renames Container.HT.Nodes;
2353 if Container.K /= Plain then
2354 raise Constraint_Error
2355 with "Can't modify part of container";
2358 if Position.Node = 0 then
2359 raise Constraint_Error with
2360 "Position cursor equals No_Element";
2364 -- if HT.Buckets = null
2365 -- or else HT.Buckets'Length = 0
2366 -- or else HT.Length = 0
2367 -- or else Position.Node.Next = Position.Node
2369 -- raise Program_Error with
2370 -- "Position cursor is bad (set is empty)";
2374 (Vet (Container, Position),
2375 "bad cursor in Update_Element_Preserving_Key");
2377 -- Record bucket now, in case key is changed.
2378 Indx := HT_Ops.Index (Container.HT.Buckets, N (Position.Node));
2381 E : Element_Type renames N (Position.Node).Element;
2382 K : constant Key_Type := Key (E);
2384 B : Natural renames Container.HT.Busy;
2385 L : Natural renames Container.HT.Lock;
2403 if Equivalent_Keys (K, Key (E)) then
2404 pragma Assert (Hash (K) = Hash (E));
2409 -- Key was modified, so remove this node from set.
2411 if Container.HT.Buckets (Indx) = Position.Node then
2412 Container.HT.Buckets (Indx) := N (Position.Node).Next;
2416 Prev : Count_Type := Container.HT.Buckets (Indx);
2419 while N (Prev).Next /= Position.Node loop
2420 Prev := N (Prev).Next;
2423 raise Program_Error with
2424 "Position cursor is bad (node not found)";
2428 N (Prev).Next := N (Position.Node).Next;
2432 Container.Length := Container.Length - 1;
2433 Free (Container.HT.all, Position.Node);
2435 raise Program_Error with "key was modified";
2436 end Update_Element_Preserving_Key;
2440 end Ada.Containers.Formal_Hashed_Sets;