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-2013, 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 -----------------------
43 -- Local Subprograms --
44 -----------------------
46 function Equivalent_Keys
48 Node
: Node_Type
) return Boolean;
49 pragma Inline
(Equivalent_Keys
);
51 function Hash_Node
(Node
: Node_Type
) return Hash_Type
;
52 pragma Inline
(Hash_Node
);
55 (Container
: in out Set
;
56 New_Item
: Element_Type
;
57 Node
: out Count_Type
;
58 Inserted
: out Boolean);
60 function Is_In
(HT
: Set
; Key
: Node_Type
) return Boolean;
61 pragma Inline
(Is_In
);
63 procedure Set_Element
(Node
: in out Node_Type
; Item
: Element_Type
);
64 pragma Inline
(Set_Element
);
66 function Next
(Node
: Node_Type
) return Count_Type
;
69 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
);
70 pragma Inline
(Set_Next
);
72 function Vet
(Position
: Cursor
) return Boolean;
74 --------------------------
75 -- Local Instantiations --
76 --------------------------
78 package HT_Ops
is new Hash_Tables
.Generic_Bounded_Operations
79 (HT_Types
=> HT_Types
,
80 Hash_Node
=> Hash_Node
,
82 Set_Next
=> Set_Next
);
84 package Element_Keys
is new Hash_Tables
.Generic_Bounded_Keys
85 (HT_Types
=> HT_Types
,
88 Key_Type
=> Element_Type
,
90 Equivalent_Keys
=> Equivalent_Keys
);
92 procedure Replace_Element
is
93 new Element_Keys
.Generic_Replace_Element
(Hash_Node
, Set_Element
);
99 function "=" (Left
, Right
: Set
) return Boolean is
100 function Find_Equal_Key
101 (R_HT
: Hash_Table_Type
'Class;
102 L_Node
: Node_Type
) return Boolean;
103 pragma Inline
(Find_Equal_Key
);
106 new HT_Ops
.Generic_Equal
(Find_Equal_Key
);
112 function Find_Equal_Key
113 (R_HT
: Hash_Table_Type
'Class;
114 L_Node
: Node_Type
) return Boolean
116 R_Index
: constant Hash_Type
:=
117 Element_Keys
.Index
(R_HT
, L_Node
.Element
);
119 R_Node
: Count_Type
:= R_HT
.Buckets
(R_Index
);
127 if L_Node
.Element
= R_HT
.Nodes
(R_Node
).Element
then
131 R_Node
:= Next
(R_HT
.Nodes
(R_Node
));
135 -- Start of processing for "="
138 return Is_Equal
(Left
, Right
);
145 procedure Assign
(Target
: in out Set
; Source
: Set
) is
146 procedure Insert_Element
(Source_Node
: Count_Type
);
148 procedure Insert_Elements
is
149 new HT_Ops
.Generic_Iteration
(Insert_Element
);
155 procedure Insert_Element
(Source_Node
: Count_Type
) is
156 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
160 Insert
(Target
, N
.Element
, X
, B
);
164 -- Start of processing for Assign
167 if Target
'Address = Source
'Address then
171 if Target
.Capacity
< Source
.Length
then
173 with "Target capacity is less than Source length";
176 HT_Ops
.Clear
(Target
);
177 Insert_Elements
(Source
);
184 function Capacity
(Container
: Set
) return Count_Type
is
186 return Container
.Capacity
;
193 procedure Clear
(Container
: in out Set
) is
195 HT_Ops
.Clear
(Container
);
198 ------------------------
199 -- Constant_Reference --
200 ------------------------
202 function Constant_Reference
203 (Container
: aliased Set
;
204 Position
: Cursor
) return Constant_Reference_Type
207 if Position
.Container
= null then
208 raise Constraint_Error
with "Position cursor has no element";
211 if Position
.Container
/= Container
'Unrestricted_Access then
212 raise Program_Error
with
213 "Position cursor designates wrong container";
216 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
219 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
221 return (Element
=> N
.Element
'Access);
223 end Constant_Reference
;
229 function Contains
(Container
: Set
; Item
: Element_Type
) return Boolean is
231 return Find
(Container
, Item
) /= No_Element
;
240 Capacity
: Count_Type
:= 0;
241 Modulus
: Hash_Type
:= 0) return Set
249 elsif Capacity
>= Source
.Length
then
252 raise Capacity_Error
with "Capacity value too small";
256 M
:= Default_Modulus
(C
);
261 return Target
: Set
(Capacity
=> C
, Modulus
=> M
) do
262 Assign
(Target
=> Target
, Source
=> Source
);
266 ---------------------
267 -- Default_Modulus --
268 ---------------------
270 function Default_Modulus
(Capacity
: Count_Type
) return Hash_Type
is
272 return To_Prime
(Capacity
);
280 (Container
: in out Set
;
286 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
289 raise Constraint_Error
with "attempt to delete element not in set";
292 HT_Ops
.Free
(Container
, X
);
296 (Container
: in out Set
;
297 Position
: in out Cursor
)
300 if Position
.Node
= 0 then
301 raise Constraint_Error
with "Position cursor equals No_Element";
304 if Position
.Container
/= Container
'Unrestricted_Access then
305 raise Program_Error
with "Position cursor designates wrong set";
308 if Container
.Busy
> 0 then
309 raise Program_Error
with
310 "attempt to tamper with cursors (set is busy)";
313 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
315 HT_Ops
.Delete_Node_Sans_Free
(Container
, Position
.Node
);
316 HT_Ops
.Free
(Container
, Position
.Node
);
318 Position
:= No_Element
;
326 (Target
: in out Set
;
329 Tgt_Node
, Src_Node
: Count_Type
;
331 Src
: Set
renames Source
'Unrestricted_Access.all;
333 TN
: Nodes_Type
renames Target
.Nodes
;
334 SN
: Nodes_Type
renames Source
.Nodes
;
337 if Target
'Address = Source
'Address then
338 HT_Ops
.Clear
(Target
);
342 if Source
.Length
= 0 then
346 if Target
.Busy
> 0 then
347 raise Program_Error
with
348 "attempt to tamper with cursors (set is busy)";
351 if Source
.Length
< Target
.Length
then
352 Src_Node
:= HT_Ops
.First
(Source
);
353 while Src_Node
/= 0 loop
354 Tgt_Node
:= Element_Keys
.Find
(Target
, SN
(Src_Node
).Element
);
356 if Tgt_Node
/= 0 then
357 HT_Ops
.Delete_Node_Sans_Free
(Target
, Tgt_Node
);
358 HT_Ops
.Free
(Target
, Tgt_Node
);
361 Src_Node
:= HT_Ops
.Next
(Src
, Src_Node
);
365 Tgt_Node
:= HT_Ops
.First
(Target
);
366 while Tgt_Node
/= 0 loop
367 if Is_In
(Source
, TN
(Tgt_Node
)) then
369 X
: constant Count_Type
:= Tgt_Node
;
371 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
372 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
373 HT_Ops
.Free
(Target
, X
);
377 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
383 function Difference
(Left
, Right
: Set
) return Set
is
385 if Left
'Address = Right
'Address then
389 if Left
.Length
= 0 then
393 if Right
.Length
= 0 then
397 return Result
: Set
(Left
.Length
, To_Prime
(Left
.Length
)) do
398 Iterate_Left
: declare
399 procedure Process
(L_Node
: Count_Type
);
402 new HT_Ops
.Generic_Iteration
(Process
);
408 procedure Process
(L_Node
: Count_Type
) is
409 N
: Node_Type
renames Left
.Nodes
(L_Node
);
413 if not Is_In
(Right
, N
) then
414 Insert
(Result
, N
.Element
, X
, B
); -- optimize this ???
416 pragma Assert
(X
> 0);
420 -- Start of processing for Iterate_Left
432 function Element
(Position
: Cursor
) return Element_Type
is
434 if Position
.Node
= 0 then
435 raise Constraint_Error
with "Position cursor equals No_Element";
438 pragma Assert
(Vet
(Position
), "bad cursor in function Element");
441 S
: Set
renames Position
.Container
.all;
442 N
: Node_Type
renames S
.Nodes
(Position
.Node
);
448 ---------------------
449 -- Equivalent_Sets --
450 ---------------------
452 function Equivalent_Sets
(Left
, Right
: Set
) return Boolean is
453 function Find_Equivalent_Key
454 (R_HT
: Hash_Table_Type
'Class;
455 L_Node
: Node_Type
) return Boolean;
456 pragma Inline
(Find_Equivalent_Key
);
458 function Is_Equivalent
is
459 new HT_Ops
.Generic_Equal
(Find_Equivalent_Key
);
461 -------------------------
462 -- Find_Equivalent_Key --
463 -------------------------
465 function Find_Equivalent_Key
466 (R_HT
: Hash_Table_Type
'Class;
467 L_Node
: Node_Type
) return Boolean
469 R_Index
: constant Hash_Type
:=
470 Element_Keys
.Index
(R_HT
, L_Node
.Element
);
472 R_Node
: Count_Type
:= R_HT
.Buckets
(R_Index
);
474 RN
: Nodes_Type
renames R_HT
.Nodes
;
482 if Equivalent_Elements
(L_Node
.Element
, RN
(R_Node
).Element
) then
486 R_Node
:= Next
(R_HT
.Nodes
(R_Node
));
488 end Find_Equivalent_Key
;
490 -- Start of processing for Equivalent_Sets
493 return Is_Equivalent
(Left
, Right
);
496 -------------------------
497 -- Equivalent_Elements --
498 -------------------------
500 function Equivalent_Elements
(Left
, Right
: Cursor
)
504 if Left
.Node
= 0 then
505 raise Constraint_Error
with
506 "Left cursor of Equivalent_Elements equals No_Element";
509 if Right
.Node
= 0 then
510 raise Constraint_Error
with
511 "Right cursor of Equivalent_Elements equals No_Element";
514 pragma Assert
(Vet
(Left
), "bad Left cursor in Equivalent_Elements");
515 pragma Assert
(Vet
(Right
), "bad Right cursor in Equivalent_Elements");
517 -- AI05-0022 requires that a container implementation detect element
518 -- tampering by a generic actual subprogram. However, the following case
519 -- falls outside the scope of that AI. Randy Brukardt explained on the
520 -- ARG list on 2013/02/07 that:
523 -- But for an operation like "<" [the ordered set analog of
524 -- Equivalent_Elements], there is no need to "dereference" a cursor
525 -- after the call to the generic formal parameter function, so nothing
526 -- bad could happen if tampering is undetected. And the operation can
527 -- safely return a result without a problem even if an element is
528 -- deleted from the container.
532 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
533 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
535 return Equivalent_Elements
(LN
.Element
, RN
.Element
);
537 end Equivalent_Elements
;
539 function Equivalent_Elements
541 Right
: Element_Type
) return Boolean
544 if Left
.Node
= 0 then
545 raise Constraint_Error
with
546 "Left cursor of Equivalent_Elements equals No_Element";
549 pragma Assert
(Vet
(Left
), "Left cursor in Equivalent_Elements is bad");
552 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
554 return Equivalent_Elements
(LN
.Element
, Right
);
556 end Equivalent_Elements
;
558 function Equivalent_Elements
559 (Left
: Element_Type
;
560 Right
: Cursor
) return Boolean
563 if Right
.Node
= 0 then
564 raise Constraint_Error
with
565 "Right cursor of Equivalent_Elements equals No_Element";
570 "Right cursor of Equivalent_Elements is bad");
573 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
575 return Equivalent_Elements
(Left
, RN
.Element
);
577 end Equivalent_Elements
;
579 ---------------------
580 -- Equivalent_Keys --
581 ---------------------
583 function Equivalent_Keys
585 Node
: Node_Type
) return Boolean
588 return Equivalent_Elements
(Key
, Node
.Element
);
596 (Container
: in out Set
;
601 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
602 HT_Ops
.Free
(Container
, X
);
609 procedure Finalize
(Object
: in out Iterator
) is
611 if Object
.Container
/= null then
613 B
: Natural renames Object
.Container
.all.Busy
;
626 Item
: Element_Type
) return Cursor
628 Node
: constant Count_Type
:=
629 Element_Keys
.Find
(Container
'Unrestricted_Access.all, Item
);
631 return (if Node
= 0 then No_Element
632 else Cursor
'(Container'Unrestricted_Access, Node));
639 function First (Container : Set) return Cursor is
640 Node : constant Count_Type := HT_Ops.First (Container);
642 return (if Node = 0 then No_Element
643 else Cursor'(Container
'Unrestricted_Access, Node
));
646 overriding
function First
(Object
: Iterator
) return Cursor
is
648 return Object
.Container
.First
;
655 function Has_Element
(Position
: Cursor
) return Boolean is
657 pragma Assert
(Vet
(Position
), "bad cursor in Has_Element");
658 return Position
.Node
/= 0;
665 function Hash_Node
(Node
: Node_Type
) return Hash_Type
is
667 return Hash
(Node
.Element
);
675 (Container
: in out Set
;
676 New_Item
: Element_Type
)
682 Insert
(Container
, New_Item
, Position
, Inserted
);
685 if Container
.Lock
> 0 then
686 raise Program_Error
with
687 "attempt to tamper with elements (set is locked)";
690 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
699 (Container
: in out Set
;
700 New_Item
: Element_Type
;
701 Position
: out Cursor
;
702 Inserted
: out Boolean)
705 Insert
(Container
, New_Item
, Position
.Node
, Inserted
);
706 Position
.Container
:= Container
'Unchecked_Access;
710 (Container
: in out Set
;
711 New_Item
: Element_Type
)
714 pragma Unreferenced
(Position
);
719 Insert
(Container
, New_Item
, Position
, Inserted
);
722 raise Constraint_Error
with
723 "attempt to insert element already in set";
728 (Container
: in out Set
;
729 New_Item
: Element_Type
;
730 Node
: out Count_Type
;
731 Inserted
: out Boolean)
733 procedure Allocate_Set_Element
(Node
: in out Node_Type
);
734 pragma Inline
(Allocate_Set_Element
);
736 function New_Node
return Count_Type
;
737 pragma Inline
(New_Node
);
739 procedure Local_Insert
is
740 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
742 procedure Allocate
is
743 new HT_Ops
.Generic_Allocate
(Allocate_Set_Element
);
745 ---------------------------
746 -- Allocate_Set_Element --
747 ---------------------------
749 procedure Allocate_Set_Element
(Node
: in out Node_Type
) is
751 Node
.Element
:= New_Item
;
752 end Allocate_Set_Element
;
758 function New_Node
return Count_Type
is
761 Allocate
(Container
, Result
);
765 -- Start of processing for Insert
768 -- The buckets array length is specified by the user as a discriminant
769 -- of the container type, so it is possible for the buckets array to
770 -- have a length of zero. We must check for this case specifically, in
771 -- order to prevent divide-by-zero errors later, when we compute the
772 -- buckets array index value for an element, given its hash value.
774 if Container
.Buckets
'Length = 0 then
775 raise Capacity_Error
with "No capacity for insertion";
778 Local_Insert
(Container
, New_Item
, Node
, Inserted
);
785 procedure Intersection
786 (Target
: in out Set
;
789 Tgt_Node
: Count_Type
;
790 TN
: Nodes_Type
renames Target
.Nodes
;
793 if Target
'Address = Source
'Address then
797 if Source
.Length
= 0 then
798 HT_Ops
.Clear
(Target
);
802 if Target
.Busy
> 0 then
803 raise Program_Error
with
804 "attempt to tamper with cursors (set is busy)";
807 Tgt_Node
:= HT_Ops
.First
(Target
);
808 while Tgt_Node
/= 0 loop
809 if Is_In
(Source
, TN
(Tgt_Node
)) then
810 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
814 X
: constant Count_Type
:= Tgt_Node
;
816 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
817 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
818 HT_Ops
.Free
(Target
, X
);
824 function Intersection
(Left
, Right
: Set
) return Set
is
828 if Left
'Address = Right
'Address then
832 C
:= Count_Type
'Min (Left
.Length
, Right
.Length
);
838 return Result
: Set
(C
, To_Prime
(C
)) do
839 Iterate_Left
: declare
840 procedure Process
(L_Node
: Count_Type
);
843 new HT_Ops
.Generic_Iteration
(Process
);
849 procedure Process
(L_Node
: Count_Type
) is
850 N
: Node_Type
renames Left
.Nodes
(L_Node
);
855 if Is_In
(Right
, N
) then
856 Insert
(Result
, N
.Element
, X
, B
); -- optimize ???
858 pragma Assert
(X
> 0);
862 -- Start of processing for Iterate_Left
874 function Is_Empty
(Container
: Set
) return Boolean is
876 return Container
.Length
= 0;
883 function Is_In
(HT
: Set
; Key
: Node_Type
) return Boolean is
885 return Element_Keys
.Find
(HT
'Unrestricted_Access.all, Key
.Element
) /= 0;
892 function Is_Subset
(Subset
: Set
; Of_Set
: Set
) return Boolean is
893 Subset_Node
: Count_Type
;
894 SN
: Nodes_Type
renames Subset
.Nodes
;
897 if Subset
'Address = Of_Set
'Address then
901 if Subset
.Length
> Of_Set
.Length
then
905 Subset_Node
:= HT_Ops
.First
(Subset
);
906 while Subset_Node
/= 0 loop
907 if not Is_In
(Of_Set
, SN
(Subset_Node
)) then
910 Subset_Node
:= HT_Ops
.Next
911 (Subset
'Unrestricted_Access.all, Subset_Node
);
923 Process
: not null access procedure (Position
: Cursor
))
925 procedure Process_Node
(Node
: Count_Type
);
926 pragma Inline
(Process_Node
);
929 new HT_Ops
.Generic_Iteration
(Process_Node
);
935 procedure Process_Node
(Node
: Count_Type
) is
937 Process
(Cursor
'(Container'Unrestricted_Access, Node));
940 B : Natural renames Container'Unrestricted_Access.all.Busy;
942 -- Start of processing for Iterate
958 function Iterate (Container : Set)
959 return Set_Iterator_Interfaces.Forward_Iterator'Class
961 B : Natural renames Container'Unrestricted_Access.all.Busy;
964 return It : constant Iterator :=
965 Iterator'(Limited_Controlled
with
966 Container
=> Container
'Unrestricted_Access);
973 function Length
(Container
: Set
) return Count_Type
is
975 return Container
.Length
;
982 procedure Move
(Target
: in out Set
; Source
: in out Set
) is
984 if Target
'Address = Source
'Address then
988 if Source
.Busy
> 0 then
989 raise Program_Error
with
990 "attempt to tamper with cursors (container is busy)";
993 Target
.Assign
(Source
);
1001 function Next
(Node
: Node_Type
) return Count_Type
is
1006 function Next
(Position
: Cursor
) return Cursor
is
1008 if Position
.Node
= 0 then
1012 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1015 HT
: Set
renames Position
.Container
.all;
1016 Node
: constant Count_Type
:= HT_Ops
.Next
(HT
, Position
.Node
);
1023 return Cursor
'(Position.Container, Node);
1027 procedure Next (Position : in out Cursor) is
1029 Position := Next (Position);
1034 Position : Cursor) return Cursor
1037 if Position.Container = null then
1041 if Position.Container /= Object.Container then
1042 raise Program_Error with
1043 "Position cursor of Next designates wrong set";
1046 return Next (Position);
1053 function Overlap (Left, Right : Set) return Boolean is
1054 Left_Node : Count_Type;
1057 if Right.Length = 0 then
1061 if Left'Address = Right'Address then
1065 Left_Node := HT_Ops.First (Left);
1066 while Left_Node /= 0 loop
1067 if Is_In (Right, Left.Nodes (Left_Node)) then
1070 Left_Node := HT_Ops.Next (Left'Unrestricted_Access.all, Left_Node);
1080 procedure Query_Element
1082 Process : not null access procedure (Element : Element_Type))
1085 if Position.Node = 0 then
1086 raise Constraint_Error with
1087 "Position cursor of Query_Element equals No_Element";
1090 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1093 S : Set renames Position.Container.all;
1094 B : Natural renames S.Busy;
1095 L : Natural renames S.Lock;
1102 Process (S.Nodes (Position.Node).Element);
1120 (Stream : not null access Root_Stream_Type'Class;
1121 Container : out Set)
1123 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1126 procedure Read_Nodes is
1127 new HT_Ops.Generic_Read (Read_Node);
1133 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1136 procedure Read_Element (Node : in out Node_Type);
1137 pragma Inline (Read_Element);
1139 procedure Allocate is
1140 new HT_Ops.Generic_Allocate (Read_Element);
1142 procedure Read_Element (Node : in out Node_Type) is
1144 Element_Type'Read (Stream, Node.Element);
1149 -- Start of processing for Read_Node
1152 Allocate (Container, Node);
1156 -- Start of processing for Read
1159 Read_Nodes (Stream, Container);
1163 (Stream : not null access Root_Stream_Type'Class;
1167 raise Program_Error with "attempt to stream set cursor";
1171 (Stream : not null access Root_Stream_Type'Class;
1172 Item : out Constant_Reference_Type)
1175 raise Program_Error with "attempt to stream reference";
1183 (Container : in out Set;
1184 New_Item : Element_Type)
1186 Node : constant Count_Type := Element_Keys.Find (Container, New_Item);
1190 raise Constraint_Error with
1191 "attempt to replace element not in set";
1194 if Container.Lock > 0 then
1195 raise Program_Error with
1196 "attempt to tamper with elements (set is locked)";
1199 Container.Nodes (Node).Element := New_Item;
1202 procedure Replace_Element
1203 (Container : in out Set;
1205 New_Item : Element_Type)
1208 if Position.Node = 0 then
1209 raise Constraint_Error with
1210 "Position cursor equals No_Element";
1213 if Position.Container /= Container'Unrestricted_Access then
1214 raise Program_Error with
1215 "Position cursor designates wrong set";
1218 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1220 Replace_Element (Container, Position.Node, New_Item);
1221 end Replace_Element;
1223 ----------------------
1224 -- Reserve_Capacity --
1225 ----------------------
1227 procedure Reserve_Capacity
1228 (Container : in out Set;
1229 Capacity : Count_Type)
1232 if Capacity > Container.Capacity then
1233 raise Capacity_Error with "requested capacity is too large";
1235 end Reserve_Capacity;
1241 procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1243 Node.Element := Item;
1250 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1255 --------------------------
1256 -- Symmetric_Difference --
1257 --------------------------
1259 procedure Symmetric_Difference
1260 (Target : in out Set;
1263 procedure Process (Source_Node : Count_Type);
1264 pragma Inline (Process);
1266 procedure Iterate is
1267 new HT_Ops.Generic_Iteration (Process);
1273 procedure Process (Source_Node : Count_Type) is
1274 N : Node_Type renames Source.Nodes (Source_Node);
1279 if Is_In (Target, N) then
1280 Delete (Target, N.Element);
1282 Insert (Target, N.Element, X, B);
1287 -- Start of processing for Symmetric_Difference
1290 if Target'Address = Source'Address then
1291 HT_Ops.Clear (Target);
1295 if Target.Length = 0 then
1296 Assign (Target => Target, Source => Source);
1300 if Target.Busy > 0 then
1301 raise Program_Error with
1302 "attempt to tamper with cursors (set is busy)";
1306 end Symmetric_Difference;
1308 function Symmetric_Difference (Left, Right : Set) return Set is
1312 if Left'Address = Right'Address then
1316 if Right.Length = 0 then
1320 if Left.Length = 0 then
1324 C := Left.Length + Right.Length;
1326 return Result : Set (C, To_Prime (C)) do
1327 Iterate_Left : declare
1328 procedure Process (L_Node : Count_Type);
1330 procedure Iterate is
1331 new HT_Ops.Generic_Iteration (Process);
1337 procedure Process (L_Node : Count_Type) is
1338 N : Node_Type renames Left.Nodes (L_Node);
1342 if not Is_In (Right, N) then
1343 Insert (Result, N.Element, X, B);
1348 -- Start of processing for Iterate_Left
1354 Iterate_Right : declare
1355 procedure Process (R_Node : Count_Type);
1357 procedure Iterate is
1358 new HT_Ops.Generic_Iteration (Process);
1364 procedure Process (R_Node : Count_Type) is
1365 N : Node_Type renames Right.Nodes (R_Node);
1369 if not Is_In (Left, N) then
1370 Insert (Result, N.Element, X, B);
1375 -- Start of processing for Iterate_Right
1381 end Symmetric_Difference;
1387 function To_Set (New_Item : Element_Type) return Set is
1391 return Result : Set (1, 1) do
1392 Insert (Result, New_Item, X, B);
1402 (Target : in out Set;
1405 procedure Process (Src_Node : Count_Type);
1407 procedure Iterate is
1408 new HT_Ops.Generic_Iteration (Process);
1414 procedure Process (Src_Node : Count_Type) is
1415 N : Node_Type renames Source.Nodes (Src_Node);
1419 Insert (Target, N.Element, X, B);
1422 -- Start of processing for Union
1425 if Target'Address = Source'Address then
1429 if Target.Busy > 0 then
1430 raise Program_Error with
1431 "attempt to tamper with cursors (set is busy)";
1434 -- ??? why is this code commented out ???
1436 -- N : constant Count_Type := Target.Length + Source.Length;
1438 -- if N > HT_Ops.Capacity (Target.HT) then
1439 -- HT_Ops.Reserve_Capacity (Target.HT, N);
1446 function Union (Left, Right : Set) return Set is
1450 if Left'Address = Right'Address then
1454 if Right.Length = 0 then
1458 if Left.Length = 0 then
1462 C := Left.Length + Right.Length;
1464 return Result : Set (C, To_Prime (C)) do
1465 Assign (Target => Result, Source => Left);
1466 Union (Target => Result, Source => Right);
1474 function Vet (Position : Cursor) return Boolean is
1476 if Position.Node = 0 then
1477 return Position.Container = null;
1480 if Position.Container = null then
1485 S : Set renames Position.Container.all;
1486 N : Nodes_Type renames S.Nodes;
1490 if S.Length = 0 then
1494 if Position.Node > N'Last then
1498 if N (Position.Node).Next = Position.Node then
1502 X := S.Buckets (Element_Keys.Checked_Index
1503 (S, N (Position.Node).Element));
1505 for J in 1 .. S.Length loop
1506 if X = Position.Node then
1514 if X = N (X).Next then -- to prevent unnecessary looping
1530 (Stream : not null access Root_Stream_Type'Class;
1533 procedure Write_Node
1534 (Stream : not null access Root_Stream_Type'Class;
1536 pragma Inline (Write_Node);
1538 procedure Write_Nodes is
1539 new HT_Ops.Generic_Write (Write_Node);
1545 procedure Write_Node
1546 (Stream : not null access Root_Stream_Type'Class;
1550 Element_Type'Write (Stream, Node.Element);
1553 -- Start of processing for Write
1556 Write_Nodes (Stream, Container);
1560 (Stream : not null access Root_Stream_Type'Class;
1564 raise Program_Error with "attempt to stream set cursor";
1568 (Stream : not null access Root_Stream_Type'Class;
1569 Item : Constant_Reference_Type)
1572 raise Program_Error with "attempt to stream reference";
1575 package body Generic_Keys is
1577 -----------------------
1578 -- Local Subprograms --
1579 -----------------------
1581 function Equivalent_Key_Node
1583 Node : Node_Type) return Boolean;
1584 pragma Inline (Equivalent_Key_Node);
1586 --------------------------
1587 -- Local Instantiations --
1588 --------------------------
1591 new Hash_Tables.Generic_Bounded_Keys
1592 (HT_Types => HT_Types,
1594 Set_Next => Set_Next,
1595 Key_Type => Key_Type,
1597 Equivalent_Keys => Equivalent_Key_Node);
1599 ------------------------
1600 -- Constant_Reference --
1601 ------------------------
1603 function Constant_Reference
1604 (Container : aliased Set;
1605 Key : Key_Type) return Constant_Reference_Type
1607 Node : constant Count_Type :=
1608 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1612 raise Constraint_Error with "key not in set";
1616 N : Node_Type renames Container.Nodes (Node);
1618 return (Element => N.Element'Access);
1620 end Constant_Reference;
1628 Key : Key_Type) return Boolean
1631 return Find (Container, Key) /= No_Element;
1639 (Container : in out Set;
1645 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1648 raise Constraint_Error with "attempt to delete key not in set";
1651 HT_Ops.Free (Container, X);
1660 Key : Key_Type) return Element_Type
1662 Node : constant Count_Type :=
1663 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1667 raise Constraint_Error with "key not in set";
1670 return Container.Nodes (Node).Element;
1673 -------------------------
1674 -- Equivalent_Key_Node --
1675 -------------------------
1677 function Equivalent_Key_Node
1679 Node : Node_Type) return Boolean
1682 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1683 end Equivalent_Key_Node;
1690 (Container : in out Set;
1695 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1696 HT_Ops.Free (Container, X);
1705 Key : Key_Type) return Cursor
1707 Node : constant Count_Type :=
1708 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1710 return (if Node = 0 then No_Element
1711 else Cursor'(Container
'Unrestricted_Access, Node
));
1718 function Key
(Position
: Cursor
) return Key_Type
is
1720 if Position
.Node
= 0 then
1721 raise Constraint_Error
with
1722 "Position cursor equals No_Element";
1725 pragma Assert
(Vet
(Position
), "bad cursor in function Key");
1726 return Key
(Position
.Container
.Nodes
(Position
.Node
).Element
);
1734 (Stream
: not null access Root_Stream_Type
'Class;
1735 Item
: out Reference_Type
)
1738 raise Program_Error
with "attempt to stream reference";
1741 ------------------------------
1742 -- Reference_Preserving_Key --
1743 ------------------------------
1745 function Reference_Preserving_Key
1746 (Container
: aliased in out Set
;
1747 Position
: Cursor
) return Reference_Type
1750 if Position
.Container
= null then
1751 raise Constraint_Error
with "Position cursor has no element";
1754 if Position
.Container
/= Container
'Unrestricted_Access then
1755 raise Program_Error
with
1756 "Position cursor designates wrong container";
1761 "bad cursor in function Reference_Preserving_Key");
1763 -- Some form of finalization will be required in order to actually
1764 -- check that the key-part of the element designated by Position has
1768 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
1770 return (Element
=> N
.Element
'Access);
1772 end Reference_Preserving_Key
;
1774 function Reference_Preserving_Key
1775 (Container
: aliased in out Set
;
1776 Key
: Key_Type
) return Reference_Type
1778 Node
: constant Count_Type
:= Key_Keys
.Find
(Container
, Key
);
1782 raise Constraint_Error
with "key not in set";
1786 N
: Node_Type
renames Container
.Nodes
(Node
);
1788 return (Element
=> N
.Element
'Access);
1790 end Reference_Preserving_Key
;
1797 (Container
: in out Set
;
1799 New_Item
: Element_Type
)
1801 Node
: constant Count_Type
:= Key_Keys
.Find
(Container
, Key
);
1805 raise Constraint_Error
with
1806 "attempt to replace key not in set";
1809 Replace_Element
(Container
, Node
, New_Item
);
1812 -----------------------------------
1813 -- Update_Element_Preserving_Key --
1814 -----------------------------------
1816 procedure Update_Element_Preserving_Key
1817 (Container
: in out Set
;
1819 Process
: not null access
1820 procedure (Element
: in out Element_Type
))
1823 N
: Nodes_Type
renames Container
.Nodes
;
1826 if Position
.Node
= 0 then
1827 raise Constraint_Error
with
1828 "Position cursor equals No_Element";
1831 if Position
.Container
/= Container
'Unrestricted_Access then
1832 raise Program_Error
with
1833 "Position cursor designates wrong set";
1836 -- ??? why is this code commented out ???
1837 -- if HT.Buckets = null
1838 -- or else HT.Buckets'Length = 0
1839 -- or else HT.Length = 0
1840 -- or else Position.Node.Next = Position.Node
1842 -- raise Program_Error with
1843 -- "Position cursor is bad (set is empty)";
1848 "bad cursor in Update_Element_Preserving_Key");
1850 -- Per AI05-0022, the container implementation is required to detect
1851 -- element tampering by a generic actual subprogram.
1854 E
: Element_Type
renames N
(Position
.Node
).Element
;
1855 K
: constant Key_Type
:= Key
(E
);
1857 B
: Natural renames Container
.Busy
;
1858 L
: Natural renames Container
.Lock
;
1867 -- Record bucket now, in case key is changed
1868 Indx
:= HT_Ops
.Index
(Container
.Buckets
, N
(Position
.Node
));
1872 Eq
:= Equivalent_Keys
(K
, Key
(E
));
1888 -- Key was modified, so remove this node from set.
1890 if Container
.Buckets
(Indx
) = Position
.Node
then
1891 Container
.Buckets
(Indx
) := N
(Position
.Node
).Next
;
1895 Prev
: Count_Type
:= Container
.Buckets
(Indx
);
1898 while N
(Prev
).Next
/= Position
.Node
loop
1899 Prev
:= N
(Prev
).Next
;
1902 raise Program_Error
with
1903 "Position cursor is bad (node not found)";
1907 N
(Prev
).Next
:= N
(Position
.Node
).Next
;
1911 Container
.Length
:= Container
.Length
- 1;
1912 HT_Ops
.Free
(Container
, Position
.Node
);
1914 raise Program_Error
with "key was modified";
1915 end Update_Element_Preserving_Key
;
1922 (Stream
: not null access Root_Stream_Type
'Class;
1923 Item
: Reference_Type
)
1926 raise Program_Error
with "attempt to stream reference";
1931 end Ada
.Containers
.Bounded_Hashed_Sets
;