1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_HASHED_SETS --
9 -- Copyright (C) 2004-2024, 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
;
43 with System
.Put_Images
;
45 package body Ada
.Containers
.Indefinite_Hashed_Sets
with
49 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
50 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
51 -- See comment in Ada.Containers.Helpers
53 -----------------------
54 -- Local Subprograms --
55 -----------------------
57 procedure Assign
(Node
: Node_Access
; Item
: Element_Type
);
58 pragma Inline
(Assign
);
60 function Copy_Node
(Source
: Node_Access
) return Node_Access
;
61 pragma Inline
(Copy_Node
);
63 function Equivalent_Keys
65 Node
: Node_Access
) return Boolean;
66 pragma Inline
(Equivalent_Keys
);
68 function Find_Equal_Key
69 (R_HT
: Hash_Table_Type
;
70 L_Node
: Node_Access
) return Boolean;
72 function Find_Equivalent_Key
73 (R_HT
: Hash_Table_Type
;
74 L_Node
: Node_Access
) return Boolean;
76 procedure Free
(X
: in out Node_Access
);
78 function Hash_Node
(Node
: Node_Access
) return Hash_Type
;
79 pragma Inline
(Hash_Node
);
82 (HT
: in out Hash_Table_Type
;
83 New_Item
: Element_Type
;
84 Node
: out Node_Access
;
85 Inserted
: out Boolean);
88 (HT
: aliased in out Hash_Table_Type
;
89 Key
: Node_Access
) return Boolean;
90 pragma Inline
(Is_In
);
92 function Next
(Node
: Node_Access
) return Node_Access
;
95 function Read_Node
(Stream
: not null access Root_Stream_Type
'Class)
97 pragma Inline
(Read_Node
);
99 procedure Set_Next
(Node
: Node_Access
; Next
: Node_Access
);
100 pragma Inline
(Set_Next
);
102 function Vet
(Position
: Cursor
) return Boolean with Inline
;
105 (Stream
: not null access Root_Stream_Type
'Class;
107 pragma Inline
(Write_Node
);
109 --------------------------
110 -- Local Instantiations --
111 --------------------------
113 procedure Free_Element
is
114 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
116 package HT_Ops
is new Hash_Tables
.Generic_Operations
117 (HT_Types
=> HT_Types
,
118 Hash_Node
=> Hash_Node
,
120 Set_Next
=> Set_Next
,
121 Copy_Node
=> Copy_Node
,
124 package Element_Keys
is new Hash_Tables
.Generic_Keys
125 (HT_Types
=> HT_Types
,
127 Set_Next
=> Set_Next
,
128 Key_Type
=> Element_Type
,
130 Equivalent_Keys
=> Equivalent_Keys
);
133 new HT_Ops
.Generic_Equal
(Find_Equal_Key
);
135 function Is_Equivalent
is
136 new HT_Ops
.Generic_Equal
(Find_Equivalent_Key
);
138 procedure Read_Nodes
is
139 new HT_Ops
.Generic_Read
(Read_Node
);
141 procedure Replace_Element
is
142 new Element_Keys
.Generic_Replace_Element
(Hash_Node
, Assign
);
144 procedure Write_Nodes
is
145 new HT_Ops
.Generic_Write
(Write_Node
);
151 function "=" (Left
, Right
: Set
) return Boolean is
153 return Is_Equal
(Left
.HT
, Right
.HT
);
160 procedure Adjust
(Container
: in out Set
) is
162 HT_Ops
.Adjust
(Container
.HT
);
169 procedure Assign
(Node
: Node_Access
; Item
: Element_Type
) is
170 X
: Element_Access
:= Node
.Element
;
172 -- The element allocator may need an accessibility check in the case the
173 -- actual type is class-wide or has access discriminants (RM 4.8(10.1)
176 pragma Unsuppress
(Accessibility_Check
);
179 Node
.Element
:= new Element_Type
'(Item);
183 procedure Assign (Target : in out Set; Source : Set) is
185 if Target'Address = Source'Address then
189 Target.Union (Source);
197 function Capacity (Container : Set) return Count_Type is
199 return HT_Ops.Capacity (Container.HT);
206 procedure Clear (Container : in out Set) is
208 HT_Ops.Clear (Container.HT);
211 ------------------------
212 -- Constant_Reference --
213 ------------------------
215 function Constant_Reference
216 (Container : aliased Set;
217 Position : Cursor) return Constant_Reference_Type
220 if Checks and then Position.Container = null then
221 raise Constraint_Error with "Position cursor has no element";
224 if Checks and then Position.Container /= Container'Unrestricted_Access
226 raise Program_Error with
227 "Position cursor designates wrong container";
230 if Checks and then Position.Node.Element = null then
231 raise Program_Error with "Node has no element";
234 pragma Assert (Vet (Position), "bad cursor in Constant_Reference");
237 HT : Hash_Table_Type renames Position.Container.all.HT;
238 TC : constant Tamper_Counts_Access :=
239 HT.TC'Unrestricted_Access;
241 return R : constant Constant_Reference_Type :=
242 (Element => Position.Node.Element.all'Access,
243 Control => (Controlled with TC))
248 end Constant_Reference;
254 function Contains (Container : Set; Item : Element_Type) return Boolean is
256 return Find (Container, Item) /= No_Element;
265 Capacity : Count_Type := 0) return Set
270 if Capacity < Source.Length then
271 if Checks and then Capacity /= 0 then
273 with "Requested capacity is less than Source length";
281 return Target : Set do
282 Target.Reserve_Capacity (C);
283 Target.Assign (Source);
291 function Copy_Node (Source : Node_Access) return Node_Access is
292 E : Element_Access := new Element_Type'(Source
.Element
.all);
294 return new Node_Type
'(Element => E, Next => null);
306 (Container : in out Set;
312 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
314 if Checks and then X = null then
315 raise Constraint_Error with "attempt to delete element not in set";
322 (Container : in out Set;
323 Position : in out Cursor)
326 TC_Check (Container.HT.TC);
328 if Checks and then Position.Node = null then
329 raise Constraint_Error with "Position cursor equals No_Element";
332 if Checks and then Position.Node.Element = null then
333 raise Program_Error with "Position cursor is bad";
336 if Checks and then Position.Container /= Container'Unrestricted_Access
338 raise Program_Error with "Position cursor designates wrong set";
341 pragma Assert (Vet (Position), "Position cursor is bad");
343 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
345 Free (Position.Node);
346 Position.Container := null;
354 (Target : in out Set;
357 Src_HT : Hash_Table_Type renames Source'Unrestricted_Access.HT;
358 Tgt_Node : Node_Access;
361 if Target'Address = Source'Address then
366 if Src_HT.Length = 0 then
370 TC_Check (Target.HT.TC);
372 if Src_HT.Length < Target.HT.Length then
374 Src_Node : Node_Access;
377 Src_Node := HT_Ops.First (Src_HT);
378 while Src_Node /= null loop
379 Tgt_Node := Element_Keys.Find (Target.HT, Src_Node.Element.all);
381 if Tgt_Node /= null then
382 HT_Ops.Delete_Node_Sans_Free (Target.HT, Tgt_Node);
386 Src_Node := HT_Ops.Next (Src_HT, Src_Node);
391 Tgt_Node := HT_Ops.First (Target.HT);
392 while Tgt_Node /= null loop
393 if Is_In (Src_HT, Tgt_Node) then
395 X : Node_Access := Tgt_Node;
397 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
398 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
403 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
409 function Difference (Left, Right : Set) return Set is
410 Left_HT : Hash_Table_Type renames Left'Unrestricted_Access.HT;
411 Right_HT : Hash_Table_Type renames Right'Unrestricted_Access.HT;
412 Buckets : HT_Types.Buckets_Access;
416 if Left'Address = Right'Address then
420 if Left.Length = 0 then
424 if Right.Length = 0 then
429 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
431 Buckets := HT_Ops.New_Buckets (Length => Size);
436 Iterate_Left : declare
437 procedure Process (L_Node : Node_Access);
440 new HT_Ops.Generic_Iteration (Process);
446 procedure Process (L_Node : Node_Access) is
448 if not Is_In (Right_HT, L_Node) then
450 -- Per AI05-0022, the container implementation is required
451 -- to detect element tampering by a generic actual
452 -- subprogram, hence the use of Checked_Index instead of a
453 -- simple invocation of generic formal Hash.
455 Indx : constant Hash_Type :=
456 HT_Ops.Checked_Index (Left_HT, Buckets.all, L_Node);
458 Bucket : Node_Access renames Buckets (Indx);
459 Src : Element_Type renames L_Node.Element.all;
460 Tgt : Element_Access := new Element_Type'(Src
);
463 Bucket
:= new Node_Type
'(Tgt, Bucket);
471 Length := Length + 1;
475 -- Start of processing for Iterate_Left
482 HT_Ops.Free_Hash_Table (Buckets);
486 return (Controlled with HT => (Buckets, Length, (Busy => 0, Lock => 0)));
493 function Element (Position : Cursor) return Element_Type is
495 if Checks and then Position.Node = null then
496 raise Constraint_Error with "Position cursor of equals No_Element";
499 if Checks and then Position.Node.Element = null then
500 -- handle dangling reference
501 raise Program_Error with "Position cursor is bad";
504 pragma Assert (Vet (Position), "bad cursor in function Element");
506 return Position.Node.Element.all;
513 function Empty (Capacity : Count_Type := 1000) return Set is
515 return Result : Set do
516 Reserve_Capacity (Result, Capacity);
520 ---------------------
521 -- Equivalent_Sets --
522 ---------------------
524 function Equivalent_Sets (Left, Right : Set) return Boolean is
526 return Is_Equivalent (Left.HT, Right.HT);
529 -------------------------
530 -- Equivalent_Elements --
531 -------------------------
533 function Equivalent_Elements (Left, Right : Cursor) return Boolean is
535 if Checks and then Left.Node = null then
536 raise Constraint_Error with
537 "Left cursor of Equivalent_Elements equals No_Element";
540 if Checks and then Right.Node = null then
541 raise Constraint_Error with
542 "Right cursor of Equivalent_Elements equals No_Element";
545 if Checks and then Left.Node.Element = null then
546 raise Program_Error with
547 "Left cursor of Equivalent_Elements is bad";
550 if Checks and then Right.Node.Element = null then
551 raise Program_Error with
552 "Right cursor of Equivalent_Elements is bad";
555 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
556 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
558 -- AI05-0022 requires that a container implementation detect element
559 -- tampering by a generic actual subprogram. However, the following case
560 -- falls outside the scope of that AI. Randy Brukardt explained on the
561 -- ARG list on 2013/02/07 that:
564 -- But for an operation like "<" [the ordered set analog of
565 -- Equivalent_Elements], there is no need to "dereference" a cursor
566 -- after the call to the generic formal parameter function, so nothing
567 -- bad could happen if tampering is undetected. And the operation can
568 -- safely return a result without a problem even if an element is
569 -- deleted from the container.
572 return Equivalent_Elements
573 (Left.Node.Element.all,
574 Right.Node.Element.all);
575 end Equivalent_Elements;
577 function Equivalent_Elements
579 Right : Element_Type) return Boolean
582 if Checks and then Left.Node = null then
583 raise Constraint_Error with
584 "Left cursor of Equivalent_Elements equals No_Element";
587 if Checks and then Left.Node.Element = null then
588 raise Program_Error with
589 "Left cursor of Equivalent_Elements is bad";
592 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
594 return Equivalent_Elements (Left.Node.Element.all, Right);
595 end Equivalent_Elements;
597 function Equivalent_Elements
598 (Left : Element_Type;
599 Right : Cursor) return Boolean
602 if Checks and then Right.Node = null then
603 raise Constraint_Error with
604 "Right cursor of Equivalent_Elements equals No_Element";
607 if Checks and then Right.Node.Element = null then
608 raise Program_Error with
609 "Right cursor of Equivalent_Elements is bad";
612 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
614 return Equivalent_Elements (Left, Right.Node.Element.all);
615 end Equivalent_Elements;
617 ---------------------
618 -- Equivalent_Keys --
619 ---------------------
621 function Equivalent_Keys
623 Node : Node_Access) return Boolean
626 return Equivalent_Elements (Key, Node.Element.all);
634 (Container : in out Set;
639 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
647 procedure Finalize (Container : in out Set) is
649 HT_Ops.Finalize (Container.HT);
652 procedure Finalize (Object : in out Iterator) is
654 if Object.Container /= null then
655 Unbusy (Object.Container.HT.TC);
665 Item : Element_Type) return Cursor
667 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
668 Node : constant Node_Access := Element_Keys.Find (HT, Item);
670 return (if Node = null then No_Element
671 else Cursor'(Container
'Unrestricted_Access, Node
));
678 function Find_Equal_Key
679 (R_HT
: Hash_Table_Type
;
680 L_Node
: Node_Access
) return Boolean
682 R_Index
: constant Hash_Type
:=
683 Element_Keys
.Index
(R_HT
, L_Node
.Element
.all);
685 R_Node
: Node_Access
:= R_HT
.Buckets
(R_Index
);
689 if R_Node
= null then
693 if L_Node
.Element
.all = R_Node
.Element
.all then
697 R_Node
:= Next
(R_Node
);
701 -------------------------
702 -- Find_Equivalent_Key --
703 -------------------------
705 function Find_Equivalent_Key
706 (R_HT
: Hash_Table_Type
;
707 L_Node
: Node_Access
) return Boolean
709 R_Index
: constant Hash_Type
:=
710 Element_Keys
.Index
(R_HT
, L_Node
.Element
.all);
712 R_Node
: Node_Access
:= R_HT
.Buckets
(R_Index
);
716 if R_Node
= null then
720 if Equivalent_Elements
(L_Node
.Element
.all, R_Node
.Element
.all) then
724 R_Node
:= Next
(R_Node
);
726 end Find_Equivalent_Key
;
732 function First
(Container
: Set
) return Cursor
is
733 Node
: constant Node_Access
:= HT_Ops
.First
(Container
.HT
);
735 return (if Node
= null then No_Element
736 else Cursor
'(Container'Unrestricted_Access, Node));
739 function First (Object : Iterator) return Cursor is
741 return Object.Container.First;
748 procedure Free (X : in out Node_Access) is
749 procedure Deallocate is
750 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
757 X.Next := X; -- detect mischief (in Vet)
760 Free_Element (X.Element);
772 ------------------------
773 -- Get_Element_Access --
774 ------------------------
776 function Get_Element_Access
777 (Position : Cursor) return not null Element_Access is
779 return Position.Node.Element;
780 end Get_Element_Access;
786 function Has_Element (Position : Cursor) return Boolean is
788 pragma Assert (Vet (Position), "bad cursor in Has_Element");
789 return Position.Node /= null;
796 function Hash_Node (Node : Node_Access) return Hash_Type is
798 return Hash (Node.Element.all);
806 (Container : in out Set;
807 New_Item : Element_Type)
815 Insert (Container, New_Item, Position, Inserted);
818 TE_Check (Container.HT.TC);
820 X := Position.Node.Element;
823 -- The element allocator may need an accessibility check in the
824 -- case the actual type is class-wide or has access discriminants
825 -- (see RM 4.8(10.1) and AI12-0035).
827 pragma Unsuppress (Accessibility_Check);
830 Position.Node.Element := new Element_Type'(New_Item
);
842 (Container
: in out Set
;
843 New_Item
: Element_Type
;
844 Position
: out Cursor
;
845 Inserted
: out Boolean)
848 Insert
(Container
.HT
, New_Item
, Position
.Node
, Inserted
);
849 Position
.Container
:= Container
'Unchecked_Access;
853 (Container
: in out Set
;
854 New_Item
: Element_Type
)
860 Insert
(Container
, New_Item
, Position
, Inserted
);
862 if Checks
and then not Inserted
then
863 raise Constraint_Error
with
864 "attempt to insert element already in set";
869 (HT
: in out Hash_Table_Type
;
870 New_Item
: Element_Type
;
871 Node
: out Node_Access
;
872 Inserted
: out Boolean)
874 function New_Node
(Next
: Node_Access
) return Node_Access
;
875 pragma Inline
(New_Node
);
877 procedure Local_Insert
is
878 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
884 function New_Node
(Next
: Node_Access
) return Node_Access
is
886 -- The element allocator may need an accessibility check in the case
887 -- the actual type is class-wide or has access discriminants (see
888 -- RM 4.8(10.1) and AI12-0035).
890 pragma Unsuppress
(Accessibility_Check
);
892 Element
: Element_Access
:= new Element_Type
'(New_Item);
895 return new Node_Type'(Element
, Next
);
899 Free_Element
(Element
);
903 -- Start of processing for Insert
906 if HT_Ops
.Capacity
(HT
) = 0 then
907 HT_Ops
.Reserve_Capacity
(HT
, 1);
910 Local_Insert
(HT
, New_Item
, Node
, Inserted
);
912 if Inserted
and then HT
.Length
> HT_Ops
.Capacity
(HT
) then
913 HT_Ops
.Reserve_Capacity
(HT
, HT
.Length
);
921 procedure Intersection
922 (Target
: in out Set
;
925 Src_HT
: Hash_Table_Type
renames Source
'Unrestricted_Access.HT
;
926 Tgt_Node
: Node_Access
;
929 if Target
'Address = Source
'Address then
933 if Source
.Length
= 0 then
938 TC_Check
(Target
.HT
.TC
);
940 Tgt_Node
:= HT_Ops
.First
(Target
.HT
);
941 while Tgt_Node
/= null loop
942 if Is_In
(Src_HT
, Tgt_Node
) then
943 Tgt_Node
:= HT_Ops
.Next
(Target
.HT
, Tgt_Node
);
947 X
: Node_Access
:= Tgt_Node
;
949 Tgt_Node
:= HT_Ops
.Next
(Target
.HT
, Tgt_Node
);
950 HT_Ops
.Delete_Node_Sans_Free
(Target
.HT
, X
);
957 function Intersection
(Left
, Right
: Set
) return Set
is
958 Left_HT
: Hash_Table_Type
renames Left
'Unrestricted_Access.HT
;
959 Right_HT
: Hash_Table_Type
renames Right
'Unrestricted_Access.HT
;
960 Buckets
: HT_Types
.Buckets_Access
;
964 if Left
'Address = Right
'Address then
968 Length
:= Count_Type
'Min (Left
.Length
, Right
.Length
);
975 Size
: constant Hash_Type
:= Prime_Numbers
.To_Prime
(Length
);
977 Buckets
:= HT_Ops
.New_Buckets
(Length
=> Size
);
982 Iterate_Left
: declare
983 procedure Process
(L_Node
: Node_Access
);
986 new HT_Ops
.Generic_Iteration
(Process
);
992 procedure Process
(L_Node
: Node_Access
) is
994 if Is_In
(Right_HT
, L_Node
) then
996 -- Per AI05-0022, the container implementation is required
997 -- to detect element tampering by a generic actual
998 -- subprogram, hence the use of Checked_Index instead of a
999 -- simple invocation of generic formal Hash.
1001 Indx
: constant Hash_Type
:=
1002 HT_Ops
.Checked_Index
(Left_HT
, Buckets
.all, L_Node
);
1004 Bucket
: Node_Access
renames Buckets
(Indx
);
1006 Src
: Element_Type
renames L_Node
.Element
.all;
1007 Tgt
: Element_Access
:= new Element_Type
'(Src);
1010 Bucket := new Node_Type'(Tgt
, Bucket
);
1018 Length
:= Length
+ 1;
1022 -- Start of processing for Iterate_Left
1029 HT_Ops
.Free_Hash_Table
(Buckets
);
1033 return (Controlled
with HT
=> (Buckets
, Length
, (Busy
=> 0, Lock
=> 0)));
1040 function Is_Empty
(Container
: Set
) return Boolean is
1042 return Container
.HT
.Length
= 0;
1050 (HT
: aliased in out Hash_Table_Type
;
1051 Key
: Node_Access
) return Boolean
1054 return Element_Keys
.Find
(HT
, Key
.Element
.all) /= null;
1063 Of_Set
: Set
) return Boolean
1065 Subset_HT
: Hash_Table_Type
renames Subset
'Unrestricted_Access.HT
;
1066 Of_Set_HT
: Hash_Table_Type
renames Of_Set
'Unrestricted_Access.HT
;
1067 Subset_Node
: Node_Access
;
1070 if Subset
'Address = Of_Set
'Address then
1074 if Subset
.Length
> Of_Set
.Length
then
1078 Subset_Node
:= HT_Ops
.First
(Subset_HT
);
1079 while Subset_Node
/= null loop
1080 if not Is_In
(Of_Set_HT
, Subset_Node
) then
1084 Subset_Node
:= HT_Ops
.Next
(Subset_HT
, Subset_Node
);
1096 Process
: not null access procedure (Position
: Cursor
))
1098 procedure Process_Node
(Node
: Node_Access
);
1099 pragma Inline
(Process_Node
);
1101 procedure Iterate
is
1102 new HT_Ops
.Generic_Iteration
(Process_Node
);
1108 procedure Process_Node
(Node
: Node_Access
) is
1110 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1113 Busy : With_Busy (Container.HT.TC'Unrestricted_Access);
1115 -- Start of processing for Iterate
1118 Iterate (Container.HT);
1121 function Iterate (Container : Set)
1122 return Set_Iterator_Interfaces.Forward_Iterator'Class
1125 return It : constant Iterator :=
1126 Iterator'(Limited_Controlled
with
1127 Container
=> Container
'Unrestricted_Access)
1129 Busy
(Container
.HT
.TC
'Unrestricted_Access.all);
1137 function Length
(Container
: Set
) return Count_Type
is
1139 return Container
.HT
.Length
;
1146 procedure Move
(Target
: in out Set
; Source
: in out Set
) is
1148 HT_Ops
.Move
(Target
=> Target
.HT
, Source
=> Source
.HT
);
1155 function Next
(Node
: Node_Access
) return Node_Access
is
1160 function Next
(Position
: Cursor
) return Cursor
is
1162 if Position
.Node
= null then
1166 if Checks
and then Position
.Node
.Element
= null then
1167 raise Program_Error
with "bad cursor in Next";
1170 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1173 HT
: Hash_Table_Type
renames Position
.Container
.HT
;
1174 Node
: constant Node_Access
:= HT_Ops
.Next
(HT
, Position
.Node
);
1176 return (if Node
= null then No_Element
1177 else Cursor
'(Position.Container, Node));
1181 procedure Next (Position : in out Cursor) is
1183 Position := Next (Position);
1188 Position : Cursor) return Cursor
1191 if Position.Container = null then
1195 if Checks and then Position.Container /= Object.Container then
1196 raise Program_Error with
1197 "Position cursor of Next designates wrong set";
1200 return Next (Position);
1207 function Overlap (Left, Right : Set) return Boolean is
1208 Left_HT : Hash_Table_Type renames Left'Unrestricted_Access.HT;
1209 Right_HT : Hash_Table_Type renames Right'Unrestricted_Access.HT;
1210 Left_Node : Node_Access;
1213 if Right.Length = 0 then
1217 if Left'Address = Right'Address then
1221 Left_Node := HT_Ops.First (Left_HT);
1222 while Left_Node /= null loop
1223 if Is_In (Right_HT, Left_Node) then
1227 Left_Node := HT_Ops.Next (Left_HT, Left_Node);
1233 ----------------------
1234 -- Pseudo_Reference --
1235 ----------------------
1237 function Pseudo_Reference
1238 (Container : aliased Set'Class) return Reference_Control_Type
1240 TC : constant Tamper_Counts_Access :=
1241 Container.HT.TC'Unrestricted_Access;
1243 return R : constant Reference_Control_Type := (Controlled with TC) do
1246 end Pseudo_Reference;
1252 procedure Query_Element
1254 Process : not null access procedure (Element : Element_Type))
1257 if Checks and then Position.Node = null then
1258 raise Constraint_Error with
1259 "Position cursor of Query_Element equals No_Element";
1262 if Checks and then Position.Node.Element = null then
1263 raise Program_Error with "bad cursor in Query_Element";
1266 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1269 HT : Hash_Table_Type renames
1270 Position.Container'Unrestricted_Access.all.HT;
1271 Lock : With_Lock (HT.TC'Unrestricted_Access);
1273 Process (Position.Node.Element.all);
1282 (S : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class; V : Set)
1284 First_Time : Boolean := True;
1285 use System.Put_Images;
1291 First_Time := False;
1293 Simple_Array_Between (S);
1296 Element_Type'Put_Image (S, X);
1307 (Stream : not null access Root_Stream_Type'Class;
1308 Container : out Set)
1311 Read_Nodes (Stream, Container.HT);
1315 (Stream : not null access Root_Stream_Type'Class;
1319 raise Program_Error with "attempt to stream set cursor";
1323 (Stream : not null access Root_Stream_Type'Class;
1324 Item : out Constant_Reference_Type)
1327 raise Program_Error with "attempt to stream reference";
1335 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1337 X : Element_Access := new Element_Type'(Element_Type
'Input (Stream
));
1339 return new Node_Type
'(X, null);
1351 (Container : in out Set;
1352 New_Item : Element_Type)
1354 Node : constant Node_Access :=
1355 Element_Keys.Find (Container.HT, New_Item);
1358 pragma Warnings (Off, X);
1361 TE_Check (Container.HT.TC);
1363 if Checks and then Node = null then
1364 raise Constraint_Error with
1365 "attempt to replace element not in set";
1371 -- The element allocator may need an accessibility check in the case
1372 -- the actual type is class-wide or has access discriminants (see
1373 -- RM 4.8(10.1) and AI12-0035).
1375 pragma Unsuppress (Accessibility_Check);
1378 Node.Element := new Element_Type'(New_Item
);
1384 ---------------------
1385 -- Replace_Element --
1386 ---------------------
1388 procedure Replace_Element
1389 (Container
: in out Set
;
1391 New_Item
: Element_Type
)
1394 if Checks
and then Position
.Node
= null then
1395 raise Constraint_Error
with "Position cursor equals No_Element";
1398 if Checks
and then Position
.Node
.Element
= null then
1399 raise Program_Error
with "bad cursor in Replace_Element";
1402 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
1404 raise Program_Error
with
1405 "Position cursor designates wrong set";
1408 pragma Assert
(Vet
(Position
), "bad cursor in Replace_Element");
1410 Replace_Element
(Container
.HT
, Position
.Node
, New_Item
);
1411 end Replace_Element
;
1413 ----------------------
1414 -- Reserve_Capacity --
1415 ----------------------
1417 procedure Reserve_Capacity
1418 (Container
: in out Set
;
1419 Capacity
: Count_Type
)
1422 HT_Ops
.Reserve_Capacity
(Container
.HT
, Capacity
);
1423 end Reserve_Capacity
;
1429 procedure Set_Next
(Node
: Node_Access
; Next
: Node_Access
) is
1434 --------------------------
1435 -- Symmetric_Difference --
1436 --------------------------
1438 procedure Symmetric_Difference
1439 (Target
: in out Set
;
1442 Tgt_HT
: Hash_Table_Type
renames Target
.HT
;
1443 Src_HT
: Hash_Table_Type
renames Source
.HT
'Unrestricted_Access.all;
1445 if Target
'Address = Source
'Address then
1450 TC_Check
(Tgt_HT
.TC
);
1453 N
: constant Count_Type
:= Target
.Length
+ Source
.Length
;
1455 if N
> HT_Ops
.Capacity
(Tgt_HT
) then
1456 HT_Ops
.Reserve_Capacity
(Tgt_HT
, N
);
1460 if Target
.Length
= 0 then
1461 Iterate_Source_When_Empty_Target
: declare
1462 procedure Process
(Src_Node
: Node_Access
);
1464 procedure Iterate
is new HT_Ops
.Generic_Iteration
(Process
);
1470 procedure Process
(Src_Node
: Node_Access
) is
1471 E
: Element_Type
renames Src_Node
.Element
.all;
1472 B
: Buckets_Type
renames Tgt_HT
.Buckets
.all;
1473 J
: constant Hash_Type
:= Hash
(E
) mod B
'Length;
1474 N
: Count_Type
renames Tgt_HT
.Length
;
1478 X
: Element_Access
:= new Element_Type
'(E);
1480 B (J) := new Node_Type'(X
, B
(J
));
1490 -- Per AI05-0022, the container implementation is required to
1491 -- detect element tampering by a generic actual subprogram.
1493 Lock_Tgt
: With_Lock
(Tgt_HT
.TC
'Unrestricted_Access);
1494 Lock_Src
: With_Lock
(Src_HT
.TC
'Unrestricted_Access);
1496 -- Start of processing for Iterate_Source_When_Empty_Target
1500 end Iterate_Source_When_Empty_Target
;
1503 Iterate_Source
: declare
1504 procedure Process
(Src_Node
: Node_Access
);
1506 procedure Iterate
is
1507 new HT_Ops
.Generic_Iteration
(Process
);
1513 procedure Process
(Src_Node
: Node_Access
) is
1514 E
: Element_Type
renames Src_Node
.Element
.all;
1515 B
: Buckets_Type
renames Tgt_HT
.Buckets
.all;
1516 J
: constant Hash_Type
:= Hash
(E
) mod B
'Length;
1517 N
: Count_Type
renames Tgt_HT
.Length
;
1520 if B
(J
) = null then
1522 X
: Element_Access
:= new Element_Type
'(E);
1524 B (J) := new Node_Type'(X
, null);
1533 elsif Equivalent_Elements
(E
, B
(J
).Element
.all) then
1535 X
: Node_Access
:= B
(J
);
1537 B
(J
) := B
(J
).Next
;
1544 Prev
: Node_Access
:= B
(J
);
1545 Curr
: Node_Access
:= Prev
.Next
;
1548 while Curr
/= null loop
1549 if Equivalent_Elements
(E
, Curr
.Element
.all) then
1550 Prev
.Next
:= Curr
.Next
;
1561 X
: Element_Access
:= new Element_Type
'(E);
1563 B (J) := new Node_Type'(X
, B
(J
));
1575 -- Per AI05-0022, the container implementation is required to
1576 -- detect element tampering by a generic actual subprogram.
1578 Lock_Tgt
: With_Lock
(Tgt_HT
.TC
'Unrestricted_Access);
1579 Lock_Src
: With_Lock
(Src_HT
.TC
'Unrestricted_Access);
1581 -- Start of processing for Iterate_Source
1587 end Symmetric_Difference
;
1589 function Symmetric_Difference
(Left
, Right
: Set
) return Set
is
1590 Left_HT
: Hash_Table_Type
renames Left
'Unrestricted_Access.HT
;
1591 Right_HT
: Hash_Table_Type
renames Right
'Unrestricted_Access.HT
;
1592 Buckets
: HT_Types
.Buckets_Access
;
1593 Length
: Count_Type
;
1596 if Left
'Address = Right
'Address then
1600 if Right
.Length
= 0 then
1604 if Left
.Length
= 0 then
1609 Size
: constant Hash_Type
:=
1610 Prime_Numbers
.To_Prime
(Left
.Length
+ Right
.Length
);
1612 Buckets
:= HT_Ops
.New_Buckets
(Length
=> Size
);
1617 Iterate_Left
: declare
1618 procedure Process
(L_Node
: Node_Access
);
1620 procedure Iterate
is
1621 new HT_Ops
.Generic_Iteration
(Process
);
1627 procedure Process
(L_Node
: Node_Access
) is
1629 if not Is_In
(Right_HT
, L_Node
) then
1631 E
: Element_Type
renames L_Node
.Element
.all;
1633 -- Per AI05-0022, the container implementation is required
1634 -- to detect element tampering by a generic actual
1635 -- subprogram, hence the use of Checked_Index instead of a
1636 -- simple invocation of generic formal Hash.
1638 J
: constant Hash_Type
:=
1639 HT_Ops
.Checked_Index
(Left_HT
, Buckets
.all, L_Node
);
1643 X
: Element_Access
:= new Element_Type
'(E);
1645 Buckets (J) := new Node_Type'(X
, Buckets
(J
));
1652 Length
:= Length
+ 1;
1657 -- Start of processing for Iterate_Left
1663 HT_Ops
.Free_Hash_Table
(Buckets
);
1667 Iterate_Right
: declare
1668 procedure Process
(R_Node
: Node_Access
);
1670 procedure Iterate
is
1671 new HT_Ops
.Generic_Iteration
(Process
);
1677 procedure Process
(R_Node
: Node_Access
) is
1679 if not Is_In
(Left_HT
, R_Node
) then
1681 E
: Element_Type
renames R_Node
.Element
.all;
1683 -- Per AI05-0022, the container implementation is required
1684 -- to detect element tampering by a generic actual
1685 -- subprogram, hence the use of Checked_Index instead of a
1686 -- simple invocation of generic formal Hash.
1688 J
: constant Hash_Type
:=
1689 HT_Ops
.Checked_Index
(Right_HT
, Buckets
.all, R_Node
);
1693 X
: Element_Access
:= new Element_Type
'(E);
1695 Buckets (J) := new Node_Type'(X
, Buckets
(J
));
1702 Length
:= Length
+ 1;
1707 -- Start of processing for Iterate_Right
1714 HT_Ops
.Free_Hash_Table
(Buckets
);
1718 return (Controlled
with HT
=> (Buckets
, Length
, (Busy
=> 0, Lock
=> 0)));
1719 end Symmetric_Difference
;
1725 function To_Set
(New_Item
: Element_Type
) return Set
is
1726 HT
: Hash_Table_Type
;
1730 Insert
(HT
, New_Item
, Node
, Inserted
);
1731 return Set
'(Controlled with HT);
1739 (Target : in out Set;
1742 procedure Process (Src_Node : Node_Access);
1744 procedure Iterate is
1745 new HT_Ops.Generic_Iteration (Process);
1751 procedure Process (Src_Node : Node_Access) is
1752 Src : Element_Type renames Src_Node.Element.all;
1754 function New_Node (Next : Node_Access) return Node_Access;
1755 pragma Inline (New_Node);
1758 new Element_Keys.Generic_Conditional_Insert (New_Node);
1764 function New_Node (Next : Node_Access) return Node_Access is
1765 Tgt : Element_Access := new Element_Type'(Src
);
1767 return new Node_Type
'(Tgt, Next);
1774 Tgt_Node : Node_Access;
1777 -- Start of processing for Process
1780 Insert (Target.HT, Src, Tgt_Node, Success);
1783 -- Start of processing for Union
1786 if Target'Address = Source'Address then
1790 TC_Check (Target.HT.TC);
1793 N : constant Count_Type := Target.Length + Source.Length;
1795 if N > HT_Ops.Capacity (Target.HT) then
1796 HT_Ops.Reserve_Capacity (Target.HT, N);
1800 Iterate (Source.HT);
1803 function Union (Left, Right : Set) return Set is
1804 Left_HT : Hash_Table_Type renames Left.HT'Unrestricted_Access.all;
1805 Right_HT : Hash_Table_Type renames Right.HT'Unrestricted_Access.all;
1806 Buckets : HT_Types.Buckets_Access;
1807 Length : Count_Type;
1810 if Left'Address = Right'Address then
1814 if Right.Length = 0 then
1818 if Left.Length = 0 then
1823 Size : constant Hash_Type :=
1824 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1826 Buckets := HT_Ops.New_Buckets (Length => Size);
1829 Iterate_Left : declare
1830 procedure Process (L_Node : Node_Access);
1832 procedure Iterate is
1833 new HT_Ops.Generic_Iteration (Process);
1839 procedure Process (L_Node : Node_Access) is
1840 Src : Element_Type renames L_Node.Element.all;
1841 J : constant Hash_Type := Hash (Src) mod Buckets'Length;
1842 Bucket : Node_Access renames Buckets (J);
1843 Tgt : Element_Access := new Element_Type'(Src
);
1845 Bucket
:= new Node_Type
'(Tgt, Bucket);
1852 -- Per AI05-0022, the container implementation is required to detect
1853 -- element tampering by a generic actual subprogram, hence the use of
1854 -- Checked_Index instead of a simple invocation of generic formal
1857 Lock_Left : With_Lock (Left_HT.TC'Unrestricted_Access);
1859 -- Start of processing for Iterate_Left
1865 HT_Ops.Free_Hash_Table (Buckets);
1869 Length := Left.Length;
1871 Iterate_Right : declare
1872 procedure Process (Src_Node : Node_Access);
1874 procedure Iterate is
1875 new HT_Ops.Generic_Iteration (Process);
1881 procedure Process (Src_Node : Node_Access) is
1882 Src : Element_Type renames Src_Node.Element.all;
1883 Idx : constant Hash_Type := Hash (Src) mod Buckets'Length;
1885 Tgt_Node : Node_Access := Buckets (Idx);
1888 while Tgt_Node /= null loop
1889 if Equivalent_Elements (Src, Tgt_Node.Element.all) then
1892 Tgt_Node := Next (Tgt_Node);
1896 Tgt : Element_Access := new Element_Type'(Src
);
1898 Buckets
(Idx
) := new Node_Type
'(Tgt, Buckets (Idx));
1905 Length := Length + 1;
1908 -- Per AI05-0022, the container implementation is required to detect
1909 -- element tampering by a generic actual subprogram, hence the use of
1910 -- Checked_Index instead of a simple invocation of generic formal
1913 Lock_Left : With_Lock (Left_HT.TC'Unrestricted_Access);
1914 Lock_Right : With_Lock (Right_HT.TC'Unrestricted_Access);
1916 -- Start of processing for Iterate_Right
1922 HT_Ops.Free_Hash_Table (Buckets);
1926 return (Controlled with HT => (Buckets, Length, (Busy => 0, Lock => 0)));
1933 function Vet (Position : Cursor) return Boolean is
1935 if not Container_Checks'Enabled then
1939 if Position.Node = null then
1940 return Position.Container = null;
1943 if Position.Container = null then
1947 if Position.Node.Next = Position.Node then
1951 if Position.Node.Element = null then
1956 HT : Hash_Table_Type renames Position.Container.HT;
1960 if HT.Length = 0 then
1964 if HT.Buckets = null
1965 or else HT.Buckets'Length = 0
1970 X := HT.Buckets (Element_Keys.Checked_Index
1972 Position.Node.Element.all));
1974 for J in 1 .. HT.Length loop
1975 if X = Position.Node then
1983 if X = X.Next then -- to prevent unnecessary looping
1999 (Stream : not null access Root_Stream_Type'Class;
2003 Write_Nodes (Stream, Container.HT);
2007 (Stream : not null access Root_Stream_Type'Class;
2011 raise Program_Error with "attempt to stream set cursor";
2015 (Stream : not null access Root_Stream_Type'Class;
2016 Item : Constant_Reference_Type)
2019 raise Program_Error with "attempt to stream reference";
2026 procedure Write_Node
2027 (Stream : not null access Root_Stream_Type'Class;
2031 Element_Type'Output (Stream, Node.Element.all);
2034 -- Ada 2022 features:
2036 function Has_Element (Container : Set; Position : Cursor) return Boolean is
2038 pragma Assert (Vet (Position), "bad cursor in Has_Element");
2039 pragma Assert ((Position.Container = null) = (Position.Node = null),
2040 "bad nullity in Has_Element");
2041 return Position.Container = Container'Unrestricted_Access;
2044 function Tampering_With_Cursors_Prohibited
2045 (Container : Set) return Boolean
2048 return Is_Busy (Container.HT.TC);
2049 end Tampering_With_Cursors_Prohibited;
2051 function Element (Container : Set; Position : Cursor) return Element_Type is
2053 if Checks and then not Has_Element (Container, Position) then
2054 raise Program_Error with "Position for wrong Container";
2057 return Element (Position);
2060 procedure Query_Element
2063 Process : not null access procedure (Element : Element_Type)) is
2065 if Checks and then not Has_Element (Container, Position) then
2066 raise Program_Error with "Position for wrong Container";
2069 Query_Element (Position, Process);
2072 function Next (Container : Set; Position : Cursor) return Cursor is
2075 not (Position = No_Element or else Has_Element (Container, Position))
2077 raise Program_Error with "Position for wrong Container";
2080 return Next (Position);
2083 procedure Next (Container : Set; Position : in out Cursor) is
2085 Position := Next (Container, Position);
2092 package body Generic_Keys is
2094 -----------------------
2095 -- Local Subprograms --
2096 -----------------------
2098 function Equivalent_Key_Node
2100 Node : Node_Access) return Boolean;
2101 pragma Inline (Equivalent_Key_Node);
2103 --------------------------
2104 -- Local Instantiations --
2105 --------------------------
2108 new Hash_Tables.Generic_Keys
2109 (HT_Types => HT_Types,
2111 Set_Next => Set_Next,
2112 Key_Type => Key_Type,
2114 Equivalent_Keys => Equivalent_Key_Node);
2116 ------------------------
2117 -- Constant_Reference --
2118 ------------------------
2120 function Constant_Reference
2121 (Container : aliased Set;
2122 Key : Key_Type) return Constant_Reference_Type
2124 Position : constant Cursor := Find (Container, Key);
2127 if Checks and then Position = No_Element then
2128 raise Constraint_Error with "Key not in set";
2131 return Constant_Reference (Container, Position);
2132 end Constant_Reference;
2140 Key : Key_Type) return Boolean
2143 return Find (Container, Key) /= No_Element;
2151 (Container : in out Set;
2157 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
2159 if Checks and then X = null then
2160 raise Constraint_Error with "key not in set";
2172 Key : Key_Type) return Element_Type
2174 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
2175 Node : constant Node_Access := Key_Keys.Find (HT, Key);
2178 if Checks and then Node = null then
2179 raise Constraint_Error with "key not in set";
2182 return Node.Element.all;
2185 -------------------------
2186 -- Equivalent_Key_Node --
2187 -------------------------
2189 function Equivalent_Key_Node
2191 Node : Node_Access) return Boolean is
2193 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element.all));
2194 end Equivalent_Key_Node;
2201 (Container : in out Set;
2206 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
2214 procedure Finalize (Control : in out Reference_Control_Type) is
2216 if Control.Container /= null then
2217 Impl.Reference_Control_Type (Control).Finalize;
2219 if Checks and then Hash (Key (Control.Old_Pos)) /= Control.Old_Hash
2221 HT_Ops.Delete_Node_At_Index
2222 (Control.Container.HT, Control.Index, Control.Old_Pos.Node);
2223 raise Program_Error;
2226 Control.Container := null;
2236 Key : Key_Type) return Cursor
2238 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
2239 Node : constant Node_Access := Key_Keys.Find (HT, Key);
2241 return (if Node = null then No_Element
2242 else Cursor'(Container
'Unrestricted_Access, Node
));
2249 function Key
(Position
: Cursor
) return Key_Type
is
2251 if Checks
and then Position
.Node
= null then
2252 raise Constraint_Error
with
2253 "Position cursor equals No_Element";
2256 if Checks
and then Position
.Node
.Element
= null then
2257 raise Program_Error
with "Position cursor is bad";
2260 pragma Assert
(Vet
(Position
), "bad cursor in function Key");
2262 return Key
(Position
.Node
.Element
.all);
2270 (Stream
: not null access Root_Stream_Type
'Class;
2271 Item
: out Reference_Type
)
2274 raise Program_Error
with "attempt to stream reference";
2277 ------------------------------
2278 -- Reference_Preserving_Key --
2279 ------------------------------
2281 function Reference_Preserving_Key
2282 (Container
: aliased in out Set
;
2283 Position
: Cursor
) return Reference_Type
2286 if Checks
and then Position
.Container
= null then
2287 raise Constraint_Error
with "Position cursor has no element";
2290 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2292 raise Program_Error
with
2293 "Position cursor designates wrong container";
2296 if Checks
and then Position
.Node
.Element
= null then
2297 raise Program_Error
with "Node has no element";
2302 "bad cursor in function Reference_Preserving_Key");
2305 HT
: Hash_Table_Type
renames Container
.HT
;
2307 return R
: constant Reference_Type
:=
2308 (Element
=> Position
.Node
.Element
.all'Access,
2311 HT
.TC
'Unrestricted_Access,
2312 Container
=> Container
'Unchecked_Access,
2313 Index
=> HT_Ops
.Index
(HT
, Position
.Node
),
2314 Old_Pos
=> Position
,
2315 Old_Hash
=> Hash
(Key
(Position
))))
2320 end Reference_Preserving_Key
;
2322 function Reference_Preserving_Key
2323 (Container
: aliased in out Set
;
2324 Key
: Key_Type
) return Reference_Type
2326 Position
: constant Cursor
:= Find
(Container
, Key
);
2329 if Checks
and then Position
= No_Element
then
2330 raise Constraint_Error
with "Key not in set";
2333 return Reference_Preserving_Key
(Container
, Position
);
2334 end Reference_Preserving_Key
;
2341 (Container
: in out Set
;
2343 New_Item
: Element_Type
)
2345 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.HT
, Key
);
2348 if Checks
and then Node
= null then
2349 raise Constraint_Error
with
2350 "attempt to replace key not in set";
2353 Replace_Element
(Container
.HT
, Node
, New_Item
);
2356 -----------------------------------
2357 -- Update_Element_Preserving_Key --
2358 -----------------------------------
2360 procedure Update_Element_Preserving_Key
2361 (Container
: in out Set
;
2363 Process
: not null access
2364 procedure (Element
: in out Element_Type
))
2366 HT
: Hash_Table_Type
renames Container
.HT
;
2370 if Checks
and then Position
.Node
= null then
2371 raise Constraint_Error
with
2372 "Position cursor equals No_Element";
2376 (Position
.Node
.Element
= null
2377 or else Position
.Node
.Next
= Position
.Node
)
2379 raise Program_Error
with "Position cursor is bad";
2382 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2384 raise Program_Error
with
2385 "Position cursor designates wrong set";
2390 or else HT
.Buckets
'Length = 0
2391 or else HT
.Length
= 0)
2393 raise Program_Error
with "Position cursor is bad (set is empty)";
2398 "bad cursor in Update_Element_Preserving_Key");
2400 -- Per AI05-0022, the container implementation is required to detect
2401 -- element tampering by a generic actual subprogram.
2404 E
: Element_Type
renames Position
.Node
.Element
.all;
2405 K
: constant Key_Type
:= Key
(E
);
2406 Lock
: With_Lock
(HT
.TC
'Unrestricted_Access);
2408 Indx
:= HT_Ops
.Index
(HT
, Position
.Node
);
2411 if Equivalent_Keys
(K
, Key
(E
)) then
2416 if HT
.Buckets
(Indx
) = Position
.Node
then
2417 HT
.Buckets
(Indx
) := Position
.Node
.Next
;
2421 Prev
: Node_Access
:= HT
.Buckets
(Indx
);
2424 while Prev
.Next
/= Position
.Node
loop
2427 if Checks
and then Prev
= null then
2428 raise Program_Error
with
2429 "Position cursor is bad (node not found)";
2433 Prev
.Next
:= Position
.Node
.Next
;
2437 HT
.Length
:= HT
.Length
- 1;
2440 X
: Node_Access
:= Position
.Node
;
2446 raise Program_Error
with "key was modified";
2447 end Update_Element_Preserving_Key
;
2454 (Stream
: not null access Root_Stream_Type
'Class;
2455 Item
: Reference_Type
)
2458 raise Program_Error
with "attempt to stream reference";
2463 end Ada
.Containers
.Indefinite_Hashed_Sets
;