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;
38 with System; use type System.Address;
40 package body Ada.Containers.Bounded_Hashed_Sets is
42 -----------------------
43 -- Local Subprograms --
44 -----------------------
46 function Equivalent_Keys
48 Node : Node_Type) return Boolean;
49 pragma Inline (Equivalent_Keys);
51 function Hash_Node (Node : Node_Type) return Hash_Type;
52 pragma Inline (Hash_Node);
55 (Container : in out Set;
56 New_Item : Element_Type;
57 Node : out Count_Type;
58 Inserted : out Boolean);
62 Key : Node_Type) return Boolean;
63 pragma Inline (Is_In);
65 procedure Set_Element (Node : in out Node_Type; Item : Element_Type);
66 pragma Inline (Set_Element);
68 function Next (Node : Node_Type) return Count_Type;
71 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
72 pragma Inline (Set_Next);
74 function Vet (Position : Cursor) return Boolean;
76 --------------------------
77 -- Local Instantiations --
78 --------------------------
80 package HT_Ops is new Hash_Tables.Generic_Bounded_Operations
81 (HT_Types => HT_Types,
82 Hash_Node => Hash_Node,
84 Set_Next => Set_Next);
86 package Element_Keys is new Hash_Tables.Generic_Bounded_Keys
87 (HT_Types => HT_Types,
90 Key_Type => Element_Type,
92 Equivalent_Keys => Equivalent_Keys);
94 procedure Replace_Element is
95 new Element_Keys.Generic_Replace_Element (Hash_Node, Set_Element);
101 function "=" (Left, Right : Set) return Boolean is
102 function Find_Equal_Key
103 (R_HT : Hash_Table_Type'Class;
104 L_Node : Node_Type) return Boolean;
105 pragma Inline (Find_Equal_Key);
108 new HT_Ops.Generic_Equal (Find_Equal_Key);
114 function Find_Equal_Key
115 (R_HT : Hash_Table_Type'Class;
116 L_Node : Node_Type) return Boolean
118 R_Index : constant Hash_Type :=
119 Element_Keys.Index (R_HT, L_Node.Element);
121 R_Node : Count_Type := R_HT.Buckets (R_Index);
129 if L_Node.Element = R_HT.Nodes (R_Node).Element then
133 R_Node := Next (R_HT.Nodes (R_Node));
137 -- Start of processing for "="
140 return Is_Equal (Left, Right);
147 procedure Assign (Target : in out Set; Source : Set) is
148 procedure Insert_Element (Source_Node : Count_Type);
150 procedure Insert_Elements is
151 new HT_Ops.Generic_Iteration (Insert_Element);
157 procedure Insert_Element (Source_Node : Count_Type) is
158 N : Node_Type renames Source.Nodes (Source_Node);
163 Insert (Target, N.Element, X, B);
167 -- Start of processing for Assign
170 if Target'Address = Source'Address then
174 if Target.Capacity < Source.Length then
176 with "Target capacity is less than Source length";
179 HT_Ops.Clear (Target);
180 Insert_Elements (Source);
187 function Capacity (Container : Set) return Count_Type is
189 return Container.Capacity;
196 procedure Clear (Container : in out Set) is
198 HT_Ops.Clear (Container);
205 function Contains (Container : Set; Item : Element_Type) return Boolean is
207 return Find (Container, Item) /= No_Element;
216 Capacity : Count_Type := 0;
217 Modulus : Hash_Type := 0) return Set
226 elsif Capacity >= Source.Length then
230 raise Capacity_Error with "Capacity value too small";
234 M := Default_Modulus (C);
239 return Target : Set (Capacity => C, Modulus => M) do
240 Assign (Target => Target, Source => Source);
244 ---------------------
245 -- Default_Modulus --
246 ---------------------
248 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
250 return To_Prime (Capacity);
258 (Container : in out Set;
264 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
267 raise Constraint_Error with "attempt to delete element not in set";
270 HT_Ops.Free (Container, X);
274 (Container : in out Set;
275 Position : in out Cursor)
278 if Position.Node = 0 then
279 raise Constraint_Error with "Position cursor equals No_Element";
282 if Position.Container /= Container'Unrestricted_Access then
283 raise Program_Error with "Position cursor designates wrong set";
286 if Container.Busy > 0 then
287 raise Program_Error with
288 "attempt to tamper with cursors (set is busy)";
291 pragma Assert (Vet (Position), "bad cursor in Delete");
293 HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
294 HT_Ops.Free (Container, Position.Node);
296 Position := No_Element;
304 (Target : in out Set;
307 Tgt_Node, Src_Node : Count_Type;
309 TN : Nodes_Type renames Target.Nodes;
310 SN : Nodes_Type renames Source.Nodes;
313 if Target'Address = Source'Address then
314 HT_Ops.Clear (Target);
318 if Source.Length = 0 then
322 if Target.Busy > 0 then
323 raise Program_Error with
324 "attempt to tamper with cursors (set is busy)";
327 if Source.Length < Target.Length then
328 Src_Node := HT_Ops.First (Source);
329 while Src_Node /= 0 loop
330 Tgt_Node := Element_Keys.Find (Target, SN (Src_Node).Element);
332 if Tgt_Node /= 0 then
333 HT_Ops.Delete_Node_Sans_Free (Target, Tgt_Node);
334 HT_Ops.Free (Target, Tgt_Node);
337 Src_Node := HT_Ops.Next (Source, Src_Node);
341 Tgt_Node := HT_Ops.First (Target);
342 while Tgt_Node /= 0 loop
343 if Is_In (Source, TN (Tgt_Node)) then
345 X : constant Count_Type := Tgt_Node;
347 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
348 HT_Ops.Delete_Node_Sans_Free (Target, X);
349 HT_Ops.Free (Target, X);
353 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
359 function Difference (Left, Right : Set) return Set is
361 if Left'Address = Right'Address then
365 if Left.Length = 0 then
369 if Right.Length = 0 then
373 return Result : Set (Left.Length, To_Prime (Left.Length)) do
374 Iterate_Left : declare
375 procedure Process (L_Node : Count_Type);
378 new HT_Ops.Generic_Iteration (Process);
384 procedure Process (L_Node : Count_Type) is
385 N : Node_Type renames Left.Nodes (L_Node);
390 if not Is_In (Right, N) then
391 Insert (Result, N.Element, X, B); -- optimize this ???
393 pragma Assert (X > 0);
397 -- Start of processing for Iterate_Left
409 function Element (Position : Cursor) return Element_Type is
411 if Position.Node = 0 then
412 raise Constraint_Error with "Position cursor equals No_Element";
415 pragma Assert (Vet (Position), "bad cursor in function Element");
418 S : Set renames Position.Container.all;
419 N : Node_Type renames S.Nodes (Position.Node);
426 ---------------------
427 -- Equivalent_Sets --
428 ---------------------
430 function Equivalent_Sets (Left, Right : Set) return Boolean is
431 function Find_Equivalent_Key
432 (R_HT : Hash_Table_Type'Class;
433 L_Node : Node_Type) return Boolean;
434 pragma Inline (Find_Equivalent_Key);
436 function Is_Equivalent is
437 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
439 -------------------------
440 -- Find_Equivalent_Key --
441 -------------------------
443 function Find_Equivalent_Key
444 (R_HT : Hash_Table_Type'Class;
445 L_Node : Node_Type) return Boolean
447 R_Index : constant Hash_Type :=
448 Element_Keys.Index (R_HT, L_Node.Element);
450 R_Node : Count_Type := R_HT.Buckets (R_Index);
452 RN : Nodes_Type renames R_HT.Nodes;
460 if Equivalent_Elements (L_Node.Element, RN (R_Node).Element) then
464 R_Node := HT_Ops.Next (R_HT, R_Node);
466 end Find_Equivalent_Key;
468 -- Start of processing for Equivalent_Sets
471 return Is_Equivalent (Left, Right);
474 -------------------------
475 -- Equivalent_Elements --
476 -------------------------
478 function Equivalent_Elements (Left, Right : Cursor)
481 if Left.Node = 0 then
482 raise Constraint_Error with
483 "Left cursor of Equivalent_Elements equals No_Element";
486 if Right.Node = 0 then
487 raise Constraint_Error with
488 "Right cursor of Equivalent_Elements equals No_Element";
491 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
492 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
495 LN : Node_Type renames Left.Container.Nodes (Left.Node);
496 RN : Node_Type renames Right.Container.Nodes (Right.Node);
499 return Equivalent_Elements (LN.Element, RN.Element);
501 end Equivalent_Elements;
503 function Equivalent_Elements (Left : Cursor; Right : Element_Type)
506 if Left.Node = 0 then
507 raise Constraint_Error with
508 "Left cursor of Equivalent_Elements equals No_Element";
511 pragma Assert (Vet (Left), "Left cursor in Equivalent_Elements is bad");
514 LN : Node_Type renames Left.Container.Nodes (Left.Node);
516 return Equivalent_Elements (LN.Element, Right);
518 end Equivalent_Elements;
520 function Equivalent_Elements (Left : Element_Type; Right : Cursor)
523 if Right.Node = 0 then
524 raise Constraint_Error with
525 "Right cursor of Equivalent_Elements equals No_Element";
530 "Right cursor of Equivalent_Elements is bad");
533 RN : Node_Type renames Right.Container.Nodes (Right.Node);
535 return Equivalent_Elements (Left, RN.Element);
537 end Equivalent_Elements;
539 ---------------------
540 -- Equivalent_Keys --
541 ---------------------
543 function Equivalent_Keys (Key : Element_Type; Node : Node_Type)
546 return Equivalent_Elements (Key, Node.Element);
554 (Container : in out Set;
559 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
560 HT_Ops.Free (Container, X);
569 Item : Element_Type) return Cursor
571 Node : constant Count_Type := Element_Keys.Find (Container, Item);
578 return Cursor'(Container'Unrestricted_Access, Node);
585 function First (Container : Set) return Cursor is
586 Node : constant Count_Type := HT_Ops.First (Container);
593 return Cursor'(Container'Unrestricted_Access, Node);
600 function Has_Element (Position : Cursor) return Boolean is
602 pragma Assert (Vet (Position), "bad cursor in Has_Element");
603 return Position.Node /= 0;
610 function Hash_Node (Node : Node_Type) return Hash_Type is
612 return Hash (Node.Element);
620 (Container : in out Set;
621 New_Item : Element_Type)
627 Insert (Container, New_Item, Position, Inserted);
630 if Container.Lock > 0 then
631 raise Program_Error with
632 "attempt to tamper with elements (set is locked)";
635 Container.Nodes (Position.Node).Element := New_Item;
644 (Container : in out Set;
645 New_Item : Element_Type;
646 Position : out Cursor;
647 Inserted : out Boolean)
650 Insert (Container, New_Item, Position.Node, Inserted);
651 Position.Container := Container'Unchecked_Access;
655 (Container : in out Set;
656 New_Item : Element_Type)
659 pragma Unreferenced (Position);
664 Insert (Container, New_Item, Position, Inserted);
667 raise Constraint_Error with
668 "attempt to insert element already in set";
673 (Container : in out Set;
674 New_Item : Element_Type;
675 Node : out Count_Type;
676 Inserted : out Boolean)
678 procedure Allocate_Set_Element (Node : in out Node_Type);
679 pragma Inline (Allocate_Set_Element);
681 function New_Node return Count_Type;
682 pragma Inline (New_Node);
684 procedure Local_Insert is
685 new Element_Keys.Generic_Conditional_Insert (New_Node);
687 procedure Allocate is
688 new HT_Ops.Generic_Allocate (Allocate_Set_Element);
690 ---------------------------
691 -- Allocate_Set_Element --
692 ---------------------------
694 procedure Allocate_Set_Element (Node : in out Node_Type) is
696 Node.Element := New_Item;
697 end Allocate_Set_Element;
703 function New_Node return Count_Type is
706 Allocate (Container, Result);
710 -- Start of processing for Insert
713 -- The buckets array length is specified by the user as a discriminant
714 -- of the container type, so it is possible for the buckets array to
715 -- have a length of zero. We must check for this case specifically, in
716 -- order to prevent divide-by-zero errors later, when we compute the
717 -- buckets array index value for an element, given its hash value.
719 if Container.Buckets'Length = 0 then
720 raise Capacity_Error with "No capacity for insertion";
723 Local_Insert (Container, New_Item, Node, Inserted);
730 procedure Intersection
731 (Target : in out Set;
734 Tgt_Node : Count_Type;
735 TN : Nodes_Type renames Target.Nodes;
738 if Target'Address = Source'Address then
742 if Source.Length = 0 then
743 HT_Ops.Clear (Target);
747 if Target.Busy > 0 then
748 raise Program_Error with
749 "attempt to tamper with cursors (set is busy)";
752 Tgt_Node := HT_Ops.First (Target);
753 while Tgt_Node /= 0 loop
754 if Is_In (Source, TN (Tgt_Node)) then
755 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
759 X : constant Count_Type := Tgt_Node;
761 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
762 HT_Ops.Delete_Node_Sans_Free (Target, X);
763 HT_Ops.Free (Target, X);
769 function Intersection (Left, Right : Set) return Set is
773 if Left'Address = Right'Address then
777 C := Count_Type'Min (Left.Length, Right.Length);
783 return Result : Set (C, To_Prime (C)) do
784 Iterate_Left : declare
785 procedure Process (L_Node : Count_Type);
788 new HT_Ops.Generic_Iteration (Process);
794 procedure Process (L_Node : Count_Type) is
795 N : Node_Type renames Left.Nodes (L_Node);
800 if Is_In (Right, N) then
801 Insert (Result, N.Element, X, B); -- optimize ???
803 pragma Assert (X > 0);
807 -- Start of processing for Iterate_Left
819 function Is_Empty (Container : Set) return Boolean is
821 return Container.Length = 0;
828 function Is_In (HT : Set; Key : Node_Type) return Boolean is
830 return Element_Keys.Find (HT, Key.Element) /= 0;
837 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
838 Subset_Node : Count_Type;
839 SN : Nodes_Type renames Subset.Nodes;
842 if Subset'Address = Of_Set'Address then
846 if Subset.Length > Of_Set.Length then
850 Subset_Node := HT_Ops.First (Subset);
851 while Subset_Node /= 0 loop
852 if not Is_In (Of_Set, SN (Subset_Node)) then
855 Subset_Node := HT_Ops.Next (Subset, Subset_Node);
867 Process : not null access procedure (Position : Cursor))
869 procedure Process_Node (Node : Count_Type);
870 pragma Inline (Process_Node);
873 new HT_Ops.Generic_Iteration (Process_Node);
879 procedure Process_Node (Node : Count_Type) is
881 Process (Cursor'(Container'Unrestricted_Access, Node));
884 B : Natural renames Container'Unrestricted_Access.Busy;
886 -- Start of processing for Iterate
906 function Length (Container : Set) return Count_Type is
908 return Container.Length;
915 procedure Move (Target : in out Set; Source : in out Set) is
917 if Target'Address = Source'Address then
921 if Source.Busy > 0 then
922 raise Program_Error with
923 "attempt to tamper with cursors (container is busy)";
926 Target.Assign (Source);
934 function Next (Node : Node_Type) return Count_Type is
939 function Next (Position : Cursor) return Cursor is
941 if Position.Node = 0 then
945 pragma Assert (Vet (Position), "bad cursor in Next");
948 HT : Set renames Position.Container.all;
949 Node : constant Count_Type := HT_Ops.Next (HT, Position.Node);
956 return Cursor'(Position.Container, Node);
960 procedure Next (Position : in out Cursor) is
962 Position := Next (Position);
969 function Overlap (Left, Right : Set) return Boolean is
970 Left_Node : Count_Type;
973 if Right.Length = 0 then
977 if Left'Address = Right'Address then
981 Left_Node := HT_Ops.First (Left);
982 while Left_Node /= 0 loop
983 if Is_In (Right, Left.Nodes (Left_Node)) then
986 Left_Node := HT_Ops.Next (Left, Left_Node);
996 procedure Query_Element
998 Process : not null access procedure (Element : Element_Type))
1001 if Position.Node = 0 then
1002 raise Constraint_Error with
1003 "Position cursor of Query_Element equals No_Element";
1006 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1009 S : Set renames Position.Container.all;
1010 B : Natural renames S.Busy;
1011 L : Natural renames S.Lock;
1018 Process (S.Nodes (Position.Node).Element);
1036 (Stream : not null access Root_Stream_Type'Class;
1037 Container : out Set)
1039 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1042 procedure Read_Nodes is
1043 new HT_Ops.Generic_Read (Read_Node);
1049 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1052 procedure Read_Element (Node : in out Node_Type);
1053 pragma Inline (Read_Element);
1055 procedure Allocate is
1056 new HT_Ops.Generic_Allocate (Read_Element);
1058 procedure Read_Element (Node : in out Node_Type) is
1060 Element_Type'Read (Stream, Node.Element);
1065 -- Start of processing for Read_Node
1068 Allocate (Container, Node);
1072 -- Start of processing for Read
1075 Read_Nodes (Stream, Container);
1079 (Stream : not null access Root_Stream_Type'Class;
1083 raise Program_Error with "attempt to stream set cursor";
1091 (Container : in out Set;
1092 New_Item : Element_Type)
1094 Node : constant Count_Type :=
1095 Element_Keys.Find (Container, New_Item);
1099 raise Constraint_Error with
1100 "attempt to replace element not in set";
1103 if Container.Lock > 0 then
1104 raise Program_Error with
1105 "attempt to tamper with elements (set is locked)";
1108 Container.Nodes (Node).Element := New_Item;
1111 procedure Replace_Element
1112 (Container : in out Set;
1114 New_Item : Element_Type)
1117 if Position.Node = 0 then
1118 raise Constraint_Error with
1119 "Position cursor equals No_Element";
1122 if Position.Container /= Container'Unrestricted_Access then
1123 raise Program_Error with
1124 "Position cursor designates wrong set";
1127 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1129 Replace_Element (Container, Position.Node, New_Item);
1130 end Replace_Element;
1132 ----------------------
1133 -- Reserve_Capacity --
1134 ----------------------
1136 procedure Reserve_Capacity
1137 (Container : in out Set;
1138 Capacity : Count_Type)
1141 if Capacity > Container.Capacity then
1142 raise Capacity_Error with "requested capacity is too large";
1144 end Reserve_Capacity;
1150 procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1152 Node.Element := Item;
1159 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1164 --------------------------
1165 -- Symmetric_Difference --
1166 --------------------------
1168 procedure Symmetric_Difference
1169 (Target : in out Set;
1172 procedure Process (Source_Node : Count_Type);
1173 pragma Inline (Process);
1175 procedure Iterate is
1176 new HT_Ops.Generic_Iteration (Process);
1182 procedure Process (Source_Node : Count_Type) is
1183 N : Node_Type renames Source.Nodes (Source_Node);
1188 if Is_In (Target, N) then
1189 Delete (Target, N.Element);
1191 Insert (Target, N.Element, X, B);
1196 -- Start of processing for Symmetric_Difference
1199 if Target'Address = Source'Address then
1200 HT_Ops.Clear (Target);
1204 if Target.Length = 0 then
1205 Assign (Target => Target, Source => Source);
1209 if Target.Busy > 0 then
1210 raise Program_Error with
1211 "attempt to tamper with cursors (set is busy)";
1215 end Symmetric_Difference;
1217 function Symmetric_Difference (Left, Right : Set) return Set is
1221 if Left'Address = Right'Address then
1225 if Right.Length = 0 then
1229 if Left.Length = 0 then
1233 C := Left.Length + Right.Length;
1235 return Result : Set (C, To_Prime (C)) do
1236 Iterate_Left : declare
1237 procedure Process (L_Node : Count_Type);
1239 procedure Iterate is
1240 new HT_Ops.Generic_Iteration (Process);
1246 procedure Process (L_Node : Count_Type) is
1247 N : Node_Type renames Left.Nodes (L_Node);
1252 if not Is_In (Right, N) then
1253 Insert (Result, N.Element, X, B);
1258 -- Start of processing for Iterate_Left
1264 Iterate_Right : declare
1265 procedure Process (R_Node : Count_Type);
1267 procedure Iterate is
1268 new HT_Ops.Generic_Iteration (Process);
1274 procedure Process (R_Node : Count_Type) is
1275 N : Node_Type renames Right.Nodes (R_Node);
1280 if not Is_In (Left, N) then
1281 Insert (Result, N.Element, X, B);
1286 -- Start of processing for Iterate_Right
1292 end Symmetric_Difference;
1298 function To_Set (New_Item : Element_Type) return Set is
1303 return Result : Set (1, 1) do
1304 Insert (Result, New_Item, X, B);
1314 (Target : in out Set;
1317 procedure Process (Src_Node : Count_Type);
1319 procedure Iterate is
1320 new HT_Ops.Generic_Iteration (Process);
1326 procedure Process (Src_Node : Count_Type) is
1327 N : Node_Type renames Source.Nodes (Src_Node);
1332 Insert (Target, N.Element, X, B);
1335 -- Start of processing for Union
1338 if Target'Address = Source'Address then
1342 if Target.Busy > 0 then
1343 raise Program_Error with
1344 "attempt to tamper with cursors (set is busy)";
1349 -- N : constant Count_Type := Target.Length + Source.Length;
1351 -- if N > HT_Ops.Capacity (Target.HT) then
1352 -- HT_Ops.Reserve_Capacity (Target.HT, N);
1359 function Union (Left, Right : Set) return Set is
1363 if Left'Address = Right'Address then
1367 if Right.Length = 0 then
1371 if Left.Length = 0 then
1375 C := Left.Length + Right.Length;
1377 return Result : Set (C, To_Prime (C)) do
1378 Assign (Target => Result, Source => Left);
1379 Union (Target => Result, Source => Right);
1387 function Vet (Position : Cursor) return Boolean is
1389 if Position.Node = 0 then
1390 return Position.Container = null;
1393 if Position.Container = null then
1398 S : Set renames Position.Container.all;
1399 N : Nodes_Type renames S.Nodes;
1403 if S.Length = 0 then
1407 if Position.Node > N'Last then
1411 if N (Position.Node).Next = Position.Node then
1415 X := S.Buckets (Element_Keys.Index (S, N (Position.Node).Element));
1417 for J in 1 .. S.Length loop
1418 if X = Position.Node then
1426 if X = N (X).Next then -- to prevent unnecessary looping
1442 (Stream : not null access Root_Stream_Type'Class;
1445 procedure Write_Node
1446 (Stream : not null access Root_Stream_Type'Class;
1448 pragma Inline (Write_Node);
1450 procedure Write_Nodes is
1451 new HT_Ops.Generic_Write (Write_Node);
1457 procedure Write_Node
1458 (Stream : not null access Root_Stream_Type'Class;
1462 Element_Type'Write (Stream, Node.Element);
1465 -- Start of processing for Write
1468 Write_Nodes (Stream, Container);
1472 (Stream : not null access Root_Stream_Type'Class;
1476 raise Program_Error with "attempt to stream set cursor";
1479 package body Generic_Keys is
1481 -----------------------
1482 -- Local Subprograms --
1483 -----------------------
1485 function Equivalent_Key_Node
1487 Node : Node_Type) return Boolean;
1488 pragma Inline (Equivalent_Key_Node);
1490 --------------------------
1491 -- Local Instantiations --
1492 --------------------------
1495 new Hash_Tables.Generic_Bounded_Keys
1496 (HT_Types => HT_Types,
1498 Set_Next => Set_Next,
1499 Key_Type => Key_Type,
1501 Equivalent_Keys => Equivalent_Key_Node);
1509 Key : Key_Type) return Boolean
1512 return Find (Container, Key) /= No_Element;
1520 (Container : in out Set;
1526 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1529 raise Constraint_Error with "attempt to delete key not in set";
1532 HT_Ops.Free (Container, X);
1541 Key : Key_Type) return Element_Type
1543 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1547 raise Constraint_Error with "key not in map";
1550 return Container.Nodes (Node).Element;
1553 -------------------------
1554 -- Equivalent_Key_Node --
1555 -------------------------
1557 function Equivalent_Key_Node
1559 Node : Node_Type) return Boolean
1562 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1563 end Equivalent_Key_Node;
1570 (Container : in out Set;
1575 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1576 HT_Ops.Free (Container, X);
1585 Key : Key_Type) return Cursor
1587 Node : constant Count_Type :=
1588 Key_Keys.Find (Container, Key);
1595 return Cursor'(Container'Unrestricted_Access, Node);
1602 function Key (Position : Cursor) return Key_Type is
1604 if Position.Node = 0 then
1605 raise Constraint_Error with
1606 "Position cursor equals No_Element";
1609 pragma Assert (Vet (Position), "bad cursor in function Key");
1611 return Key (Position.Container.Nodes (Position.Node).Element);
1619 (Container : in out Set;
1621 New_Item : Element_Type)
1623 Node : constant Count_Type :=
1624 Key_Keys.Find (Container, Key);
1628 raise Constraint_Error with
1629 "attempt to replace key not in set";
1632 Replace_Element (Container, Node, New_Item);
1635 -----------------------------------
1636 -- Update_Element_Preserving_Key --
1637 -----------------------------------
1639 procedure Update_Element_Preserving_Key
1640 (Container : in out Set;
1642 Process : not null access
1643 procedure (Element : in out Element_Type))
1646 N : Nodes_Type renames Container.Nodes;
1649 if Position.Node = 0 then
1650 raise Constraint_Error with
1651 "Position cursor equals No_Element";
1654 if Position.Container /= Container'Unrestricted_Access then
1655 raise Program_Error with
1656 "Position cursor designates wrong set";
1660 -- if HT.Buckets = null
1661 -- or else HT.Buckets'Length = 0
1662 -- or else HT.Length = 0
1663 -- or else Position.Node.Next = Position.Node
1665 -- raise Program_Error with
1666 -- "Position cursor is bad (set is empty)";
1671 "bad cursor in Update_Element_Preserving_Key");
1673 -- Record bucket now, in case key is changed.
1674 Indx := HT_Ops.Index (Container.Buckets, N (Position.Node));
1677 E : Element_Type renames N (Position.Node).Element;
1678 K : constant Key_Type := Key (E);
1680 B : Natural renames Container.Busy;
1681 L : Natural renames Container.Lock;
1699 if Equivalent_Keys (K, Key (E)) then
1700 pragma Assert (Hash (K) = Hash (E));
1705 -- Key was modified, so remove this node from set.
1707 if Container.Buckets (Indx) = Position.Node then
1708 Container.Buckets (Indx) := N (Position.Node).Next;
1712 Prev : Count_Type := Container.Buckets (Indx);
1715 while N (Prev).Next /= Position.Node loop
1716 Prev := N (Prev).Next;
1719 raise Program_Error with
1720 "Position cursor is bad (node not found)";
1724 N (Prev).Next := N (Position.Node).Next;
1728 Container.Length := Container.Length - 1;
1729 HT_Ops.Free (Container, Position.Node);
1731 raise Program_Error with "key was modified";
1732 end Update_Element_Preserving_Key;
1736 end Ada.Containers.Bounded_Hashed_Sets;