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 -----------------------
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 Adjust
(Control
: in out Reference_Control_Type
) is
147 if Control
.Container
/= null then
149 C
: Set
renames Control
.Container
.all;
150 B
: Natural renames C
.Busy
;
151 L
: Natural renames C
.Lock
;
163 procedure Assign
(Target
: in out Set
; Source
: Set
) is
164 procedure Insert_Element
(Source_Node
: Count_Type
);
166 procedure Insert_Elements
is
167 new HT_Ops
.Generic_Iteration
(Insert_Element
);
173 procedure Insert_Element
(Source_Node
: Count_Type
) is
174 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
178 Insert
(Target
, N
.Element
, X
, B
);
182 -- Start of processing for Assign
185 if Target
'Address = Source
'Address then
189 if Target
.Capacity
< Source
.Length
then
191 with "Target capacity is less than Source length";
194 HT_Ops
.Clear
(Target
);
195 Insert_Elements
(Source
);
202 function Capacity
(Container
: Set
) return Count_Type
is
204 return Container
.Capacity
;
211 procedure Clear
(Container
: in out Set
) is
213 HT_Ops
.Clear
(Container
);
216 ------------------------
217 -- Constant_Reference --
218 ------------------------
220 function Constant_Reference
221 (Container
: aliased Set
;
222 Position
: Cursor
) return Constant_Reference_Type
225 if Position
.Container
= null then
226 raise Constraint_Error
with "Position cursor has no element";
229 if Position
.Container
/= Container
'Unrestricted_Access then
230 raise Program_Error
with
231 "Position cursor designates wrong container";
234 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
237 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
238 B
: Natural renames Position
.Container
.Busy
;
239 L
: Natural renames Position
.Container
.Lock
;
242 return R
: constant Constant_Reference_Type
:=
243 (Element
=> N
.Element
'Access,
244 Control
=> (Controlled
with Container
'Unrestricted_Access))
250 end Constant_Reference
;
256 function Contains
(Container
: Set
; Item
: Element_Type
) return Boolean is
258 return Find
(Container
, Item
) /= No_Element
;
267 Capacity
: Count_Type
:= 0;
268 Modulus
: Hash_Type
:= 0) return Set
276 elsif Capacity
>= Source
.Length
then
279 raise Capacity_Error
with "Capacity value too small";
283 M
:= Default_Modulus
(C
);
288 return Target
: Set
(Capacity
=> C
, Modulus
=> M
) do
289 Assign
(Target
=> Target
, Source
=> Source
);
293 ---------------------
294 -- Default_Modulus --
295 ---------------------
297 function Default_Modulus
(Capacity
: Count_Type
) return Hash_Type
is
299 return To_Prime
(Capacity
);
307 (Container
: in out Set
;
313 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
316 raise Constraint_Error
with "attempt to delete element not in set";
319 HT_Ops
.Free
(Container
, X
);
323 (Container
: in out Set
;
324 Position
: in out Cursor
)
327 if Position
.Node
= 0 then
328 raise Constraint_Error
with "Position cursor equals No_Element";
331 if Position
.Container
/= Container
'Unrestricted_Access then
332 raise Program_Error
with "Position cursor designates wrong set";
335 if Container
.Busy
> 0 then
336 raise Program_Error
with
337 "attempt to tamper with cursors (set is busy)";
340 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
342 HT_Ops
.Delete_Node_Sans_Free
(Container
, Position
.Node
);
343 HT_Ops
.Free
(Container
, Position
.Node
);
345 Position
:= No_Element
;
353 (Target
: in out Set
;
356 Tgt_Node
, Src_Node
: Count_Type
;
358 Src
: Set
renames Source
'Unrestricted_Access.all;
360 TN
: Nodes_Type
renames Target
.Nodes
;
361 SN
: Nodes_Type
renames Source
.Nodes
;
364 if Target
'Address = Source
'Address then
365 HT_Ops
.Clear
(Target
);
369 if Source
.Length
= 0 then
373 if Target
.Busy
> 0 then
374 raise Program_Error
with
375 "attempt to tamper with cursors (set is busy)";
378 if Source
.Length
< Target
.Length
then
379 Src_Node
:= HT_Ops
.First
(Source
);
380 while Src_Node
/= 0 loop
381 Tgt_Node
:= Element_Keys
.Find
(Target
, SN
(Src_Node
).Element
);
383 if Tgt_Node
/= 0 then
384 HT_Ops
.Delete_Node_Sans_Free
(Target
, Tgt_Node
);
385 HT_Ops
.Free
(Target
, Tgt_Node
);
388 Src_Node
:= HT_Ops
.Next
(Src
, Src_Node
);
392 Tgt_Node
:= HT_Ops
.First
(Target
);
393 while Tgt_Node
/= 0 loop
394 if Is_In
(Source
, TN
(Tgt_Node
)) then
396 X
: constant Count_Type
:= Tgt_Node
;
398 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
399 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
400 HT_Ops
.Free
(Target
, X
);
404 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
410 function Difference
(Left
, Right
: Set
) return Set
is
412 if Left
'Address = Right
'Address then
416 if Left
.Length
= 0 then
420 if Right
.Length
= 0 then
424 return Result
: Set
(Left
.Length
, To_Prime
(Left
.Length
)) do
425 Iterate_Left
: declare
426 procedure Process
(L_Node
: Count_Type
);
429 new HT_Ops
.Generic_Iteration
(Process
);
435 procedure Process
(L_Node
: Count_Type
) is
436 N
: Node_Type
renames Left
.Nodes
(L_Node
);
440 if not Is_In
(Right
, N
) then
441 Insert
(Result
, N
.Element
, X
, B
); -- optimize this ???
443 pragma Assert
(X
> 0);
447 -- Start of processing for Iterate_Left
459 function Element
(Position
: Cursor
) return Element_Type
is
461 if Position
.Node
= 0 then
462 raise Constraint_Error
with "Position cursor equals No_Element";
465 pragma Assert
(Vet
(Position
), "bad cursor in function Element");
468 S
: Set
renames Position
.Container
.all;
469 N
: Node_Type
renames S
.Nodes
(Position
.Node
);
475 ---------------------
476 -- Equivalent_Sets --
477 ---------------------
479 function Equivalent_Sets
(Left
, Right
: Set
) return Boolean is
480 function Find_Equivalent_Key
481 (R_HT
: Hash_Table_Type
'Class;
482 L_Node
: Node_Type
) return Boolean;
483 pragma Inline
(Find_Equivalent_Key
);
485 function Is_Equivalent
is
486 new HT_Ops
.Generic_Equal
(Find_Equivalent_Key
);
488 -------------------------
489 -- Find_Equivalent_Key --
490 -------------------------
492 function Find_Equivalent_Key
493 (R_HT
: Hash_Table_Type
'Class;
494 L_Node
: Node_Type
) return Boolean
496 R_Index
: constant Hash_Type
:=
497 Element_Keys
.Index
(R_HT
, L_Node
.Element
);
499 R_Node
: Count_Type
:= R_HT
.Buckets
(R_Index
);
501 RN
: Nodes_Type
renames R_HT
.Nodes
;
509 if Equivalent_Elements
(L_Node
.Element
, RN
(R_Node
).Element
) then
513 R_Node
:= Next
(R_HT
.Nodes
(R_Node
));
515 end Find_Equivalent_Key
;
517 -- Start of processing for Equivalent_Sets
520 return Is_Equivalent
(Left
, Right
);
523 -------------------------
524 -- Equivalent_Elements --
525 -------------------------
527 function Equivalent_Elements
(Left
, Right
: Cursor
)
531 if Left
.Node
= 0 then
532 raise Constraint_Error
with
533 "Left cursor of Equivalent_Elements equals No_Element";
536 if Right
.Node
= 0 then
537 raise Constraint_Error
with
538 "Right cursor of Equivalent_Elements equals No_Element";
541 pragma Assert
(Vet
(Left
), "bad Left cursor in Equivalent_Elements");
542 pragma Assert
(Vet
(Right
), "bad Right cursor in Equivalent_Elements");
544 -- AI05-0022 requires that a container implementation detect element
545 -- tampering by a generic actual subprogram. However, the following case
546 -- falls outside the scope of that AI. Randy Brukardt explained on the
547 -- ARG list on 2013/02/07 that:
550 -- But for an operation like "<" [the ordered set analog of
551 -- Equivalent_Elements], there is no need to "dereference" a cursor
552 -- after the call to the generic formal parameter function, so nothing
553 -- bad could happen if tampering is undetected. And the operation can
554 -- safely return a result without a problem even if an element is
555 -- deleted from the container.
559 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
560 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
562 return Equivalent_Elements
(LN
.Element
, RN
.Element
);
564 end Equivalent_Elements
;
566 function Equivalent_Elements
568 Right
: Element_Type
) return Boolean
571 if Left
.Node
= 0 then
572 raise Constraint_Error
with
573 "Left cursor of Equivalent_Elements equals No_Element";
576 pragma Assert
(Vet
(Left
), "Left cursor in Equivalent_Elements is bad");
579 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
581 return Equivalent_Elements
(LN
.Element
, Right
);
583 end Equivalent_Elements
;
585 function Equivalent_Elements
586 (Left
: Element_Type
;
587 Right
: Cursor
) return Boolean
590 if Right
.Node
= 0 then
591 raise Constraint_Error
with
592 "Right cursor of Equivalent_Elements equals No_Element";
597 "Right cursor of Equivalent_Elements is bad");
600 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
602 return Equivalent_Elements
(Left
, RN
.Element
);
604 end Equivalent_Elements
;
606 ---------------------
607 -- Equivalent_Keys --
608 ---------------------
610 function Equivalent_Keys
612 Node
: Node_Type
) return Boolean
615 return Equivalent_Elements
(Key
, Node
.Element
);
623 (Container
: in out Set
;
628 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
629 HT_Ops
.Free
(Container
, X
);
636 procedure Finalize
(Object
: in out Iterator
) is
638 if Object
.Container
/= null then
640 B
: Natural renames Object
.Container
.all.Busy
;
647 procedure Finalize
(Control
: in out Reference_Control_Type
) is
649 if Control
.Container
/= null then
651 C
: Set
renames Control
.Container
.all;
652 B
: Natural renames C
.Busy
;
653 L
: Natural renames C
.Lock
;
659 Control
.Container
:= null;
669 Item
: Element_Type
) return Cursor
671 Node
: constant Count_Type
:=
672 Element_Keys
.Find
(Container
'Unrestricted_Access.all, Item
);
674 return (if Node
= 0 then No_Element
675 else Cursor
'(Container'Unrestricted_Access, Node));
682 function First (Container : Set) return Cursor is
683 Node : constant Count_Type := HT_Ops.First (Container);
685 return (if Node = 0 then No_Element
686 else Cursor'(Container
'Unrestricted_Access, Node
));
689 overriding
function First
(Object
: Iterator
) return Cursor
is
691 return Object
.Container
.First
;
698 function Has_Element
(Position
: Cursor
) return Boolean is
700 pragma Assert
(Vet
(Position
), "bad cursor in Has_Element");
701 return Position
.Node
/= 0;
708 function Hash_Node
(Node
: Node_Type
) return Hash_Type
is
710 return Hash
(Node
.Element
);
718 (Container
: in out Set
;
719 New_Item
: Element_Type
)
725 Insert
(Container
, New_Item
, Position
, Inserted
);
728 if Container
.Lock
> 0 then
729 raise Program_Error
with
730 "attempt to tamper with elements (set is locked)";
733 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
742 (Container
: in out Set
;
743 New_Item
: Element_Type
;
744 Position
: out Cursor
;
745 Inserted
: out Boolean)
748 Insert
(Container
, New_Item
, Position
.Node
, Inserted
);
749 Position
.Container
:= Container
'Unchecked_Access;
753 (Container
: in out Set
;
754 New_Item
: Element_Type
)
757 pragma Unreferenced
(Position
);
762 Insert
(Container
, New_Item
, Position
, Inserted
);
765 raise Constraint_Error
with
766 "attempt to insert element already in set";
771 (Container
: in out Set
;
772 New_Item
: Element_Type
;
773 Node
: out Count_Type
;
774 Inserted
: out Boolean)
776 procedure Allocate_Set_Element
(Node
: in out Node_Type
);
777 pragma Inline
(Allocate_Set_Element
);
779 function New_Node
return Count_Type
;
780 pragma Inline
(New_Node
);
782 procedure Local_Insert
is
783 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
785 procedure Allocate
is
786 new HT_Ops
.Generic_Allocate
(Allocate_Set_Element
);
788 ---------------------------
789 -- Allocate_Set_Element --
790 ---------------------------
792 procedure Allocate_Set_Element
(Node
: in out Node_Type
) is
794 Node
.Element
:= New_Item
;
795 end Allocate_Set_Element
;
801 function New_Node
return Count_Type
is
804 Allocate
(Container
, Result
);
808 -- Start of processing for Insert
811 -- The buckets array length is specified by the user as a discriminant
812 -- of the container type, so it is possible for the buckets array to
813 -- have a length of zero. We must check for this case specifically, in
814 -- order to prevent divide-by-zero errors later, when we compute the
815 -- buckets array index value for an element, given its hash value.
817 if Container
.Buckets
'Length = 0 then
818 raise Capacity_Error
with "No capacity for insertion";
821 Local_Insert
(Container
, New_Item
, Node
, Inserted
);
828 procedure Intersection
829 (Target
: in out Set
;
832 Tgt_Node
: Count_Type
;
833 TN
: Nodes_Type
renames Target
.Nodes
;
836 if Target
'Address = Source
'Address then
840 if Source
.Length
= 0 then
841 HT_Ops
.Clear
(Target
);
845 if Target
.Busy
> 0 then
846 raise Program_Error
with
847 "attempt to tamper with cursors (set is busy)";
850 Tgt_Node
:= HT_Ops
.First
(Target
);
851 while Tgt_Node
/= 0 loop
852 if Is_In
(Source
, TN
(Tgt_Node
)) then
853 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
857 X
: constant Count_Type
:= Tgt_Node
;
859 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
860 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
861 HT_Ops
.Free
(Target
, X
);
867 function Intersection
(Left
, Right
: Set
) return Set
is
871 if Left
'Address = Right
'Address then
875 C
:= Count_Type
'Min (Left
.Length
, Right
.Length
);
881 return Result
: Set
(C
, To_Prime
(C
)) do
882 Iterate_Left
: declare
883 procedure Process
(L_Node
: Count_Type
);
886 new HT_Ops
.Generic_Iteration
(Process
);
892 procedure Process
(L_Node
: Count_Type
) is
893 N
: Node_Type
renames Left
.Nodes
(L_Node
);
898 if Is_In
(Right
, N
) then
899 Insert
(Result
, N
.Element
, X
, B
); -- optimize ???
901 pragma Assert
(X
> 0);
905 -- Start of processing for Iterate_Left
917 function Is_Empty
(Container
: Set
) return Boolean is
919 return Container
.Length
= 0;
926 function Is_In
(HT
: Set
; Key
: Node_Type
) return Boolean is
928 return Element_Keys
.Find
(HT
'Unrestricted_Access.all, Key
.Element
) /= 0;
935 function Is_Subset
(Subset
: Set
; Of_Set
: Set
) return Boolean is
936 Subset_Node
: Count_Type
;
937 SN
: Nodes_Type
renames Subset
.Nodes
;
940 if Subset
'Address = Of_Set
'Address then
944 if Subset
.Length
> Of_Set
.Length
then
948 Subset_Node
:= HT_Ops
.First
(Subset
);
949 while Subset_Node
/= 0 loop
950 if not Is_In
(Of_Set
, SN
(Subset_Node
)) then
953 Subset_Node
:= HT_Ops
.Next
954 (Subset
'Unrestricted_Access.all, Subset_Node
);
966 Process
: not null access procedure (Position
: Cursor
))
968 procedure Process_Node
(Node
: Count_Type
);
969 pragma Inline
(Process_Node
);
972 new HT_Ops
.Generic_Iteration
(Process_Node
);
978 procedure Process_Node
(Node
: Count_Type
) is
980 Process
(Cursor
'(Container'Unrestricted_Access, Node));
983 B : Natural renames Container'Unrestricted_Access.all.Busy;
985 -- Start of processing for Iterate
1001 function Iterate (Container : Set)
1002 return Set_Iterator_Interfaces.Forward_Iterator'Class
1004 B : Natural renames Container'Unrestricted_Access.all.Busy;
1007 return It : constant Iterator :=
1008 Iterator'(Limited_Controlled
with
1009 Container
=> Container
'Unrestricted_Access);
1016 function Length
(Container
: Set
) return Count_Type
is
1018 return Container
.Length
;
1025 procedure Move
(Target
: in out Set
; Source
: in out Set
) is
1027 if Target
'Address = Source
'Address then
1031 if Source
.Busy
> 0 then
1032 raise Program_Error
with
1033 "attempt to tamper with cursors (container is busy)";
1036 Target
.Assign
(Source
);
1044 function Next
(Node
: Node_Type
) return Count_Type
is
1049 function Next
(Position
: Cursor
) return Cursor
is
1051 if Position
.Node
= 0 then
1055 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1058 HT
: Set
renames Position
.Container
.all;
1059 Node
: constant Count_Type
:= HT_Ops
.Next
(HT
, Position
.Node
);
1066 return Cursor
'(Position.Container, Node);
1070 procedure Next (Position : in out Cursor) is
1072 Position := Next (Position);
1077 Position : Cursor) return Cursor
1080 if Position.Container = null then
1084 if Position.Container /= Object.Container then
1085 raise Program_Error with
1086 "Position cursor of Next designates wrong set";
1089 return Next (Position);
1096 function Overlap (Left, Right : Set) return Boolean is
1097 Left_Node : Count_Type;
1100 if Right.Length = 0 then
1104 if Left'Address = Right'Address then
1108 Left_Node := HT_Ops.First (Left);
1109 while Left_Node /= 0 loop
1110 if Is_In (Right, Left.Nodes (Left_Node)) then
1113 Left_Node := HT_Ops.Next (Left'Unrestricted_Access.all, Left_Node);
1123 procedure Query_Element
1125 Process : not null access procedure (Element : Element_Type))
1128 if Position.Node = 0 then
1129 raise Constraint_Error with
1130 "Position cursor of Query_Element equals No_Element";
1133 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1136 S : Set renames Position.Container.all;
1137 B : Natural renames S.Busy;
1138 L : Natural renames S.Lock;
1145 Process (S.Nodes (Position.Node).Element);
1163 (Stream : not null access Root_Stream_Type'Class;
1164 Container : out Set)
1166 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1169 procedure Read_Nodes is
1170 new HT_Ops.Generic_Read (Read_Node);
1176 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1179 procedure Read_Element (Node : in out Node_Type);
1180 pragma Inline (Read_Element);
1182 procedure Allocate is
1183 new HT_Ops.Generic_Allocate (Read_Element);
1185 procedure Read_Element (Node : in out Node_Type) is
1187 Element_Type'Read (Stream, Node.Element);
1192 -- Start of processing for Read_Node
1195 Allocate (Container, Node);
1199 -- Start of processing for Read
1202 Read_Nodes (Stream, Container);
1206 (Stream : not null access Root_Stream_Type'Class;
1210 raise Program_Error with "attempt to stream set cursor";
1214 (Stream : not null access Root_Stream_Type'Class;
1215 Item : out Constant_Reference_Type)
1218 raise Program_Error with "attempt to stream reference";
1226 (Container : in out Set;
1227 New_Item : Element_Type)
1229 Node : constant Count_Type := Element_Keys.Find (Container, New_Item);
1233 raise Constraint_Error with
1234 "attempt to replace element not in set";
1237 if Container.Lock > 0 then
1238 raise Program_Error with
1239 "attempt to tamper with elements (set is locked)";
1242 Container.Nodes (Node).Element := New_Item;
1245 procedure Replace_Element
1246 (Container : in out Set;
1248 New_Item : Element_Type)
1251 if Position.Node = 0 then
1252 raise Constraint_Error with
1253 "Position cursor equals No_Element";
1256 if Position.Container /= Container'Unrestricted_Access then
1257 raise Program_Error with
1258 "Position cursor designates wrong set";
1261 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1263 Replace_Element (Container, Position.Node, New_Item);
1264 end Replace_Element;
1266 ----------------------
1267 -- Reserve_Capacity --
1268 ----------------------
1270 procedure Reserve_Capacity
1271 (Container : in out Set;
1272 Capacity : Count_Type)
1275 if Capacity > Container.Capacity then
1276 raise Capacity_Error with "requested capacity is too large";
1278 end Reserve_Capacity;
1284 procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1286 Node.Element := Item;
1293 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1298 --------------------------
1299 -- Symmetric_Difference --
1300 --------------------------
1302 procedure Symmetric_Difference
1303 (Target : in out Set;
1306 procedure Process (Source_Node : Count_Type);
1307 pragma Inline (Process);
1309 procedure Iterate is
1310 new HT_Ops.Generic_Iteration (Process);
1316 procedure Process (Source_Node : Count_Type) is
1317 N : Node_Type renames Source.Nodes (Source_Node);
1322 if Is_In (Target, N) then
1323 Delete (Target, N.Element);
1325 Insert (Target, N.Element, X, B);
1330 -- Start of processing for Symmetric_Difference
1333 if Target'Address = Source'Address then
1334 HT_Ops.Clear (Target);
1338 if Target.Length = 0 then
1339 Assign (Target => Target, Source => Source);
1343 if Target.Busy > 0 then
1344 raise Program_Error with
1345 "attempt to tamper with cursors (set is busy)";
1349 end Symmetric_Difference;
1351 function Symmetric_Difference (Left, Right : Set) return Set is
1355 if Left'Address = Right'Address then
1359 if Right.Length = 0 then
1363 if Left.Length = 0 then
1367 C := Left.Length + Right.Length;
1369 return Result : Set (C, To_Prime (C)) do
1370 Iterate_Left : declare
1371 procedure Process (L_Node : Count_Type);
1373 procedure Iterate is
1374 new HT_Ops.Generic_Iteration (Process);
1380 procedure Process (L_Node : Count_Type) is
1381 N : Node_Type renames Left.Nodes (L_Node);
1385 if not Is_In (Right, N) then
1386 Insert (Result, N.Element, X, B);
1391 -- Start of processing for Iterate_Left
1397 Iterate_Right : declare
1398 procedure Process (R_Node : Count_Type);
1400 procedure Iterate is
1401 new HT_Ops.Generic_Iteration (Process);
1407 procedure Process (R_Node : Count_Type) is
1408 N : Node_Type renames Right.Nodes (R_Node);
1412 if not Is_In (Left, N) then
1413 Insert (Result, N.Element, X, B);
1418 -- Start of processing for Iterate_Right
1424 end Symmetric_Difference;
1430 function To_Set (New_Item : Element_Type) return Set is
1434 return Result : Set (1, 1) do
1435 Insert (Result, New_Item, X, B);
1445 (Target : in out Set;
1448 procedure Process (Src_Node : Count_Type);
1450 procedure Iterate is
1451 new HT_Ops.Generic_Iteration (Process);
1457 procedure Process (Src_Node : Count_Type) is
1458 N : Node_Type renames Source.Nodes (Src_Node);
1462 Insert (Target, N.Element, X, B);
1465 -- Start of processing for Union
1468 if Target'Address = Source'Address then
1472 if Target.Busy > 0 then
1473 raise Program_Error with
1474 "attempt to tamper with cursors (set is busy)";
1477 -- ??? why is this code commented out ???
1479 -- N : constant Count_Type := Target.Length + Source.Length;
1481 -- if N > HT_Ops.Capacity (Target.HT) then
1482 -- HT_Ops.Reserve_Capacity (Target.HT, N);
1489 function Union (Left, Right : Set) return Set is
1493 if Left'Address = Right'Address then
1497 if Right.Length = 0 then
1501 if Left.Length = 0 then
1505 C := Left.Length + Right.Length;
1507 return Result : Set (C, To_Prime (C)) do
1508 Assign (Target => Result, Source => Left);
1509 Union (Target => Result, Source => Right);
1517 function Vet (Position : Cursor) return Boolean is
1519 if Position.Node = 0 then
1520 return Position.Container = null;
1523 if Position.Container = null then
1528 S : Set renames Position.Container.all;
1529 N : Nodes_Type renames S.Nodes;
1533 if S.Length = 0 then
1537 if Position.Node > N'Last then
1541 if N (Position.Node).Next = Position.Node then
1545 X := S.Buckets (Element_Keys.Checked_Index
1546 (S, N (Position.Node).Element));
1548 for J in 1 .. S.Length loop
1549 if X = Position.Node then
1557 if X = N (X).Next then -- to prevent unnecessary looping
1573 (Stream : not null access Root_Stream_Type'Class;
1576 procedure Write_Node
1577 (Stream : not null access Root_Stream_Type'Class;
1579 pragma Inline (Write_Node);
1581 procedure Write_Nodes is
1582 new HT_Ops.Generic_Write (Write_Node);
1588 procedure Write_Node
1589 (Stream : not null access Root_Stream_Type'Class;
1593 Element_Type'Write (Stream, Node.Element);
1596 -- Start of processing for Write
1599 Write_Nodes (Stream, Container);
1603 (Stream : not null access Root_Stream_Type'Class;
1607 raise Program_Error with "attempt to stream set cursor";
1611 (Stream : not null access Root_Stream_Type'Class;
1612 Item : Constant_Reference_Type)
1615 raise Program_Error with "attempt to stream reference";
1618 package body Generic_Keys is
1620 -----------------------
1621 -- Local Subprograms --
1622 -----------------------
1628 procedure Adjust (Control : in out Reference_Control_Type) is
1630 if Control.Container /= null then
1632 B : Natural renames Control.Container.Busy;
1633 L : Natural renames Control.Container.Lock;
1641 function Equivalent_Key_Node
1643 Node : Node_Type) return Boolean;
1644 pragma Inline (Equivalent_Key_Node);
1646 --------------------------
1647 -- Local Instantiations --
1648 --------------------------
1651 new Hash_Tables.Generic_Bounded_Keys
1652 (HT_Types => HT_Types,
1654 Set_Next => Set_Next,
1655 Key_Type => Key_Type,
1657 Equivalent_Keys => Equivalent_Key_Node);
1659 ------------------------
1660 -- Constant_Reference --
1661 ------------------------
1663 function Constant_Reference
1664 (Container : aliased Set;
1665 Key : Key_Type) return Constant_Reference_Type
1667 Node : constant Count_Type :=
1668 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1672 raise Constraint_Error with "key not in set";
1676 Cur : Cursor := Find (Container, Key);
1677 pragma Unmodified (Cur);
1679 N : Node_Type renames Container.Nodes (Node);
1680 B : Natural renames Cur.Container.Busy;
1681 L : Natural renames Cur.Container.Lock;
1684 return R : constant Constant_Reference_Type :=
1685 (Element => N.Element'Access,
1686 Control => (Controlled with Container'Unrestricted_Access))
1692 end Constant_Reference;
1700 Key : Key_Type) return Boolean
1703 return Find (Container, Key) /= No_Element;
1711 (Container : in out Set;
1717 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1720 raise Constraint_Error with "attempt to delete key not in set";
1723 HT_Ops.Free (Container, X);
1732 Key : Key_Type) return Element_Type
1734 Node : constant Count_Type :=
1735 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1739 raise Constraint_Error with "key not in set";
1742 return Container.Nodes (Node).Element;
1745 -------------------------
1746 -- Equivalent_Key_Node --
1747 -------------------------
1749 function Equivalent_Key_Node
1751 Node : Node_Type) return Boolean
1754 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1755 end Equivalent_Key_Node;
1762 (Container : in out Set;
1767 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1768 HT_Ops.Free (Container, X);
1775 procedure Finalize (Control : in out Reference_Control_Type) is
1777 if Control.Container /= null then
1779 B : Natural renames Control.Container.Busy;
1780 L : Natural renames Control.Container.Lock;
1786 if Hash (Key (Element (Control.Old_Pos))) /= Control.Old_Hash
1788 HT_Ops.Delete_Node_At_Index
1789 (Control.Container.all, Control.Index, Control.Old_Pos.Node);
1790 raise Program_Error with "key not preserved in reference";
1793 Control.Container := null;
1803 Key : Key_Type) return Cursor
1805 Node : constant Count_Type :=
1806 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1808 return (if Node = 0 then No_Element
1809 else Cursor'(Container
'Unrestricted_Access, Node
));
1816 function Key
(Position
: Cursor
) return Key_Type
is
1818 if Position
.Node
= 0 then
1819 raise Constraint_Error
with
1820 "Position cursor equals No_Element";
1823 pragma Assert
(Vet
(Position
), "bad cursor in function Key");
1824 return Key
(Position
.Container
.Nodes
(Position
.Node
).Element
);
1832 (Stream
: not null access Root_Stream_Type
'Class;
1833 Item
: out Reference_Type
)
1836 raise Program_Error
with "attempt to stream reference";
1839 ------------------------------
1840 -- Reference_Preserving_Key --
1841 ------------------------------
1843 function Reference_Preserving_Key
1844 (Container
: aliased in out Set
;
1845 Position
: Cursor
) return Reference_Type
1848 if Position
.Container
= null then
1849 raise Constraint_Error
with "Position cursor has no element";
1852 if Position
.Container
/= Container
'Unrestricted_Access then
1853 raise Program_Error
with
1854 "Position cursor designates wrong container";
1859 "bad cursor in function Reference_Preserving_Key");
1862 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
1863 B
: Natural renames Container
.Busy
;
1864 L
: Natural renames Container
.Lock
;
1867 return R
: constant Reference_Type
:=
1868 (Element
=> N
.Element
'Unrestricted_Access,
1871 Container
'Unrestricted_Access,
1872 Index
=> Key_Keys
.Index
(Container
, Key
(Position
)),
1873 Old_Pos
=> Position
,
1874 Old_Hash
=> Hash
(Key
(Position
))))
1880 end Reference_Preserving_Key
;
1882 function Reference_Preserving_Key
1883 (Container
: aliased in out Set
;
1884 Key
: Key_Type
) return Reference_Type
1886 Node
: constant Count_Type
:= Key_Keys
.Find
(Container
, Key
);
1890 raise Constraint_Error
with "key not in set";
1894 P
: constant Cursor
:= Find
(Container
, Key
);
1895 B
: Natural renames Container
.Busy
;
1896 L
: Natural renames Container
.Lock
;
1899 return R
: constant Reference_Type
:=
1900 (Element
=> Container
.Nodes
(Node
).Element
'Unrestricted_Access,
1903 Container
'Unrestricted_Access,
1904 Index
=> Key_Keys
.Index
(Container
, Key
),
1906 Old_Hash
=> Hash
(Key
)))
1912 end Reference_Preserving_Key
;
1919 (Container
: in out Set
;
1921 New_Item
: Element_Type
)
1923 Node
: constant Count_Type
:= Key_Keys
.Find
(Container
, Key
);
1927 raise Constraint_Error
with
1928 "attempt to replace key not in set";
1931 Replace_Element
(Container
, Node
, New_Item
);
1934 -----------------------------------
1935 -- Update_Element_Preserving_Key --
1936 -----------------------------------
1938 procedure Update_Element_Preserving_Key
1939 (Container
: in out Set
;
1941 Process
: not null access
1942 procedure (Element
: in out Element_Type
))
1945 N
: Nodes_Type
renames Container
.Nodes
;
1948 if Position
.Node
= 0 then
1949 raise Constraint_Error
with
1950 "Position cursor equals No_Element";
1953 if Position
.Container
/= Container
'Unrestricted_Access then
1954 raise Program_Error
with
1955 "Position cursor designates wrong set";
1958 -- ??? why is this code commented out ???
1959 -- if HT.Buckets = null
1960 -- or else HT.Buckets'Length = 0
1961 -- or else HT.Length = 0
1962 -- or else Position.Node.Next = Position.Node
1964 -- raise Program_Error with
1965 -- "Position cursor is bad (set is empty)";
1970 "bad cursor in Update_Element_Preserving_Key");
1972 -- Per AI05-0022, the container implementation is required to detect
1973 -- element tampering by a generic actual subprogram.
1976 E
: Element_Type
renames N
(Position
.Node
).Element
;
1977 K
: constant Key_Type
:= Key
(E
);
1979 B
: Natural renames Container
.Busy
;
1980 L
: Natural renames Container
.Lock
;
1989 -- Record bucket now, in case key is changed
1990 Indx
:= HT_Ops
.Index
(Container
.Buckets
, N
(Position
.Node
));
1994 Eq
:= Equivalent_Keys
(K
, Key
(E
));
2010 -- Key was modified, so remove this node from set.
2012 if Container
.Buckets
(Indx
) = Position
.Node
then
2013 Container
.Buckets
(Indx
) := N
(Position
.Node
).Next
;
2017 Prev
: Count_Type
:= Container
.Buckets
(Indx
);
2020 while N
(Prev
).Next
/= Position
.Node
loop
2021 Prev
:= N
(Prev
).Next
;
2024 raise Program_Error
with
2025 "Position cursor is bad (node not found)";
2029 N
(Prev
).Next
:= N
(Position
.Node
).Next
;
2033 Container
.Length
:= Container
.Length
- 1;
2034 HT_Ops
.Free
(Container
, Position
.Node
);
2036 raise Program_Error
with "key was modified";
2037 end Update_Element_Preserving_Key
;
2044 (Stream
: not null access Root_Stream_Type
'Class;
2045 Item
: Reference_Type
)
2048 raise Program_Error
with "attempt to stream reference";
2053 end Ada
.Containers
.Bounded_Hashed_Sets
;