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-2010, 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);
62 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 Assign
(Target
: in out Set
; Source
: Set
) is
148 procedure Insert_Element
(Source_Node
: Count_Type
);
150 procedure Insert_Elements
is
151 new HT_Ops
.Generic_Iteration
(Insert_Element
);
157 procedure Insert_Element
(Source_Node
: Count_Type
) is
158 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
163 Insert
(Target
, N
.Element
, X
, B
);
167 -- Start of processing for Assign
170 if Target
'Address = Source
'Address then
174 if Target
.Capacity
< Source
.Length
then
176 with "Target capacity is less than Source length";
179 HT_Ops
.Clear
(Target
);
180 Insert_Elements
(Source
);
187 function Capacity
(Container
: Set
) return Count_Type
is
189 return Container
.Capacity
;
196 procedure Clear
(Container
: in out Set
) is
198 HT_Ops
.Clear
(Container
);
205 function Contains
(Container
: Set
; Item
: Element_Type
) return Boolean is
207 return Find
(Container
, Item
) /= No_Element
;
216 Capacity
: Count_Type
:= 0;
217 Modulus
: Hash_Type
:= 0) return Set
226 elsif Capacity
>= Source
.Length
then
230 raise Capacity_Error
with "Capacity value too small";
234 M
:= Default_Modulus
(C
);
239 return Target
: Set
(Capacity
=> C
, Modulus
=> M
) do
240 Assign
(Target
=> Target
, Source
=> Source
);
244 ---------------------
245 -- Default_Modulus --
246 ---------------------
248 function Default_Modulus
(Capacity
: Count_Type
) return Hash_Type
is
250 return To_Prime
(Capacity
);
258 (Container
: in out Set
;
264 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
267 raise Constraint_Error
with "attempt to delete element not in set";
270 HT_Ops
.Free
(Container
, X
);
274 (Container
: in out Set
;
275 Position
: in out Cursor
)
278 if Position
.Node
= 0 then
279 raise Constraint_Error
with "Position cursor equals No_Element";
282 if Position
.Container
/= Container
'Unrestricted_Access then
283 raise Program_Error
with "Position cursor designates wrong set";
286 if Container
.Busy
> 0 then
287 raise Program_Error
with
288 "attempt to tamper with cursors (set is busy)";
291 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
293 HT_Ops
.Delete_Node_Sans_Free
(Container
, Position
.Node
);
294 HT_Ops
.Free
(Container
, Position
.Node
);
296 Position
:= No_Element
;
304 (Target
: in out Set
;
307 Tgt_Node
, Src_Node
: Count_Type
;
309 TN
: Nodes_Type
renames Target
.Nodes
;
310 SN
: Nodes_Type
renames Source
.Nodes
;
313 if Target
'Address = Source
'Address then
314 HT_Ops
.Clear
(Target
);
318 if Source
.Length
= 0 then
322 if Target
.Busy
> 0 then
323 raise Program_Error
with
324 "attempt to tamper with cursors (set is busy)";
327 if Source
.Length
< Target
.Length
then
328 Src_Node
:= HT_Ops
.First
(Source
);
329 while Src_Node
/= 0 loop
330 Tgt_Node
:= Element_Keys
.Find
(Target
, SN
(Src_Node
).Element
);
332 if Tgt_Node
/= 0 then
333 HT_Ops
.Delete_Node_Sans_Free
(Target
, Tgt_Node
);
334 HT_Ops
.Free
(Target
, Tgt_Node
);
337 Src_Node
:= HT_Ops
.Next
(Source
, Src_Node
);
341 Tgt_Node
:= HT_Ops
.First
(Target
);
342 while Tgt_Node
/= 0 loop
343 if Is_In
(Source
, TN
(Tgt_Node
)) then
345 X
: constant Count_Type
:= Tgt_Node
;
347 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
348 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
349 HT_Ops
.Free
(Target
, X
);
353 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
359 function Difference
(Left
, Right
: Set
) return Set
is
361 if Left
'Address = Right
'Address then
365 if Left
.Length
= 0 then
369 if Right
.Length
= 0 then
373 return Result
: Set
(Left
.Length
, To_Prime
(Left
.Length
)) do
374 Iterate_Left
: declare
375 procedure Process
(L_Node
: Count_Type
);
378 new HT_Ops
.Generic_Iteration
(Process
);
384 procedure Process
(L_Node
: Count_Type
) is
385 N
: Node_Type
renames Left
.Nodes
(L_Node
);
390 if not Is_In
(Right
, N
) then
391 Insert
(Result
, N
.Element
, X
, B
); -- optimize this ???
393 pragma Assert
(X
> 0);
397 -- Start of processing for Iterate_Left
409 function Element
(Position
: Cursor
) return Element_Type
is
411 if Position
.Node
= 0 then
412 raise Constraint_Error
with "Position cursor equals No_Element";
415 pragma Assert
(Vet
(Position
), "bad cursor in function Element");
418 S
: Set
renames Position
.Container
.all;
419 N
: Node_Type
renames S
.Nodes
(Position
.Node
);
426 ---------------------
427 -- Equivalent_Sets --
428 ---------------------
430 function Equivalent_Sets
(Left
, Right
: Set
) return Boolean is
431 function Find_Equivalent_Key
432 (R_HT
: Hash_Table_Type
'Class;
433 L_Node
: Node_Type
) return Boolean;
434 pragma Inline
(Find_Equivalent_Key
);
436 function Is_Equivalent
is
437 new HT_Ops
.Generic_Equal
(Find_Equivalent_Key
);
439 -------------------------
440 -- Find_Equivalent_Key --
441 -------------------------
443 function Find_Equivalent_Key
444 (R_HT
: Hash_Table_Type
'Class;
445 L_Node
: Node_Type
) return Boolean
447 R_Index
: constant Hash_Type
:=
448 Element_Keys
.Index
(R_HT
, L_Node
.Element
);
450 R_Node
: Count_Type
:= R_HT
.Buckets
(R_Index
);
452 RN
: Nodes_Type
renames R_HT
.Nodes
;
460 if Equivalent_Elements
(L_Node
.Element
, RN
(R_Node
).Element
) then
464 R_Node
:= HT_Ops
.Next
(R_HT
, R_Node
);
466 end Find_Equivalent_Key
;
468 -- Start of processing for Equivalent_Sets
471 return Is_Equivalent
(Left
, Right
);
474 -------------------------
475 -- Equivalent_Elements --
476 -------------------------
478 function Equivalent_Elements
(Left
, Right
: Cursor
)
481 if Left
.Node
= 0 then
482 raise Constraint_Error
with
483 "Left cursor of Equivalent_Elements equals No_Element";
486 if Right
.Node
= 0 then
487 raise Constraint_Error
with
488 "Right cursor of Equivalent_Elements equals No_Element";
491 pragma Assert
(Vet
(Left
), "bad Left cursor in Equivalent_Elements");
492 pragma Assert
(Vet
(Right
), "bad Right cursor in Equivalent_Elements");
495 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
496 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
499 return Equivalent_Elements
(LN
.Element
, RN
.Element
);
501 end Equivalent_Elements
;
503 function Equivalent_Elements
(Left
: Cursor
; Right
: Element_Type
)
506 if Left
.Node
= 0 then
507 raise Constraint_Error
with
508 "Left cursor of Equivalent_Elements equals No_Element";
511 pragma Assert
(Vet
(Left
), "Left cursor in Equivalent_Elements is bad");
514 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
516 return Equivalent_Elements
(LN
.Element
, Right
);
518 end Equivalent_Elements
;
520 function Equivalent_Elements
(Left
: Element_Type
; Right
: Cursor
)
523 if Right
.Node
= 0 then
524 raise Constraint_Error
with
525 "Right cursor of Equivalent_Elements equals No_Element";
530 "Right cursor of Equivalent_Elements is bad");
533 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
535 return Equivalent_Elements
(Left
, RN
.Element
);
537 end Equivalent_Elements
;
539 ---------------------
540 -- Equivalent_Keys --
541 ---------------------
543 function Equivalent_Keys
(Key
: Element_Type
; Node
: Node_Type
)
546 return Equivalent_Elements
(Key
, Node
.Element
);
554 (Container
: in out Set
;
559 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
560 HT_Ops
.Free
(Container
, X
);
569 Item
: Element_Type
) return Cursor
571 Node
: constant Count_Type
:= Element_Keys
.Find
(Container
, Item
);
578 return Cursor
'(Container'Unrestricted_Access, Node);
585 function First (Container : Set) return Cursor is
586 Node : constant Count_Type := HT_Ops.First (Container);
593 return Cursor'(Container
'Unrestricted_Access, Node
);
600 function Has_Element
(Position
: Cursor
) return Boolean is
602 pragma Assert
(Vet
(Position
), "bad cursor in Has_Element");
603 return Position
.Node
/= 0;
610 function Hash_Node
(Node
: Node_Type
) return Hash_Type
is
612 return Hash
(Node
.Element
);
620 (Container
: in out Set
;
621 New_Item
: Element_Type
)
627 Insert
(Container
, New_Item
, Position
, Inserted
);
630 if Container
.Lock
> 0 then
631 raise Program_Error
with
632 "attempt to tamper with elements (set is locked)";
635 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
644 (Container
: in out Set
;
645 New_Item
: Element_Type
;
646 Position
: out Cursor
;
647 Inserted
: out Boolean)
650 Insert
(Container
, New_Item
, Position
.Node
, Inserted
);
651 Position
.Container
:= Container
'Unchecked_Access;
655 (Container
: in out Set
;
656 New_Item
: Element_Type
)
659 pragma Unreferenced
(Position
);
664 Insert
(Container
, New_Item
, Position
, Inserted
);
667 raise Constraint_Error
with
668 "attempt to insert element already in set";
673 (Container
: in out Set
;
674 New_Item
: Element_Type
;
675 Node
: out Count_Type
;
676 Inserted
: out Boolean)
678 procedure Allocate_Set_Element
(Node
: in out Node_Type
);
679 pragma Inline
(Allocate_Set_Element
);
681 function New_Node
return Count_Type
;
682 pragma Inline
(New_Node
);
684 procedure Local_Insert
is
685 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
687 procedure Allocate
is
688 new HT_Ops
.Generic_Allocate
(Allocate_Set_Element
);
690 ---------------------------
691 -- Allocate_Set_Element --
692 ---------------------------
694 procedure Allocate_Set_Element
(Node
: in out Node_Type
) is
696 Node
.Element
:= New_Item
;
697 end Allocate_Set_Element
;
703 function New_Node
return Count_Type
is
706 Allocate
(Container
, Result
);
710 -- Start of processing for Insert
714 -- if HT_Ops.Capacity (HT) = 0 then
715 -- HT_Ops.Reserve_Capacity (HT, 1);
718 Local_Insert
(Container
, New_Item
, Node
, Inserted
);
722 -- and then HT.Length > HT_Ops.Capacity (HT)
724 -- HT_Ops.Reserve_Capacity (HT, HT.Length);
732 procedure Intersection
733 (Target
: in out Set
;
736 Tgt_Node
: Count_Type
;
737 TN
: Nodes_Type
renames Target
.Nodes
;
740 if Target
'Address = Source
'Address then
744 if Source
.Length
= 0 then
745 HT_Ops
.Clear
(Target
);
749 if Target
.Busy
> 0 then
750 raise Program_Error
with
751 "attempt to tamper with cursors (set is busy)";
754 Tgt_Node
:= HT_Ops
.First
(Target
);
755 while Tgt_Node
/= 0 loop
756 if Is_In
(Source
, TN
(Tgt_Node
)) then
757 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
761 X
: constant Count_Type
:= Tgt_Node
;
763 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
764 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
765 HT_Ops
.Free
(Target
, X
);
771 function Intersection
(Left
, Right
: Set
) return Set
is
775 if Left
'Address = Right
'Address then
779 C
:= Count_Type
'Min (Left
.Length
, Right
.Length
);
785 return Result
: Set
(C
, To_Prime
(C
)) do
786 Iterate_Left
: declare
787 procedure Process
(L_Node
: Count_Type
);
790 new HT_Ops
.Generic_Iteration
(Process
);
796 procedure Process
(L_Node
: Count_Type
) is
797 N
: Node_Type
renames Left
.Nodes
(L_Node
);
802 if Is_In
(Right
, N
) then
803 Insert
(Result
, N
.Element
, X
, B
); -- optimize ???
805 pragma Assert
(X
> 0);
809 -- Start of processing for Iterate_Left
821 function Is_Empty
(Container
: Set
) return Boolean is
823 return Container
.Length
= 0;
830 function Is_In
(HT
: Set
; Key
: Node_Type
) return Boolean is
832 return Element_Keys
.Find
(HT
, Key
.Element
) /= 0;
839 function Is_Subset
(Subset
: Set
; Of_Set
: Set
) return Boolean is
840 Subset_Node
: Count_Type
;
841 SN
: Nodes_Type
renames Subset
.Nodes
;
844 if Subset
'Address = Of_Set
'Address then
848 if Subset
.Length
> Of_Set
.Length
then
852 Subset_Node
:= HT_Ops
.First
(Subset
);
853 while Subset_Node
/= 0 loop
854 if not Is_In
(Of_Set
, SN
(Subset_Node
)) then
857 Subset_Node
:= HT_Ops
.Next
(Subset
, Subset_Node
);
869 Process
: not null access procedure (Position
: Cursor
))
871 procedure Process_Node
(Node
: Count_Type
);
872 pragma Inline
(Process_Node
);
875 new HT_Ops
.Generic_Iteration
(Process_Node
);
881 procedure Process_Node
(Node
: Count_Type
) is
883 Process
(Cursor
'(Container'Unrestricted_Access, Node));
886 B : Natural renames Container'Unrestricted_Access.Busy;
888 -- Start of processing for Iterate
908 function Length (Container : Set) return Count_Type is
910 return Container.Length;
917 procedure Move (Target : in out Set; Source : in out Set) is
919 if Target'Address = Source'Address then
923 if Source.Busy > 0 then
924 raise Program_Error with
925 "attempt to tamper with cursors (container is busy)";
928 Assign (Target => Target, Source => Source);
935 function Next (Node : Node_Type) return Count_Type is
940 function Next (Position : Cursor) return Cursor is
942 if Position.Node = 0 then
946 pragma Assert (Vet (Position), "bad cursor in Next");
949 HT : Set renames Position.Container.all;
950 Node : constant Count_Type := HT_Ops.Next (HT, Position.Node);
957 return Cursor'(Position
.Container
, Node
);
961 procedure Next
(Position
: in out Cursor
) is
963 Position
:= Next
(Position
);
970 function Overlap
(Left
, Right
: Set
) return Boolean is
971 Left_Node
: Count_Type
;
974 if Right
.Length
= 0 then
978 if Left
'Address = Right
'Address then
982 Left_Node
:= HT_Ops
.First
(Left
);
983 while Left_Node
/= 0 loop
984 if Is_In
(Right
, Left
.Nodes
(Left_Node
)) then
987 Left_Node
:= HT_Ops
.Next
(Left
, Left_Node
);
997 procedure Query_Element
999 Process
: not null access procedure (Element
: Element_Type
))
1002 if Position
.Node
= 0 then
1003 raise Constraint_Error
with
1004 "Position cursor of Query_Element equals No_Element";
1007 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
1010 S
: Set
renames Position
.Container
.all;
1011 B
: Natural renames S
.Busy
;
1012 L
: Natural renames S
.Lock
;
1019 Process
(S
.Nodes
(Position
.Node
).Element
);
1037 (Stream
: not null access Root_Stream_Type
'Class;
1038 Container
: out Set
)
1040 function Read_Node
(Stream
: not null access Root_Stream_Type
'Class)
1043 procedure Read_Nodes
is
1044 new HT_Ops
.Generic_Read
(Read_Node
);
1050 function Read_Node
(Stream
: not null access Root_Stream_Type
'Class)
1053 procedure Read_Element
(Node
: in out Node_Type
);
1054 pragma Inline
(Read_Element
);
1056 procedure Allocate
is
1057 new HT_Ops
.Generic_Allocate
(Read_Element
);
1059 procedure Read_Element
(Node
: in out Node_Type
) is
1061 Element_Type
'Read (Stream
, Node
.Element
);
1066 -- Start of processing for Read_Node
1069 Allocate
(Container
, Node
);
1073 -- Start of processing for Read
1076 Read_Nodes
(Stream
, Container
);
1080 (Stream
: not null access Root_Stream_Type
'Class;
1084 raise Program_Error
with "attempt to stream set cursor";
1092 (Container
: in out Set
;
1093 New_Item
: Element_Type
)
1095 Node
: constant Count_Type
:=
1096 Element_Keys
.Find
(Container
, New_Item
);
1100 raise Constraint_Error
with
1101 "attempt to replace element not in set";
1104 if Container
.Lock
> 0 then
1105 raise Program_Error
with
1106 "attempt to tamper with elements (set is locked)";
1109 Container
.Nodes
(Node
).Element
:= New_Item
;
1112 procedure Replace_Element
1113 (Container
: in out Set
;
1115 New_Item
: Element_Type
)
1118 if Position
.Node
= 0 then
1119 raise Constraint_Error
with
1120 "Position cursor equals No_Element";
1123 if Position
.Container
/= Container
'Unrestricted_Access then
1124 raise Program_Error
with
1125 "Position cursor designates wrong set";
1128 pragma Assert
(Vet
(Position
), "bad cursor in Replace_Element");
1130 Replace_Element
(Container
, Position
.Node
, New_Item
);
1131 end Replace_Element
;
1133 ----------------------
1134 -- Reserve_Capacity --
1135 ----------------------
1137 procedure Reserve_Capacity
1138 (Container
: in out Set
;
1139 Capacity
: Count_Type
)
1142 if Capacity
> Container
.Capacity
then
1143 raise Capacity_Error
with "requested capacity is too large";
1145 end Reserve_Capacity
;
1151 procedure Set_Element
(Node
: in out Node_Type
; Item
: Element_Type
) is
1153 Node
.Element
:= Item
;
1160 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
) is
1165 --------------------------
1166 -- Symmetric_Difference --
1167 --------------------------
1169 procedure Symmetric_Difference
1170 (Target
: in out Set
;
1173 procedure Process
(Source_Node
: Count_Type
);
1174 pragma Inline
(Process
);
1176 procedure Iterate
is
1177 new HT_Ops
.Generic_Iteration
(Process
);
1183 procedure Process
(Source_Node
: Count_Type
) is
1184 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
1189 if Is_In
(Target
, N
) then
1190 Delete
(Target
, N
.Element
);
1192 Insert
(Target
, N
.Element
, X
, B
);
1197 -- Start of processing for Symmetric_Difference
1200 if Target
'Address = Source
'Address then
1201 HT_Ops
.Clear
(Target
);
1205 if Target
.Length
= 0 then
1206 Assign
(Target
=> Target
, Source
=> Source
);
1210 if Target
.Busy
> 0 then
1211 raise Program_Error
with
1212 "attempt to tamper with cursors (set is busy)";
1216 end Symmetric_Difference
;
1218 function Symmetric_Difference
(Left
, Right
: Set
) return Set
is
1222 if Left
'Address = Right
'Address then
1226 if Right
.Length
= 0 then
1230 if Left
.Length
= 0 then
1234 C
:= Left
.Length
+ Right
.Length
;
1236 return Result
: Set
(C
, To_Prime
(C
)) do
1237 Iterate_Left
: declare
1238 procedure Process
(L_Node
: Count_Type
);
1240 procedure Iterate
is
1241 new HT_Ops
.Generic_Iteration
(Process
);
1247 procedure Process
(L_Node
: Count_Type
) is
1248 N
: Node_Type
renames Left
.Nodes
(L_Node
);
1253 if not Is_In
(Right
, N
) then
1254 Insert
(Result
, N
.Element
, X
, B
);
1259 -- Start of processing for Iterate_Left
1265 Iterate_Right
: declare
1266 procedure Process
(R_Node
: Count_Type
);
1268 procedure Iterate
is
1269 new HT_Ops
.Generic_Iteration
(Process
);
1275 procedure Process
(R_Node
: Count_Type
) is
1276 N
: Node_Type
renames Left
.Nodes
(R_Node
);
1281 if not Is_In
(Left
, N
) then
1282 Insert
(Result
, N
.Element
, X
, B
);
1287 -- Start of processing for Iterate_Right
1293 end Symmetric_Difference
;
1299 function To_Set
(New_Item
: Element_Type
) return Set
is
1304 return Result
: Set
(1, 1) do
1305 Insert
(Result
, New_Item
, X
, B
);
1315 (Target
: in out Set
;
1318 procedure Process
(Src_Node
: Count_Type
);
1320 procedure Iterate
is
1321 new HT_Ops
.Generic_Iteration
(Process
);
1327 procedure Process
(Src_Node
: Count_Type
) is
1328 N
: Node_Type
renames Source
.Nodes
(Src_Node
);
1333 Insert
(Target
, N
.Element
, X
, B
);
1336 -- Start of processing for Union
1339 if Target
'Address = Source
'Address then
1343 if Target
.Busy
> 0 then
1344 raise Program_Error
with
1345 "attempt to tamper with cursors (set is busy)";
1350 -- N : constant Count_Type := Target.Length + Source.Length;
1352 -- if N > HT_Ops.Capacity (Target.HT) then
1353 -- HT_Ops.Reserve_Capacity (Target.HT, N);
1360 function Union
(Left
, Right
: Set
) return Set
is
1364 if Left
'Address = Right
'Address then
1368 if Right
.Length
= 0 then
1372 if Left
.Length
= 0 then
1376 C
:= Left
.Length
+ Right
.Length
;
1378 return Result
: Set
(C
, To_Prime
(C
)) do
1379 Assign
(Target
=> Result
, Source
=> Left
);
1380 Union
(Target
=> Result
, Source
=> Right
);
1388 function Vet
(Position
: Cursor
) return Boolean is
1390 if Position
.Node
= 0 then
1391 return Position
.Container
= null;
1394 if Position
.Container
= null then
1399 S
: Set
renames Position
.Container
.all;
1400 N
: Nodes_Type
renames S
.Nodes
;
1404 if S
.Length
= 0 then
1408 if Position
.Node
> N
'Last then
1412 if N
(Position
.Node
).Next
= Position
.Node
then
1416 X
:= S
.Buckets
(Element_Keys
.Index
(S
, N
(Position
.Node
).Element
));
1418 for J
in 1 .. S
.Length
loop
1419 if X
= Position
.Node
then
1427 if X
= N
(X
).Next
then -- to prevent unnecessary looping
1443 (Stream
: not null access Root_Stream_Type
'Class;
1446 procedure Write_Node
1447 (Stream
: not null access Root_Stream_Type
'Class;
1449 pragma Inline
(Write_Node
);
1451 procedure Write_Nodes
is
1452 new HT_Ops
.Generic_Write
(Write_Node
);
1458 procedure Write_Node
1459 (Stream
: not null access Root_Stream_Type
'Class;
1463 Element_Type
'Write (Stream
, Node
.Element
);
1466 -- Start of processing for Write
1469 Write_Nodes
(Stream
, Container
);
1473 (Stream
: not null access Root_Stream_Type
'Class;
1477 raise Program_Error
with "attempt to stream set cursor";
1480 package body Generic_Keys
is
1482 -----------------------
1483 -- Local Subprograms --
1484 -----------------------
1486 function Equivalent_Key_Node
1488 Node
: Node_Type
) return Boolean;
1489 pragma Inline
(Equivalent_Key_Node
);
1491 --------------------------
1492 -- Local Instantiations --
1493 --------------------------
1496 new Hash_Tables
.Generic_Bounded_Keys
1497 (HT_Types
=> HT_Types
,
1499 Set_Next
=> Set_Next
,
1500 Key_Type
=> Key_Type
,
1502 Equivalent_Keys
=> Equivalent_Key_Node
);
1510 Key
: Key_Type
) return Boolean
1513 return Find
(Container
, Key
) /= No_Element
;
1521 (Container
: in out Set
;
1527 Key_Keys
.Delete_Key_Sans_Free
(Container
, Key
, X
);
1530 raise Constraint_Error
with "attempt to delete key not in set";
1533 HT_Ops
.Free
(Container
, X
);
1542 Key
: Key_Type
) return Element_Type
1544 Node
: constant Count_Type
:= Key_Keys
.Find
(Container
, Key
);
1548 raise Constraint_Error
with "key not in map";
1551 return Container
.Nodes
(Node
).Element
;
1554 -------------------------
1555 -- Equivalent_Key_Node --
1556 -------------------------
1558 function Equivalent_Key_Node
1560 Node
: Node_Type
) return Boolean
1563 return Equivalent_Keys
(Key
, Generic_Keys
.Key
(Node
.Element
));
1564 end Equivalent_Key_Node
;
1571 (Container
: in out Set
;
1576 Key_Keys
.Delete_Key_Sans_Free
(Container
, Key
, X
);
1577 HT_Ops
.Free
(Container
, X
);
1586 Key
: Key_Type
) return Cursor
1588 Node
: constant Count_Type
:=
1589 Key_Keys
.Find
(Container
, Key
);
1596 return Cursor
'(Container'Unrestricted_Access, Node);
1603 function Key (Position : Cursor) return Key_Type is
1605 if Position.Node = 0 then
1606 raise Constraint_Error with
1607 "Position cursor equals No_Element";
1610 pragma Assert (Vet (Position), "bad cursor in function Key");
1612 return Key (Position.Container.Nodes (Position.Node).Element);
1620 (Container : in out Set;
1622 New_Item : Element_Type)
1624 Node : constant Count_Type :=
1625 Key_Keys.Find (Container, Key);
1629 raise Constraint_Error with
1630 "attempt to replace key not in set";
1633 Replace_Element (Container, Node, New_Item);
1636 -----------------------------------
1637 -- Update_Element_Preserving_Key --
1638 -----------------------------------
1640 procedure Update_Element_Preserving_Key
1641 (Container : in out Set;
1643 Process : not null access
1644 procedure (Element : in out Element_Type))
1647 N : Nodes_Type renames Container.Nodes;
1650 if Position.Node = 0 then
1651 raise Constraint_Error with
1652 "Position cursor equals No_Element";
1655 if Position.Container /= Container'Unrestricted_Access then
1656 raise Program_Error with
1657 "Position cursor designates wrong set";
1661 -- if HT.Buckets = null
1662 -- or else HT.Buckets'Length = 0
1663 -- or else HT.Length = 0
1664 -- or else Position.Node.Next = Position.Node
1666 -- raise Program_Error with
1667 -- "Position cursor is bad (set is empty)";
1672 "bad cursor in Update_Element_Preserving_Key");
1674 -- Record bucket now, in case key is changed.
1675 Indx := HT_Ops.Index (Container.Buckets, N (Position.Node));
1678 E : Element_Type renames N (Position.Node).Element;
1679 K : constant Key_Type := Key (E);
1681 B : Natural renames Container.Busy;
1682 L : Natural renames Container.Lock;
1700 if Equivalent_Keys (K, Key (E)) then
1701 pragma Assert (Hash (K) = Hash (E));
1706 -- Key was modified, so remove this node from set.
1708 if Container.Buckets (Indx) = Position.Node then
1709 Container.Buckets (Indx) := N (Position.Node).Next;
1713 Prev : Count_Type := Container.Buckets (Indx);
1716 while N (Prev).Next /= Position.Node loop
1717 Prev := N (Prev).Next;
1720 raise Program_Error with
1721 "Position cursor is bad (node not found)";
1725 N (Prev).Next := N (Position.Node).Next;
1729 Container.Length := Container.Length - 1;
1730 HT_Ops.Free (Container, Position.Node);
1732 raise Program_Error with "key was modified";
1733 end Update_Element_Preserving_Key;
1737 end Ada.Containers.Bounded_Hashed_Sets;