1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . --
6 -- I N D E F I N I T E _ H A S H E D _ S E T S --
10 -- Copyright (C) 2004-2007, Free Software Foundation, Inc. --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
21 -- Boston, MA 02110-1301, USA. --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
30 -- This unit has originally being developed by Matthew J Heaney. --
31 ------------------------------------------------------------------------------
33 with Ada
.Unchecked_Deallocation
;
35 with Ada
.Containers
.Hash_Tables
.Generic_Operations
;
36 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Operations
);
38 with Ada
.Containers
.Hash_Tables
.Generic_Keys
;
39 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Keys
);
41 with Ada
.Containers
.Prime_Numbers
;
43 with System
; use type System
.Address
;
45 package body Ada
.Containers
.Indefinite_Hashed_Sets
is
47 -----------------------
48 -- Local Subprograms --
49 -----------------------
51 procedure Assign
(Node
: Node_Access
; Item
: Element_Type
);
52 pragma Inline
(Assign
);
54 function Copy_Node
(Source
: Node_Access
) return Node_Access
;
55 pragma Inline
(Copy_Node
);
57 function Equivalent_Keys
59 Node
: Node_Access
) return Boolean;
60 pragma Inline
(Equivalent_Keys
);
62 function Find_Equal_Key
63 (R_HT
: Hash_Table_Type
;
64 L_Node
: Node_Access
) return Boolean;
66 function Find_Equivalent_Key
67 (R_HT
: Hash_Table_Type
;
68 L_Node
: Node_Access
) return Boolean;
70 procedure Free
(X
: in out Node_Access
);
72 function Hash_Node
(Node
: Node_Access
) return Hash_Type
;
73 pragma Inline
(Hash_Node
);
76 (HT
: in out Hash_Table_Type
;
77 New_Item
: Element_Type
;
78 Node
: out Node_Access
;
79 Inserted
: out Boolean);
81 function Is_In
(HT
: Hash_Table_Type
; Key
: Node_Access
) return Boolean;
82 pragma Inline
(Is_In
);
84 function Next
(Node
: Node_Access
) return Node_Access
;
87 function Read_Node
(Stream
: not null access Root_Stream_Type
'Class)
89 pragma Inline
(Read_Node
);
91 procedure Set_Next
(Node
: Node_Access
; Next
: Node_Access
);
92 pragma Inline
(Set_Next
);
94 function Vet
(Position
: Cursor
) return Boolean;
97 (Stream
: not null access Root_Stream_Type
'Class;
99 pragma Inline
(Write_Node
);
101 --------------------------
102 -- Local Instantiations --
103 --------------------------
105 procedure Free_Element
is
106 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
109 new Hash_Tables
.Generic_Operations
110 (HT_Types
=> HT_Types
,
111 Hash_Node
=> Hash_Node
,
113 Set_Next
=> Set_Next
,
114 Copy_Node
=> Copy_Node
,
117 package Element_Keys
is
118 new Hash_Tables
.Generic_Keys
119 (HT_Types
=> HT_Types
,
121 Set_Next
=> Set_Next
,
122 Key_Type
=> Element_Type
,
124 Equivalent_Keys
=> Equivalent_Keys
);
127 new HT_Ops
.Generic_Equal
(Find_Equal_Key
);
129 function Is_Equivalent
is
130 new HT_Ops
.Generic_Equal
(Find_Equivalent_Key
);
132 procedure Read_Nodes
is
133 new HT_Ops
.Generic_Read
(Read_Node
);
135 procedure Replace_Element
is
136 new Element_Keys
.Generic_Replace_Element
(Hash_Node
, Assign
);
138 procedure Write_Nodes
is
139 new HT_Ops
.Generic_Write
(Write_Node
);
145 function "=" (Left
, Right
: Set
) return Boolean is
147 return Is_Equal
(Left
.HT
, Right
.HT
);
154 procedure Adjust
(Container
: in out Set
) is
156 HT_Ops
.Adjust
(Container
.HT
);
163 procedure Assign
(Node
: Node_Access
; Item
: Element_Type
) is
164 X
: Element_Access
:= Node
.Element
;
166 Node
.Element
:= new Element_Type
'(Item);
174 function Capacity (Container : Set) return Count_Type is
176 return HT_Ops.Capacity (Container.HT);
183 procedure Clear (Container : in out Set) is
185 HT_Ops.Clear (Container.HT);
192 function Contains (Container : Set; Item : Element_Type) return Boolean is
194 return Find (Container, Item) /= No_Element;
201 function Copy_Node (Source : Node_Access) return Node_Access is
202 E : Element_Access := new Element_Type'(Source
.Element
.all);
204 return new Node_Type
'(Element => E, Next => null);
216 (Container : in out Set;
222 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
225 raise Constraint_Error with "attempt to delete element not in set";
232 (Container : in out Set;
233 Position : in out Cursor)
236 if Position.Node = null then
237 raise Constraint_Error with "Position cursor equals No_Element";
240 if Position.Node.Element = null then
241 raise Program_Error with "Position cursor is bad";
244 if Position.Container /= Container'Unrestricted_Access then
245 raise Program_Error with "Position cursor designates wrong set";
248 if Container.HT.Busy > 0 then
249 raise Program_Error with
250 "attempt to tamper with elements (set is busy)";
253 pragma Assert (Vet (Position), "Position cursor is bad");
255 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
257 Free (Position.Node);
258 Position.Container := null;
266 (Target : in out Set;
269 Tgt_Node : Node_Access;
272 if Target'Address = Source'Address then
277 if Source.HT.Length = 0 then
281 if Target.HT.Busy > 0 then
282 raise Program_Error with
283 "attempt to tamper with elements (set is busy)";
286 if Source.HT.Length < Target.HT.Length then
288 Src_Node : Node_Access;
291 Src_Node := HT_Ops.First (Source.HT);
292 while Src_Node /= null loop
293 Tgt_Node := Element_Keys.Find (Target.HT, Src_Node.Element.all);
295 if Tgt_Node /= null then
296 HT_Ops.Delete_Node_Sans_Free (Target.HT, Tgt_Node);
300 Src_Node := HT_Ops.Next (Source.HT, Src_Node);
305 Tgt_Node := HT_Ops.First (Target.HT);
306 while Tgt_Node /= null loop
307 if Is_In (Source.HT, Tgt_Node) then
309 X : Node_Access := Tgt_Node;
311 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
312 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
317 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
323 function Difference (Left, Right : Set) return Set is
324 Buckets : HT_Types.Buckets_Access;
328 if Left'Address = Right'Address then
332 if Left.Length = 0 then
336 if Right.Length = 0 then
341 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
343 Buckets := HT_Ops.New_Buckets (Length => Size);
348 Iterate_Left : declare
349 procedure Process (L_Node : Node_Access);
352 new HT_Ops.Generic_Iteration (Process);
358 procedure Process (L_Node : Node_Access) is
360 if not Is_In (Right.HT, L_Node) then
362 Src : Element_Type renames L_Node.Element.all;
363 Indx : constant Hash_Type := Hash (Src) mod Buckets'Length;
364 Bucket : Node_Access renames Buckets (Indx);
365 Tgt : Element_Access := new Element_Type'(Src
);
367 Bucket
:= new Node_Type
'(Tgt, Bucket);
374 Length := Length + 1;
378 -- Start of processing for Iterate_Left
384 HT_Ops.Free_Hash_Table (Buckets);
388 return (Controlled with HT => (Buckets, Length, 0, 0));
395 function Element (Position : Cursor) return Element_Type is
397 if Position.Node = null then
398 raise Constraint_Error with "Position cursor of equals No_Element";
401 if Position.Node.Element = null then -- handle dangling reference
402 raise Program_Error with "Position cursor is bad";
405 pragma Assert (Vet (Position), "bad cursor in function Element");
407 return Position.Node.Element.all;
410 ---------------------
411 -- Equivalent_Sets --
412 ---------------------
414 function Equivalent_Sets (Left, Right : Set) return Boolean is
416 return Is_Equivalent (Left.HT, Right.HT);
419 -------------------------
420 -- Equivalent_Elements --
421 -------------------------
423 function Equivalent_Elements (Left, Right : Cursor)
426 if Left.Node = null then
427 raise Constraint_Error with
428 "Left cursor of Equivalent_Elements equals No_Element";
431 if Right.Node = null then
432 raise Constraint_Error with
433 "Right cursor of Equivalent_Elements equals No_Element";
436 if Left.Node.Element = null then
437 raise Program_Error with
438 "Left cursor of Equivalent_Elements is bad";
441 if Right.Node.Element = null then
442 raise Program_Error with
443 "Right cursor of Equivalent_Elements is bad";
446 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
447 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
449 return Equivalent_Elements
450 (Left.Node.Element.all,
451 Right.Node.Element.all);
452 end Equivalent_Elements;
454 function Equivalent_Elements (Left : Cursor; Right : Element_Type)
457 if Left.Node = null then
458 raise Constraint_Error with
459 "Left cursor of Equivalent_Elements equals No_Element";
462 if Left.Node.Element = null then
463 raise Program_Error with
464 "Left cursor of Equivalent_Elements is bad";
467 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
469 return Equivalent_Elements (Left.Node.Element.all, Right);
470 end Equivalent_Elements;
472 function Equivalent_Elements (Left : Element_Type; Right : Cursor)
475 if Right.Node = null then
476 raise Constraint_Error with
477 "Right cursor of Equivalent_Elements equals No_Element";
480 if Right.Node.Element = null then
481 raise Program_Error with
482 "Right cursor of Equivalent_Elements is bad";
485 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
487 return Equivalent_Elements (Left, Right.Node.Element.all);
488 end Equivalent_Elements;
490 ---------------------
491 -- Equivalent_Keys --
492 ---------------------
494 function Equivalent_Keys (Key : Element_Type; Node : Node_Access)
497 return Equivalent_Elements (Key, Node.Element.all);
505 (Container : in out Set;
510 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
518 procedure Finalize (Container : in out Set) is
520 HT_Ops.Finalize (Container.HT);
529 Item : Element_Type) return Cursor
531 Node : constant Node_Access := Element_Keys.Find (Container.HT, Item);
538 return Cursor'(Container
'Unrestricted_Access, Node
);
545 function Find_Equal_Key
546 (R_HT
: Hash_Table_Type
;
547 L_Node
: Node_Access
) return Boolean
549 R_Index
: constant Hash_Type
:=
550 Element_Keys
.Index
(R_HT
, L_Node
.Element
.all);
552 R_Node
: Node_Access
:= R_HT
.Buckets
(R_Index
);
556 if R_Node
= null then
560 if L_Node
.Element
.all = R_Node
.Element
.all then
564 R_Node
:= Next
(R_Node
);
568 -------------------------
569 -- Find_Equivalent_Key --
570 -------------------------
572 function Find_Equivalent_Key
573 (R_HT
: Hash_Table_Type
;
574 L_Node
: Node_Access
) return Boolean
576 R_Index
: constant Hash_Type
:=
577 Element_Keys
.Index
(R_HT
, L_Node
.Element
.all);
579 R_Node
: Node_Access
:= R_HT
.Buckets
(R_Index
);
583 if R_Node
= null then
587 if Equivalent_Elements
(L_Node
.Element
.all, R_Node
.Element
.all) then
591 R_Node
:= Next
(R_Node
);
593 end Find_Equivalent_Key
;
599 function First
(Container
: Set
) return Cursor
is
600 Node
: constant Node_Access
:= HT_Ops
.First
(Container
.HT
);
607 return Cursor
'(Container'Unrestricted_Access, Node);
614 procedure Free (X : in out Node_Access) is
615 procedure Deallocate is
616 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
623 X.Next := X; -- detect mischief (in Vet)
626 Free_Element (X.Element);
641 function Has_Element (Position : Cursor) return Boolean is
643 pragma Assert (Vet (Position), "bad cursor in Has_Element");
644 return Position.Node /= null;
651 function Hash_Node (Node : Node_Access) return Hash_Type is
653 return Hash (Node.Element.all);
661 (Container : in out Set;
662 New_Item : Element_Type)
670 Insert (Container, New_Item, Position, Inserted);
673 if Container.HT.Lock > 0 then
674 raise Program_Error with
675 "attempt to tamper with cursors (set is locked)";
678 X := Position.Node.Element;
680 Position.Node.Element := new Element_Type'(New_Item
);
691 (Container
: in out Set
;
692 New_Item
: Element_Type
;
693 Position
: out Cursor
;
694 Inserted
: out Boolean)
697 Insert
(Container
.HT
, New_Item
, Position
.Node
, Inserted
);
698 Position
.Container
:= Container
'Unchecked_Access;
702 (Container
: in out Set
;
703 New_Item
: Element_Type
)
706 pragma Unreferenced
(Position
);
711 Insert
(Container
, New_Item
, Position
, Inserted
);
714 raise Constraint_Error
with
715 "attempt to insert element already in set";
720 (HT
: in out Hash_Table_Type
;
721 New_Item
: Element_Type
;
722 Node
: out Node_Access
;
723 Inserted
: out Boolean)
725 function New_Node
(Next
: Node_Access
) return Node_Access
;
726 pragma Inline
(New_Node
);
728 procedure Local_Insert
is
729 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
735 function New_Node
(Next
: Node_Access
) return Node_Access
is
736 Element
: Element_Access
:= new Element_Type
'(New_Item);
739 return new Node_Type'(Element
, Next
);
742 Free_Element
(Element
);
746 -- Start of processing for Insert
749 if HT_Ops
.Capacity
(HT
) = 0 then
750 HT_Ops
.Reserve_Capacity
(HT
, 1);
753 Local_Insert
(HT
, New_Item
, Node
, Inserted
);
756 and then HT
.Length
> HT_Ops
.Capacity
(HT
)
758 HT_Ops
.Reserve_Capacity
(HT
, HT
.Length
);
766 procedure Intersection
767 (Target
: in out Set
;
770 Tgt_Node
: Node_Access
;
773 if Target
'Address = Source
'Address then
777 if Source
.Length
= 0 then
782 if Target
.HT
.Busy
> 0 then
783 raise Program_Error
with
784 "attempt to tamper with elements (set is busy)";
787 Tgt_Node
:= HT_Ops
.First
(Target
.HT
);
788 while Tgt_Node
/= null loop
789 if Is_In
(Source
.HT
, Tgt_Node
) then
790 Tgt_Node
:= HT_Ops
.Next
(Target
.HT
, Tgt_Node
);
794 X
: Node_Access
:= Tgt_Node
;
796 Tgt_Node
:= HT_Ops
.Next
(Target
.HT
, Tgt_Node
);
797 HT_Ops
.Delete_Node_Sans_Free
(Target
.HT
, X
);
804 function Intersection
(Left
, Right
: Set
) return Set
is
805 Buckets
: HT_Types
.Buckets_Access
;
809 if Left
'Address = Right
'Address then
813 Length
:= Count_Type
'Min (Left
.Length
, Right
.Length
);
820 Size
: constant Hash_Type
:= Prime_Numbers
.To_Prime
(Length
);
822 Buckets
:= HT_Ops
.New_Buckets
(Length
=> Size
);
827 Iterate_Left
: declare
828 procedure Process
(L_Node
: Node_Access
);
831 new HT_Ops
.Generic_Iteration
(Process
);
837 procedure Process
(L_Node
: Node_Access
) is
839 if Is_In
(Right
.HT
, L_Node
) then
841 Src
: Element_Type
renames L_Node
.Element
.all;
843 Indx
: constant Hash_Type
:= Hash
(Src
) mod Buckets
'Length;
845 Bucket
: Node_Access
renames Buckets
(Indx
);
847 Tgt
: Element_Access
:= new Element_Type
'(Src);
850 Bucket := new Node_Type'(Tgt
, Bucket
);
857 Length
:= Length
+ 1;
861 -- Start of processing for Iterate_Left
867 HT_Ops
.Free_Hash_Table
(Buckets
);
871 return (Controlled
with HT
=> (Buckets
, Length
, 0, 0));
878 function Is_Empty
(Container
: Set
) return Boolean is
880 return Container
.HT
.Length
= 0;
887 function Is_In
(HT
: Hash_Table_Type
; Key
: Node_Access
) return Boolean is
889 return Element_Keys
.Find
(HT
, Key
.Element
.all) /= null;
898 Of_Set
: Set
) return Boolean
900 Subset_Node
: Node_Access
;
903 if Subset
'Address = Of_Set
'Address then
907 if Subset
.Length
> Of_Set
.Length
then
911 Subset_Node
:= HT_Ops
.First
(Subset
.HT
);
912 while Subset_Node
/= null loop
913 if not Is_In
(Of_Set
.HT
, Subset_Node
) then
917 Subset_Node
:= HT_Ops
.Next
(Subset
.HT
, Subset_Node
);
929 Process
: not null access procedure (Position
: Cursor
))
931 procedure Process_Node
(Node
: Node_Access
);
932 pragma Inline
(Process_Node
);
935 new HT_Ops
.Generic_Iteration
(Process_Node
);
941 procedure Process_Node
(Node
: Node_Access
) is
943 Process
(Cursor
'(Container'Unrestricted_Access, Node));
946 B : Natural renames Container'Unrestricted_Access.HT.Busy;
948 -- Start of processing for Iterate
954 Iterate (Container.HT);
968 function Length (Container : Set) return Count_Type is
970 return Container.HT.Length;
977 procedure Move (Target : in out Set; Source : in out Set) is
979 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
986 function Next (Node : Node_Access) return Node_Access is
991 function Next (Position : Cursor) return Cursor is
993 if Position.Node = null then
997 if Position.Node.Element = null then
998 raise Program_Error with "bad cursor in Next";
1001 pragma Assert (Vet (Position), "bad cursor in Next");
1004 HT : Hash_Table_Type renames Position.Container.HT;
1005 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
1012 return Cursor'(Position
.Container
, Node
);
1016 procedure Next
(Position
: in out Cursor
) is
1018 Position
:= Next
(Position
);
1025 function Overlap
(Left
, Right
: Set
) return Boolean is
1026 Left_Node
: Node_Access
;
1029 if Right
.Length
= 0 then
1033 if Left
'Address = Right
'Address then
1037 Left_Node
:= HT_Ops
.First
(Left
.HT
);
1038 while Left_Node
/= null loop
1039 if Is_In
(Right
.HT
, Left_Node
) then
1043 Left_Node
:= HT_Ops
.Next
(Left
.HT
, Left_Node
);
1053 procedure Query_Element
1055 Process
: not null access procedure (Element
: Element_Type
))
1058 if Position
.Node
= null then
1059 raise Constraint_Error
with
1060 "Position cursor of Query_Element equals No_Element";
1063 if Position
.Node
.Element
= null then
1064 raise Program_Error
with "bad cursor in Query_Element";
1067 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
1070 HT
: Hash_Table_Type
renames
1071 Position
.Container
'Unrestricted_Access.all.HT
;
1073 B
: Natural renames HT
.Busy
;
1074 L
: Natural renames HT
.Lock
;
1081 Process
(Position
.Node
.Element
.all);
1099 (Stream
: not null access Root_Stream_Type
'Class;
1100 Container
: out Set
)
1103 Read_Nodes
(Stream
, Container
.HT
);
1107 (Stream
: not null access Root_Stream_Type
'Class;
1111 raise Program_Error
with "attempt to stream set cursor";
1119 (Stream
: not null access Root_Stream_Type
'Class) return Node_Access
1121 X
: Element_Access
:= new Element_Type
'(Element_Type'Input (Stream));
1124 return new Node_Type'(X
, null);
1136 (Container
: in out Set
;
1137 New_Item
: Element_Type
)
1139 Node
: constant Node_Access
:=
1140 Element_Keys
.Find
(Container
.HT
, New_Item
);
1143 pragma Warnings
(Off
, X
);
1147 raise Constraint_Error
with
1148 "attempt to replace element not in set";
1151 if Container
.HT
.Lock
> 0 then
1152 raise Program_Error
with
1153 "attempt to tamper with cursors (set is locked)";
1158 Node
.Element
:= new Element_Type
'(New_Item);
1163 ---------------------
1164 -- Replace_Element --
1165 ---------------------
1167 procedure Replace_Element
1168 (Container : in out Set;
1170 New_Item : Element_Type)
1173 if Position.Node = null then
1174 raise Constraint_Error with "Position cursor equals No_Element";
1177 if Position.Node.Element = null then
1178 raise Program_Error with "bad cursor in Replace_Element";
1181 if Position.Container /= Container'Unrestricted_Access then
1182 raise Program_Error with
1183 "Position cursor designates wrong set";
1186 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1188 Replace_Element (Container.HT, Position.Node, New_Item);
1189 end Replace_Element;
1191 ----------------------
1192 -- Reserve_Capacity --
1193 ----------------------
1195 procedure Reserve_Capacity
1196 (Container : in out Set;
1197 Capacity : Count_Type)
1200 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1201 end Reserve_Capacity;
1207 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1212 --------------------------
1213 -- Symmetric_Difference --
1214 --------------------------
1216 procedure Symmetric_Difference
1217 (Target : in out Set;
1221 if Target'Address = Source'Address then
1226 if Target.HT.Busy > 0 then
1227 raise Program_Error with
1228 "attempt to tamper with elements (set is busy)";
1232 N : constant Count_Type := Target.Length + Source.Length;
1234 if N > HT_Ops.Capacity (Target.HT) then
1235 HT_Ops.Reserve_Capacity (Target.HT, N);
1239 if Target.Length = 0 then
1240 Iterate_Source_When_Empty_Target : declare
1241 procedure Process (Src_Node : Node_Access);
1243 procedure Iterate is
1244 new HT_Ops.Generic_Iteration (Process);
1250 procedure Process (Src_Node : Node_Access) is
1251 E : Element_Type renames Src_Node.Element.all;
1252 B : Buckets_Type renames Target.HT.Buckets.all;
1253 J : constant Hash_Type := Hash (E) mod B'Length;
1254 N : Count_Type renames Target.HT.Length;
1258 X : Element_Access := new Element_Type'(E
);
1260 B
(J
) := new Node_Type
'(X, B (J));
1270 -- Start of processing for Iterate_Source_When_Empty_Target
1273 Iterate (Source.HT);
1274 end Iterate_Source_When_Empty_Target;
1277 Iterate_Source : declare
1278 procedure Process (Src_Node : Node_Access);
1280 procedure Iterate is
1281 new HT_Ops.Generic_Iteration (Process);
1287 procedure Process (Src_Node : Node_Access) is
1288 E : Element_Type renames Src_Node.Element.all;
1289 B : Buckets_Type renames Target.HT.Buckets.all;
1290 J : constant Hash_Type := Hash (E) mod B'Length;
1291 N : Count_Type renames Target.HT.Length;
1294 if B (J) = null then
1296 X : Element_Access := new Element_Type'(E
);
1298 B
(J
) := new Node_Type
'(X, null);
1307 elsif Equivalent_Elements (E, B (J).Element.all) then
1309 X : Node_Access := B (J);
1311 B (J) := B (J).Next;
1318 Prev : Node_Access := B (J);
1319 Curr : Node_Access := Prev.Next;
1322 while Curr /= null loop
1323 if Equivalent_Elements (E, Curr.Element.all) then
1324 Prev.Next := Curr.Next;
1335 X : Element_Access := new Element_Type'(E
);
1337 B
(J
) := new Node_Type
'(X, B (J));
1349 -- Start of processing for Iterate_Source
1352 Iterate (Source.HT);
1355 end Symmetric_Difference;
1357 function Symmetric_Difference (Left, Right : Set) return Set is
1358 Buckets : HT_Types.Buckets_Access;
1359 Length : Count_Type;
1362 if Left'Address = Right'Address then
1366 if Right.Length = 0 then
1370 if Left.Length = 0 then
1375 Size : constant Hash_Type :=
1376 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1378 Buckets := HT_Ops.New_Buckets (Length => Size);
1383 Iterate_Left : declare
1384 procedure Process (L_Node : Node_Access);
1386 procedure Iterate is
1387 new HT_Ops.Generic_Iteration (Process);
1393 procedure Process (L_Node : Node_Access) is
1395 if not Is_In (Right.HT, L_Node) then
1397 E : Element_Type renames L_Node.Element.all;
1398 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1402 X : Element_Access := new Element_Type'(E
);
1404 Buckets
(J
) := new Node_Type
'(X, Buckets (J));
1411 Length := Length + 1;
1416 -- Start of processing for Iterate_Left
1422 HT_Ops.Free_Hash_Table (Buckets);
1426 Iterate_Right : declare
1427 procedure Process (R_Node : Node_Access);
1429 procedure Iterate is
1430 new HT_Ops.Generic_Iteration (Process);
1436 procedure Process (R_Node : Node_Access) is
1438 if not Is_In (Left.HT, R_Node) then
1440 E : Element_Type renames R_Node.Element.all;
1441 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1445 X : Element_Access := new Element_Type'(E
);
1447 Buckets
(J
) := new Node_Type
'(X, Buckets (J));
1454 Length := Length + 1;
1459 -- Start of processing for Iterate_Right
1465 HT_Ops.Free_Hash_Table (Buckets);
1469 return (Controlled with HT => (Buckets, Length, 0, 0));
1470 end Symmetric_Difference;
1476 function To_Set (New_Item : Element_Type) return Set is
1477 HT : Hash_Table_Type;
1481 pragma Unreferenced (Node, Inserted);
1484 Insert (HT, New_Item, Node, Inserted);
1485 return Set'(Controlled
with HT
);
1493 (Target
: in out Set
;
1496 procedure Process
(Src_Node
: Node_Access
);
1498 procedure Iterate
is
1499 new HT_Ops
.Generic_Iteration
(Process
);
1505 procedure Process
(Src_Node
: Node_Access
) is
1506 Src
: Element_Type
renames Src_Node
.Element
.all;
1508 function New_Node
(Next
: Node_Access
) return Node_Access
;
1509 pragma Inline
(New_Node
);
1512 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
1518 function New_Node
(Next
: Node_Access
) return Node_Access
is
1519 Tgt
: Element_Access
:= new Element_Type
'(Src);
1522 return new Node_Type'(Tgt
, Next
);
1529 Tgt_Node
: Node_Access
;
1531 pragma Unreferenced
(Tgt_Node
, Success
);
1533 -- Start of processing for Process
1536 Insert
(Target
.HT
, Src
, Tgt_Node
, Success
);
1539 -- Start of processing for Union
1542 if Target
'Address = Source
'Address then
1546 if Target
.HT
.Busy
> 0 then
1547 raise Program_Error
with
1548 "attempt to tamper with elements (set is busy)";
1552 N
: constant Count_Type
:= Target
.Length
+ Source
.Length
;
1554 if N
> HT_Ops
.Capacity
(Target
.HT
) then
1555 HT_Ops
.Reserve_Capacity
(Target
.HT
, N
);
1559 Iterate
(Source
.HT
);
1562 function Union
(Left
, Right
: Set
) return Set
is
1563 Buckets
: HT_Types
.Buckets_Access
;
1564 Length
: Count_Type
;
1567 if Left
'Address = Right
'Address then
1571 if Right
.Length
= 0 then
1575 if Left
.Length
= 0 then
1580 Size
: constant Hash_Type
:=
1581 Prime_Numbers
.To_Prime
(Left
.Length
+ Right
.Length
);
1583 Buckets
:= HT_Ops
.New_Buckets
(Length
=> Size
);
1586 Iterate_Left
: declare
1587 procedure Process
(L_Node
: Node_Access
);
1589 procedure Iterate
is
1590 new HT_Ops
.Generic_Iteration
(Process
);
1596 procedure Process
(L_Node
: Node_Access
) is
1597 Src
: Element_Type
renames L_Node
.Element
.all;
1599 J
: constant Hash_Type
:= Hash
(Src
) mod Buckets
'Length;
1601 Bucket
: Node_Access
renames Buckets
(J
);
1603 Tgt
: Element_Access
:= new Element_Type
'(Src);
1606 Bucket := new Node_Type'(Tgt
, Bucket
);
1613 -- Start of processing for Process
1619 HT_Ops
.Free_Hash_Table
(Buckets
);
1623 Length
:= Left
.Length
;
1625 Iterate_Right
: declare
1626 procedure Process
(Src_Node
: Node_Access
);
1628 procedure Iterate
is
1629 new HT_Ops
.Generic_Iteration
(Process
);
1635 procedure Process
(Src_Node
: Node_Access
) is
1636 Src
: Element_Type
renames Src_Node
.Element
.all;
1637 Idx
: constant Hash_Type
:= Hash
(Src
) mod Buckets
'Length;
1639 Tgt_Node
: Node_Access
:= Buckets
(Idx
);
1642 while Tgt_Node
/= null loop
1643 if Equivalent_Elements
(Src
, Tgt_Node
.Element
.all) then
1646 Tgt_Node
:= Next
(Tgt_Node
);
1650 Tgt
: Element_Access
:= new Element_Type
'(Src);
1652 Buckets (Idx) := new Node_Type'(Tgt
, Buckets
(Idx
));
1659 Length
:= Length
+ 1;
1662 -- Start of processing for Iterate_Right
1668 HT_Ops
.Free_Hash_Table
(Buckets
);
1672 return (Controlled
with HT
=> (Buckets
, Length
, 0, 0));
1679 function Vet
(Position
: Cursor
) return Boolean is
1681 if Position
.Node
= null then
1682 return Position
.Container
= null;
1685 if Position
.Container
= null then
1689 if Position
.Node
.Next
= Position
.Node
then
1693 if Position
.Node
.Element
= null then
1698 HT
: Hash_Table_Type
renames Position
.Container
.HT
;
1702 if HT
.Length
= 0 then
1706 if HT
.Buckets
= null
1707 or else HT
.Buckets
'Length = 0
1712 X
:= HT
.Buckets
(Element_Keys
.Index
(HT
, Position
.Node
.Element
.all));
1714 for J
in 1 .. HT
.Length
loop
1715 if X
= Position
.Node
then
1723 if X
= X
.Next
then -- to prevent unnecessary looping
1739 (Stream
: not null access Root_Stream_Type
'Class;
1743 Write_Nodes
(Stream
, Container
.HT
);
1747 (Stream
: not null access Root_Stream_Type
'Class;
1751 raise Program_Error
with "attempt to stream set cursor";
1758 procedure Write_Node
1759 (Stream
: not null access Root_Stream_Type
'Class;
1763 Element_Type
'Output (Stream
, Node
.Element
.all);
1766 package body Generic_Keys
is
1768 -----------------------
1769 -- Local Subprograms --
1770 -----------------------
1772 function Equivalent_Key_Node
1774 Node
: Node_Access
) return Boolean;
1775 pragma Inline
(Equivalent_Key_Node
);
1777 --------------------------
1778 -- Local Instantiations --
1779 --------------------------
1782 new Hash_Tables
.Generic_Keys
1783 (HT_Types
=> HT_Types
,
1785 Set_Next
=> Set_Next
,
1786 Key_Type
=> Key_Type
,
1788 Equivalent_Keys
=> Equivalent_Key_Node
);
1796 Key
: Key_Type
) return Boolean
1799 return Find
(Container
, Key
) /= No_Element
;
1807 (Container
: in out Set
;
1813 Key_Keys
.Delete_Key_Sans_Free
(Container
.HT
, Key
, X
);
1816 raise Constraint_Error
with "key not in map";
1828 Key
: Key_Type
) return Element_Type
1830 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.HT
, Key
);
1834 raise Constraint_Error
with "key not in map";
1837 return Node
.Element
.all;
1840 -------------------------
1841 -- Equivalent_Key_Node --
1842 -------------------------
1844 function Equivalent_Key_Node
1846 Node
: Node_Access
) return Boolean is
1848 return Equivalent_Keys
(Key
, Generic_Keys
.Key
(Node
.Element
.all));
1849 end Equivalent_Key_Node
;
1856 (Container
: in out Set
;
1861 Key_Keys
.Delete_Key_Sans_Free
(Container
.HT
, Key
, X
);
1871 Key
: Key_Type
) return Cursor
1873 Node
: constant Node_Access
:= Key_Keys
.Find
(Container
.HT
, Key
);
1880 return Cursor
'(Container'Unrestricted_Access, Node);
1887 function Key (Position : Cursor) return Key_Type is
1889 if Position.Node = null then
1890 raise Constraint_Error with
1891 "Position cursor equals No_Element";
1894 if Position.Node.Element = null then
1895 raise Program_Error with "Position cursor is bad";
1898 pragma Assert (Vet (Position), "bad cursor in function Key");
1900 return Key (Position.Node.Element.all);
1908 (Container : in out Set;
1910 New_Item : Element_Type)
1912 Node : constant Node_Access :=
1913 Key_Keys.Find (Container.HT, Key);
1917 raise Constraint_Error with
1918 "attempt to replace key not in set";
1921 Replace_Element (Container.HT, Node, New_Item);
1924 procedure Update_Element_Preserving_Key
1925 (Container : in out Set;
1927 Process : not null access
1928 procedure (Element : in out Element_Type))
1930 HT : Hash_Table_Type renames Container.HT;
1934 if Position.Node = null then
1935 raise Constraint_Error with
1936 "Position cursor equals No_Element";
1939 if Position.Node.Element = null
1940 or else Position.Node.Next = Position.Node
1942 raise Program_Error with "Position cursor is bad";
1945 if Position.Container /= Container'Unrestricted_Access then
1946 raise Program_Error with
1947 "Position cursor designates wrong set";
1950 if HT.Buckets = null
1951 or else HT.Buckets'Length = 0
1952 or else HT.Length = 0
1954 raise Program_Error with "Position cursor is bad (set is empty)";
1959 "bad cursor in Update_Element_Preserving_Key");
1961 Indx := HT_Ops.Index (HT, Position.Node);
1964 E : Element_Type renames Position.Node.Element.all;
1965 K : constant Key_Type := Key (E);
1967 B : Natural renames HT.Busy;
1968 L : Natural renames HT.Lock;
1986 if Equivalent_Keys (K, Key (E)) then
1987 pragma Assert (Hash (K) = Hash (E));
1992 if HT.Buckets (Indx) = Position.Node then
1993 HT.Buckets (Indx) := Position.Node.Next;
1997 Prev : Node_Access := HT.Buckets (Indx);
2000 while Prev.Next /= Position.Node loop
2004 raise Program_Error with
2005 "Position cursor is bad (node not found)";
2009 Prev.Next := Position.Node.Next;
2013 HT.Length := HT.Length - 1;
2016 X : Node_Access := Position.Node;
2022 raise Program_Error with "key was modified";
2023 end Update_Element_Preserving_Key;
2027 end Ada.Containers.Indefinite_Hashed_Sets;