1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . B O U N D E D _ H A S H E D _ S E T S --
9 -- Copyright (C) 2004-2018, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada
.Containers
.Hash_Tables
.Generic_Bounded_Operations
;
31 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Bounded_Operations
);
33 with Ada
.Containers
.Hash_Tables
.Generic_Bounded_Keys
;
34 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Bounded_Keys
);
36 with Ada
.Containers
.Helpers
; use Ada
.Containers
.Helpers
;
38 with Ada
.Containers
.Prime_Numbers
; use Ada
.Containers
.Prime_Numbers
;
40 with System
; use type System
.Address
;
42 package body Ada
.Containers
.Bounded_Hashed_Sets
is
44 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
45 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
46 -- See comment in Ada.Containers.Helpers
48 -----------------------
49 -- Local Subprograms --
50 -----------------------
52 function Equivalent_Keys
54 Node
: Node_Type
) return Boolean;
55 pragma Inline
(Equivalent_Keys
);
57 function Hash_Node
(Node
: Node_Type
) return Hash_Type
;
58 pragma Inline
(Hash_Node
);
61 (Container
: in out Set
;
62 New_Item
: Element_Type
;
63 Node
: out Count_Type
;
64 Inserted
: out Boolean);
66 function Is_In
(HT
: Set
; Key
: Node_Type
) return Boolean;
67 pragma Inline
(Is_In
);
69 procedure Set_Element
(Node
: in out Node_Type
; Item
: Element_Type
);
70 pragma Inline
(Set_Element
);
72 function Next
(Node
: Node_Type
) return Count_Type
;
75 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
);
76 pragma Inline
(Set_Next
);
78 function Vet
(Position
: Cursor
) return Boolean;
80 --------------------------
81 -- Local Instantiations --
82 --------------------------
84 package HT_Ops
is new Hash_Tables
.Generic_Bounded_Operations
85 (HT_Types
=> HT_Types
,
86 Hash_Node
=> Hash_Node
,
88 Set_Next
=> Set_Next
);
90 package Element_Keys
is new Hash_Tables
.Generic_Bounded_Keys
91 (HT_Types
=> HT_Types
,
94 Key_Type
=> Element_Type
,
96 Equivalent_Keys
=> Equivalent_Keys
);
98 procedure Replace_Element
is
99 new Element_Keys
.Generic_Replace_Element
(Hash_Node
, Set_Element
);
105 function "=" (Left
, Right
: Set
) return Boolean is
106 function Find_Equal_Key
107 (R_HT
: Hash_Table_Type
'Class;
108 L_Node
: Node_Type
) return Boolean;
109 pragma Inline
(Find_Equal_Key
);
112 new HT_Ops
.Generic_Equal
(Find_Equal_Key
);
118 function Find_Equal_Key
119 (R_HT
: Hash_Table_Type
'Class;
120 L_Node
: Node_Type
) return Boolean
122 R_Index
: constant Hash_Type
:=
123 Element_Keys
.Index
(R_HT
, L_Node
.Element
);
125 R_Node
: Count_Type
:= R_HT
.Buckets
(R_Index
);
133 if L_Node
.Element
= R_HT
.Nodes
(R_Node
).Element
then
137 R_Node
:= Next
(R_HT
.Nodes
(R_Node
));
141 -- Start of processing for "="
144 return Is_Equal
(Left
, Right
);
151 procedure Assign
(Target
: in out Set
; Source
: Set
) is
152 procedure Insert_Element
(Source_Node
: Count_Type
);
154 procedure Insert_Elements
is
155 new HT_Ops
.Generic_Iteration
(Insert_Element
);
161 procedure Insert_Element
(Source_Node
: Count_Type
) is
162 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
166 Insert
(Target
, N
.Element
, X
, B
);
170 -- Start of processing for Assign
173 if Target
'Address = Source
'Address then
177 if Checks
and then Target
.Capacity
< Source
.Length
then
179 with "Target capacity is less than Source length";
182 HT_Ops
.Clear
(Target
);
183 Insert_Elements
(Source
);
190 function Capacity
(Container
: Set
) return Count_Type
is
192 return Container
.Capacity
;
199 procedure Clear
(Container
: in out Set
) is
201 HT_Ops
.Clear
(Container
);
204 ------------------------
205 -- Constant_Reference --
206 ------------------------
208 function Constant_Reference
209 (Container
: aliased Set
;
210 Position
: Cursor
) return Constant_Reference_Type
213 if Checks
and then Position
.Container
= null then
214 raise Constraint_Error
with "Position cursor has no element";
217 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
219 raise Program_Error
with
220 "Position cursor designates wrong container";
223 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
226 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
227 TC
: constant Tamper_Counts_Access
:=
228 Container
.TC
'Unrestricted_Access;
230 return R
: constant Constant_Reference_Type
:=
231 (Element
=> N
.Element
'Access,
232 Control
=> (Controlled
with TC
))
237 end Constant_Reference
;
243 function Contains
(Container
: Set
; Item
: Element_Type
) return Boolean is
245 return Find
(Container
, Item
) /= No_Element
;
254 Capacity
: Count_Type
:= 0;
255 Modulus
: Hash_Type
:= 0) return Set
263 elsif Capacity
>= Source
.Length
then
266 raise Capacity_Error
with "Capacity value too small";
270 M
:= Default_Modulus
(C
);
275 return Target
: Set
(Capacity
=> C
, Modulus
=> M
) do
276 Assign
(Target
=> Target
, Source
=> Source
);
280 ---------------------
281 -- Default_Modulus --
282 ---------------------
284 function Default_Modulus
(Capacity
: Count_Type
) return Hash_Type
is
286 return To_Prime
(Capacity
);
294 (Container
: in out Set
;
300 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
302 if Checks
and then X
= 0 then
303 raise Constraint_Error
with "attempt to delete element not in set";
306 HT_Ops
.Free
(Container
, X
);
310 (Container
: in out Set
;
311 Position
: in out Cursor
)
314 if Checks
and then Position
.Node
= 0 then
315 raise Constraint_Error
with "Position cursor equals No_Element";
318 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
320 raise Program_Error
with "Position cursor designates wrong set";
323 TC_Check
(Container
.TC
);
325 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
327 HT_Ops
.Delete_Node_Sans_Free
(Container
, Position
.Node
);
328 HT_Ops
.Free
(Container
, Position
.Node
);
330 Position
:= No_Element
;
338 (Target
: in out Set
;
341 Tgt_Node
, Src_Node
: Count_Type
;
343 Src
: Set
renames Source
'Unrestricted_Access.all;
345 TN
: Nodes_Type
renames Target
.Nodes
;
346 SN
: Nodes_Type
renames Source
.Nodes
;
349 if Target
'Address = Source
'Address then
350 HT_Ops
.Clear
(Target
);
354 if Source
.Length
= 0 then
358 TC_Check
(Target
.TC
);
360 if Source
.Length
< Target
.Length
then
361 Src_Node
:= HT_Ops
.First
(Source
);
362 while Src_Node
/= 0 loop
363 Tgt_Node
:= Element_Keys
.Find
(Target
, SN
(Src_Node
).Element
);
365 if Tgt_Node
/= 0 then
366 HT_Ops
.Delete_Node_Sans_Free
(Target
, Tgt_Node
);
367 HT_Ops
.Free
(Target
, Tgt_Node
);
370 Src_Node
:= HT_Ops
.Next
(Src
, Src_Node
);
374 Tgt_Node
:= HT_Ops
.First
(Target
);
375 while Tgt_Node
/= 0 loop
376 if Is_In
(Source
, TN
(Tgt_Node
)) then
378 X
: constant Count_Type
:= Tgt_Node
;
380 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
381 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
382 HT_Ops
.Free
(Target
, X
);
386 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
392 function Difference
(Left
, Right
: Set
) return Set
is
394 if Left
'Address = Right
'Address then
398 if Left
.Length
= 0 then
402 if Right
.Length
= 0 then
406 return Result
: Set
(Left
.Length
, To_Prime
(Left
.Length
)) do
407 Iterate_Left
: declare
408 procedure Process
(L_Node
: Count_Type
);
411 new HT_Ops
.Generic_Iteration
(Process
);
417 procedure Process
(L_Node
: Count_Type
) is
418 N
: Node_Type
renames Left
.Nodes
(L_Node
);
422 if not Is_In
(Right
, N
) then
423 Insert
(Result
, N
.Element
, X
, B
); -- optimize this ???
425 pragma Assert
(X
> 0);
429 -- Start of processing for Iterate_Left
441 function Element
(Position
: Cursor
) return Element_Type
is
443 if Checks
and then Position
.Node
= 0 then
444 raise Constraint_Error
with "Position cursor equals No_Element";
447 pragma Assert
(Vet
(Position
), "bad cursor in function Element");
450 S
: Set
renames Position
.Container
.all;
451 N
: Node_Type
renames S
.Nodes
(Position
.Node
);
457 ---------------------
458 -- Equivalent_Sets --
459 ---------------------
461 function Equivalent_Sets
(Left
, Right
: Set
) return Boolean is
462 function Find_Equivalent_Key
463 (R_HT
: Hash_Table_Type
'Class;
464 L_Node
: Node_Type
) return Boolean;
465 pragma Inline
(Find_Equivalent_Key
);
467 function Is_Equivalent
is
468 new HT_Ops
.Generic_Equal
(Find_Equivalent_Key
);
470 -------------------------
471 -- Find_Equivalent_Key --
472 -------------------------
474 function Find_Equivalent_Key
475 (R_HT
: Hash_Table_Type
'Class;
476 L_Node
: Node_Type
) return Boolean
478 R_Index
: constant Hash_Type
:=
479 Element_Keys
.Index
(R_HT
, L_Node
.Element
);
481 R_Node
: Count_Type
:= R_HT
.Buckets
(R_Index
);
483 RN
: Nodes_Type
renames R_HT
.Nodes
;
491 if Equivalent_Elements
(L_Node
.Element
, RN
(R_Node
).Element
) then
495 R_Node
:= Next
(R_HT
.Nodes
(R_Node
));
497 end Find_Equivalent_Key
;
499 -- Start of processing for Equivalent_Sets
502 return Is_Equivalent
(Left
, Right
);
505 -------------------------
506 -- Equivalent_Elements --
507 -------------------------
509 function Equivalent_Elements
(Left
, Right
: Cursor
)
513 if Checks
and then Left
.Node
= 0 then
514 raise Constraint_Error
with
515 "Left cursor of Equivalent_Elements equals No_Element";
518 if Checks
and then Right
.Node
= 0 then
519 raise Constraint_Error
with
520 "Right cursor of Equivalent_Elements equals No_Element";
523 pragma Assert
(Vet
(Left
), "bad Left cursor in Equivalent_Elements");
524 pragma Assert
(Vet
(Right
), "bad Right cursor in Equivalent_Elements");
526 -- AI05-0022 requires that a container implementation detect element
527 -- tampering by a generic actual subprogram. However, the following case
528 -- falls outside the scope of that AI. Randy Brukardt explained on the
529 -- ARG list on 2013/02/07 that:
532 -- But for an operation like "<" [the ordered set analog of
533 -- Equivalent_Elements], there is no need to "dereference" a cursor
534 -- after the call to the generic formal parameter function, so nothing
535 -- bad could happen if tampering is undetected. And the operation can
536 -- safely return a result without a problem even if an element is
537 -- deleted from the container.
541 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
542 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
544 return Equivalent_Elements
(LN
.Element
, RN
.Element
);
546 end Equivalent_Elements
;
548 function Equivalent_Elements
550 Right
: Element_Type
) return Boolean
553 if Checks
and then Left
.Node
= 0 then
554 raise Constraint_Error
with
555 "Left cursor of Equivalent_Elements equals No_Element";
558 pragma Assert
(Vet
(Left
), "Left cursor in Equivalent_Elements is bad");
561 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
563 return Equivalent_Elements
(LN
.Element
, Right
);
565 end Equivalent_Elements
;
567 function Equivalent_Elements
568 (Left
: Element_Type
;
569 Right
: Cursor
) return Boolean
572 if Checks
and then Right
.Node
= 0 then
573 raise Constraint_Error
with
574 "Right cursor of Equivalent_Elements equals No_Element";
579 "Right cursor of Equivalent_Elements is bad");
582 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
584 return Equivalent_Elements
(Left
, RN
.Element
);
586 end Equivalent_Elements
;
588 ---------------------
589 -- Equivalent_Keys --
590 ---------------------
592 function Equivalent_Keys
594 Node
: Node_Type
) return Boolean
597 return Equivalent_Elements
(Key
, Node
.Element
);
605 (Container
: in out Set
;
610 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
611 HT_Ops
.Free
(Container
, X
);
618 procedure Finalize
(Object
: in out Iterator
) is
620 if Object
.Container
/= null then
621 Unbusy
(Object
.Container
.TC
);
631 Item
: Element_Type
) return Cursor
633 Node
: constant Count_Type
:=
634 Element_Keys
.Find
(Container
'Unrestricted_Access.all, Item
);
636 return (if Node
= 0 then No_Element
637 else Cursor
'(Container'Unrestricted_Access, Node));
644 function First (Container : Set) return Cursor is
645 Node : constant Count_Type := HT_Ops.First (Container);
647 return (if Node = 0 then No_Element
648 else Cursor'(Container
'Unrestricted_Access, Node
));
651 overriding
function First
(Object
: Iterator
) return Cursor
is
653 return Object
.Container
.First
;
656 ------------------------
657 -- Get_Element_Access --
658 ------------------------
660 function Get_Element_Access
661 (Position
: Cursor
) return not null Element_Access
is
663 return Position
.Container
.Nodes
(Position
.Node
).Element
'Access;
664 end Get_Element_Access
;
670 function Has_Element
(Position
: Cursor
) return Boolean is
672 pragma Assert
(Vet
(Position
), "bad cursor in Has_Element");
673 return Position
.Node
/= 0;
680 function Hash_Node
(Node
: Node_Type
) return Hash_Type
is
682 return Hash
(Node
.Element
);
690 (Container
: in out Set
;
691 New_Item
: Element_Type
)
697 Insert
(Container
, New_Item
, Position
, Inserted
);
700 TE_Check
(Container
.TC
);
702 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
711 (Container
: in out Set
;
712 New_Item
: Element_Type
;
713 Position
: out Cursor
;
714 Inserted
: out Boolean)
717 Insert
(Container
, New_Item
, Position
.Node
, Inserted
);
718 Position
.Container
:= Container
'Unchecked_Access;
722 (Container
: in out Set
;
723 New_Item
: Element_Type
)
726 pragma Unreferenced
(Position
);
731 Insert
(Container
, New_Item
, Position
, Inserted
);
733 if Checks
and then not Inserted
then
734 raise Constraint_Error
with
735 "attempt to insert element already in set";
740 (Container
: in out Set
;
741 New_Item
: Element_Type
;
742 Node
: out Count_Type
;
743 Inserted
: out Boolean)
745 procedure Allocate_Set_Element
(Node
: in out Node_Type
);
746 pragma Inline
(Allocate_Set_Element
);
748 function New_Node
return Count_Type
;
749 pragma Inline
(New_Node
);
751 procedure Local_Insert
is
752 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
754 procedure Allocate
is
755 new HT_Ops
.Generic_Allocate
(Allocate_Set_Element
);
757 ---------------------------
758 -- Allocate_Set_Element --
759 ---------------------------
761 procedure Allocate_Set_Element
(Node
: in out Node_Type
) is
763 Node
.Element
:= New_Item
;
764 end Allocate_Set_Element
;
770 function New_Node
return Count_Type
is
773 Allocate
(Container
, Result
);
777 -- Start of processing for Insert
780 -- The buckets array length is specified by the user as a discriminant
781 -- of the container type, so it is possible for the buckets array to
782 -- have a length of zero. We must check for this case specifically, in
783 -- order to prevent divide-by-zero errors later, when we compute the
784 -- buckets array index value for an element, given its hash value.
786 if Checks
and then Container
.Buckets
'Length = 0 then
787 raise Capacity_Error
with "No capacity for insertion";
790 Local_Insert
(Container
, New_Item
, Node
, Inserted
);
797 procedure Intersection
798 (Target
: in out Set
;
801 Tgt_Node
: Count_Type
;
802 TN
: Nodes_Type
renames Target
.Nodes
;
805 if Target
'Address = Source
'Address then
809 if Source
.Length
= 0 then
810 HT_Ops
.Clear
(Target
);
814 TC_Check
(Target
.TC
);
816 Tgt_Node
:= HT_Ops
.First
(Target
);
817 while Tgt_Node
/= 0 loop
818 if Is_In
(Source
, TN
(Tgt_Node
)) then
819 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
823 X
: constant Count_Type
:= Tgt_Node
;
825 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
826 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
827 HT_Ops
.Free
(Target
, X
);
833 function Intersection
(Left
, Right
: Set
) return Set
is
837 if Left
'Address = Right
'Address then
841 C
:= Count_Type
'Min (Left
.Length
, Right
.Length
);
847 return Result
: Set
(C
, To_Prime
(C
)) do
848 Iterate_Left
: declare
849 procedure Process
(L_Node
: Count_Type
);
852 new HT_Ops
.Generic_Iteration
(Process
);
858 procedure Process
(L_Node
: Count_Type
) is
859 N
: Node_Type
renames Left
.Nodes
(L_Node
);
864 if Is_In
(Right
, N
) then
865 Insert
(Result
, N
.Element
, X
, B
); -- optimize ???
867 pragma Assert
(X
> 0);
871 -- Start of processing for Iterate_Left
883 function Is_Empty
(Container
: Set
) return Boolean is
885 return Container
.Length
= 0;
892 function Is_In
(HT
: Set
; Key
: Node_Type
) return Boolean is
894 return Element_Keys
.Find
(HT
'Unrestricted_Access.all, Key
.Element
) /= 0;
901 function Is_Subset
(Subset
: Set
; Of_Set
: Set
) return Boolean is
902 Subset_Node
: Count_Type
;
903 SN
: Nodes_Type
renames Subset
.Nodes
;
906 if Subset
'Address = Of_Set
'Address then
910 if Subset
.Length
> Of_Set
.Length
then
914 Subset_Node
:= HT_Ops
.First
(Subset
);
915 while Subset_Node
/= 0 loop
916 if not Is_In
(Of_Set
, SN
(Subset_Node
)) then
919 Subset_Node
:= HT_Ops
.Next
920 (Subset
'Unrestricted_Access.all, Subset_Node
);
932 Process
: not null access procedure (Position
: Cursor
))
934 procedure Process_Node
(Node
: Count_Type
);
935 pragma Inline
(Process_Node
);
938 new HT_Ops
.Generic_Iteration
(Process_Node
);
944 procedure Process_Node
(Node
: Count_Type
) is
946 Process
(Cursor
'(Container'Unrestricted_Access, Node));
949 Busy : With_Busy (Container.TC'Unrestricted_Access);
951 -- Start of processing for Iterate
957 function Iterate (Container : Set)
958 return Set_Iterator_Interfaces.Forward_Iterator'Class
961 Busy (Container.TC'Unrestricted_Access.all);
962 return It : constant Iterator :=
963 Iterator'(Limited_Controlled
with
964 Container
=> Container
'Unrestricted_Access);
971 function Length
(Container
: Set
) return Count_Type
is
973 return Container
.Length
;
980 procedure Move
(Target
: in out Set
; Source
: in out Set
) is
982 if Target
'Address = Source
'Address then
986 TC_Check
(Source
.TC
);
988 Target
.Assign
(Source
);
996 function Next
(Node
: Node_Type
) return Count_Type
is
1001 function Next
(Position
: Cursor
) return Cursor
is
1003 if Position
.Node
= 0 then
1007 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1010 HT
: Set
renames Position
.Container
.all;
1011 Node
: constant Count_Type
:= HT_Ops
.Next
(HT
, Position
.Node
);
1018 return Cursor
'(Position.Container, Node);
1022 procedure Next (Position : in out Cursor) is
1024 Position := Next (Position);
1029 Position : Cursor) return Cursor
1032 if Position.Container = null then
1036 if Checks and then Position.Container /= Object.Container then
1037 raise Program_Error with
1038 "Position cursor of Next designates wrong set";
1041 return Next (Position);
1048 function Overlap (Left, Right : Set) return Boolean is
1049 Left_Node : Count_Type;
1052 if Right.Length = 0 then
1056 if Left'Address = Right'Address then
1060 Left_Node := HT_Ops.First (Left);
1061 while Left_Node /= 0 loop
1062 if Is_In (Right, Left.Nodes (Left_Node)) then
1065 Left_Node := HT_Ops.Next (Left'Unrestricted_Access.all, Left_Node);
1071 ----------------------
1072 -- Pseudo_Reference --
1073 ----------------------
1075 function Pseudo_Reference
1076 (Container : aliased Set'Class) return Reference_Control_Type
1078 TC : constant Tamper_Counts_Access :=
1079 Container.TC'Unrestricted_Access;
1081 return R : constant Reference_Control_Type := (Controlled with TC) do
1084 end Pseudo_Reference;
1090 procedure Query_Element
1092 Process : not null access procedure (Element : Element_Type))
1095 if Checks and then Position.Node = 0 then
1096 raise Constraint_Error with
1097 "Position cursor of Query_Element equals No_Element";
1100 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1103 S : Set renames Position.Container.all;
1104 Lock : With_Lock (S.TC'Unrestricted_Access);
1106 Process (S.Nodes (Position.Node).Element);
1115 (Stream : not null access Root_Stream_Type'Class;
1116 Container : out Set)
1118 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1121 procedure Read_Nodes is
1122 new HT_Ops.Generic_Read (Read_Node);
1128 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1131 procedure Read_Element (Node : in out Node_Type);
1132 pragma Inline (Read_Element);
1134 procedure Allocate is
1135 new HT_Ops.Generic_Allocate (Read_Element);
1137 procedure Read_Element (Node : in out Node_Type) is
1139 Element_Type'Read (Stream, Node.Element);
1144 -- Start of processing for Read_Node
1147 Allocate (Container, Node);
1151 -- Start of processing for Read
1154 Read_Nodes (Stream, Container);
1158 (Stream : not null access Root_Stream_Type'Class;
1162 raise Program_Error with "attempt to stream set cursor";
1166 (Stream : not null access Root_Stream_Type'Class;
1167 Item : out Constant_Reference_Type)
1170 raise Program_Error with "attempt to stream reference";
1178 (Container : in out Set;
1179 New_Item : Element_Type)
1181 Node : constant Count_Type := Element_Keys.Find (Container, New_Item);
1184 if Checks and then Node = 0 then
1185 raise Constraint_Error with
1186 "attempt to replace element not in set";
1189 TE_Check (Container.TC);
1191 Container.Nodes (Node).Element := New_Item;
1194 procedure Replace_Element
1195 (Container : in out Set;
1197 New_Item : Element_Type)
1200 if Checks and then Position.Node = 0 then
1201 raise Constraint_Error with
1202 "Position cursor equals No_Element";
1205 if Checks and then Position.Container /= Container'Unrestricted_Access
1207 raise Program_Error with
1208 "Position cursor designates wrong set";
1211 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1213 Replace_Element (Container, Position.Node, New_Item);
1214 end Replace_Element;
1216 ----------------------
1217 -- Reserve_Capacity --
1218 ----------------------
1220 procedure Reserve_Capacity
1221 (Container : in out Set;
1222 Capacity : Count_Type)
1225 if Checks and then Capacity > Container.Capacity then
1226 raise Capacity_Error with "requested capacity is too large";
1228 end Reserve_Capacity;
1234 procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1236 Node.Element := Item;
1243 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1248 --------------------------
1249 -- Symmetric_Difference --
1250 --------------------------
1252 procedure Symmetric_Difference
1253 (Target : in out Set;
1256 procedure Process (Source_Node : Count_Type);
1257 pragma Inline (Process);
1259 procedure Iterate is
1260 new HT_Ops.Generic_Iteration (Process);
1266 procedure Process (Source_Node : Count_Type) is
1267 N : Node_Type renames Source.Nodes (Source_Node);
1272 if Is_In (Target, N) then
1273 Delete (Target, N.Element);
1275 Insert (Target, N.Element, X, B);
1280 -- Start of processing for Symmetric_Difference
1283 if Target'Address = Source'Address then
1284 HT_Ops.Clear (Target);
1288 if Target.Length = 0 then
1289 Assign (Target => Target, Source => Source);
1293 TC_Check (Target.TC);
1296 end Symmetric_Difference;
1298 function Symmetric_Difference (Left, Right : Set) return Set is
1302 if Left'Address = Right'Address then
1306 if Right.Length = 0 then
1310 if Left.Length = 0 then
1314 C := Left.Length + Right.Length;
1316 return Result : Set (C, To_Prime (C)) do
1317 Iterate_Left : declare
1318 procedure Process (L_Node : Count_Type);
1320 procedure Iterate is
1321 new HT_Ops.Generic_Iteration (Process);
1327 procedure Process (L_Node : Count_Type) is
1328 N : Node_Type renames Left.Nodes (L_Node);
1332 if not Is_In (Right, N) then
1333 Insert (Result, N.Element, X, B);
1338 -- Start of processing for Iterate_Left
1344 Iterate_Right : declare
1345 procedure Process (R_Node : Count_Type);
1347 procedure Iterate is
1348 new HT_Ops.Generic_Iteration (Process);
1354 procedure Process (R_Node : Count_Type) is
1355 N : Node_Type renames Right.Nodes (R_Node);
1359 if not Is_In (Left, N) then
1360 Insert (Result, N.Element, X, B);
1365 -- Start of processing for Iterate_Right
1371 end Symmetric_Difference;
1377 function To_Set (New_Item : Element_Type) return Set is
1381 return Result : Set (1, 1) do
1382 Insert (Result, New_Item, X, B);
1392 (Target : in out Set;
1395 procedure Process (Src_Node : Count_Type);
1397 procedure Iterate is
1398 new HT_Ops.Generic_Iteration (Process);
1404 procedure Process (Src_Node : Count_Type) is
1405 N : Node_Type renames Source.Nodes (Src_Node);
1409 Insert (Target, N.Element, X, B);
1412 -- Start of processing for Union
1415 if Target'Address = Source'Address then
1419 TC_Check (Target.TC);
1421 -- ??? why is this code commented out ???
1423 -- N : constant Count_Type := Target.Length + Source.Length;
1425 -- if N > HT_Ops.Capacity (Target.HT) then
1426 -- HT_Ops.Reserve_Capacity (Target.HT, N);
1433 function Union (Left, Right : Set) return Set is
1437 if Left'Address = Right'Address then
1441 if Right.Length = 0 then
1445 if Left.Length = 0 then
1449 C := Left.Length + Right.Length;
1451 return Result : Set (C, To_Prime (C)) do
1452 Assign (Target => Result, Source => Left);
1453 Union (Target => Result, Source => Right);
1461 function Vet (Position : Cursor) return Boolean is
1463 if Position.Node = 0 then
1464 return Position.Container = null;
1467 if Position.Container = null then
1472 S : Set renames Position.Container.all;
1473 N : Nodes_Type renames S.Nodes;
1477 if S.Length = 0 then
1481 if Position.Node > N'Last then
1485 if N (Position.Node).Next = Position.Node then
1489 X := S.Buckets (Element_Keys.Checked_Index
1490 (S, N (Position.Node).Element));
1492 for J in 1 .. S.Length loop
1493 if X = Position.Node then
1501 if X = N (X).Next then -- to prevent unnecessary looping
1517 (Stream : not null access Root_Stream_Type'Class;
1520 procedure Write_Node
1521 (Stream : not null access Root_Stream_Type'Class;
1523 pragma Inline (Write_Node);
1525 procedure Write_Nodes is
1526 new HT_Ops.Generic_Write (Write_Node);
1532 procedure Write_Node
1533 (Stream : not null access Root_Stream_Type'Class;
1537 Element_Type'Write (Stream, Node.Element);
1540 -- Start of processing for Write
1543 Write_Nodes (Stream, Container);
1547 (Stream : not null access Root_Stream_Type'Class;
1551 raise Program_Error with "attempt to stream set cursor";
1555 (Stream : not null access Root_Stream_Type'Class;
1556 Item : Constant_Reference_Type)
1559 raise Program_Error with "attempt to stream reference";
1562 package body Generic_Keys is
1564 -----------------------
1565 -- Local Subprograms --
1566 -----------------------
1568 function Equivalent_Key_Node
1570 Node : Node_Type) return Boolean;
1571 pragma Inline (Equivalent_Key_Node);
1573 --------------------------
1574 -- Local Instantiations --
1575 --------------------------
1578 new Hash_Tables.Generic_Bounded_Keys
1579 (HT_Types => HT_Types,
1581 Set_Next => Set_Next,
1582 Key_Type => Key_Type,
1584 Equivalent_Keys => Equivalent_Key_Node);
1586 ------------------------
1587 -- Constant_Reference --
1588 ------------------------
1590 function Constant_Reference
1591 (Container : aliased Set;
1592 Key : Key_Type) return Constant_Reference_Type
1594 Node : constant Count_Type :=
1595 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1598 if Checks and then Node = 0 then
1599 raise Constraint_Error with "key not in set";
1603 N : Node_Type renames Container.Nodes (Node);
1604 TC : constant Tamper_Counts_Access :=
1605 Container.TC'Unrestricted_Access;
1607 return R : constant Constant_Reference_Type :=
1608 (Element => N.Element'Access,
1609 Control => (Controlled with TC))
1614 end Constant_Reference;
1622 Key : Key_Type) return Boolean
1625 return Find (Container, Key) /= No_Element;
1633 (Container : in out Set;
1639 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1641 if Checks and then X = 0 then
1642 raise Constraint_Error with "attempt to delete key not in set";
1645 HT_Ops.Free (Container, X);
1654 Key : Key_Type) return Element_Type
1656 Node : constant Count_Type :=
1657 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1660 if Checks and then Node = 0 then
1661 raise Constraint_Error with "key not in set";
1664 return Container.Nodes (Node).Element;
1667 -------------------------
1668 -- Equivalent_Key_Node --
1669 -------------------------
1671 function Equivalent_Key_Node
1673 Node : Node_Type) return Boolean
1676 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1677 end Equivalent_Key_Node;
1684 (Container : in out Set;
1689 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1690 HT_Ops.Free (Container, X);
1697 procedure Finalize (Control : in out Reference_Control_Type) is
1699 if Control.Container /= null then
1700 Impl.Reference_Control_Type (Control).Finalize;
1703 Hash (Key (Element (Control.Old_Pos))) /= Control.Old_Hash
1705 HT_Ops.Delete_Node_At_Index
1706 (Control.Container.all, Control.Index, Control.Old_Pos.Node);
1707 raise Program_Error with "key not preserved in reference";
1710 Control.Container := null;
1720 Key : Key_Type) return Cursor
1722 Node : constant Count_Type :=
1723 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1725 return (if Node = 0 then No_Element
1726 else Cursor'(Container
'Unrestricted_Access, Node
));
1733 function Key
(Position
: Cursor
) return Key_Type
is
1735 if Checks
and then Position
.Node
= 0 then
1736 raise Constraint_Error
with
1737 "Position cursor equals No_Element";
1740 pragma Assert
(Vet
(Position
), "bad cursor in function Key");
1741 return Key
(Position
.Container
.Nodes
(Position
.Node
).Element
);
1749 (Stream
: not null access Root_Stream_Type
'Class;
1750 Item
: out Reference_Type
)
1753 raise Program_Error
with "attempt to stream reference";
1756 ------------------------------
1757 -- Reference_Preserving_Key --
1758 ------------------------------
1760 function Reference_Preserving_Key
1761 (Container
: aliased in out Set
;
1762 Position
: Cursor
) return Reference_Type
1765 if Checks
and then Position
.Container
= null then
1766 raise Constraint_Error
with "Position cursor has no element";
1769 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
1771 raise Program_Error
with
1772 "Position cursor designates wrong container";
1777 "bad cursor in function Reference_Preserving_Key");
1780 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
1782 return R
: constant Reference_Type
:=
1783 (Element
=> N
.Element
'Unrestricted_Access,
1786 Container
.TC
'Unrestricted_Access,
1787 Container
'Unrestricted_Access,
1788 Index
=> Key_Keys
.Index
(Container
, Key
(Position
)),
1789 Old_Pos
=> Position
,
1790 Old_Hash
=> Hash
(Key
(Position
))))
1792 Lock
(Container
.TC
);
1795 end Reference_Preserving_Key
;
1797 function Reference_Preserving_Key
1798 (Container
: aliased in out Set
;
1799 Key
: Key_Type
) return Reference_Type
1801 Node
: constant Count_Type
:= Key_Keys
.Find
(Container
, Key
);
1804 if Checks
and then Node
= 0 then
1805 raise Constraint_Error
with "key not in set";
1809 P
: constant Cursor
:= Find
(Container
, Key
);
1811 return R
: constant Reference_Type
:=
1812 (Element
=> Container
.Nodes
(Node
).Element
'Unrestricted_Access,
1815 Container
.TC
'Unrestricted_Access,
1816 Container
'Unrestricted_Access,
1817 Index
=> Key_Keys
.Index
(Container
, Key
),
1819 Old_Hash
=> Hash
(Key
)))
1821 Lock
(Container
.TC
);
1824 end Reference_Preserving_Key
;
1831 (Container
: in out Set
;
1833 New_Item
: Element_Type
)
1835 Node
: constant Count_Type
:= Key_Keys
.Find
(Container
, Key
);
1838 if Checks
and then Node
= 0 then
1839 raise Constraint_Error
with
1840 "attempt to replace key not in set";
1843 Replace_Element
(Container
, Node
, New_Item
);
1846 -----------------------------------
1847 -- Update_Element_Preserving_Key --
1848 -----------------------------------
1850 procedure Update_Element_Preserving_Key
1851 (Container
: in out Set
;
1853 Process
: not null access
1854 procedure (Element
: in out Element_Type
))
1857 N
: Nodes_Type
renames Container
.Nodes
;
1860 if Checks
and then Position
.Node
= 0 then
1861 raise Constraint_Error
with
1862 "Position cursor equals No_Element";
1865 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
1867 raise Program_Error
with
1868 "Position cursor designates wrong set";
1871 -- ??? why is this code commented out ???
1872 -- if HT.Buckets = null
1873 -- or else HT.Buckets'Length = 0
1874 -- or else HT.Length = 0
1875 -- or else Position.Node.Next = Position.Node
1877 -- raise Program_Error with
1878 -- "Position cursor is bad (set is empty)";
1883 "bad cursor in Update_Element_Preserving_Key");
1885 -- Per AI05-0022, the container implementation is required to detect
1886 -- element tampering by a generic actual subprogram.
1889 E
: Element_Type
renames N
(Position
.Node
).Element
;
1890 K
: constant Key_Type
:= Key
(E
);
1891 Lock
: With_Lock
(Container
.TC
'Unrestricted_Access);
1893 -- Record bucket now, in case key is changed
1894 Indx
:= HT_Ops
.Index
(Container
.Buckets
, N
(Position
.Node
));
1898 if Equivalent_Keys
(K
, Key
(E
)) then
1903 -- Key was modified, so remove this node from set.
1905 if Container
.Buckets
(Indx
) = Position
.Node
then
1906 Container
.Buckets
(Indx
) := N
(Position
.Node
).Next
;
1910 Prev
: Count_Type
:= Container
.Buckets
(Indx
);
1913 while N
(Prev
).Next
/= Position
.Node
loop
1914 Prev
:= N
(Prev
).Next
;
1916 if Checks
and then Prev
= 0 then
1917 raise Program_Error
with
1918 "Position cursor is bad (node not found)";
1922 N
(Prev
).Next
:= N
(Position
.Node
).Next
;
1926 Container
.Length
:= Container
.Length
- 1;
1927 HT_Ops
.Free
(Container
, Position
.Node
);
1929 raise Program_Error
with "key was modified";
1930 end Update_Element_Preserving_Key
;
1937 (Stream
: not null access Root_Stream_Type
'Class;
1938 Item
: Reference_Type
)
1941 raise Program_Error
with "attempt to stream reference";
1946 end Ada
.Containers
.Bounded_Hashed_Sets
;