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-2014, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada
.Containers
.Hash_Tables
.Generic_Bounded_Operations
;
31 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Bounded_Operations
);
33 with Ada
.Containers
.Hash_Tables
.Generic_Bounded_Keys
;
34 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Bounded_Keys
);
36 with Ada
.Containers
.Prime_Numbers
; use Ada
.Containers
.Prime_Numbers
;
38 with System
; use type System
.Address
;
40 package body Ada
.Containers
.Bounded_Hashed_Sets
is
42 pragma Annotate
(CodePeer
, Skip_Analysis
);
44 -----------------------
45 -- Local Subprograms --
46 -----------------------
48 function Equivalent_Keys
50 Node
: Node_Type
) return Boolean;
51 pragma Inline
(Equivalent_Keys
);
53 function Hash_Node
(Node
: Node_Type
) return Hash_Type
;
54 pragma Inline
(Hash_Node
);
57 (Container
: in out Set
;
58 New_Item
: Element_Type
;
59 Node
: out Count_Type
;
60 Inserted
: out Boolean);
62 function Is_In
(HT
: Set
; Key
: Node_Type
) return Boolean;
63 pragma Inline
(Is_In
);
65 procedure Set_Element
(Node
: in out Node_Type
; Item
: Element_Type
);
66 pragma Inline
(Set_Element
);
68 function Next
(Node
: Node_Type
) return Count_Type
;
71 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
);
72 pragma Inline
(Set_Next
);
74 function Vet
(Position
: Cursor
) return Boolean;
76 --------------------------
77 -- Local Instantiations --
78 --------------------------
80 package HT_Ops
is new Hash_Tables
.Generic_Bounded_Operations
81 (HT_Types
=> HT_Types
,
82 Hash_Node
=> Hash_Node
,
84 Set_Next
=> Set_Next
);
86 package Element_Keys
is new Hash_Tables
.Generic_Bounded_Keys
87 (HT_Types
=> HT_Types
,
90 Key_Type
=> Element_Type
,
92 Equivalent_Keys
=> Equivalent_Keys
);
94 procedure Replace_Element
is
95 new Element_Keys
.Generic_Replace_Element
(Hash_Node
, Set_Element
);
101 function "=" (Left
, Right
: Set
) return Boolean is
102 function Find_Equal_Key
103 (R_HT
: Hash_Table_Type
'Class;
104 L_Node
: Node_Type
) return Boolean;
105 pragma Inline
(Find_Equal_Key
);
108 new HT_Ops
.Generic_Equal
(Find_Equal_Key
);
114 function Find_Equal_Key
115 (R_HT
: Hash_Table_Type
'Class;
116 L_Node
: Node_Type
) return Boolean
118 R_Index
: constant Hash_Type
:=
119 Element_Keys
.Index
(R_HT
, L_Node
.Element
);
121 R_Node
: Count_Type
:= R_HT
.Buckets
(R_Index
);
129 if L_Node
.Element
= R_HT
.Nodes
(R_Node
).Element
then
133 R_Node
:= Next
(R_HT
.Nodes
(R_Node
));
137 -- Start of processing for "="
140 return Is_Equal
(Left
, Right
);
147 procedure Adjust
(Control
: in out Reference_Control_Type
) is
149 if Control
.Container
/= null then
151 C
: Set
renames Control
.Container
.all;
152 B
: Natural renames C
.Busy
;
153 L
: Natural renames C
.Lock
;
165 procedure Assign
(Target
: in out Set
; Source
: Set
) is
166 procedure Insert_Element
(Source_Node
: Count_Type
);
168 procedure Insert_Elements
is
169 new HT_Ops
.Generic_Iteration
(Insert_Element
);
175 procedure Insert_Element
(Source_Node
: Count_Type
) is
176 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
180 Insert
(Target
, N
.Element
, X
, B
);
184 -- Start of processing for Assign
187 if Target
'Address = Source
'Address then
191 if Target
.Capacity
< Source
.Length
then
193 with "Target capacity is less than Source length";
196 HT_Ops
.Clear
(Target
);
197 Insert_Elements
(Source
);
204 function Capacity
(Container
: Set
) return Count_Type
is
206 return Container
.Capacity
;
213 procedure Clear
(Container
: in out Set
) is
215 HT_Ops
.Clear
(Container
);
218 ------------------------
219 -- Constant_Reference --
220 ------------------------
222 function Constant_Reference
223 (Container
: aliased Set
;
224 Position
: Cursor
) return Constant_Reference_Type
227 if Position
.Container
= null then
228 raise Constraint_Error
with "Position cursor has no element";
231 if Position
.Container
/= Container
'Unrestricted_Access then
232 raise Program_Error
with
233 "Position cursor designates wrong container";
236 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
239 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
240 B
: Natural renames Position
.Container
.Busy
;
241 L
: Natural renames Position
.Container
.Lock
;
244 return R
: constant Constant_Reference_Type
:=
245 (Element
=> N
.Element
'Access,
246 Control
=> (Controlled
with Container
'Unrestricted_Access))
252 end Constant_Reference
;
258 function Contains
(Container
: Set
; Item
: Element_Type
) return Boolean is
260 return Find
(Container
, Item
) /= No_Element
;
269 Capacity
: Count_Type
:= 0;
270 Modulus
: Hash_Type
:= 0) return Set
278 elsif Capacity
>= Source
.Length
then
281 raise Capacity_Error
with "Capacity value too small";
285 M
:= Default_Modulus
(C
);
290 return Target
: Set
(Capacity
=> C
, Modulus
=> M
) do
291 Assign
(Target
=> Target
, Source
=> Source
);
295 ---------------------
296 -- Default_Modulus --
297 ---------------------
299 function Default_Modulus
(Capacity
: Count_Type
) return Hash_Type
is
301 return To_Prime
(Capacity
);
309 (Container
: in out Set
;
315 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
318 raise Constraint_Error
with "attempt to delete element not in set";
321 HT_Ops
.Free
(Container
, X
);
325 (Container
: in out Set
;
326 Position
: in out Cursor
)
329 if Position
.Node
= 0 then
330 raise Constraint_Error
with "Position cursor equals No_Element";
333 if Position
.Container
/= Container
'Unrestricted_Access then
334 raise Program_Error
with "Position cursor designates wrong set";
337 if Container
.Busy
> 0 then
338 raise Program_Error
with
339 "attempt to tamper with cursors (set is busy)";
342 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
344 HT_Ops
.Delete_Node_Sans_Free
(Container
, Position
.Node
);
345 HT_Ops
.Free
(Container
, Position
.Node
);
347 Position
:= No_Element
;
355 (Target
: in out Set
;
358 Tgt_Node
, Src_Node
: Count_Type
;
360 Src
: Set
renames Source
'Unrestricted_Access.all;
362 TN
: Nodes_Type
renames Target
.Nodes
;
363 SN
: Nodes_Type
renames Source
.Nodes
;
366 if Target
'Address = Source
'Address then
367 HT_Ops
.Clear
(Target
);
371 if Source
.Length
= 0 then
375 if Target
.Busy
> 0 then
376 raise Program_Error
with
377 "attempt to tamper with cursors (set is busy)";
380 if Source
.Length
< Target
.Length
then
381 Src_Node
:= HT_Ops
.First
(Source
);
382 while Src_Node
/= 0 loop
383 Tgt_Node
:= Element_Keys
.Find
(Target
, SN
(Src_Node
).Element
);
385 if Tgt_Node
/= 0 then
386 HT_Ops
.Delete_Node_Sans_Free
(Target
, Tgt_Node
);
387 HT_Ops
.Free
(Target
, Tgt_Node
);
390 Src_Node
:= HT_Ops
.Next
(Src
, Src_Node
);
394 Tgt_Node
:= HT_Ops
.First
(Target
);
395 while Tgt_Node
/= 0 loop
396 if Is_In
(Source
, TN
(Tgt_Node
)) then
398 X
: constant Count_Type
:= Tgt_Node
;
400 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
401 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
402 HT_Ops
.Free
(Target
, X
);
406 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
412 function Difference
(Left
, Right
: Set
) return Set
is
414 if Left
'Address = Right
'Address then
418 if Left
.Length
= 0 then
422 if Right
.Length
= 0 then
426 return Result
: Set
(Left
.Length
, To_Prime
(Left
.Length
)) do
427 Iterate_Left
: declare
428 procedure Process
(L_Node
: Count_Type
);
431 new HT_Ops
.Generic_Iteration
(Process
);
437 procedure Process
(L_Node
: Count_Type
) is
438 N
: Node_Type
renames Left
.Nodes
(L_Node
);
442 if not Is_In
(Right
, N
) then
443 Insert
(Result
, N
.Element
, X
, B
); -- optimize this ???
445 pragma Assert
(X
> 0);
449 -- Start of processing for Iterate_Left
461 function Element
(Position
: Cursor
) return Element_Type
is
463 if Position
.Node
= 0 then
464 raise Constraint_Error
with "Position cursor equals No_Element";
467 pragma Assert
(Vet
(Position
), "bad cursor in function Element");
470 S
: Set
renames Position
.Container
.all;
471 N
: Node_Type
renames S
.Nodes
(Position
.Node
);
477 ---------------------
478 -- Equivalent_Sets --
479 ---------------------
481 function Equivalent_Sets
(Left
, Right
: Set
) return Boolean is
482 function Find_Equivalent_Key
483 (R_HT
: Hash_Table_Type
'Class;
484 L_Node
: Node_Type
) return Boolean;
485 pragma Inline
(Find_Equivalent_Key
);
487 function Is_Equivalent
is
488 new HT_Ops
.Generic_Equal
(Find_Equivalent_Key
);
490 -------------------------
491 -- Find_Equivalent_Key --
492 -------------------------
494 function Find_Equivalent_Key
495 (R_HT
: Hash_Table_Type
'Class;
496 L_Node
: Node_Type
) return Boolean
498 R_Index
: constant Hash_Type
:=
499 Element_Keys
.Index
(R_HT
, L_Node
.Element
);
501 R_Node
: Count_Type
:= R_HT
.Buckets
(R_Index
);
503 RN
: Nodes_Type
renames R_HT
.Nodes
;
511 if Equivalent_Elements
(L_Node
.Element
, RN
(R_Node
).Element
) then
515 R_Node
:= Next
(R_HT
.Nodes
(R_Node
));
517 end Find_Equivalent_Key
;
519 -- Start of processing for Equivalent_Sets
522 return Is_Equivalent
(Left
, Right
);
525 -------------------------
526 -- Equivalent_Elements --
527 -------------------------
529 function Equivalent_Elements
(Left
, Right
: Cursor
)
533 if Left
.Node
= 0 then
534 raise Constraint_Error
with
535 "Left cursor of Equivalent_Elements equals No_Element";
538 if Right
.Node
= 0 then
539 raise Constraint_Error
with
540 "Right cursor of Equivalent_Elements equals No_Element";
543 pragma Assert
(Vet
(Left
), "bad Left cursor in Equivalent_Elements");
544 pragma Assert
(Vet
(Right
), "bad Right cursor in Equivalent_Elements");
546 -- AI05-0022 requires that a container implementation detect element
547 -- tampering by a generic actual subprogram. However, the following case
548 -- falls outside the scope of that AI. Randy Brukardt explained on the
549 -- ARG list on 2013/02/07 that:
552 -- But for an operation like "<" [the ordered set analog of
553 -- Equivalent_Elements], there is no need to "dereference" a cursor
554 -- after the call to the generic formal parameter function, so nothing
555 -- bad could happen if tampering is undetected. And the operation can
556 -- safely return a result without a problem even if an element is
557 -- deleted from the container.
561 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
562 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
564 return Equivalent_Elements
(LN
.Element
, RN
.Element
);
566 end Equivalent_Elements
;
568 function Equivalent_Elements
570 Right
: Element_Type
) return Boolean
573 if Left
.Node
= 0 then
574 raise Constraint_Error
with
575 "Left cursor of Equivalent_Elements equals No_Element";
578 pragma Assert
(Vet
(Left
), "Left cursor in Equivalent_Elements is bad");
581 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
583 return Equivalent_Elements
(LN
.Element
, Right
);
585 end Equivalent_Elements
;
587 function Equivalent_Elements
588 (Left
: Element_Type
;
589 Right
: Cursor
) return Boolean
592 if Right
.Node
= 0 then
593 raise Constraint_Error
with
594 "Right cursor of Equivalent_Elements equals No_Element";
599 "Right cursor of Equivalent_Elements is bad");
602 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
604 return Equivalent_Elements
(Left
, RN
.Element
);
606 end Equivalent_Elements
;
608 ---------------------
609 -- Equivalent_Keys --
610 ---------------------
612 function Equivalent_Keys
614 Node
: Node_Type
) return Boolean
617 return Equivalent_Elements
(Key
, Node
.Element
);
625 (Container
: in out Set
;
630 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
631 HT_Ops
.Free
(Container
, X
);
638 procedure Finalize
(Object
: in out Iterator
) is
640 if Object
.Container
/= null then
642 B
: Natural renames Object
.Container
.all.Busy
;
649 procedure Finalize
(Control
: in out Reference_Control_Type
) is
651 if Control
.Container
/= null then
653 C
: Set
renames Control
.Container
.all;
654 B
: Natural renames C
.Busy
;
655 L
: Natural renames C
.Lock
;
661 Control
.Container
:= null;
671 Item
: Element_Type
) return Cursor
673 Node
: constant Count_Type
:=
674 Element_Keys
.Find
(Container
'Unrestricted_Access.all, Item
);
676 return (if Node
= 0 then No_Element
677 else Cursor
'(Container'Unrestricted_Access, Node));
684 function First (Container : Set) return Cursor is
685 Node : constant Count_Type := HT_Ops.First (Container);
687 return (if Node = 0 then No_Element
688 else Cursor'(Container
'Unrestricted_Access, Node
));
691 overriding
function First
(Object
: Iterator
) return Cursor
is
693 return Object
.Container
.First
;
700 function Has_Element
(Position
: Cursor
) return Boolean is
702 pragma Assert
(Vet
(Position
), "bad cursor in Has_Element");
703 return Position
.Node
/= 0;
710 function Hash_Node
(Node
: Node_Type
) return Hash_Type
is
712 return Hash
(Node
.Element
);
720 (Container
: in out Set
;
721 New_Item
: Element_Type
)
727 Insert
(Container
, New_Item
, Position
, Inserted
);
730 if Container
.Lock
> 0 then
731 raise Program_Error
with
732 "attempt to tamper with elements (set is locked)";
735 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
744 (Container
: in out Set
;
745 New_Item
: Element_Type
;
746 Position
: out Cursor
;
747 Inserted
: out Boolean)
750 Insert
(Container
, New_Item
, Position
.Node
, Inserted
);
751 Position
.Container
:= Container
'Unchecked_Access;
755 (Container
: in out Set
;
756 New_Item
: Element_Type
)
759 pragma Unreferenced
(Position
);
764 Insert
(Container
, New_Item
, Position
, Inserted
);
767 raise Constraint_Error
with
768 "attempt to insert element already in set";
773 (Container
: in out Set
;
774 New_Item
: Element_Type
;
775 Node
: out Count_Type
;
776 Inserted
: out Boolean)
778 procedure Allocate_Set_Element
(Node
: in out Node_Type
);
779 pragma Inline
(Allocate_Set_Element
);
781 function New_Node
return Count_Type
;
782 pragma Inline
(New_Node
);
784 procedure Local_Insert
is
785 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
787 procedure Allocate
is
788 new HT_Ops
.Generic_Allocate
(Allocate_Set_Element
);
790 ---------------------------
791 -- Allocate_Set_Element --
792 ---------------------------
794 procedure Allocate_Set_Element
(Node
: in out Node_Type
) is
796 Node
.Element
:= New_Item
;
797 end Allocate_Set_Element
;
803 function New_Node
return Count_Type
is
806 Allocate
(Container
, Result
);
810 -- Start of processing for Insert
813 -- The buckets array length is specified by the user as a discriminant
814 -- of the container type, so it is possible for the buckets array to
815 -- have a length of zero. We must check for this case specifically, in
816 -- order to prevent divide-by-zero errors later, when we compute the
817 -- buckets array index value for an element, given its hash value.
819 if Container
.Buckets
'Length = 0 then
820 raise Capacity_Error
with "No capacity for insertion";
823 Local_Insert
(Container
, New_Item
, Node
, Inserted
);
830 procedure Intersection
831 (Target
: in out Set
;
834 Tgt_Node
: Count_Type
;
835 TN
: Nodes_Type
renames Target
.Nodes
;
838 if Target
'Address = Source
'Address then
842 if Source
.Length
= 0 then
843 HT_Ops
.Clear
(Target
);
847 if Target
.Busy
> 0 then
848 raise Program_Error
with
849 "attempt to tamper with cursors (set is busy)";
852 Tgt_Node
:= HT_Ops
.First
(Target
);
853 while Tgt_Node
/= 0 loop
854 if Is_In
(Source
, TN
(Tgt_Node
)) then
855 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
859 X
: constant Count_Type
:= Tgt_Node
;
861 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
862 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
863 HT_Ops
.Free
(Target
, X
);
869 function Intersection
(Left
, Right
: Set
) return Set
is
873 if Left
'Address = Right
'Address then
877 C
:= Count_Type
'Min (Left
.Length
, Right
.Length
);
883 return Result
: Set
(C
, To_Prime
(C
)) do
884 Iterate_Left
: declare
885 procedure Process
(L_Node
: Count_Type
);
888 new HT_Ops
.Generic_Iteration
(Process
);
894 procedure Process
(L_Node
: Count_Type
) is
895 N
: Node_Type
renames Left
.Nodes
(L_Node
);
900 if Is_In
(Right
, N
) then
901 Insert
(Result
, N
.Element
, X
, B
); -- optimize ???
903 pragma Assert
(X
> 0);
907 -- Start of processing for Iterate_Left
919 function Is_Empty
(Container
: Set
) return Boolean is
921 return Container
.Length
= 0;
928 function Is_In
(HT
: Set
; Key
: Node_Type
) return Boolean is
930 return Element_Keys
.Find
(HT
'Unrestricted_Access.all, Key
.Element
) /= 0;
937 function Is_Subset
(Subset
: Set
; Of_Set
: Set
) return Boolean is
938 Subset_Node
: Count_Type
;
939 SN
: Nodes_Type
renames Subset
.Nodes
;
942 if Subset
'Address = Of_Set
'Address then
946 if Subset
.Length
> Of_Set
.Length
then
950 Subset_Node
:= HT_Ops
.First
(Subset
);
951 while Subset_Node
/= 0 loop
952 if not Is_In
(Of_Set
, SN
(Subset_Node
)) then
955 Subset_Node
:= HT_Ops
.Next
956 (Subset
'Unrestricted_Access.all, Subset_Node
);
968 Process
: not null access procedure (Position
: Cursor
))
970 procedure Process_Node
(Node
: Count_Type
);
971 pragma Inline
(Process_Node
);
974 new HT_Ops
.Generic_Iteration
(Process_Node
);
980 procedure Process_Node
(Node
: Count_Type
) is
982 Process
(Cursor
'(Container'Unrestricted_Access, Node));
985 B : Natural renames Container'Unrestricted_Access.all.Busy;
987 -- Start of processing for Iterate
1003 function Iterate (Container : Set)
1004 return Set_Iterator_Interfaces.Forward_Iterator'Class
1006 B : Natural renames Container'Unrestricted_Access.all.Busy;
1009 return It : constant Iterator :=
1010 Iterator'(Limited_Controlled
with
1011 Container
=> Container
'Unrestricted_Access);
1018 function Length
(Container
: Set
) return Count_Type
is
1020 return Container
.Length
;
1027 procedure Move
(Target
: in out Set
; Source
: in out Set
) is
1029 if Target
'Address = Source
'Address then
1033 if Source
.Busy
> 0 then
1034 raise Program_Error
with
1035 "attempt to tamper with cursors (container is busy)";
1038 Target
.Assign
(Source
);
1046 function Next
(Node
: Node_Type
) return Count_Type
is
1051 function Next
(Position
: Cursor
) return Cursor
is
1053 if Position
.Node
= 0 then
1057 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1060 HT
: Set
renames Position
.Container
.all;
1061 Node
: constant Count_Type
:= HT_Ops
.Next
(HT
, Position
.Node
);
1068 return Cursor
'(Position.Container, Node);
1072 procedure Next (Position : in out Cursor) is
1074 Position := Next (Position);
1079 Position : Cursor) return Cursor
1082 if Position.Container = null then
1086 if Position.Container /= Object.Container then
1087 raise Program_Error with
1088 "Position cursor of Next designates wrong set";
1091 return Next (Position);
1098 function Overlap (Left, Right : Set) return Boolean is
1099 Left_Node : Count_Type;
1102 if Right.Length = 0 then
1106 if Left'Address = Right'Address then
1110 Left_Node := HT_Ops.First (Left);
1111 while Left_Node /= 0 loop
1112 if Is_In (Right, Left.Nodes (Left_Node)) then
1115 Left_Node := HT_Ops.Next (Left'Unrestricted_Access.all, Left_Node);
1125 procedure Query_Element
1127 Process : not null access procedure (Element : Element_Type))
1130 if Position.Node = 0 then
1131 raise Constraint_Error with
1132 "Position cursor of Query_Element equals No_Element";
1135 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1138 S : Set renames Position.Container.all;
1139 B : Natural renames S.Busy;
1140 L : Natural renames S.Lock;
1147 Process (S.Nodes (Position.Node).Element);
1165 (Stream : not null access Root_Stream_Type'Class;
1166 Container : out Set)
1168 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1171 procedure Read_Nodes is
1172 new HT_Ops.Generic_Read (Read_Node);
1178 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1181 procedure Read_Element (Node : in out Node_Type);
1182 pragma Inline (Read_Element);
1184 procedure Allocate is
1185 new HT_Ops.Generic_Allocate (Read_Element);
1187 procedure Read_Element (Node : in out Node_Type) is
1189 Element_Type'Read (Stream, Node.Element);
1194 -- Start of processing for Read_Node
1197 Allocate (Container, Node);
1201 -- Start of processing for Read
1204 Read_Nodes (Stream, Container);
1208 (Stream : not null access Root_Stream_Type'Class;
1212 raise Program_Error with "attempt to stream set cursor";
1216 (Stream : not null access Root_Stream_Type'Class;
1217 Item : out Constant_Reference_Type)
1220 raise Program_Error with "attempt to stream reference";
1228 (Container : in out Set;
1229 New_Item : Element_Type)
1231 Node : constant Count_Type := Element_Keys.Find (Container, New_Item);
1235 raise Constraint_Error with
1236 "attempt to replace element not in set";
1239 if Container.Lock > 0 then
1240 raise Program_Error with
1241 "attempt to tamper with elements (set is locked)";
1244 Container.Nodes (Node).Element := New_Item;
1247 procedure Replace_Element
1248 (Container : in out Set;
1250 New_Item : Element_Type)
1253 if Position.Node = 0 then
1254 raise Constraint_Error with
1255 "Position cursor equals No_Element";
1258 if Position.Container /= Container'Unrestricted_Access then
1259 raise Program_Error with
1260 "Position cursor designates wrong set";
1263 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1265 Replace_Element (Container, Position.Node, New_Item);
1266 end Replace_Element;
1268 ----------------------
1269 -- Reserve_Capacity --
1270 ----------------------
1272 procedure Reserve_Capacity
1273 (Container : in out Set;
1274 Capacity : Count_Type)
1277 if Capacity > Container.Capacity then
1278 raise Capacity_Error with "requested capacity is too large";
1280 end Reserve_Capacity;
1286 procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1288 Node.Element := Item;
1295 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1300 --------------------------
1301 -- Symmetric_Difference --
1302 --------------------------
1304 procedure Symmetric_Difference
1305 (Target : in out Set;
1308 procedure Process (Source_Node : Count_Type);
1309 pragma Inline (Process);
1311 procedure Iterate is
1312 new HT_Ops.Generic_Iteration (Process);
1318 procedure Process (Source_Node : Count_Type) is
1319 N : Node_Type renames Source.Nodes (Source_Node);
1324 if Is_In (Target, N) then
1325 Delete (Target, N.Element);
1327 Insert (Target, N.Element, X, B);
1332 -- Start of processing for Symmetric_Difference
1335 if Target'Address = Source'Address then
1336 HT_Ops.Clear (Target);
1340 if Target.Length = 0 then
1341 Assign (Target => Target, Source => Source);
1345 if Target.Busy > 0 then
1346 raise Program_Error with
1347 "attempt to tamper with cursors (set is busy)";
1351 end Symmetric_Difference;
1353 function Symmetric_Difference (Left, Right : Set) return Set is
1357 if Left'Address = Right'Address then
1361 if Right.Length = 0 then
1365 if Left.Length = 0 then
1369 C := Left.Length + Right.Length;
1371 return Result : Set (C, To_Prime (C)) do
1372 Iterate_Left : declare
1373 procedure Process (L_Node : Count_Type);
1375 procedure Iterate is
1376 new HT_Ops.Generic_Iteration (Process);
1382 procedure Process (L_Node : Count_Type) is
1383 N : Node_Type renames Left.Nodes (L_Node);
1387 if not Is_In (Right, N) then
1388 Insert (Result, N.Element, X, B);
1393 -- Start of processing for Iterate_Left
1399 Iterate_Right : declare
1400 procedure Process (R_Node : Count_Type);
1402 procedure Iterate is
1403 new HT_Ops.Generic_Iteration (Process);
1409 procedure Process (R_Node : Count_Type) is
1410 N : Node_Type renames Right.Nodes (R_Node);
1414 if not Is_In (Left, N) then
1415 Insert (Result, N.Element, X, B);
1420 -- Start of processing for Iterate_Right
1426 end Symmetric_Difference;
1432 function To_Set (New_Item : Element_Type) return Set is
1436 return Result : Set (1, 1) do
1437 Insert (Result, New_Item, X, B);
1447 (Target : in out Set;
1450 procedure Process (Src_Node : Count_Type);
1452 procedure Iterate is
1453 new HT_Ops.Generic_Iteration (Process);
1459 procedure Process (Src_Node : Count_Type) is
1460 N : Node_Type renames Source.Nodes (Src_Node);
1464 Insert (Target, N.Element, X, B);
1467 -- Start of processing for Union
1470 if Target'Address = Source'Address then
1474 if Target.Busy > 0 then
1475 raise Program_Error with
1476 "attempt to tamper with cursors (set is busy)";
1479 -- ??? why is this code commented out ???
1481 -- N : constant Count_Type := Target.Length + Source.Length;
1483 -- if N > HT_Ops.Capacity (Target.HT) then
1484 -- HT_Ops.Reserve_Capacity (Target.HT, N);
1491 function Union (Left, Right : Set) return Set is
1495 if Left'Address = Right'Address then
1499 if Right.Length = 0 then
1503 if Left.Length = 0 then
1507 C := Left.Length + Right.Length;
1509 return Result : Set (C, To_Prime (C)) do
1510 Assign (Target => Result, Source => Left);
1511 Union (Target => Result, Source => Right);
1519 function Vet (Position : Cursor) return Boolean is
1521 if Position.Node = 0 then
1522 return Position.Container = null;
1525 if Position.Container = null then
1530 S : Set renames Position.Container.all;
1531 N : Nodes_Type renames S.Nodes;
1535 if S.Length = 0 then
1539 if Position.Node > N'Last then
1543 if N (Position.Node).Next = Position.Node then
1547 X := S.Buckets (Element_Keys.Checked_Index
1548 (S, N (Position.Node).Element));
1550 for J in 1 .. S.Length loop
1551 if X = Position.Node then
1559 if X = N (X).Next then -- to prevent unnecessary looping
1575 (Stream : not null access Root_Stream_Type'Class;
1578 procedure Write_Node
1579 (Stream : not null access Root_Stream_Type'Class;
1581 pragma Inline (Write_Node);
1583 procedure Write_Nodes is
1584 new HT_Ops.Generic_Write (Write_Node);
1590 procedure Write_Node
1591 (Stream : not null access Root_Stream_Type'Class;
1595 Element_Type'Write (Stream, Node.Element);
1598 -- Start of processing for Write
1601 Write_Nodes (Stream, Container);
1605 (Stream : not null access Root_Stream_Type'Class;
1609 raise Program_Error with "attempt to stream set cursor";
1613 (Stream : not null access Root_Stream_Type'Class;
1614 Item : Constant_Reference_Type)
1617 raise Program_Error with "attempt to stream reference";
1620 package body Generic_Keys is
1622 -----------------------
1623 -- Local Subprograms --
1624 -----------------------
1630 procedure Adjust (Control : in out Reference_Control_Type) is
1632 if Control.Container /= null then
1634 B : Natural renames Control.Container.Busy;
1635 L : Natural renames Control.Container.Lock;
1643 function Equivalent_Key_Node
1645 Node : Node_Type) return Boolean;
1646 pragma Inline (Equivalent_Key_Node);
1648 --------------------------
1649 -- Local Instantiations --
1650 --------------------------
1653 new Hash_Tables.Generic_Bounded_Keys
1654 (HT_Types => HT_Types,
1656 Set_Next => Set_Next,
1657 Key_Type => Key_Type,
1659 Equivalent_Keys => Equivalent_Key_Node);
1661 ------------------------
1662 -- Constant_Reference --
1663 ------------------------
1665 function Constant_Reference
1666 (Container : aliased Set;
1667 Key : Key_Type) return Constant_Reference_Type
1669 Node : constant Count_Type :=
1670 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1674 raise Constraint_Error with "key not in set";
1678 Cur : Cursor := Find (Container, Key);
1679 pragma Unmodified (Cur);
1681 N : Node_Type renames Container.Nodes (Node);
1682 B : Natural renames Cur.Container.Busy;
1683 L : Natural renames Cur.Container.Lock;
1686 return R : constant Constant_Reference_Type :=
1687 (Element => N.Element'Access,
1688 Control => (Controlled with Container'Unrestricted_Access))
1694 end Constant_Reference;
1702 Key : Key_Type) return Boolean
1705 return Find (Container, Key) /= No_Element;
1713 (Container : in out Set;
1719 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1722 raise Constraint_Error with "attempt to delete key not in set";
1725 HT_Ops.Free (Container, X);
1734 Key : Key_Type) return Element_Type
1736 Node : constant Count_Type :=
1737 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1741 raise Constraint_Error with "key not in set";
1744 return Container.Nodes (Node).Element;
1747 -------------------------
1748 -- Equivalent_Key_Node --
1749 -------------------------
1751 function Equivalent_Key_Node
1753 Node : Node_Type) return Boolean
1756 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1757 end Equivalent_Key_Node;
1764 (Container : in out Set;
1769 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1770 HT_Ops.Free (Container, X);
1777 procedure Finalize (Control : in out Reference_Control_Type) is
1779 if Control.Container /= null then
1781 B : Natural renames Control.Container.Busy;
1782 L : Natural renames Control.Container.Lock;
1788 if Hash (Key (Element (Control.Old_Pos))) /= Control.Old_Hash
1790 HT_Ops.Delete_Node_At_Index
1791 (Control.Container.all, Control.Index, Control.Old_Pos.Node);
1792 raise Program_Error with "key not preserved in reference";
1795 Control.Container := null;
1805 Key : Key_Type) return Cursor
1807 Node : constant Count_Type :=
1808 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1810 return (if Node = 0 then No_Element
1811 else Cursor'(Container
'Unrestricted_Access, Node
));
1818 function Key
(Position
: Cursor
) return Key_Type
is
1820 if Position
.Node
= 0 then
1821 raise Constraint_Error
with
1822 "Position cursor equals No_Element";
1825 pragma Assert
(Vet
(Position
), "bad cursor in function Key");
1826 return Key
(Position
.Container
.Nodes
(Position
.Node
).Element
);
1834 (Stream
: not null access Root_Stream_Type
'Class;
1835 Item
: out Reference_Type
)
1838 raise Program_Error
with "attempt to stream reference";
1841 ------------------------------
1842 -- Reference_Preserving_Key --
1843 ------------------------------
1845 function Reference_Preserving_Key
1846 (Container
: aliased in out Set
;
1847 Position
: Cursor
) return Reference_Type
1850 if Position
.Container
= null then
1851 raise Constraint_Error
with "Position cursor has no element";
1854 if Position
.Container
/= Container
'Unrestricted_Access then
1855 raise Program_Error
with
1856 "Position cursor designates wrong container";
1861 "bad cursor in function Reference_Preserving_Key");
1864 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
1865 B
: Natural renames Container
.Busy
;
1866 L
: Natural renames Container
.Lock
;
1869 return R
: constant Reference_Type
:=
1870 (Element
=> N
.Element
'Unrestricted_Access,
1873 Container
'Unrestricted_Access,
1874 Index
=> Key_Keys
.Index
(Container
, Key
(Position
)),
1875 Old_Pos
=> Position
,
1876 Old_Hash
=> Hash
(Key
(Position
))))
1882 end Reference_Preserving_Key
;
1884 function Reference_Preserving_Key
1885 (Container
: aliased in out Set
;
1886 Key
: Key_Type
) return Reference_Type
1888 Node
: constant Count_Type
:= Key_Keys
.Find
(Container
, Key
);
1892 raise Constraint_Error
with "key not in set";
1896 P
: constant Cursor
:= Find
(Container
, Key
);
1897 B
: Natural renames Container
.Busy
;
1898 L
: Natural renames Container
.Lock
;
1901 return R
: constant Reference_Type
:=
1902 (Element
=> Container
.Nodes
(Node
).Element
'Unrestricted_Access,
1905 Container
'Unrestricted_Access,
1906 Index
=> Key_Keys
.Index
(Container
, Key
),
1908 Old_Hash
=> Hash
(Key
)))
1914 end Reference_Preserving_Key
;
1921 (Container
: in out Set
;
1923 New_Item
: Element_Type
)
1925 Node
: constant Count_Type
:= Key_Keys
.Find
(Container
, Key
);
1929 raise Constraint_Error
with
1930 "attempt to replace key not in set";
1933 Replace_Element
(Container
, Node
, New_Item
);
1936 -----------------------------------
1937 -- Update_Element_Preserving_Key --
1938 -----------------------------------
1940 procedure Update_Element_Preserving_Key
1941 (Container
: in out Set
;
1943 Process
: not null access
1944 procedure (Element
: in out Element_Type
))
1947 N
: Nodes_Type
renames Container
.Nodes
;
1950 if Position
.Node
= 0 then
1951 raise Constraint_Error
with
1952 "Position cursor equals No_Element";
1955 if Position
.Container
/= Container
'Unrestricted_Access then
1956 raise Program_Error
with
1957 "Position cursor designates wrong set";
1960 -- ??? why is this code commented out ???
1961 -- if HT.Buckets = null
1962 -- or else HT.Buckets'Length = 0
1963 -- or else HT.Length = 0
1964 -- or else Position.Node.Next = Position.Node
1966 -- raise Program_Error with
1967 -- "Position cursor is bad (set is empty)";
1972 "bad cursor in Update_Element_Preserving_Key");
1974 -- Per AI05-0022, the container implementation is required to detect
1975 -- element tampering by a generic actual subprogram.
1978 E
: Element_Type
renames N
(Position
.Node
).Element
;
1979 K
: constant Key_Type
:= Key
(E
);
1981 B
: Natural renames Container
.Busy
;
1982 L
: Natural renames Container
.Lock
;
1991 -- Record bucket now, in case key is changed
1992 Indx
:= HT_Ops
.Index
(Container
.Buckets
, N
(Position
.Node
));
1996 Eq
:= Equivalent_Keys
(K
, Key
(E
));
2012 -- Key was modified, so remove this node from set.
2014 if Container
.Buckets
(Indx
) = Position
.Node
then
2015 Container
.Buckets
(Indx
) := N
(Position
.Node
).Next
;
2019 Prev
: Count_Type
:= Container
.Buckets
(Indx
);
2022 while N
(Prev
).Next
/= Position
.Node
loop
2023 Prev
:= N
(Prev
).Next
;
2026 raise Program_Error
with
2027 "Position cursor is bad (node not found)";
2031 N
(Prev
).Next
:= N
(Position
.Node
).Next
;
2035 Container
.Length
:= Container
.Length
- 1;
2036 HT_Ops
.Free
(Container
, Position
.Node
);
2038 raise Program_Error
with "key was modified";
2039 end Update_Element_Preserving_Key
;
2046 (Stream
: not null access Root_Stream_Type
'Class;
2047 Item
: Reference_Type
)
2050 raise Program_Error
with "attempt to stream reference";
2055 end Ada
.Containers
.Bounded_Hashed_Sets
;