1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_HASHED_SETS --
9 -- Copyright (C) 2004-2015, 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
.Unchecked_Deallocation
;
32 with Ada
.Containers
.Hash_Tables
.Generic_Operations
;
33 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Operations
);
35 with Ada
.Containers
.Hash_Tables
.Generic_Keys
;
36 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Keys
);
38 with Ada
.Containers
.Helpers
; use Ada
.Containers
.Helpers
;
40 with Ada
.Containers
.Prime_Numbers
;
42 with System
; use type System
.Address
;
44 package body Ada
.Containers
.Indefinite_Hashed_Sets
is
46 pragma Annotate
(CodePeer
, Skip_Analysis
);
48 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
49 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
50 -- See comment in Ada.Containers.Helpers
52 -----------------------
53 -- Local Subprograms --
54 -----------------------
56 procedure Assign
(Node
: Node_Access
; Item
: Element_Type
);
57 pragma Inline
(Assign
);
59 function Copy_Node
(Source
: Node_Access
) return Node_Access
;
60 pragma Inline
(Copy_Node
);
62 function Equivalent_Keys
64 Node
: Node_Access
) return Boolean;
65 pragma Inline
(Equivalent_Keys
);
67 function Find_Equal_Key
68 (R_HT
: Hash_Table_Type
;
69 L_Node
: Node_Access
) return Boolean;
71 function Find_Equivalent_Key
72 (R_HT
: Hash_Table_Type
;
73 L_Node
: Node_Access
) return Boolean;
75 procedure Free
(X
: in out Node_Access
);
77 function Hash_Node
(Node
: Node_Access
) return Hash_Type
;
78 pragma Inline
(Hash_Node
);
81 (HT
: in out Hash_Table_Type
;
82 New_Item
: Element_Type
;
83 Node
: out Node_Access
;
84 Inserted
: out Boolean);
87 (HT
: aliased in out Hash_Table_Type
;
88 Key
: Node_Access
) return Boolean;
89 pragma Inline
(Is_In
);
91 function Next
(Node
: Node_Access
) return Node_Access
;
94 function Read_Node
(Stream
: not null access Root_Stream_Type
'Class)
96 pragma Inline
(Read_Node
);
98 procedure Set_Next
(Node
: Node_Access
; Next
: Node_Access
);
99 pragma Inline
(Set_Next
);
101 function Vet
(Position
: Cursor
) return Boolean;
104 (Stream
: not null access Root_Stream_Type
'Class;
106 pragma Inline
(Write_Node
);
108 --------------------------
109 -- Local Instantiations --
110 --------------------------
112 procedure Free_Element
is
113 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
115 package HT_Ops
is new Hash_Tables
.Generic_Operations
116 (HT_Types
=> HT_Types
,
117 Hash_Node
=> Hash_Node
,
119 Set_Next
=> Set_Next
,
120 Copy_Node
=> Copy_Node
,
123 package Element_Keys
is new Hash_Tables
.Generic_Keys
124 (HT_Types
=> HT_Types
,
126 Set_Next
=> Set_Next
,
127 Key_Type
=> Element_Type
,
129 Equivalent_Keys
=> Equivalent_Keys
);
132 new HT_Ops
.Generic_Equal
(Find_Equal_Key
);
134 function Is_Equivalent
is
135 new HT_Ops
.Generic_Equal
(Find_Equivalent_Key
);
137 procedure Read_Nodes
is
138 new HT_Ops
.Generic_Read
(Read_Node
);
140 procedure Replace_Element
is
141 new Element_Keys
.Generic_Replace_Element
(Hash_Node
, Assign
);
143 procedure Write_Nodes
is
144 new HT_Ops
.Generic_Write
(Write_Node
);
150 function "=" (Left
, Right
: Set
) return Boolean is
152 return Is_Equal
(Left
.HT
, Right
.HT
);
159 procedure Adjust
(Container
: in out Set
) is
161 HT_Ops
.Adjust
(Container
.HT
);
168 procedure Assign
(Node
: Node_Access
; Item
: Element_Type
) is
169 X
: Element_Access
:= Node
.Element
;
171 -- The element allocator may need an accessibility check in the case the
172 -- actual type is class-wide or has access discriminants (RM 4.8(10.1)
175 pragma Unsuppress
(Accessibility_Check
);
178 Node
.Element
:= new Element_Type
'(Item);
182 procedure Assign (Target : in out Set; Source : Set) is
184 if Target'Address = Source'Address then
188 Target.Union (Source);
196 function Capacity (Container : Set) return Count_Type is
198 return HT_Ops.Capacity (Container.HT);
205 procedure Clear (Container : in out Set) is
207 HT_Ops.Clear (Container.HT);
210 ------------------------
211 -- Constant_Reference --
212 ------------------------
214 function Constant_Reference
215 (Container : aliased Set;
216 Position : Cursor) return Constant_Reference_Type
219 if Checks and then Position.Container = null then
220 raise Constraint_Error with "Position cursor has no element";
223 if Checks and then Position.Container /= Container'Unrestricted_Access
225 raise Program_Error with
226 "Position cursor designates wrong container";
229 if Checks and then Position.Node.Element = null then
230 raise Program_Error with "Node has no element";
233 pragma Assert (Vet (Position), "bad cursor in Constant_Reference");
236 HT : Hash_Table_Type renames Position.Container.all.HT;
237 TC : constant Tamper_Counts_Access :=
238 HT.TC'Unrestricted_Access;
240 return R : constant Constant_Reference_Type :=
241 (Element => Position.Node.Element.all'Access,
242 Control => (Controlled with TC))
247 end Constant_Reference;
253 function Contains (Container : Set; Item : Element_Type) return Boolean is
255 return Find (Container, Item) /= No_Element;
264 Capacity : Count_Type := 0) return Set
272 elsif Capacity >= Source.Length then
277 with "Requested capacity is less than Source length";
280 return Target : Set do
281 Target.Reserve_Capacity (C);
282 Target.Assign (Source);
290 function Copy_Node (Source : Node_Access) return Node_Access is
291 E : Element_Access := new Element_Type'(Source
.Element
.all);
293 return new Node_Type
'(Element => E, Next => null);
305 (Container : in out Set;
311 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
313 if Checks and then X = null then
314 raise Constraint_Error with "attempt to delete element not in set";
321 (Container : in out Set;
322 Position : in out Cursor)
325 if Checks and then Position.Node = null then
326 raise Constraint_Error with "Position cursor equals No_Element";
329 if Checks and then Position.Node.Element = null then
330 raise Program_Error with "Position cursor is bad";
333 if Checks and then Position.Container /= Container'Unrestricted_Access
335 raise Program_Error with "Position cursor designates wrong set";
338 TC_Check (Container.HT.TC);
340 pragma Assert (Vet (Position), "Position cursor is bad");
342 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
344 Free (Position.Node);
345 Position.Container := null;
353 (Target : in out Set;
356 Src_HT : Hash_Table_Type renames Source'Unrestricted_Access.HT;
357 Tgt_Node : Node_Access;
360 if Target'Address = Source'Address then
365 if Src_HT.Length = 0 then
369 TC_Check (Target.HT.TC);
371 if Src_HT.Length < Target.HT.Length then
373 Src_Node : Node_Access;
376 Src_Node := HT_Ops.First (Src_HT);
377 while Src_Node /= null loop
378 Tgt_Node := Element_Keys.Find (Target.HT, Src_Node.Element.all);
380 if Tgt_Node /= null then
381 HT_Ops.Delete_Node_Sans_Free (Target.HT, Tgt_Node);
385 Src_Node := HT_Ops.Next (Src_HT, Src_Node);
390 Tgt_Node := HT_Ops.First (Target.HT);
391 while Tgt_Node /= null loop
392 if Is_In (Src_HT, Tgt_Node) then
394 X : Node_Access := Tgt_Node;
396 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
397 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
402 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
408 function Difference (Left, Right : Set) return Set is
409 Left_HT : Hash_Table_Type renames Left'Unrestricted_Access.HT;
410 Right_HT : Hash_Table_Type renames Right'Unrestricted_Access.HT;
411 Buckets : HT_Types.Buckets_Access;
415 if Left'Address = Right'Address then
419 if Left.Length = 0 then
423 if Right.Length = 0 then
428 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
430 Buckets := HT_Ops.New_Buckets (Length => Size);
435 Iterate_Left : declare
436 procedure Process (L_Node : Node_Access);
439 new HT_Ops.Generic_Iteration (Process);
445 procedure Process (L_Node : Node_Access) is
447 if not Is_In (Right_HT, L_Node) then
449 -- Per AI05-0022, the container implementation is required
450 -- to detect element tampering by a generic actual
451 -- subprogram, hence the use of Checked_Index instead of a
452 -- simple invocation of generic formal Hash.
454 Indx : constant Hash_Type :=
455 HT_Ops.Checked_Index (Left_HT, Buckets.all, L_Node);
457 Bucket : Node_Access renames Buckets (Indx);
458 Src : Element_Type renames L_Node.Element.all;
459 Tgt : Element_Access := new Element_Type'(Src
);
462 Bucket
:= new Node_Type
'(Tgt, Bucket);
470 Length := Length + 1;
474 -- Start of processing for Iterate_Left
481 HT_Ops.Free_Hash_Table (Buckets);
485 return (Controlled with HT => (Buckets, Length, (Busy => 0, Lock => 0)));
492 function Element (Position : Cursor) return Element_Type is
494 if Checks and then Position.Node = null then
495 raise Constraint_Error with "Position cursor of equals No_Element";
498 if Checks and then Position.Node.Element = null then
499 -- handle dangling reference
500 raise Program_Error with "Position cursor is bad";
503 pragma Assert (Vet (Position), "bad cursor in function Element");
505 return Position.Node.Element.all;
508 ---------------------
509 -- Equivalent_Sets --
510 ---------------------
512 function Equivalent_Sets (Left, Right : Set) return Boolean is
514 return Is_Equivalent (Left.HT, Right.HT);
517 -------------------------
518 -- Equivalent_Elements --
519 -------------------------
521 function Equivalent_Elements (Left, Right : Cursor) return Boolean is
523 if Checks and then Left.Node = null then
524 raise Constraint_Error with
525 "Left cursor of Equivalent_Elements equals No_Element";
528 if Checks and then Right.Node = null then
529 raise Constraint_Error with
530 "Right cursor of Equivalent_Elements equals No_Element";
533 if Checks and then Left.Node.Element = null then
534 raise Program_Error with
535 "Left cursor of Equivalent_Elements is bad";
538 if Checks and then Right.Node.Element = null then
539 raise Program_Error with
540 "Right cursor of Equivalent_Elements is bad";
543 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
544 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
546 -- AI05-0022 requires that a container implementation detect element
547 -- tampering by a generic actual subprogram. However, the following case
548 -- falls outside the scope of that AI. Randy Brukardt explained on the
549 -- ARG list on 2013/02/07 that:
552 -- But for an operation like "<" [the ordered set analog of
553 -- Equivalent_Elements], there is no need to "dereference" a cursor
554 -- after the call to the generic formal parameter function, so nothing
555 -- bad could happen if tampering is undetected. And the operation can
556 -- safely return a result without a problem even if an element is
557 -- deleted from the container.
560 return Equivalent_Elements
561 (Left.Node.Element.all,
562 Right.Node.Element.all);
563 end Equivalent_Elements;
565 function Equivalent_Elements
567 Right : Element_Type) return Boolean
570 if Checks and then Left.Node = null then
571 raise Constraint_Error with
572 "Left cursor of Equivalent_Elements equals No_Element";
575 if Checks and then Left.Node.Element = null then
576 raise Program_Error with
577 "Left cursor of Equivalent_Elements is bad";
580 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
582 return Equivalent_Elements (Left.Node.Element.all, Right);
583 end Equivalent_Elements;
585 function Equivalent_Elements
586 (Left : Element_Type;
587 Right : Cursor) return Boolean
590 if Checks and then Right.Node = null then
591 raise Constraint_Error with
592 "Right cursor of Equivalent_Elements equals No_Element";
595 if Checks and then Right.Node.Element = null then
596 raise Program_Error with
597 "Right cursor of Equivalent_Elements is bad";
600 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
602 return Equivalent_Elements (Left, Right.Node.Element.all);
603 end Equivalent_Elements;
605 ---------------------
606 -- Equivalent_Keys --
607 ---------------------
609 function Equivalent_Keys
611 Node : Node_Access) return Boolean
614 return Equivalent_Elements (Key, Node.Element.all);
622 (Container : in out Set;
627 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
635 procedure Finalize (Container : in out Set) is
637 HT_Ops.Finalize (Container.HT);
640 procedure Finalize (Object : in out Iterator) is
642 if Object.Container /= null then
643 Unbusy (Object.Container.HT.TC);
653 Item : Element_Type) return Cursor
655 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
656 Node : constant Node_Access := Element_Keys.Find (HT, Item);
658 return (if Node = null then No_Element
659 else Cursor'(Container
'Unrestricted_Access, Node
));
666 function Find_Equal_Key
667 (R_HT
: Hash_Table_Type
;
668 L_Node
: Node_Access
) return Boolean
670 R_Index
: constant Hash_Type
:=
671 Element_Keys
.Index
(R_HT
, L_Node
.Element
.all);
673 R_Node
: Node_Access
:= R_HT
.Buckets
(R_Index
);
677 if R_Node
= null then
681 if L_Node
.Element
.all = R_Node
.Element
.all then
685 R_Node
:= Next
(R_Node
);
689 -------------------------
690 -- Find_Equivalent_Key --
691 -------------------------
693 function Find_Equivalent_Key
694 (R_HT
: Hash_Table_Type
;
695 L_Node
: Node_Access
) return Boolean
697 R_Index
: constant Hash_Type
:=
698 Element_Keys
.Index
(R_HT
, L_Node
.Element
.all);
700 R_Node
: Node_Access
:= R_HT
.Buckets
(R_Index
);
704 if R_Node
= null then
708 if Equivalent_Elements
(L_Node
.Element
.all, R_Node
.Element
.all) then
712 R_Node
:= Next
(R_Node
);
714 end Find_Equivalent_Key
;
720 function First
(Container
: Set
) return Cursor
is
721 Node
: constant Node_Access
:= HT_Ops
.First
(Container
.HT
);
723 return (if Node
= null then No_Element
724 else Cursor
'(Container'Unrestricted_Access, Node));
727 function First (Object : Iterator) return Cursor is
729 return Object.Container.First;
736 procedure Free (X : in out Node_Access) is
737 procedure Deallocate is
738 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
745 X.Next := X; -- detect mischief (in Vet)
748 Free_Element (X.Element);
760 ------------------------
761 -- Get_Element_Access --
762 ------------------------
764 function Get_Element_Access
765 (Position : Cursor) return not null Element_Access is
767 return Position.Node.Element;
768 end Get_Element_Access;
774 function Has_Element (Position : Cursor) return Boolean is
776 pragma Assert (Vet (Position), "bad cursor in Has_Element");
777 return Position.Node /= null;
784 function Hash_Node (Node : Node_Access) return Hash_Type is
786 return Hash (Node.Element.all);
794 (Container : in out Set;
795 New_Item : Element_Type)
803 Insert (Container, New_Item, Position, Inserted);
806 TE_Check (Container.HT.TC);
808 X := Position.Node.Element;
811 -- The element allocator may need an accessibility check in the
812 -- case the actual type is class-wide or has access discriminants
813 -- (see RM 4.8(10.1) and AI12-0035).
815 pragma Unsuppress (Accessibility_Check);
818 Position.Node.Element := new Element_Type'(New_Item
);
830 (Container
: in out Set
;
831 New_Item
: Element_Type
;
832 Position
: out Cursor
;
833 Inserted
: out Boolean)
836 Insert
(Container
.HT
, New_Item
, Position
.Node
, Inserted
);
837 Position
.Container
:= Container
'Unchecked_Access;
841 (Container
: in out Set
;
842 New_Item
: Element_Type
)
845 pragma Unreferenced
(Position
);
850 Insert
(Container
, New_Item
, Position
, Inserted
);
852 if Checks
and then not Inserted
then
853 raise Constraint_Error
with
854 "attempt to insert element already in set";
859 (HT
: in out Hash_Table_Type
;
860 New_Item
: Element_Type
;
861 Node
: out Node_Access
;
862 Inserted
: out Boolean)
864 function New_Node
(Next
: Node_Access
) return Node_Access
;
865 pragma Inline
(New_Node
);
867 procedure Local_Insert
is
868 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
874 function New_Node
(Next
: Node_Access
) return Node_Access
is
876 -- The element allocator may need an accessibility check in the case
877 -- the actual type is class-wide or has access discriminants (see
878 -- RM 4.8(10.1) and AI12-0035).
880 pragma Unsuppress
(Accessibility_Check
);
882 Element
: Element_Access
:= new Element_Type
'(New_Item);
885 return new Node_Type'(Element
, Next
);
889 Free_Element
(Element
);
893 -- Start of processing for Insert
896 if HT_Ops
.Capacity
(HT
) = 0 then
897 HT_Ops
.Reserve_Capacity
(HT
, 1);
900 Local_Insert
(HT
, New_Item
, Node
, Inserted
);
902 if Inserted
and then HT
.Length
> HT_Ops
.Capacity
(HT
) then
903 HT_Ops
.Reserve_Capacity
(HT
, HT
.Length
);
911 procedure Intersection
912 (Target
: in out Set
;
915 Src_HT
: Hash_Table_Type
renames Source
'Unrestricted_Access.HT
;
916 Tgt_Node
: Node_Access
;
919 if Target
'Address = Source
'Address then
923 if Source
.Length
= 0 then
928 TC_Check
(Target
.HT
.TC
);
930 Tgt_Node
:= HT_Ops
.First
(Target
.HT
);
931 while Tgt_Node
/= null loop
932 if Is_In
(Src_HT
, Tgt_Node
) then
933 Tgt_Node
:= HT_Ops
.Next
(Target
.HT
, Tgt_Node
);
937 X
: Node_Access
:= Tgt_Node
;
939 Tgt_Node
:= HT_Ops
.Next
(Target
.HT
, Tgt_Node
);
940 HT_Ops
.Delete_Node_Sans_Free
(Target
.HT
, X
);
947 function Intersection
(Left
, Right
: Set
) return Set
is
948 Left_HT
: Hash_Table_Type
renames Left
'Unrestricted_Access.HT
;
949 Right_HT
: Hash_Table_Type
renames Right
'Unrestricted_Access.HT
;
950 Buckets
: HT_Types
.Buckets_Access
;
954 if Left
'Address = Right
'Address then
958 Length
:= Count_Type
'Min (Left
.Length
, Right
.Length
);
965 Size
: constant Hash_Type
:= Prime_Numbers
.To_Prime
(Length
);
967 Buckets
:= HT_Ops
.New_Buckets
(Length
=> Size
);
972 Iterate_Left
: declare
973 procedure Process
(L_Node
: Node_Access
);
976 new HT_Ops
.Generic_Iteration
(Process
);
982 procedure Process
(L_Node
: Node_Access
) is
984 if Is_In
(Right_HT
, L_Node
) then
986 -- Per AI05-0022, the container implementation is required
987 -- to detect element tampering by a generic actual
988 -- subprogram, hence the use of Checked_Index instead of a
989 -- simple invocation of generic formal Hash.
991 Indx
: constant Hash_Type
:=
992 HT_Ops
.Checked_Index
(Left_HT
, Buckets
.all, L_Node
);
994 Bucket
: Node_Access
renames Buckets
(Indx
);
996 Src
: Element_Type
renames L_Node
.Element
.all;
997 Tgt
: Element_Access
:= new Element_Type
'(Src);
1000 Bucket := new Node_Type'(Tgt
, Bucket
);
1008 Length
:= Length
+ 1;
1012 -- Start of processing for Iterate_Left
1019 HT_Ops
.Free_Hash_Table
(Buckets
);
1023 return (Controlled
with HT
=> (Buckets
, Length
, (Busy
=> 0, Lock
=> 0)));
1030 function Is_Empty
(Container
: Set
) return Boolean is
1032 return Container
.HT
.Length
= 0;
1040 (HT
: aliased in out Hash_Table_Type
;
1041 Key
: Node_Access
) return Boolean
1044 return Element_Keys
.Find
(HT
, Key
.Element
.all) /= null;
1053 Of_Set
: Set
) return Boolean
1055 Subset_HT
: Hash_Table_Type
renames Subset
'Unrestricted_Access.HT
;
1056 Of_Set_HT
: Hash_Table_Type
renames Of_Set
'Unrestricted_Access.HT
;
1057 Subset_Node
: Node_Access
;
1060 if Subset
'Address = Of_Set
'Address then
1064 if Subset
.Length
> Of_Set
.Length
then
1068 Subset_Node
:= HT_Ops
.First
(Subset_HT
);
1069 while Subset_Node
/= null loop
1070 if not Is_In
(Of_Set_HT
, Subset_Node
) then
1074 Subset_Node
:= HT_Ops
.Next
(Subset_HT
, Subset_Node
);
1086 Process
: not null access procedure (Position
: Cursor
))
1088 procedure Process_Node
(Node
: Node_Access
);
1089 pragma Inline
(Process_Node
);
1091 procedure Iterate
is
1092 new HT_Ops
.Generic_Iteration
(Process_Node
);
1098 procedure Process_Node
(Node
: Node_Access
) is
1100 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1103 Busy : With_Busy (Container.HT.TC'Unrestricted_Access);
1105 -- Start of processing for Iterate
1108 Iterate (Container.HT);
1111 function Iterate (Container : Set)
1112 return Set_Iterator_Interfaces.Forward_Iterator'Class
1115 return It : constant Iterator :=
1116 Iterator'(Limited_Controlled
with
1117 Container
=> Container
'Unrestricted_Access)
1119 Busy
(Container
.HT
.TC
'Unrestricted_Access.all);
1127 function Length
(Container
: Set
) return Count_Type
is
1129 return Container
.HT
.Length
;
1136 procedure Move
(Target
: in out Set
; Source
: in out Set
) is
1138 HT_Ops
.Move
(Target
=> Target
.HT
, Source
=> Source
.HT
);
1145 function Next
(Node
: Node_Access
) return Node_Access
is
1150 function Next
(Position
: Cursor
) return Cursor
is
1152 if Position
.Node
= null then
1156 if Checks
and then Position
.Node
.Element
= null then
1157 raise Program_Error
with "bad cursor in Next";
1160 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1163 HT
: Hash_Table_Type
renames Position
.Container
.HT
;
1164 Node
: constant Node_Access
:= HT_Ops
.Next
(HT
, Position
.Node
);
1166 return (if Node
= null then No_Element
1167 else Cursor
'(Position.Container, Node));
1171 procedure Next (Position : in out Cursor) is
1173 Position := Next (Position);
1178 Position : Cursor) return Cursor
1181 if Position.Container = null then
1185 if Checks and then Position.Container /= Object.Container then
1186 raise Program_Error with
1187 "Position cursor of Next designates wrong set";
1190 return Next (Position);
1197 function Overlap (Left, Right : Set) return Boolean is
1198 Left_HT : Hash_Table_Type renames Left'Unrestricted_Access.HT;
1199 Right_HT : Hash_Table_Type renames Right'Unrestricted_Access.HT;
1200 Left_Node : Node_Access;
1203 if Right.Length = 0 then
1207 if Left'Address = Right'Address then
1211 Left_Node := HT_Ops.First (Left_HT);
1212 while Left_Node /= null loop
1213 if Is_In (Right_HT, Left_Node) then
1217 Left_Node := HT_Ops.Next (Left_HT, Left_Node);
1223 ----------------------
1224 -- Pseudo_Reference --
1225 ----------------------
1227 function Pseudo_Reference
1228 (Container : aliased Set'Class) return Reference_Control_Type
1230 TC : constant Tamper_Counts_Access :=
1231 Container.HT.TC'Unrestricted_Access;
1233 return R : constant Reference_Control_Type := (Controlled with TC) do
1236 end Pseudo_Reference;
1242 procedure Query_Element
1244 Process : not null access procedure (Element : Element_Type))
1247 if Checks and then Position.Node = null then
1248 raise Constraint_Error with
1249 "Position cursor of Query_Element equals No_Element";
1252 if Checks and then Position.Node.Element = null then
1253 raise Program_Error with "bad cursor in Query_Element";
1256 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1259 HT : Hash_Table_Type renames
1260 Position.Container'Unrestricted_Access.all.HT;
1261 Lock : With_Lock (HT.TC'Unrestricted_Access);
1263 Process (Position.Node.Element.all);
1272 (Stream : not null access Root_Stream_Type'Class;
1273 Container : out Set)
1276 Read_Nodes (Stream, Container.HT);
1280 (Stream : not null access Root_Stream_Type'Class;
1284 raise Program_Error with "attempt to stream set cursor";
1288 (Stream : not null access Root_Stream_Type'Class;
1289 Item : out Constant_Reference_Type)
1292 raise Program_Error with "attempt to stream reference";
1300 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1302 X : Element_Access := new Element_Type'(Element_Type
'Input (Stream
));
1304 return new Node_Type
'(X, null);
1316 (Container : in out Set;
1317 New_Item : Element_Type)
1319 Node : constant Node_Access :=
1320 Element_Keys.Find (Container.HT, New_Item);
1323 pragma Warnings (Off, X);
1326 if Checks and then Node = null then
1327 raise Constraint_Error with
1328 "attempt to replace element not in set";
1331 TE_Check (Container.HT.TC);
1336 -- The element allocator may need an accessibility check in the case
1337 -- the actual type is class-wide or has access discriminants (see
1338 -- RM 4.8(10.1) and AI12-0035).
1340 pragma Unsuppress (Accessibility_Check);
1343 Node.Element := new Element_Type'(New_Item
);
1349 ---------------------
1350 -- Replace_Element --
1351 ---------------------
1353 procedure Replace_Element
1354 (Container
: in out Set
;
1356 New_Item
: Element_Type
)
1359 if Checks
and then Position
.Node
= null then
1360 raise Constraint_Error
with "Position cursor equals No_Element";
1363 if Checks
and then Position
.Node
.Element
= null then
1364 raise Program_Error
with "bad cursor in Replace_Element";
1367 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
1369 raise Program_Error
with
1370 "Position cursor designates wrong set";
1373 pragma Assert
(Vet
(Position
), "bad cursor in Replace_Element");
1375 Replace_Element
(Container
.HT
, Position
.Node
, New_Item
);
1376 end Replace_Element
;
1378 ----------------------
1379 -- Reserve_Capacity --
1380 ----------------------
1382 procedure Reserve_Capacity
1383 (Container
: in out Set
;
1384 Capacity
: Count_Type
)
1387 HT_Ops
.Reserve_Capacity
(Container
.HT
, Capacity
);
1388 end Reserve_Capacity
;
1394 procedure Set_Next
(Node
: Node_Access
; Next
: Node_Access
) is
1399 --------------------------
1400 -- Symmetric_Difference --
1401 --------------------------
1403 procedure Symmetric_Difference
1404 (Target
: in out Set
;
1407 Tgt_HT
: Hash_Table_Type
renames Target
.HT
;
1408 Src_HT
: Hash_Table_Type
renames Source
.HT
'Unrestricted_Access.all;
1410 if Target
'Address = Source
'Address then
1415 TC_Check
(Tgt_HT
.TC
);
1418 N
: constant Count_Type
:= Target
.Length
+ Source
.Length
;
1420 if N
> HT_Ops
.Capacity
(Tgt_HT
) then
1421 HT_Ops
.Reserve_Capacity
(Tgt_HT
, N
);
1425 if Target
.Length
= 0 then
1426 Iterate_Source_When_Empty_Target
: declare
1427 procedure Process
(Src_Node
: Node_Access
);
1429 procedure Iterate
is new HT_Ops
.Generic_Iteration
(Process
);
1435 procedure Process
(Src_Node
: Node_Access
) is
1436 E
: Element_Type
renames Src_Node
.Element
.all;
1437 B
: Buckets_Type
renames Tgt_HT
.Buckets
.all;
1438 J
: constant Hash_Type
:= Hash
(E
) mod B
'Length;
1439 N
: Count_Type
renames Tgt_HT
.Length
;
1443 X
: Element_Access
:= new Element_Type
'(E);
1445 B (J) := new Node_Type'(X
, B
(J
));
1455 -- Per AI05-0022, the container implementation is required to
1456 -- detect element tampering by a generic actual subprogram.
1458 Lock_Tgt
: With_Lock
(Tgt_HT
.TC
'Unrestricted_Access);
1459 Lock_Src
: With_Lock
(Src_HT
.TC
'Unrestricted_Access);
1461 -- Start of processing for Iterate_Source_When_Empty_Target
1465 end Iterate_Source_When_Empty_Target
;
1468 Iterate_Source
: declare
1469 procedure Process
(Src_Node
: Node_Access
);
1471 procedure Iterate
is
1472 new HT_Ops
.Generic_Iteration
(Process
);
1478 procedure Process
(Src_Node
: Node_Access
) is
1479 E
: Element_Type
renames Src_Node
.Element
.all;
1480 B
: Buckets_Type
renames Tgt_HT
.Buckets
.all;
1481 J
: constant Hash_Type
:= Hash
(E
) mod B
'Length;
1482 N
: Count_Type
renames Tgt_HT
.Length
;
1485 if B
(J
) = null then
1487 X
: Element_Access
:= new Element_Type
'(E);
1489 B (J) := new Node_Type'(X
, null);
1498 elsif Equivalent_Elements
(E
, B
(J
).Element
.all) then
1500 X
: Node_Access
:= B
(J
);
1502 B
(J
) := B
(J
).Next
;
1509 Prev
: Node_Access
:= B
(J
);
1510 Curr
: Node_Access
:= Prev
.Next
;
1513 while Curr
/= null loop
1514 if Equivalent_Elements
(E
, Curr
.Element
.all) then
1515 Prev
.Next
:= Curr
.Next
;
1526 X
: Element_Access
:= new Element_Type
'(E);
1528 B (J) := new Node_Type'(X
, B
(J
));
1540 -- Per AI05-0022, the container implementation is required to
1541 -- detect element tampering by a generic actual subprogram.
1543 Lock_Tgt
: With_Lock
(Tgt_HT
.TC
'Unrestricted_Access);
1544 Lock_Src
: With_Lock
(Src_HT
.TC
'Unrestricted_Access);
1546 -- Start of processing for Iterate_Source
1552 end Symmetric_Difference
;
1554 function Symmetric_Difference
(Left
, Right
: Set
) return Set
is
1555 Left_HT
: Hash_Table_Type
renames Left
'Unrestricted_Access.HT
;
1556 Right_HT
: Hash_Table_Type
renames Right
'Unrestricted_Access.HT
;
1557 Buckets
: HT_Types
.Buckets_Access
;
1558 Length
: Count_Type
;
1561 if Left
'Address = Right
'Address then
1565 if Right
.Length
= 0 then
1569 if Left
.Length
= 0 then
1574 Size
: constant Hash_Type
:=
1575 Prime_Numbers
.To_Prime
(Left
.Length
+ Right
.Length
);
1577 Buckets
:= HT_Ops
.New_Buckets
(Length
=> Size
);
1582 Iterate_Left
: declare
1583 procedure Process
(L_Node
: Node_Access
);
1585 procedure Iterate
is
1586 new HT_Ops
.Generic_Iteration
(Process
);
1592 procedure Process
(L_Node
: Node_Access
) is
1594 if not Is_In
(Right_HT
, L_Node
) then
1596 E
: Element_Type
renames L_Node
.Element
.all;
1598 -- Per AI05-0022, the container implementation is required
1599 -- to detect element tampering by a generic actual
1600 -- subprogram, hence the use of Checked_Index instead of a
1601 -- simple invocation of generic formal Hash.
1603 J
: constant Hash_Type
:=
1604 HT_Ops
.Checked_Index
(Left_HT
, Buckets
.all, L_Node
);
1608 X
: Element_Access
:= new Element_Type
'(E);
1610 Buckets (J) := new Node_Type'(X
, Buckets
(J
));
1617 Length
:= Length
+ 1;
1622 -- Start of processing for Iterate_Left
1628 HT_Ops
.Free_Hash_Table
(Buckets
);
1632 Iterate_Right
: declare
1633 procedure Process
(R_Node
: Node_Access
);
1635 procedure Iterate
is
1636 new HT_Ops
.Generic_Iteration
(Process
);
1642 procedure Process
(R_Node
: Node_Access
) is
1644 if not Is_In
(Left_HT
, R_Node
) then
1646 E
: Element_Type
renames R_Node
.Element
.all;
1648 -- Per AI05-0022, the container implementation is required
1649 -- to detect element tampering by a generic actual
1650 -- subprogram, hence the use of Checked_Index instead of a
1651 -- simple invocation of generic formal Hash.
1653 J
: constant Hash_Type
:=
1654 HT_Ops
.Checked_Index
(Right_HT
, Buckets
.all, R_Node
);
1658 X
: Element_Access
:= new Element_Type
'(E);
1660 Buckets (J) := new Node_Type'(X
, Buckets
(J
));
1667 Length
:= Length
+ 1;
1672 -- Start of processing for Iterate_Right
1679 HT_Ops
.Free_Hash_Table
(Buckets
);
1683 return (Controlled
with HT
=> (Buckets
, Length
, (Busy
=> 0, Lock
=> 0)));
1684 end Symmetric_Difference
;
1690 function To_Set
(New_Item
: Element_Type
) return Set
is
1691 HT
: Hash_Table_Type
;
1694 pragma Unreferenced
(Node
, Inserted
);
1696 Insert
(HT
, New_Item
, Node
, Inserted
);
1697 return Set
'(Controlled with HT);
1705 (Target : in out Set;
1708 procedure Process (Src_Node : Node_Access);
1710 procedure Iterate is
1711 new HT_Ops.Generic_Iteration (Process);
1717 procedure Process (Src_Node : Node_Access) is
1718 Src : Element_Type renames Src_Node.Element.all;
1720 function New_Node (Next : Node_Access) return Node_Access;
1721 pragma Inline (New_Node);
1724 new Element_Keys.Generic_Conditional_Insert (New_Node);
1730 function New_Node (Next : Node_Access) return Node_Access is
1731 Tgt : Element_Access := new Element_Type'(Src
);
1733 return new Node_Type
'(Tgt, Next);
1740 Tgt_Node : Node_Access;
1742 pragma Unreferenced (Tgt_Node, Success);
1744 -- Start of processing for Process
1747 Insert (Target.HT, Src, Tgt_Node, Success);
1750 -- Start of processing for Union
1753 if Target'Address = Source'Address then
1757 TC_Check (Target.HT.TC);
1760 N : constant Count_Type := Target.Length + Source.Length;
1762 if N > HT_Ops.Capacity (Target.HT) then
1763 HT_Ops.Reserve_Capacity (Target.HT, N);
1767 Iterate (Source.HT);
1770 function Union (Left, Right : Set) return Set is
1771 Left_HT : Hash_Table_Type renames Left.HT'Unrestricted_Access.all;
1772 Right_HT : Hash_Table_Type renames Right.HT'Unrestricted_Access.all;
1773 Buckets : HT_Types.Buckets_Access;
1774 Length : Count_Type;
1777 if Left'Address = Right'Address then
1781 if Right.Length = 0 then
1785 if Left.Length = 0 then
1790 Size : constant Hash_Type :=
1791 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1793 Buckets := HT_Ops.New_Buckets (Length => Size);
1796 Iterate_Left : declare
1797 procedure Process (L_Node : Node_Access);
1799 procedure Iterate is
1800 new HT_Ops.Generic_Iteration (Process);
1806 procedure Process (L_Node : Node_Access) is
1807 Src : Element_Type renames L_Node.Element.all;
1808 J : constant Hash_Type := Hash (Src) mod Buckets'Length;
1809 Bucket : Node_Access renames Buckets (J);
1810 Tgt : Element_Access := new Element_Type'(Src
);
1812 Bucket
:= new Node_Type
'(Tgt, Bucket);
1819 -- Per AI05-0022, the container implementation is required to detect
1820 -- element tampering by a generic actual subprogram, hence the use of
1821 -- Checked_Index instead of a simple invocation of generic formal
1824 Lock_Left : With_Lock (Left_HT.TC'Unrestricted_Access);
1826 -- Start of processing for Iterate_Left
1832 HT_Ops.Free_Hash_Table (Buckets);
1836 Length := Left.Length;
1838 Iterate_Right : declare
1839 procedure Process (Src_Node : Node_Access);
1841 procedure Iterate is
1842 new HT_Ops.Generic_Iteration (Process);
1848 procedure Process (Src_Node : Node_Access) is
1849 Src : Element_Type renames Src_Node.Element.all;
1850 Idx : constant Hash_Type := Hash (Src) mod Buckets'Length;
1852 Tgt_Node : Node_Access := Buckets (Idx);
1855 while Tgt_Node /= null loop
1856 if Equivalent_Elements (Src, Tgt_Node.Element.all) then
1859 Tgt_Node := Next (Tgt_Node);
1863 Tgt : Element_Access := new Element_Type'(Src
);
1865 Buckets
(Idx
) := new Node_Type
'(Tgt, Buckets (Idx));
1872 Length := Length + 1;
1875 -- Per AI05-0022, the container implementation is required to detect
1876 -- element tampering by a generic actual subprogram, hence the use of
1877 -- Checked_Index instead of a simple invocation of generic formal
1880 Lock_Left : With_Lock (Left_HT.TC'Unrestricted_Access);
1881 Lock_Right : With_Lock (Right_HT.TC'Unrestricted_Access);
1883 -- Start of processing for Iterate_Right
1889 HT_Ops.Free_Hash_Table (Buckets);
1893 return (Controlled with HT => (Buckets, Length, (Busy => 0, Lock => 0)));
1900 function Vet (Position : Cursor) return Boolean is
1902 if Position.Node = null then
1903 return Position.Container = null;
1906 if Position.Container = null then
1910 if Position.Node.Next = Position.Node then
1914 if Position.Node.Element = null then
1919 HT : Hash_Table_Type renames Position.Container.HT;
1923 if HT.Length = 0 then
1927 if HT.Buckets = null
1928 or else HT.Buckets'Length = 0
1933 X := HT.Buckets (Element_Keys.Checked_Index
1935 Position.Node.Element.all));
1937 for J in 1 .. HT.Length loop
1938 if X = Position.Node then
1946 if X = X.Next then -- to prevent unnecessary looping
1962 (Stream : not null access Root_Stream_Type'Class;
1966 Write_Nodes (Stream, Container.HT);
1970 (Stream : not null access Root_Stream_Type'Class;
1974 raise Program_Error with "attempt to stream set cursor";
1978 (Stream : not null access Root_Stream_Type'Class;
1979 Item : Constant_Reference_Type)
1982 raise Program_Error with "attempt to stream reference";
1989 procedure Write_Node
1990 (Stream : not null access Root_Stream_Type'Class;
1994 Element_Type'Output (Stream, Node.Element.all);
1997 package body Generic_Keys is
1999 -----------------------
2000 -- Local Subprograms --
2001 -----------------------
2003 function Equivalent_Key_Node
2005 Node : Node_Access) return Boolean;
2006 pragma Inline (Equivalent_Key_Node);
2008 --------------------------
2009 -- Local Instantiations --
2010 --------------------------
2013 new Hash_Tables.Generic_Keys
2014 (HT_Types => HT_Types,
2016 Set_Next => Set_Next,
2017 Key_Type => Key_Type,
2019 Equivalent_Keys => Equivalent_Key_Node);
2021 ------------------------
2022 -- Constant_Reference --
2023 ------------------------
2025 function Constant_Reference
2026 (Container : aliased Set;
2027 Key : Key_Type) return Constant_Reference_Type
2029 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
2030 Node : constant Node_Access := Key_Keys.Find (HT, Key);
2033 if Checks and then Node = null then
2034 raise Constraint_Error with "Key not in set";
2037 if Checks and then Node.Element = null then
2038 raise Program_Error with "Node has no element";
2042 TC : constant Tamper_Counts_Access :=
2043 HT.TC'Unrestricted_Access;
2045 return R : constant Constant_Reference_Type :=
2046 (Element => Node.Element.all'Access,
2047 Control => (Controlled with TC))
2052 end Constant_Reference;
2060 Key : Key_Type) return Boolean
2063 return Find (Container, Key) /= No_Element;
2071 (Container : in out Set;
2077 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
2079 if Checks and then X = null then
2080 raise Constraint_Error with "key not in set";
2092 Key : Key_Type) return Element_Type
2094 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
2095 Node : constant Node_Access := Key_Keys.Find (HT, Key);
2098 if Checks and then Node = null then
2099 raise Constraint_Error with "key not in set";
2102 return Node.Element.all;
2105 -------------------------
2106 -- Equivalent_Key_Node --
2107 -------------------------
2109 function Equivalent_Key_Node
2111 Node : Node_Access) return Boolean is
2113 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element.all));
2114 end Equivalent_Key_Node;
2121 (Container : in out Set;
2126 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
2134 procedure Finalize (Control : in out Reference_Control_Type) is
2136 if Control.Container /= null then
2137 Impl.Reference_Control_Type (Control).Finalize;
2139 if Checks and then Hash (Key (Control.Old_Pos)) /= Control.Old_Hash
2141 HT_Ops.Delete_Node_At_Index
2142 (Control.Container.HT, Control.Index, Control.Old_Pos.Node);
2143 raise Program_Error;
2146 Control.Container := null;
2156 Key : Key_Type) return Cursor
2158 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
2159 Node : constant Node_Access := Key_Keys.Find (HT, Key);
2161 return (if Node = null then No_Element
2162 else Cursor'(Container
'Unrestricted_Access, Node
));
2169 function Key
(Position
: Cursor
) return Key_Type
is
2171 if Checks
and then Position
.Node
= null then
2172 raise Constraint_Error
with
2173 "Position cursor equals No_Element";
2176 if Checks
and then Position
.Node
.Element
= null then
2177 raise Program_Error
with "Position cursor is bad";
2180 pragma Assert
(Vet
(Position
), "bad cursor in function Key");
2182 return Key
(Position
.Node
.Element
.all);
2190 (Stream
: not null access Root_Stream_Type
'Class;
2191 Item
: out Reference_Type
)
2194 raise Program_Error
with "attempt to stream reference";
2197 ------------------------------
2198 -- Reference_Preserving_Key --
2199 ------------------------------
2201 function Reference_Preserving_Key
2202 (Container
: aliased in out Set
;
2203 Position
: Cursor
) return Reference_Type
2206 if Checks
and then Position
.Container
= null then
2207 raise Constraint_Error
with "Position cursor has no element";
2210 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2212 raise Program_Error
with
2213 "Position cursor designates wrong container";
2216 if Checks
and then Position
.Node
.Element
= null then
2217 raise Program_Error
with "Node has no element";
2222 "bad cursor in function Reference_Preserving_Key");
2225 HT
: Hash_Table_Type
renames Container
.HT
;
2227 return R
: constant Reference_Type
:=
2228 (Element
=> Position
.Node
.Element
.all'Access,
2231 HT
.TC
'Unrestricted_Access,
2232 Container
=> Container
'Access,
2233 Index
=> HT_Ops
.Index
(HT
, Position
.Node
),
2234 Old_Pos
=> Position
,
2235 Old_Hash
=> Hash
(Key
(Position
))))
2240 end Reference_Preserving_Key
;
2242 function Reference_Preserving_Key
2243 (Container
: aliased in out Set
;
2244 Key
: Key_Type
) return Reference_Type
2246 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.HT
, Key
);
2249 if Checks
and then Node
= null then
2250 raise Constraint_Error
with "Key not in set";
2253 if Checks
and then Node
.Element
= null then
2254 raise Program_Error
with "Node has no element";
2258 HT
: Hash_Table_Type
renames Container
.HT
;
2259 P
: constant Cursor
:= Find
(Container
, Key
);
2261 return R
: constant Reference_Type
:=
2262 (Element
=> Node
.Element
.all'Access,
2265 HT
.TC
'Unrestricted_Access,
2266 Container
=> Container
'Access,
2267 Index
=> HT_Ops
.Index
(HT
, P
.Node
),
2269 Old_Hash
=> Hash
(Key
)))
2274 end Reference_Preserving_Key
;
2281 (Container
: in out Set
;
2283 New_Item
: Element_Type
)
2285 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.HT
, Key
);
2288 if Checks
and then Node
= null then
2289 raise Constraint_Error
with
2290 "attempt to replace key not in set";
2293 Replace_Element
(Container
.HT
, Node
, New_Item
);
2296 -----------------------------------
2297 -- Update_Element_Preserving_Key --
2298 -----------------------------------
2300 procedure Update_Element_Preserving_Key
2301 (Container
: in out Set
;
2303 Process
: not null access
2304 procedure (Element
: in out Element_Type
))
2306 HT
: Hash_Table_Type
renames Container
.HT
;
2310 if Checks
and then Position
.Node
= null then
2311 raise Constraint_Error
with
2312 "Position cursor equals No_Element";
2316 (Position
.Node
.Element
= null
2317 or else Position
.Node
.Next
= Position
.Node
)
2319 raise Program_Error
with "Position cursor is bad";
2322 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2324 raise Program_Error
with
2325 "Position cursor designates wrong set";
2330 or else HT
.Buckets
'Length = 0
2331 or else HT
.Length
= 0)
2333 raise Program_Error
with "Position cursor is bad (set is empty)";
2338 "bad cursor in Update_Element_Preserving_Key");
2340 -- Per AI05-0022, the container implementation is required to detect
2341 -- element tampering by a generic actual subprogram.
2344 E
: Element_Type
renames Position
.Node
.Element
.all;
2345 K
: constant Key_Type
:= Key
(E
);
2346 Lock
: With_Lock
(HT
.TC
'Unrestricted_Access);
2348 Indx
:= HT_Ops
.Index
(HT
, Position
.Node
);
2351 if Equivalent_Keys
(K
, Key
(E
)) then
2356 if HT
.Buckets
(Indx
) = Position
.Node
then
2357 HT
.Buckets
(Indx
) := Position
.Node
.Next
;
2361 Prev
: Node_Access
:= HT
.Buckets
(Indx
);
2364 while Prev
.Next
/= Position
.Node
loop
2367 if Checks
and then Prev
= null then
2368 raise Program_Error
with
2369 "Position cursor is bad (node not found)";
2373 Prev
.Next
:= Position
.Node
.Next
;
2377 HT
.Length
:= HT
.Length
- 1;
2380 X
: Node_Access
:= Position
.Node
;
2386 raise Program_Error
with "key was modified";
2387 end Update_Element_Preserving_Key
;
2394 (Stream
: not null access Root_Stream_Type
'Class;
2395 Item
: Reference_Type
)
2398 raise Program_Error
with "attempt to stream reference";
2403 end Ada
.Containers
.Indefinite_Hashed_Sets
;