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 Warnings
(Off
, "variable ""Busy*"" is not referenced");
47 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
48 -- See comment in Ada.Containers.Helpers
50 -----------------------
51 -- Local Subprograms --
52 -----------------------
54 procedure Assign
(Node
: Node_Access
; Item
: Element_Type
);
55 pragma Inline
(Assign
);
57 function Copy_Node
(Source
: Node_Access
) return Node_Access
;
58 pragma Inline
(Copy_Node
);
60 function Equivalent_Keys
62 Node
: Node_Access
) return Boolean;
63 pragma Inline
(Equivalent_Keys
);
65 function Find_Equal_Key
66 (R_HT
: Hash_Table_Type
;
67 L_Node
: Node_Access
) return Boolean;
69 function Find_Equivalent_Key
70 (R_HT
: Hash_Table_Type
;
71 L_Node
: Node_Access
) return Boolean;
73 procedure Free
(X
: in out Node_Access
);
75 function Hash_Node
(Node
: Node_Access
) return Hash_Type
;
76 pragma Inline
(Hash_Node
);
79 (HT
: in out Hash_Table_Type
;
80 New_Item
: Element_Type
;
81 Node
: out Node_Access
;
82 Inserted
: out Boolean);
85 (HT
: aliased in out Hash_Table_Type
;
86 Key
: Node_Access
) return Boolean;
87 pragma Inline
(Is_In
);
89 function Next
(Node
: Node_Access
) return Node_Access
;
92 function Read_Node
(Stream
: not null access Root_Stream_Type
'Class)
94 pragma Inline
(Read_Node
);
96 procedure Set_Next
(Node
: Node_Access
; Next
: Node_Access
);
97 pragma Inline
(Set_Next
);
99 function Vet
(Position
: Cursor
) return Boolean;
102 (Stream
: not null access Root_Stream_Type
'Class;
104 pragma Inline
(Write_Node
);
106 --------------------------
107 -- Local Instantiations --
108 --------------------------
110 procedure Free_Element
is
111 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
113 package HT_Ops
is new Hash_Tables
.Generic_Operations
114 (HT_Types
=> HT_Types
,
115 Hash_Node
=> Hash_Node
,
117 Set_Next
=> Set_Next
,
118 Copy_Node
=> Copy_Node
,
121 package Element_Keys
is new Hash_Tables
.Generic_Keys
122 (HT_Types
=> HT_Types
,
124 Set_Next
=> Set_Next
,
125 Key_Type
=> Element_Type
,
127 Equivalent_Keys
=> Equivalent_Keys
);
130 new HT_Ops
.Generic_Equal
(Find_Equal_Key
);
132 function Is_Equivalent
is
133 new HT_Ops
.Generic_Equal
(Find_Equivalent_Key
);
135 procedure Read_Nodes
is
136 new HT_Ops
.Generic_Read
(Read_Node
);
138 procedure Replace_Element
is
139 new Element_Keys
.Generic_Replace_Element
(Hash_Node
, Assign
);
141 procedure Write_Nodes
is
142 new HT_Ops
.Generic_Write
(Write_Node
);
148 function "=" (Left
, Right
: Set
) return Boolean is
150 return Is_Equal
(Left
.HT
, Right
.HT
);
157 procedure Adjust
(Container
: in out Set
) is
159 HT_Ops
.Adjust
(Container
.HT
);
166 procedure Assign
(Node
: Node_Access
; Item
: Element_Type
) is
167 X
: Element_Access
:= Node
.Element
;
169 -- The element allocator may need an accessibility check in the case the
170 -- actual type is class-wide or has access discriminants (RM 4.8(10.1)
173 pragma Unsuppress
(Accessibility_Check
);
176 Node
.Element
:= new Element_Type
'(Item);
180 procedure Assign (Target : in out Set; Source : Set) is
182 if Target'Address = Source'Address then
186 Target.Union (Source);
194 function Capacity (Container : Set) return Count_Type is
196 return HT_Ops.Capacity (Container.HT);
203 procedure Clear (Container : in out Set) is
205 HT_Ops.Clear (Container.HT);
208 ------------------------
209 -- Constant_Reference --
210 ------------------------
212 function Constant_Reference
213 (Container : aliased Set;
214 Position : Cursor) return Constant_Reference_Type
217 if Checks and then Position.Container = null then
218 raise Constraint_Error with "Position cursor has no element";
221 if Checks and then Position.Container /= Container'Unrestricted_Access
223 raise Program_Error with
224 "Position cursor designates wrong container";
227 if Checks and then Position.Node.Element = null then
228 raise Program_Error with "Node has no element";
231 pragma Assert (Vet (Position), "bad cursor in Constant_Reference");
234 HT : Hash_Table_Type renames Position.Container.all.HT;
235 TC : constant Tamper_Counts_Access :=
236 HT.TC'Unrestricted_Access;
238 return R : constant Constant_Reference_Type :=
239 (Element => Position.Node.Element.all'Access,
240 Control => (Controlled with TC))
245 end Constant_Reference;
251 function Contains (Container : Set; Item : Element_Type) return Boolean is
253 return Find (Container, Item) /= No_Element;
262 Capacity : Count_Type := 0) return Set
267 if Capacity < Source.Length then
268 if Checks and then Capacity /= 0 then
270 with "Requested capacity is less than Source length";
278 return Target : Set do
279 Target.Reserve_Capacity (C);
280 Target.Assign (Source);
288 function Copy_Node (Source : Node_Access) return Node_Access is
289 E : Element_Access := new Element_Type'(Source
.Element
.all);
291 return new Node_Type
'(Element => E, Next => null);
303 (Container : in out Set;
309 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
311 if Checks and then X = null then
312 raise Constraint_Error with "attempt to delete element not in set";
319 (Container : in out Set;
320 Position : in out Cursor)
323 if Checks and then Position.Node = null then
324 raise Constraint_Error with "Position cursor equals No_Element";
327 if Checks and then Position.Node.Element = null then
328 raise Program_Error with "Position cursor is bad";
331 if Checks and then Position.Container /= Container'Unrestricted_Access
333 raise Program_Error with "Position cursor designates wrong set";
336 TC_Check (Container.HT.TC);
338 pragma Assert (Vet (Position), "Position cursor is bad");
340 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
342 Free (Position.Node);
343 Position.Container := null;
351 (Target : in out Set;
354 Src_HT : Hash_Table_Type renames Source'Unrestricted_Access.HT;
355 Tgt_Node : Node_Access;
358 if Target'Address = Source'Address then
363 if Src_HT.Length = 0 then
367 TC_Check (Target.HT.TC);
369 if Src_HT.Length < Target.HT.Length then
371 Src_Node : Node_Access;
374 Src_Node := HT_Ops.First (Src_HT);
375 while Src_Node /= null loop
376 Tgt_Node := Element_Keys.Find (Target.HT, Src_Node.Element.all);
378 if Tgt_Node /= null then
379 HT_Ops.Delete_Node_Sans_Free (Target.HT, Tgt_Node);
383 Src_Node := HT_Ops.Next (Src_HT, Src_Node);
388 Tgt_Node := HT_Ops.First (Target.HT);
389 while Tgt_Node /= null loop
390 if Is_In (Src_HT, Tgt_Node) then
392 X : Node_Access := Tgt_Node;
394 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
395 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
400 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
406 function Difference (Left, Right : Set) return Set is
407 Left_HT : Hash_Table_Type renames Left'Unrestricted_Access.HT;
408 Right_HT : Hash_Table_Type renames Right'Unrestricted_Access.HT;
409 Buckets : HT_Types.Buckets_Access;
413 if Left'Address = Right'Address then
417 if Left.Length = 0 then
421 if Right.Length = 0 then
426 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
428 Buckets := HT_Ops.New_Buckets (Length => Size);
433 Iterate_Left : declare
434 procedure Process (L_Node : Node_Access);
437 new HT_Ops.Generic_Iteration (Process);
443 procedure Process (L_Node : Node_Access) is
445 if not Is_In (Right_HT, L_Node) then
447 -- Per AI05-0022, the container implementation is required
448 -- to detect element tampering by a generic actual
449 -- subprogram, hence the use of Checked_Index instead of a
450 -- simple invocation of generic formal Hash.
452 Indx : constant Hash_Type :=
453 HT_Ops.Checked_Index (Left_HT, Buckets.all, L_Node);
455 Bucket : Node_Access renames Buckets (Indx);
456 Src : Element_Type renames L_Node.Element.all;
457 Tgt : Element_Access := new Element_Type'(Src
);
460 Bucket
:= new Node_Type
'(Tgt, Bucket);
468 Length := Length + 1;
472 -- Start of processing for Iterate_Left
479 HT_Ops.Free_Hash_Table (Buckets);
483 return (Controlled with HT => (Buckets, Length, (Busy => 0, Lock => 0)));
490 function Element (Position : Cursor) return Element_Type is
492 if Checks and then Position.Node = null then
493 raise Constraint_Error with "Position cursor of equals No_Element";
496 if Checks and then Position.Node.Element = null then
497 -- handle dangling reference
498 raise Program_Error with "Position cursor is bad";
501 pragma Assert (Vet (Position), "bad cursor in function Element");
503 return Position.Node.Element.all;
506 ---------------------
507 -- Equivalent_Sets --
508 ---------------------
510 function Equivalent_Sets (Left, Right : Set) return Boolean is
512 return Is_Equivalent (Left.HT, Right.HT);
515 -------------------------
516 -- Equivalent_Elements --
517 -------------------------
519 function Equivalent_Elements (Left, Right : Cursor) return Boolean is
521 if Checks and then Left.Node = null then
522 raise Constraint_Error with
523 "Left cursor of Equivalent_Elements equals No_Element";
526 if Checks and then Right.Node = null then
527 raise Constraint_Error with
528 "Right cursor of Equivalent_Elements equals No_Element";
531 if Checks and then Left.Node.Element = null then
532 raise Program_Error with
533 "Left cursor of Equivalent_Elements is bad";
536 if Checks and then Right.Node.Element = null then
537 raise Program_Error with
538 "Right cursor of Equivalent_Elements is bad";
541 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
542 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
544 -- AI05-0022 requires that a container implementation detect element
545 -- tampering by a generic actual subprogram. However, the following case
546 -- falls outside the scope of that AI. Randy Brukardt explained on the
547 -- ARG list on 2013/02/07 that:
550 -- But for an operation like "<" [the ordered set analog of
551 -- Equivalent_Elements], there is no need to "dereference" a cursor
552 -- after the call to the generic formal parameter function, so nothing
553 -- bad could happen if tampering is undetected. And the operation can
554 -- safely return a result without a problem even if an element is
555 -- deleted from the container.
558 return Equivalent_Elements
559 (Left.Node.Element.all,
560 Right.Node.Element.all);
561 end Equivalent_Elements;
563 function Equivalent_Elements
565 Right : Element_Type) return Boolean
568 if Checks and then Left.Node = null then
569 raise Constraint_Error with
570 "Left cursor of Equivalent_Elements equals No_Element";
573 if Checks and then Left.Node.Element = null then
574 raise Program_Error with
575 "Left cursor of Equivalent_Elements is bad";
578 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
580 return Equivalent_Elements (Left.Node.Element.all, Right);
581 end Equivalent_Elements;
583 function Equivalent_Elements
584 (Left : Element_Type;
585 Right : Cursor) return Boolean
588 if Checks and then Right.Node = null then
589 raise Constraint_Error with
590 "Right cursor of Equivalent_Elements equals No_Element";
593 if Checks and then Right.Node.Element = null then
594 raise Program_Error with
595 "Right cursor of Equivalent_Elements is bad";
598 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
600 return Equivalent_Elements (Left, Right.Node.Element.all);
601 end Equivalent_Elements;
603 ---------------------
604 -- Equivalent_Keys --
605 ---------------------
607 function Equivalent_Keys
609 Node : Node_Access) return Boolean
612 return Equivalent_Elements (Key, Node.Element.all);
620 (Container : in out Set;
625 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
633 procedure Finalize (Container : in out Set) is
635 HT_Ops.Finalize (Container.HT);
638 procedure Finalize (Object : in out Iterator) is
640 if Object.Container /= null then
641 Unbusy (Object.Container.HT.TC);
651 Item : Element_Type) return Cursor
653 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
654 Node : constant Node_Access := Element_Keys.Find (HT, Item);
656 return (if Node = null then No_Element
657 else Cursor'(Container
'Unrestricted_Access, Node
));
664 function Find_Equal_Key
665 (R_HT
: Hash_Table_Type
;
666 L_Node
: Node_Access
) return Boolean
668 R_Index
: constant Hash_Type
:=
669 Element_Keys
.Index
(R_HT
, L_Node
.Element
.all);
671 R_Node
: Node_Access
:= R_HT
.Buckets
(R_Index
);
675 if R_Node
= null then
679 if L_Node
.Element
.all = R_Node
.Element
.all then
683 R_Node
:= Next
(R_Node
);
687 -------------------------
688 -- Find_Equivalent_Key --
689 -------------------------
691 function Find_Equivalent_Key
692 (R_HT
: Hash_Table_Type
;
693 L_Node
: Node_Access
) return Boolean
695 R_Index
: constant Hash_Type
:=
696 Element_Keys
.Index
(R_HT
, L_Node
.Element
.all);
698 R_Node
: Node_Access
:= R_HT
.Buckets
(R_Index
);
702 if R_Node
= null then
706 if Equivalent_Elements
(L_Node
.Element
.all, R_Node
.Element
.all) then
710 R_Node
:= Next
(R_Node
);
712 end Find_Equivalent_Key
;
718 function First
(Container
: Set
) return Cursor
is
719 Node
: constant Node_Access
:= HT_Ops
.First
(Container
.HT
);
721 return (if Node
= null then No_Element
722 else Cursor
'(Container'Unrestricted_Access, Node));
725 function First (Object : Iterator) return Cursor is
727 return Object.Container.First;
734 procedure Free (X : in out Node_Access) is
735 procedure Deallocate is
736 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
743 X.Next := X; -- detect mischief (in Vet)
746 Free_Element (X.Element);
758 ------------------------
759 -- Get_Element_Access --
760 ------------------------
762 function Get_Element_Access
763 (Position : Cursor) return not null Element_Access is
765 return Position.Node.Element;
766 end Get_Element_Access;
772 function Has_Element (Position : Cursor) return Boolean is
774 pragma Assert (Vet (Position), "bad cursor in Has_Element");
775 return Position.Node /= null;
782 function Hash_Node (Node : Node_Access) return Hash_Type is
784 return Hash (Node.Element.all);
792 (Container : in out Set;
793 New_Item : Element_Type)
801 Insert (Container, New_Item, Position, Inserted);
804 TE_Check (Container.HT.TC);
806 X := Position.Node.Element;
809 -- The element allocator may need an accessibility check in the
810 -- case the actual type is class-wide or has access discriminants
811 -- (see RM 4.8(10.1) and AI12-0035).
813 pragma Unsuppress (Accessibility_Check);
816 Position.Node.Element := new Element_Type'(New_Item
);
828 (Container
: in out Set
;
829 New_Item
: Element_Type
;
830 Position
: out Cursor
;
831 Inserted
: out Boolean)
834 Insert
(Container
.HT
, New_Item
, Position
.Node
, Inserted
);
835 Position
.Container
:= Container
'Unchecked_Access;
839 (Container
: in out Set
;
840 New_Item
: Element_Type
)
843 pragma Unreferenced
(Position
);
848 Insert
(Container
, New_Item
, Position
, Inserted
);
850 if Checks
and then not Inserted
then
851 raise Constraint_Error
with
852 "attempt to insert element already in set";
857 (HT
: in out Hash_Table_Type
;
858 New_Item
: Element_Type
;
859 Node
: out Node_Access
;
860 Inserted
: out Boolean)
862 function New_Node
(Next
: Node_Access
) return Node_Access
;
863 pragma Inline
(New_Node
);
865 procedure Local_Insert
is
866 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
872 function New_Node
(Next
: Node_Access
) return Node_Access
is
874 -- The element allocator may need an accessibility check in the case
875 -- the actual type is class-wide or has access discriminants (see
876 -- RM 4.8(10.1) and AI12-0035).
878 pragma Unsuppress
(Accessibility_Check
);
880 Element
: Element_Access
:= new Element_Type
'(New_Item);
883 return new Node_Type'(Element
, Next
);
887 Free_Element
(Element
);
891 -- Start of processing for Insert
894 if HT_Ops
.Capacity
(HT
) = 0 then
895 HT_Ops
.Reserve_Capacity
(HT
, 1);
898 Local_Insert
(HT
, New_Item
, Node
, Inserted
);
900 if Inserted
and then HT
.Length
> HT_Ops
.Capacity
(HT
) then
901 HT_Ops
.Reserve_Capacity
(HT
, HT
.Length
);
909 procedure Intersection
910 (Target
: in out Set
;
913 Src_HT
: Hash_Table_Type
renames Source
'Unrestricted_Access.HT
;
914 Tgt_Node
: Node_Access
;
917 if Target
'Address = Source
'Address then
921 if Source
.Length
= 0 then
926 TC_Check
(Target
.HT
.TC
);
928 Tgt_Node
:= HT_Ops
.First
(Target
.HT
);
929 while Tgt_Node
/= null loop
930 if Is_In
(Src_HT
, Tgt_Node
) then
931 Tgt_Node
:= HT_Ops
.Next
(Target
.HT
, Tgt_Node
);
935 X
: Node_Access
:= Tgt_Node
;
937 Tgt_Node
:= HT_Ops
.Next
(Target
.HT
, Tgt_Node
);
938 HT_Ops
.Delete_Node_Sans_Free
(Target
.HT
, X
);
945 function Intersection
(Left
, Right
: Set
) return Set
is
946 Left_HT
: Hash_Table_Type
renames Left
'Unrestricted_Access.HT
;
947 Right_HT
: Hash_Table_Type
renames Right
'Unrestricted_Access.HT
;
948 Buckets
: HT_Types
.Buckets_Access
;
952 if Left
'Address = Right
'Address then
956 Length
:= Count_Type
'Min (Left
.Length
, Right
.Length
);
963 Size
: constant Hash_Type
:= Prime_Numbers
.To_Prime
(Length
);
965 Buckets
:= HT_Ops
.New_Buckets
(Length
=> Size
);
970 Iterate_Left
: declare
971 procedure Process
(L_Node
: Node_Access
);
974 new HT_Ops
.Generic_Iteration
(Process
);
980 procedure Process
(L_Node
: Node_Access
) is
982 if Is_In
(Right_HT
, L_Node
) then
984 -- Per AI05-0022, the container implementation is required
985 -- to detect element tampering by a generic actual
986 -- subprogram, hence the use of Checked_Index instead of a
987 -- simple invocation of generic formal Hash.
989 Indx
: constant Hash_Type
:=
990 HT_Ops
.Checked_Index
(Left_HT
, Buckets
.all, L_Node
);
992 Bucket
: Node_Access
renames Buckets
(Indx
);
994 Src
: Element_Type
renames L_Node
.Element
.all;
995 Tgt
: Element_Access
:= new Element_Type
'(Src);
998 Bucket := new Node_Type'(Tgt
, Bucket
);
1006 Length
:= Length
+ 1;
1010 -- Start of processing for Iterate_Left
1017 HT_Ops
.Free_Hash_Table
(Buckets
);
1021 return (Controlled
with HT
=> (Buckets
, Length
, (Busy
=> 0, Lock
=> 0)));
1028 function Is_Empty
(Container
: Set
) return Boolean is
1030 return Container
.HT
.Length
= 0;
1038 (HT
: aliased in out Hash_Table_Type
;
1039 Key
: Node_Access
) return Boolean
1042 return Element_Keys
.Find
(HT
, Key
.Element
.all) /= null;
1051 Of_Set
: Set
) return Boolean
1053 Subset_HT
: Hash_Table_Type
renames Subset
'Unrestricted_Access.HT
;
1054 Of_Set_HT
: Hash_Table_Type
renames Of_Set
'Unrestricted_Access.HT
;
1055 Subset_Node
: Node_Access
;
1058 if Subset
'Address = Of_Set
'Address then
1062 if Subset
.Length
> Of_Set
.Length
then
1066 Subset_Node
:= HT_Ops
.First
(Subset_HT
);
1067 while Subset_Node
/= null loop
1068 if not Is_In
(Of_Set_HT
, Subset_Node
) then
1072 Subset_Node
:= HT_Ops
.Next
(Subset_HT
, Subset_Node
);
1084 Process
: not null access procedure (Position
: Cursor
))
1086 procedure Process_Node
(Node
: Node_Access
);
1087 pragma Inline
(Process_Node
);
1089 procedure Iterate
is
1090 new HT_Ops
.Generic_Iteration
(Process_Node
);
1096 procedure Process_Node
(Node
: Node_Access
) is
1098 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1101 Busy : With_Busy (Container.HT.TC'Unrestricted_Access);
1103 -- Start of processing for Iterate
1106 Iterate (Container.HT);
1109 function Iterate (Container : Set)
1110 return Set_Iterator_Interfaces.Forward_Iterator'Class
1113 return It : constant Iterator :=
1114 Iterator'(Limited_Controlled
with
1115 Container
=> Container
'Unrestricted_Access)
1117 Busy
(Container
.HT
.TC
'Unrestricted_Access.all);
1125 function Length
(Container
: Set
) return Count_Type
is
1127 return Container
.HT
.Length
;
1134 procedure Move
(Target
: in out Set
; Source
: in out Set
) is
1136 HT_Ops
.Move
(Target
=> Target
.HT
, Source
=> Source
.HT
);
1143 function Next
(Node
: Node_Access
) return Node_Access
is
1148 function Next
(Position
: Cursor
) return Cursor
is
1150 if Position
.Node
= null then
1154 if Checks
and then Position
.Node
.Element
= null then
1155 raise Program_Error
with "bad cursor in Next";
1158 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1161 HT
: Hash_Table_Type
renames Position
.Container
.HT
;
1162 Node
: constant Node_Access
:= HT_Ops
.Next
(HT
, Position
.Node
);
1164 return (if Node
= null then No_Element
1165 else Cursor
'(Position.Container, Node));
1169 procedure Next (Position : in out Cursor) is
1171 Position := Next (Position);
1176 Position : Cursor) return Cursor
1179 if Position.Container = null then
1183 if Checks and then Position.Container /= Object.Container then
1184 raise Program_Error with
1185 "Position cursor of Next designates wrong set";
1188 return Next (Position);
1195 function Overlap (Left, Right : Set) return Boolean is
1196 Left_HT : Hash_Table_Type renames Left'Unrestricted_Access.HT;
1197 Right_HT : Hash_Table_Type renames Right'Unrestricted_Access.HT;
1198 Left_Node : Node_Access;
1201 if Right.Length = 0 then
1205 if Left'Address = Right'Address then
1209 Left_Node := HT_Ops.First (Left_HT);
1210 while Left_Node /= null loop
1211 if Is_In (Right_HT, Left_Node) then
1215 Left_Node := HT_Ops.Next (Left_HT, Left_Node);
1221 ----------------------
1222 -- Pseudo_Reference --
1223 ----------------------
1225 function Pseudo_Reference
1226 (Container : aliased Set'Class) return Reference_Control_Type
1228 TC : constant Tamper_Counts_Access :=
1229 Container.HT.TC'Unrestricted_Access;
1231 return R : constant Reference_Control_Type := (Controlled with TC) do
1234 end Pseudo_Reference;
1240 procedure Query_Element
1242 Process : not null access procedure (Element : Element_Type))
1245 if Checks and then Position.Node = null then
1246 raise Constraint_Error with
1247 "Position cursor of Query_Element equals No_Element";
1250 if Checks and then Position.Node.Element = null then
1251 raise Program_Error with "bad cursor in Query_Element";
1254 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1257 HT : Hash_Table_Type renames
1258 Position.Container'Unrestricted_Access.all.HT;
1259 Lock : With_Lock (HT.TC'Unrestricted_Access);
1261 Process (Position.Node.Element.all);
1270 (Stream : not null access Root_Stream_Type'Class;
1271 Container : out Set)
1274 Read_Nodes (Stream, Container.HT);
1278 (Stream : not null access Root_Stream_Type'Class;
1282 raise Program_Error with "attempt to stream set cursor";
1286 (Stream : not null access Root_Stream_Type'Class;
1287 Item : out Constant_Reference_Type)
1290 raise Program_Error with "attempt to stream reference";
1298 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1300 X : Element_Access := new Element_Type'(Element_Type
'Input (Stream
));
1302 return new Node_Type
'(X, null);
1314 (Container : in out Set;
1315 New_Item : Element_Type)
1317 Node : constant Node_Access :=
1318 Element_Keys.Find (Container.HT, New_Item);
1321 pragma Warnings (Off, X);
1324 if Checks and then Node = null then
1325 raise Constraint_Error with
1326 "attempt to replace element not in set";
1329 TE_Check (Container.HT.TC);
1334 -- The element allocator may need an accessibility check in the case
1335 -- the actual type is class-wide or has access discriminants (see
1336 -- RM 4.8(10.1) and AI12-0035).
1338 pragma Unsuppress (Accessibility_Check);
1341 Node.Element := new Element_Type'(New_Item
);
1347 ---------------------
1348 -- Replace_Element --
1349 ---------------------
1351 procedure Replace_Element
1352 (Container
: in out Set
;
1354 New_Item
: Element_Type
)
1357 if Checks
and then Position
.Node
= null then
1358 raise Constraint_Error
with "Position cursor equals No_Element";
1361 if Checks
and then Position
.Node
.Element
= null then
1362 raise Program_Error
with "bad cursor in Replace_Element";
1365 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
1367 raise Program_Error
with
1368 "Position cursor designates wrong set";
1371 pragma Assert
(Vet
(Position
), "bad cursor in Replace_Element");
1373 Replace_Element
(Container
.HT
, Position
.Node
, New_Item
);
1374 end Replace_Element
;
1376 ----------------------
1377 -- Reserve_Capacity --
1378 ----------------------
1380 procedure Reserve_Capacity
1381 (Container
: in out Set
;
1382 Capacity
: Count_Type
)
1385 HT_Ops
.Reserve_Capacity
(Container
.HT
, Capacity
);
1386 end Reserve_Capacity
;
1392 procedure Set_Next
(Node
: Node_Access
; Next
: Node_Access
) is
1397 --------------------------
1398 -- Symmetric_Difference --
1399 --------------------------
1401 procedure Symmetric_Difference
1402 (Target
: in out Set
;
1405 Tgt_HT
: Hash_Table_Type
renames Target
.HT
;
1406 Src_HT
: Hash_Table_Type
renames Source
.HT
'Unrestricted_Access.all;
1408 if Target
'Address = Source
'Address then
1413 TC_Check
(Tgt_HT
.TC
);
1416 N
: constant Count_Type
:= Target
.Length
+ Source
.Length
;
1418 if N
> HT_Ops
.Capacity
(Tgt_HT
) then
1419 HT_Ops
.Reserve_Capacity
(Tgt_HT
, N
);
1423 if Target
.Length
= 0 then
1424 Iterate_Source_When_Empty_Target
: declare
1425 procedure Process
(Src_Node
: Node_Access
);
1427 procedure Iterate
is new HT_Ops
.Generic_Iteration
(Process
);
1433 procedure Process
(Src_Node
: Node_Access
) is
1434 E
: Element_Type
renames Src_Node
.Element
.all;
1435 B
: Buckets_Type
renames Tgt_HT
.Buckets
.all;
1436 J
: constant Hash_Type
:= Hash
(E
) mod B
'Length;
1437 N
: Count_Type
renames Tgt_HT
.Length
;
1441 X
: Element_Access
:= new Element_Type
'(E);
1443 B (J) := new Node_Type'(X
, B
(J
));
1453 -- Per AI05-0022, the container implementation is required to
1454 -- detect element tampering by a generic actual subprogram.
1456 Lock_Tgt
: With_Lock
(Tgt_HT
.TC
'Unrestricted_Access);
1457 Lock_Src
: With_Lock
(Src_HT
.TC
'Unrestricted_Access);
1459 -- Start of processing for Iterate_Source_When_Empty_Target
1463 end Iterate_Source_When_Empty_Target
;
1466 Iterate_Source
: declare
1467 procedure Process
(Src_Node
: Node_Access
);
1469 procedure Iterate
is
1470 new HT_Ops
.Generic_Iteration
(Process
);
1476 procedure Process
(Src_Node
: Node_Access
) is
1477 E
: Element_Type
renames Src_Node
.Element
.all;
1478 B
: Buckets_Type
renames Tgt_HT
.Buckets
.all;
1479 J
: constant Hash_Type
:= Hash
(E
) mod B
'Length;
1480 N
: Count_Type
renames Tgt_HT
.Length
;
1483 if B
(J
) = null then
1485 X
: Element_Access
:= new Element_Type
'(E);
1487 B (J) := new Node_Type'(X
, null);
1496 elsif Equivalent_Elements
(E
, B
(J
).Element
.all) then
1498 X
: Node_Access
:= B
(J
);
1500 B
(J
) := B
(J
).Next
;
1507 Prev
: Node_Access
:= B
(J
);
1508 Curr
: Node_Access
:= Prev
.Next
;
1511 while Curr
/= null loop
1512 if Equivalent_Elements
(E
, Curr
.Element
.all) then
1513 Prev
.Next
:= Curr
.Next
;
1524 X
: Element_Access
:= new Element_Type
'(E);
1526 B (J) := new Node_Type'(X
, B
(J
));
1538 -- Per AI05-0022, the container implementation is required to
1539 -- detect element tampering by a generic actual subprogram.
1541 Lock_Tgt
: With_Lock
(Tgt_HT
.TC
'Unrestricted_Access);
1542 Lock_Src
: With_Lock
(Src_HT
.TC
'Unrestricted_Access);
1544 -- Start of processing for Iterate_Source
1550 end Symmetric_Difference
;
1552 function Symmetric_Difference
(Left
, Right
: Set
) return Set
is
1553 Left_HT
: Hash_Table_Type
renames Left
'Unrestricted_Access.HT
;
1554 Right_HT
: Hash_Table_Type
renames Right
'Unrestricted_Access.HT
;
1555 Buckets
: HT_Types
.Buckets_Access
;
1556 Length
: Count_Type
;
1559 if Left
'Address = Right
'Address then
1563 if Right
.Length
= 0 then
1567 if Left
.Length
= 0 then
1572 Size
: constant Hash_Type
:=
1573 Prime_Numbers
.To_Prime
(Left
.Length
+ Right
.Length
);
1575 Buckets
:= HT_Ops
.New_Buckets
(Length
=> Size
);
1580 Iterate_Left
: declare
1581 procedure Process
(L_Node
: Node_Access
);
1583 procedure Iterate
is
1584 new HT_Ops
.Generic_Iteration
(Process
);
1590 procedure Process
(L_Node
: Node_Access
) is
1592 if not Is_In
(Right_HT
, L_Node
) then
1594 E
: Element_Type
renames L_Node
.Element
.all;
1596 -- Per AI05-0022, the container implementation is required
1597 -- to detect element tampering by a generic actual
1598 -- subprogram, hence the use of Checked_Index instead of a
1599 -- simple invocation of generic formal Hash.
1601 J
: constant Hash_Type
:=
1602 HT_Ops
.Checked_Index
(Left_HT
, Buckets
.all, L_Node
);
1606 X
: Element_Access
:= new Element_Type
'(E);
1608 Buckets (J) := new Node_Type'(X
, Buckets
(J
));
1615 Length
:= Length
+ 1;
1620 -- Start of processing for Iterate_Left
1626 HT_Ops
.Free_Hash_Table
(Buckets
);
1630 Iterate_Right
: declare
1631 procedure Process
(R_Node
: Node_Access
);
1633 procedure Iterate
is
1634 new HT_Ops
.Generic_Iteration
(Process
);
1640 procedure Process
(R_Node
: Node_Access
) is
1642 if not Is_In
(Left_HT
, R_Node
) then
1644 E
: Element_Type
renames R_Node
.Element
.all;
1646 -- Per AI05-0022, the container implementation is required
1647 -- to detect element tampering by a generic actual
1648 -- subprogram, hence the use of Checked_Index instead of a
1649 -- simple invocation of generic formal Hash.
1651 J
: constant Hash_Type
:=
1652 HT_Ops
.Checked_Index
(Right_HT
, Buckets
.all, R_Node
);
1656 X
: Element_Access
:= new Element_Type
'(E);
1658 Buckets (J) := new Node_Type'(X
, Buckets
(J
));
1665 Length
:= Length
+ 1;
1670 -- Start of processing for Iterate_Right
1677 HT_Ops
.Free_Hash_Table
(Buckets
);
1681 return (Controlled
with HT
=> (Buckets
, Length
, (Busy
=> 0, Lock
=> 0)));
1682 end Symmetric_Difference
;
1688 function To_Set
(New_Item
: Element_Type
) return Set
is
1689 HT
: Hash_Table_Type
;
1692 pragma Unreferenced
(Node
, Inserted
);
1694 Insert
(HT
, New_Item
, Node
, Inserted
);
1695 return Set
'(Controlled with HT);
1703 (Target : in out Set;
1706 procedure Process (Src_Node : Node_Access);
1708 procedure Iterate is
1709 new HT_Ops.Generic_Iteration (Process);
1715 procedure Process (Src_Node : Node_Access) is
1716 Src : Element_Type renames Src_Node.Element.all;
1718 function New_Node (Next : Node_Access) return Node_Access;
1719 pragma Inline (New_Node);
1722 new Element_Keys.Generic_Conditional_Insert (New_Node);
1728 function New_Node (Next : Node_Access) return Node_Access is
1729 Tgt : Element_Access := new Element_Type'(Src
);
1731 return new Node_Type
'(Tgt, Next);
1738 Tgt_Node : Node_Access;
1740 pragma Unreferenced (Tgt_Node, Success);
1742 -- Start of processing for Process
1745 Insert (Target.HT, Src, Tgt_Node, Success);
1748 -- Start of processing for Union
1751 if Target'Address = Source'Address then
1755 TC_Check (Target.HT.TC);
1758 N : constant Count_Type := Target.Length + Source.Length;
1760 if N > HT_Ops.Capacity (Target.HT) then
1761 HT_Ops.Reserve_Capacity (Target.HT, N);
1765 Iterate (Source.HT);
1768 function Union (Left, Right : Set) return Set is
1769 Left_HT : Hash_Table_Type renames Left.HT'Unrestricted_Access.all;
1770 Right_HT : Hash_Table_Type renames Right.HT'Unrestricted_Access.all;
1771 Buckets : HT_Types.Buckets_Access;
1772 Length : Count_Type;
1775 if Left'Address = Right'Address then
1779 if Right.Length = 0 then
1783 if Left.Length = 0 then
1788 Size : constant Hash_Type :=
1789 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1791 Buckets := HT_Ops.New_Buckets (Length => Size);
1794 Iterate_Left : declare
1795 procedure Process (L_Node : Node_Access);
1797 procedure Iterate is
1798 new HT_Ops.Generic_Iteration (Process);
1804 procedure Process (L_Node : Node_Access) is
1805 Src : Element_Type renames L_Node.Element.all;
1806 J : constant Hash_Type := Hash (Src) mod Buckets'Length;
1807 Bucket : Node_Access renames Buckets (J);
1808 Tgt : Element_Access := new Element_Type'(Src
);
1810 Bucket
:= new Node_Type
'(Tgt, Bucket);
1817 -- Per AI05-0022, the container implementation is required to detect
1818 -- element tampering by a generic actual subprogram, hence the use of
1819 -- Checked_Index instead of a simple invocation of generic formal
1822 Lock_Left : With_Lock (Left_HT.TC'Unrestricted_Access);
1824 -- Start of processing for Iterate_Left
1830 HT_Ops.Free_Hash_Table (Buckets);
1834 Length := Left.Length;
1836 Iterate_Right : declare
1837 procedure Process (Src_Node : Node_Access);
1839 procedure Iterate is
1840 new HT_Ops.Generic_Iteration (Process);
1846 procedure Process (Src_Node : Node_Access) is
1847 Src : Element_Type renames Src_Node.Element.all;
1848 Idx : constant Hash_Type := Hash (Src) mod Buckets'Length;
1850 Tgt_Node : Node_Access := Buckets (Idx);
1853 while Tgt_Node /= null loop
1854 if Equivalent_Elements (Src, Tgt_Node.Element.all) then
1857 Tgt_Node := Next (Tgt_Node);
1861 Tgt : Element_Access := new Element_Type'(Src
);
1863 Buckets
(Idx
) := new Node_Type
'(Tgt, Buckets (Idx));
1870 Length := Length + 1;
1873 -- Per AI05-0022, the container implementation is required to detect
1874 -- element tampering by a generic actual subprogram, hence the use of
1875 -- Checked_Index instead of a simple invocation of generic formal
1878 Lock_Left : With_Lock (Left_HT.TC'Unrestricted_Access);
1879 Lock_Right : With_Lock (Right_HT.TC'Unrestricted_Access);
1881 -- Start of processing for Iterate_Right
1887 HT_Ops.Free_Hash_Table (Buckets);
1891 return (Controlled with HT => (Buckets, Length, (Busy => 0, Lock => 0)));
1898 function Vet (Position : Cursor) return Boolean is
1900 if Position.Node = null then
1901 return Position.Container = null;
1904 if Position.Container = null then
1908 if Position.Node.Next = Position.Node then
1912 if Position.Node.Element = null then
1917 HT : Hash_Table_Type renames Position.Container.HT;
1921 if HT.Length = 0 then
1925 if HT.Buckets = null
1926 or else HT.Buckets'Length = 0
1931 X := HT.Buckets (Element_Keys.Checked_Index
1933 Position.Node.Element.all));
1935 for J in 1 .. HT.Length loop
1936 if X = Position.Node then
1944 if X = X.Next then -- to prevent unnecessary looping
1960 (Stream : not null access Root_Stream_Type'Class;
1964 Write_Nodes (Stream, Container.HT);
1968 (Stream : not null access Root_Stream_Type'Class;
1972 raise Program_Error with "attempt to stream set cursor";
1976 (Stream : not null access Root_Stream_Type'Class;
1977 Item : Constant_Reference_Type)
1980 raise Program_Error with "attempt to stream reference";
1987 procedure Write_Node
1988 (Stream : not null access Root_Stream_Type'Class;
1992 Element_Type'Output (Stream, Node.Element.all);
1995 package body Generic_Keys is
1997 -----------------------
1998 -- Local Subprograms --
1999 -----------------------
2001 function Equivalent_Key_Node
2003 Node : Node_Access) return Boolean;
2004 pragma Inline (Equivalent_Key_Node);
2006 --------------------------
2007 -- Local Instantiations --
2008 --------------------------
2011 new Hash_Tables.Generic_Keys
2012 (HT_Types => HT_Types,
2014 Set_Next => Set_Next,
2015 Key_Type => Key_Type,
2017 Equivalent_Keys => Equivalent_Key_Node);
2019 ------------------------
2020 -- Constant_Reference --
2021 ------------------------
2023 function Constant_Reference
2024 (Container : aliased Set;
2025 Key : Key_Type) return Constant_Reference_Type
2027 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
2028 Node : constant Node_Access := Key_Keys.Find (HT, Key);
2031 if Checks and then Node = null then
2032 raise Constraint_Error with "Key not in set";
2035 if Checks and then Node.Element = null then
2036 raise Program_Error with "Node has no element";
2040 TC : constant Tamper_Counts_Access :=
2041 HT.TC'Unrestricted_Access;
2043 return R : constant Constant_Reference_Type :=
2044 (Element => Node.Element.all'Access,
2045 Control => (Controlled with TC))
2050 end Constant_Reference;
2058 Key : Key_Type) return Boolean
2061 return Find (Container, Key) /= No_Element;
2069 (Container : in out Set;
2075 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
2077 if Checks and then X = null then
2078 raise Constraint_Error with "key not in set";
2090 Key : Key_Type) return Element_Type
2092 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
2093 Node : constant Node_Access := Key_Keys.Find (HT, Key);
2096 if Checks and then Node = null then
2097 raise Constraint_Error with "key not in set";
2100 return Node.Element.all;
2103 -------------------------
2104 -- Equivalent_Key_Node --
2105 -------------------------
2107 function Equivalent_Key_Node
2109 Node : Node_Access) return Boolean is
2111 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element.all));
2112 end Equivalent_Key_Node;
2119 (Container : in out Set;
2124 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
2132 procedure Finalize (Control : in out Reference_Control_Type) is
2134 if Control.Container /= null then
2135 Impl.Reference_Control_Type (Control).Finalize;
2137 if Checks and then Hash (Key (Control.Old_Pos)) /= Control.Old_Hash
2139 HT_Ops.Delete_Node_At_Index
2140 (Control.Container.HT, Control.Index, Control.Old_Pos.Node);
2141 raise Program_Error;
2144 Control.Container := null;
2154 Key : Key_Type) return Cursor
2156 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
2157 Node : constant Node_Access := Key_Keys.Find (HT, Key);
2159 return (if Node = null then No_Element
2160 else Cursor'(Container
'Unrestricted_Access, Node
));
2167 function Key
(Position
: Cursor
) return Key_Type
is
2169 if Checks
and then Position
.Node
= null then
2170 raise Constraint_Error
with
2171 "Position cursor equals No_Element";
2174 if Checks
and then Position
.Node
.Element
= null then
2175 raise Program_Error
with "Position cursor is bad";
2178 pragma Assert
(Vet
(Position
), "bad cursor in function Key");
2180 return Key
(Position
.Node
.Element
.all);
2188 (Stream
: not null access Root_Stream_Type
'Class;
2189 Item
: out Reference_Type
)
2192 raise Program_Error
with "attempt to stream reference";
2195 ------------------------------
2196 -- Reference_Preserving_Key --
2197 ------------------------------
2199 function Reference_Preserving_Key
2200 (Container
: aliased in out Set
;
2201 Position
: Cursor
) return Reference_Type
2204 if Checks
and then Position
.Container
= null then
2205 raise Constraint_Error
with "Position cursor has no element";
2208 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2210 raise Program_Error
with
2211 "Position cursor designates wrong container";
2214 if Checks
and then Position
.Node
.Element
= null then
2215 raise Program_Error
with "Node has no element";
2220 "bad cursor in function Reference_Preserving_Key");
2223 HT
: Hash_Table_Type
renames Container
.HT
;
2225 return R
: constant Reference_Type
:=
2226 (Element
=> Position
.Node
.Element
.all'Access,
2229 HT
.TC
'Unrestricted_Access,
2230 Container
=> Container
'Access,
2231 Index
=> HT_Ops
.Index
(HT
, Position
.Node
),
2232 Old_Pos
=> Position
,
2233 Old_Hash
=> Hash
(Key
(Position
))))
2238 end Reference_Preserving_Key
;
2240 function Reference_Preserving_Key
2241 (Container
: aliased in out Set
;
2242 Key
: Key_Type
) return Reference_Type
2244 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.HT
, Key
);
2247 if Checks
and then Node
= null then
2248 raise Constraint_Error
with "Key not in set";
2251 if Checks
and then Node
.Element
= null then
2252 raise Program_Error
with "Node has no element";
2256 HT
: Hash_Table_Type
renames Container
.HT
;
2257 P
: constant Cursor
:= Find
(Container
, Key
);
2259 return R
: constant Reference_Type
:=
2260 (Element
=> Node
.Element
.all'Access,
2263 HT
.TC
'Unrestricted_Access,
2264 Container
=> Container
'Access,
2265 Index
=> HT_Ops
.Index
(HT
, P
.Node
),
2267 Old_Hash
=> Hash
(Key
)))
2272 end Reference_Preserving_Key
;
2279 (Container
: in out Set
;
2281 New_Item
: Element_Type
)
2283 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.HT
, Key
);
2286 if Checks
and then Node
= null then
2287 raise Constraint_Error
with
2288 "attempt to replace key not in set";
2291 Replace_Element
(Container
.HT
, Node
, New_Item
);
2294 -----------------------------------
2295 -- Update_Element_Preserving_Key --
2296 -----------------------------------
2298 procedure Update_Element_Preserving_Key
2299 (Container
: in out Set
;
2301 Process
: not null access
2302 procedure (Element
: in out Element_Type
))
2304 HT
: Hash_Table_Type
renames Container
.HT
;
2308 if Checks
and then Position
.Node
= null then
2309 raise Constraint_Error
with
2310 "Position cursor equals No_Element";
2314 (Position
.Node
.Element
= null
2315 or else Position
.Node
.Next
= Position
.Node
)
2317 raise Program_Error
with "Position cursor is bad";
2320 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2322 raise Program_Error
with
2323 "Position cursor designates wrong set";
2328 or else HT
.Buckets
'Length = 0
2329 or else HT
.Length
= 0)
2331 raise Program_Error
with "Position cursor is bad (set is empty)";
2336 "bad cursor in Update_Element_Preserving_Key");
2338 -- Per AI05-0022, the container implementation is required to detect
2339 -- element tampering by a generic actual subprogram.
2342 E
: Element_Type
renames Position
.Node
.Element
.all;
2343 K
: constant Key_Type
:= Key
(E
);
2344 Lock
: With_Lock
(HT
.TC
'Unrestricted_Access);
2346 Indx
:= HT_Ops
.Index
(HT
, Position
.Node
);
2349 if Equivalent_Keys
(K
, Key
(E
)) then
2354 if HT
.Buckets
(Indx
) = Position
.Node
then
2355 HT
.Buckets
(Indx
) := Position
.Node
.Next
;
2359 Prev
: Node_Access
:= HT
.Buckets
(Indx
);
2362 while Prev
.Next
/= Position
.Node
loop
2365 if Checks
and then Prev
= null then
2366 raise Program_Error
with
2367 "Position cursor is bad (node not found)";
2371 Prev
.Next
:= Position
.Node
.Next
;
2375 HT
.Length
:= HT
.Length
- 1;
2378 X
: Node_Access
:= Position
.Node
;
2384 raise Program_Error
with "key was modified";
2385 end Update_Element_Preserving_Key
;
2392 (Stream
: not null access Root_Stream_Type
'Class;
2393 Item
: Reference_Type
)
2396 raise Program_Error
with "attempt to stream reference";
2401 end Ada
.Containers
.Indefinite_Hashed_Sets
;