1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . F O R M A L _ H A S H E D _ S E T S --
9 -- Copyright (C) 2010-2015, 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/>. --
26 ------------------------------------------------------------------------------
28 with Ada
.Containers
.Hash_Tables
.Generic_Bounded_Operations
;
29 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Bounded_Operations
);
31 with Ada
.Containers
.Hash_Tables
.Generic_Bounded_Keys
;
32 pragma Elaborate_All
(Ada
.Containers
.Hash_Tables
.Generic_Bounded_Keys
);
34 with Ada
.Containers
.Prime_Numbers
; use Ada
.Containers
.Prime_Numbers
;
36 with System
; use type System
.Address
;
38 package body Ada
.Containers
.Formal_Hashed_Sets
with
42 -----------------------
43 -- Local Subprograms --
44 -----------------------
46 -- All need comments ???
52 function Equivalent_Keys
54 Node
: Node_Type
) return Boolean;
55 pragma Inline
(Equivalent_Keys
);
62 with procedure Set_Element
(Node
: in out Node_Type
);
63 procedure Generic_Allocate
65 Node
: out Count_Type
);
67 function Hash_Node
(Node
: Node_Type
) return Hash_Type
;
68 pragma Inline
(Hash_Node
);
71 (Container
: in out Set
;
72 New_Item
: Element_Type
;
73 Node
: out Count_Type
;
74 Inserted
: out Boolean);
76 procedure Intersection
83 Key
: Node_Type
) return Boolean;
84 pragma Inline
(Is_In
);
86 procedure Set_Element
(Node
: in out Node_Type
; Item
: Element_Type
);
87 pragma Inline
(Set_Element
);
89 function Next
(Node
: Node_Type
) return Count_Type
;
92 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
);
93 pragma Inline
(Set_Next
);
95 function Vet
(Container
: Set
; Position
: Cursor
) return Boolean;
97 --------------------------
98 -- Local Instantiations --
99 --------------------------
101 package HT_Ops
is new Hash_Tables
.Generic_Bounded_Operations
102 (HT_Types
=> HT_Types
,
103 Hash_Node
=> Hash_Node
,
105 Set_Next
=> Set_Next
);
107 package Element_Keys
is new Hash_Tables
.Generic_Bounded_Keys
108 (HT_Types
=> HT_Types
,
110 Set_Next
=> Set_Next
,
111 Key_Type
=> Element_Type
,
113 Equivalent_Keys
=> Equivalent_Keys
);
115 procedure Replace_Element
is
116 new Element_Keys
.Generic_Replace_Element
(Hash_Node
, Set_Element
);
122 function "=" (Left
, Right
: Set
) return Boolean is
124 if Length
(Left
) /= Length
(Right
) then
128 if Length
(Left
) = 0 then
137 Node
:= First
(Left
).Node
;
139 ENode
:= Find
(Container
=> Right
,
140 Item
=> Left
.Nodes
(Node
).Element
).Node
;
142 Right
.Nodes
(ENode
).Element
/= Left
.Nodes
(Node
).Element
147 Node
:= HT_Ops
.Next
(Left
, Node
);
160 procedure Assign
(Target
: in out Set
; Source
: Set
) is
161 procedure Insert_Element
(Source_Node
: Count_Type
);
163 procedure Insert_Elements
is
164 new HT_Ops
.Generic_Iteration
(Insert_Element
);
170 procedure Insert_Element
(Source_Node
: Count_Type
) is
171 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
176 Insert
(Target
, N
.Element
, X
, B
);
180 -- Start of processing for Assign
183 if Target
'Address = Source
'Address then
187 if Target
.Capacity
< Length
(Source
) then
188 raise Storage_Error
with "not enough capacity"; -- SE or CE? ???
191 HT_Ops
.Clear
(Target
);
192 Insert_Elements
(Source
);
199 function Capacity
(Container
: Set
) return Count_Type
is
201 return Container
.Nodes
'Length;
208 procedure Clear
(Container
: in out Set
) is
210 HT_Ops
.Clear
(Container
);
217 function Contains
(Container
: Set
; Item
: Element_Type
) return Boolean is
219 return Find
(Container
, Item
) /= No_Element
;
228 Capacity
: Count_Type
:= 0) return Set
230 C
: constant Count_Type
:=
231 Count_Type
'Max (Capacity
, Source
.Capacity
);
234 Target
: Set
(C
, Source
.Modulus
);
238 if 0 < Capacity
and then Capacity
< Source
.Capacity
then
239 raise Capacity_Error
;
242 Target
.Length
:= Source
.Length
;
243 Target
.Free
:= Source
.Free
;
246 while H
<= Source
.Modulus
loop
247 Target
.Buckets
(H
) := Source
.Buckets
(H
);
252 while N
<= Source
.Capacity
loop
253 Target
.Nodes
(N
) := Source
.Nodes
(N
);
259 Free
(Target
, Cu
.Node
);
266 ---------------------
267 -- Current_To_Last --
268 ---------------------
270 function Current_To_Last
(Container
: Set
; Current
: Cursor
) return Set
is
271 Curs
: Cursor
:= First
(Container
);
272 C
: Set
(Container
.Capacity
, Container
.Modulus
) :=
273 Copy
(Container
, Container
.Capacity
);
277 if Curs
= No_Element
then
281 elsif Current
/= No_Element
and not Has_Element
(Container
, Current
) then
282 raise Constraint_Error
;
285 while Curs
.Node
/= Current
.Node
loop
288 Curs
:= Next
(Container
, (Node
=> Node
));
295 ---------------------
296 -- Default_Modulus --
297 ---------------------
299 function Default_Modulus
(Capacity
: Count_Type
) return Hash_Type
is
301 return To_Prime
(Capacity
);
309 (Container
: in out Set
;
315 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
318 raise Constraint_Error
with "attempt to delete element not in set";
325 (Container
: in out Set
;
326 Position
: in out Cursor
)
329 if not Has_Element
(Container
, Position
) then
330 raise Constraint_Error
with "Position cursor has no element";
333 pragma Assert
(Vet
(Container
, Position
), "bad cursor in Delete");
335 HT_Ops
.Delete_Node_Sans_Free
(Container
, Position
.Node
);
336 Free
(Container
, Position
.Node
);
338 Position
:= No_Element
;
346 (Target
: in out Set
;
349 Tgt_Node
, Src_Node
, Src_Last
, Src_Length
: Count_Type
;
351 TN
: Nodes_Type
renames Target
.Nodes
;
352 SN
: Nodes_Type
renames Source
.Nodes
;
355 if Target
'Address = Source
'Address then
360 Src_Length
:= Source
.Length
;
362 if Src_Length
= 0 then
366 if Src_Length
>= Target
.Length
then
367 Tgt_Node
:= HT_Ops
.First
(Target
);
368 while Tgt_Node
/= 0 loop
369 if Element_Keys
.Find
(Source
, TN
(Tgt_Node
).Element
) /= 0 then
371 X
: constant Count_Type
:= Tgt_Node
;
373 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
374 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
379 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
385 Src_Node
:= HT_Ops
.First
(Source
);
389 while Src_Node
/= Src_Last
loop
390 Tgt_Node
:= Element_Keys
.Find
(Target
, SN
(Src_Node
).Element
);
392 if Tgt_Node
/= 0 then
393 HT_Ops
.Delete_Node_Sans_Free
(Target
, Tgt_Node
);
394 Free
(Target
, Tgt_Node
);
397 Src_Node
:= HT_Ops
.Next
(Source
, Src_Node
);
405 procedure Process
(L_Node
: Count_Type
);
408 new HT_Ops
.Generic_Iteration
(Process
);
414 procedure Process
(L_Node
: Count_Type
) is
415 E
: Element_Type
renames Left
.Nodes
(L_Node
).Element
;
419 if Find
(Right
, E
).Node
= 0 then
420 Insert
(Target
, E
, X
, B
);
425 -- Start of processing for Difference
431 function Difference
(Left
, Right
: Set
) return Set
is
436 if Left
'Address = Right
'Address then
440 if Length
(Left
) = 0 then
444 if Length
(Right
) = 0 then
449 H
:= Default_Modulus
(C
);
451 return S
: Set
(C
, H
) do
452 Difference
(Left
, Right
, Target
=> S
);
462 Position
: Cursor
) return Element_Type
465 if not Has_Element
(Container
, Position
) then
466 raise Constraint_Error
with "Position cursor equals No_Element";
469 pragma Assert
(Vet
(Container
, Position
),
470 "bad cursor in function Element");
472 return Container
.Nodes
(Position
.Node
).Element
;
475 ---------------------
476 -- Equivalent_Sets --
477 ---------------------
479 function Equivalent_Sets
(Left
, Right
: Set
) return Boolean is
481 function Find_Equivalent_Key
482 (R_HT
: Hash_Table_Type
'Class;
483 L_Node
: Node_Type
) return Boolean;
484 pragma Inline
(Find_Equivalent_Key
);
486 function Is_Equivalent
is
487 new HT_Ops
.Generic_Equal
(Find_Equivalent_Key
);
489 -------------------------
490 -- Find_Equivalent_Key --
491 -------------------------
493 function Find_Equivalent_Key
494 (R_HT
: Hash_Table_Type
'Class;
495 L_Node
: Node_Type
) return Boolean
497 R_Index
: constant Hash_Type
:=
498 Element_Keys
.Index
(R_HT
, L_Node
.Element
);
499 R_Node
: Count_Type
:= R_HT
.Buckets
(R_Index
);
500 RN
: Nodes_Type
renames R_HT
.Nodes
;
508 if Equivalent_Elements
509 (L_Node
.Element
, RN
(R_Node
).Element
)
514 R_Node
:= HT_Ops
.Next
(R_HT
, R_Node
);
516 end Find_Equivalent_Key
;
518 -- Start of processing for Equivalent_Sets
521 return Is_Equivalent
(Left
, Right
);
524 -------------------------
525 -- Equivalent_Elements --
526 -------------------------
528 function Equivalent_Elements
532 CRight
: Cursor
) return Boolean
535 if not Has_Element
(Left
, CLeft
) then
536 raise Constraint_Error
with
537 "Left cursor of Equivalent_Elements has no element";
540 if not Has_Element
(Right
, CRight
) then
541 raise Constraint_Error
with
542 "Right cursor of Equivalent_Elements has no element";
545 pragma Assert
(Vet
(Left
, CLeft
),
546 "bad Left cursor in Equivalent_Elements");
547 pragma Assert
(Vet
(Right
, CRight
),
548 "bad Right cursor in Equivalent_Elements");
551 LN
: Node_Type
renames Left
.Nodes
(CLeft
.Node
);
552 RN
: Node_Type
renames Right
.Nodes
(CRight
.Node
);
554 return Equivalent_Elements
(LN
.Element
, RN
.Element
);
556 end Equivalent_Elements
;
558 function Equivalent_Elements
561 Right
: Element_Type
) return Boolean
564 if not Has_Element
(Left
, CLeft
) then
565 raise Constraint_Error
with
566 "Left cursor of Equivalent_Elements has no element";
569 pragma Assert
(Vet
(Left
, CLeft
),
570 "Left cursor in Equivalent_Elements is bad");
573 LN
: Node_Type
renames Left
.Nodes
(CLeft
.Node
);
575 return Equivalent_Elements
(LN
.Element
, Right
);
577 end Equivalent_Elements
;
579 function Equivalent_Elements
580 (Left
: Element_Type
;
582 CRight
: Cursor
) return Boolean
585 if not Has_Element
(Right
, CRight
) then
586 raise Constraint_Error
with
587 "Right cursor of Equivalent_Elements has no element";
591 (Vet
(Right
, CRight
),
592 "Right cursor of Equivalent_Elements is bad");
595 RN
: Node_Type
renames Right
.Nodes
(CRight
.Node
);
597 return Equivalent_Elements
(Left
, RN
.Element
);
599 end Equivalent_Elements
;
601 ---------------------
602 -- Equivalent_Keys --
603 ---------------------
605 function Equivalent_Keys
607 Node
: Node_Type
) return Boolean
610 return Equivalent_Elements
(Key
, Node
.Element
);
618 (Container
: in out Set
;
623 Element_Keys
.Delete_Key_Sans_Free
(Container
, Item
, X
);
633 Item
: Element_Type
) return Cursor
635 Node
: constant Count_Type
:= Element_Keys
.Find
(Container
, Item
);
642 return (Node
=> Node
);
649 function First
(Container
: Set
) return Cursor
is
650 Node
: constant Count_Type
:= HT_Ops
.First
(Container
);
657 return (Node
=> Node
);
660 -----------------------
661 -- First_To_Previous --
662 -----------------------
664 function First_To_Previous
666 Current
: Cursor
) return Set
668 Curs
: Cursor
:= Current
;
669 C
: Set
(Container
.Capacity
, Container
.Modulus
) :=
670 Copy
(Container
, Container
.Capacity
);
674 if Curs
= No_Element
then
677 elsif not Has_Element
(Container
, Curs
) then
678 raise Constraint_Error
;
681 while Curs
.Node
/= 0 loop
684 Curs
:= Next
(Container
, (Node
=> Node
));
689 end First_To_Previous
;
700 HT
.Nodes
(X
).Has_Element
:= False;
704 ----------------------
705 -- Generic_Allocate --
706 ----------------------
708 procedure Generic_Allocate
710 Node
: out Count_Type
)
712 procedure Allocate
is new HT_Ops
.Generic_Allocate
(Set_Element
);
715 HT
.Nodes
(Node
).Has_Element
:= True;
716 end Generic_Allocate
;
722 function Has_Element
(Container
: Set
; Position
: Cursor
) return Boolean is
725 or else not Container
.Nodes
(Position
.Node
).Has_Element
737 function Hash_Node
(Node
: Node_Type
) return Hash_Type
is
739 return Hash
(Node
.Element
);
747 (Container
: in out Set
;
748 New_Item
: Element_Type
)
754 Insert
(Container
, New_Item
, Position
, Inserted
);
757 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
766 (Container
: in out Set
;
767 New_Item
: Element_Type
;
768 Position
: out Cursor
;
769 Inserted
: out Boolean)
772 Insert
(Container
, New_Item
, Position
.Node
, Inserted
);
776 (Container
: in out Set
;
777 New_Item
: Element_Type
)
783 Insert
(Container
, New_Item
, Position
, Inserted
);
786 raise Constraint_Error
with
787 "attempt to insert element already in set";
792 (Container
: in out Set
;
793 New_Item
: Element_Type
;
794 Node
: out Count_Type
;
795 Inserted
: out Boolean)
797 procedure Allocate_Set_Element
(Node
: in out Node_Type
);
798 pragma Inline
(Allocate_Set_Element
);
800 function New_Node
return Count_Type
;
801 pragma Inline
(New_Node
);
803 procedure Local_Insert
is
804 new Element_Keys
.Generic_Conditional_Insert
(New_Node
);
806 procedure Allocate
is
807 new Generic_Allocate
(Allocate_Set_Element
);
809 ---------------------------
810 -- Allocate_Set_Element --
811 ---------------------------
813 procedure Allocate_Set_Element
(Node
: in out Node_Type
) is
815 Node
.Element
:= New_Item
;
816 end Allocate_Set_Element
;
822 function New_Node
return Count_Type
is
825 Allocate
(Container
, Result
);
829 -- Start of processing for Insert
832 Local_Insert
(Container
, New_Item
, Node
, Inserted
);
839 procedure Intersection
840 (Target
: in out Set
;
843 Tgt_Node
: Count_Type
;
844 TN
: Nodes_Type
renames Target
.Nodes
;
847 if Target
'Address = Source
'Address then
851 if Source
.Length
= 0 then
856 Tgt_Node
:= HT_Ops
.First
(Target
);
857 while Tgt_Node
/= 0 loop
858 if Find
(Source
, TN
(Tgt_Node
).Element
).Node
/= 0 then
859 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
863 X
: constant Count_Type
:= Tgt_Node
;
865 Tgt_Node
:= HT_Ops
.Next
(Target
, Tgt_Node
);
866 HT_Ops
.Delete_Node_Sans_Free
(Target
, X
);
873 procedure Intersection
878 procedure Process
(L_Node
: Count_Type
);
881 new HT_Ops
.Generic_Iteration
(Process
);
887 procedure Process
(L_Node
: Count_Type
) is
888 E
: Element_Type
renames Left
.Nodes
(L_Node
).Element
;
893 if Find
(Right
, E
).Node
/= 0 then
894 Insert
(Target
, E
, X
, B
);
899 -- Start of processing for Intersection
905 function Intersection
(Left
, Right
: Set
) return Set
is
910 if Left
'Address = Right
'Address then
914 C
:= Count_Type
'Min (Length
(Left
), Length
(Right
)); -- ???
915 H
:= Default_Modulus
(C
);
917 return S
: Set
(C
, H
) do
918 if Length
(Left
) /= 0 and Length
(Right
) /= 0 then
919 Intersection
(Left
, Right
, Target
=> S
);
928 function Is_Empty
(Container
: Set
) return Boolean is
930 return Length
(Container
) = 0;
937 function Is_In
(HT
: Set
; Key
: Node_Type
) return Boolean is
939 return Element_Keys
.Find
(HT
, Key
.Element
) /= 0;
946 function Is_Subset
(Subset
: Set
; Of_Set
: Set
) return Boolean is
947 Subset_Node
: Count_Type
;
948 Subset_Nodes
: Nodes_Type
renames Subset
.Nodes
;
951 if Subset
'Address = Of_Set
'Address then
955 if Length
(Subset
) > Length
(Of_Set
) then
959 Subset_Node
:= First
(Subset
).Node
;
960 while Subset_Node
/= 0 loop
962 N
: Node_Type
renames Subset_Nodes
(Subset_Node
);
963 E
: Element_Type
renames N
.Element
;
966 if Find
(Of_Set
, E
).Node
= 0 then
971 Subset_Node
:= HT_Ops
.Next
(Subset
, Subset_Node
);
981 function Length
(Container
: Set
) return Count_Type
is
983 return Container
.Length
;
992 procedure Move
(Target
: in out Set
; Source
: in out Set
) is
993 NN
: HT_Types
.Nodes_Type
renames Source
.Nodes
;
997 if Target
'Address = Source
'Address then
1001 if Target
.Capacity
< Length
(Source
) then
1002 raise Constraint_Error
with -- ???
1003 "Source length exceeds Target capacity";
1008 if Source
.Length
= 0 then
1012 X
:= HT_Ops
.First
(Source
);
1014 Insert
(Target
, NN
(X
).Element
); -- optimize???
1016 Y
:= HT_Ops
.Next
(Source
, X
);
1018 HT_Ops
.Delete_Node_Sans_Free
(Source
, X
);
1029 function Next
(Node
: Node_Type
) return Count_Type
is
1034 function Next
(Container
: Set
; Position
: Cursor
) return Cursor
is
1036 if Position
.Node
= 0 then
1040 if not Has_Element
(Container
, Position
) then
1041 raise Constraint_Error
1042 with "Position has no element";
1045 pragma Assert
(Vet
(Container
, Position
), "bad cursor in Next");
1047 return (Node
=> HT_Ops
.Next
(Container
, Position
.Node
));
1050 procedure Next
(Container
: Set
; Position
: in out Cursor
) is
1052 Position
:= Next
(Container
, Position
);
1059 function Overlap
(Left
, Right
: Set
) return Boolean is
1060 Left_Node
: Count_Type
;
1061 Left_Nodes
: Nodes_Type
renames Left
.Nodes
;
1064 if Length
(Right
) = 0 or Length
(Left
) = 0 then
1068 if Left
'Address = Right
'Address then
1072 Left_Node
:= First
(Left
).Node
;
1073 while Left_Node
/= 0 loop
1075 N
: Node_Type
renames Left_Nodes
(Left_Node
);
1076 E
: Element_Type
renames N
.Element
;
1078 if Find
(Right
, E
).Node
/= 0 then
1083 Left_Node
:= HT_Ops
.Next
(Left
, Left_Node
);
1094 (Container
: in out Set
;
1095 New_Item
: Element_Type
)
1097 Node
: constant Count_Type
:= Element_Keys
.Find
(Container
, New_Item
);
1101 raise Constraint_Error
with
1102 "attempt to replace element not in set";
1105 Container
.Nodes
(Node
).Element
:= New_Item
;
1108 ---------------------
1109 -- Replace_Element --
1110 ---------------------
1112 procedure Replace_Element
1113 (Container
: in out Set
;
1115 New_Item
: Element_Type
)
1118 if not Has_Element
(Container
, Position
) then
1119 raise Constraint_Error
with
1120 "Position cursor equals No_Element";
1123 pragma Assert
(Vet
(Container
, Position
),
1124 "bad cursor in Replace_Element");
1126 Replace_Element
(Container
, Position
.Node
, New_Item
);
1127 end Replace_Element
;
1129 ----------------------
1130 -- Reserve_Capacity --
1131 ----------------------
1133 procedure Reserve_Capacity
1134 (Container
: in out Set
;
1135 Capacity
: Count_Type
)
1138 if Capacity
> Container
.Capacity
then
1139 raise Constraint_Error
with "requested capacity is too large";
1141 end Reserve_Capacity
;
1147 procedure Set_Element
(Node
: in out Node_Type
; Item
: Element_Type
) is
1149 Node
.Element
:= Item
;
1156 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
) is
1165 function Strict_Equal
(Left
, Right
: Set
) return Boolean is
1166 CuL
: Cursor
:= First
(Left
);
1167 CuR
: Cursor
:= First
(Right
);
1170 if Length
(Left
) /= Length
(Right
) then
1174 while CuL
.Node
/= 0 or CuR
.Node
/= 0 loop
1175 if CuL
.Node
/= CuR
.Node
1176 or else Left
.Nodes
(CuL
.Node
).Element
/=
1177 Right
.Nodes
(CuR
.Node
).Element
1182 CuL
:= Next
(Left
, CuL
);
1183 CuR
:= Next
(Right
, CuR
);
1189 --------------------------
1190 -- Symmetric_Difference --
1191 --------------------------
1193 procedure Symmetric_Difference
1194 (Target
: in out Set
;
1197 procedure Process
(Source_Node
: Count_Type
);
1198 pragma Inline
(Process
);
1200 procedure Iterate
is new HT_Ops
.Generic_Iteration
(Process
);
1206 procedure Process
(Source_Node
: Count_Type
) is
1207 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
1211 if Is_In
(Target
, N
) then
1212 Delete
(Target
, N
.Element
);
1214 Insert
(Target
, N
.Element
, X
, B
);
1219 -- Start of processing for Symmetric_Difference
1222 if Target
'Address = Source
'Address then
1227 if Length
(Target
) = 0 then
1228 Assign
(Target
, Source
);
1233 end Symmetric_Difference
;
1235 function Symmetric_Difference
(Left
, Right
: Set
) return Set
is
1240 if Left
'Address = Right
'Address then
1244 if Length
(Right
) = 0 then
1248 if Length
(Left
) = 0 then
1252 C
:= Length
(Left
) + Length
(Right
);
1253 H
:= Default_Modulus
(C
);
1255 return S
: Set
(C
, H
) do
1256 Difference
(Left
, Right
, S
);
1257 Difference
(Right
, Left
, S
);
1259 end Symmetric_Difference
;
1265 function To_Set
(New_Item
: Element_Type
) return Set
is
1270 return S
: Set
(Capacity
=> 1, Modulus
=> 1) do
1271 Insert
(S
, New_Item
, X
, B
);
1281 (Target
: in out Set
;
1284 procedure Process
(Src_Node
: Count_Type
);
1286 procedure Iterate
is
1287 new HT_Ops
.Generic_Iteration
(Process
);
1293 procedure Process
(Src_Node
: Count_Type
) is
1294 N
: Node_Type
renames Source
.Nodes
(Src_Node
);
1295 E
: Element_Type
renames N
.Element
;
1301 Insert
(Target
, E
, X
, B
);
1304 -- Start of processing for Union
1307 if Target
'Address = Source
'Address then
1314 function Union
(Left
, Right
: Set
) return Set
is
1319 if Left
'Address = Right
'Address then
1323 if Length
(Right
) = 0 then
1327 if Length
(Left
) = 0 then
1331 C
:= Length
(Left
) + Length
(Right
);
1332 H
:= Default_Modulus
(C
);
1333 return S
: Set
(C
, H
) do
1334 Assign
(Target
=> S
, Source
=> Left
);
1335 Union
(Target
=> S
, Source
=> Right
);
1343 function Vet
(Container
: Set
; Position
: Cursor
) return Boolean is
1345 if Position
.Node
= 0 then
1350 S
: Set
renames Container
;
1351 N
: Nodes_Type
renames S
.Nodes
;
1355 if S
.Length
= 0 then
1359 if Position
.Node
> N
'Last then
1363 if N
(Position
.Node
).Next
= Position
.Node
then
1367 X
:= S
.Buckets
(Element_Keys
.Index
(S
, N
(Position
.Node
).Element
));
1369 for J
in 1 .. S
.Length
loop
1370 if X
= Position
.Node
then
1378 if X
= N
(X
).Next
then -- to prevent unnecessary looping
1389 package body Generic_Keys
with SPARK_Mode
=> Off
is
1391 -----------------------
1392 -- Local Subprograms --
1393 -----------------------
1395 function Equivalent_Key_Node
1397 Node
: Node_Type
) return Boolean;
1398 pragma Inline
(Equivalent_Key_Node
);
1400 --------------------------
1401 -- Local Instantiations --
1402 --------------------------
1405 new Hash_Tables
.Generic_Bounded_Keys
1406 (HT_Types
=> HT_Types
,
1408 Set_Next
=> Set_Next
,
1409 Key_Type
=> Key_Type
,
1411 Equivalent_Keys
=> Equivalent_Key_Node
);
1419 Key
: Key_Type
) return Boolean
1422 return Find
(Container
, Key
) /= No_Element
;
1430 (Container
: in out Set
;
1436 Key_Keys
.Delete_Key_Sans_Free
(Container
, Key
, X
);
1439 raise Constraint_Error
with "attempt to delete key not in set";
1442 Free
(Container
, X
);
1451 Key
: Key_Type
) return Element_Type
1453 Node
: constant Count_Type
:= Find
(Container
, Key
).Node
;
1457 raise Constraint_Error
with "key not in map";
1460 return Container
.Nodes
(Node
).Element
;
1463 -------------------------
1464 -- Equivalent_Key_Node --
1465 -------------------------
1467 function Equivalent_Key_Node
1469 Node
: Node_Type
) return Boolean
1472 return Equivalent_Keys
(Key
, Generic_Keys
.Key
(Node
.Element
));
1473 end Equivalent_Key_Node
;
1480 (Container
: in out Set
;
1485 Key_Keys
.Delete_Key_Sans_Free
(Container
, Key
, X
);
1486 Free
(Container
, X
);
1495 Key
: Key_Type
) return Cursor
1497 Node
: constant Count_Type
:= Key_Keys
.Find
(Container
, Key
);
1499 return (if Node
= 0 then No_Element
else (Node
=> Node
));
1506 function Key
(Container
: Set
; Position
: Cursor
) return Key_Type
is
1508 if not Has_Element
(Container
, Position
) then
1509 raise Constraint_Error
with
1510 "Position cursor has no element";
1514 (Vet
(Container
, Position
), "bad cursor in function Key");
1517 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
1519 return Key
(N
.Element
);
1528 (Container
: in out Set
;
1530 New_Item
: Element_Type
)
1532 Node
: constant Count_Type
:= Key_Keys
.Find
(Container
, Key
);
1536 raise Constraint_Error
with
1537 "attempt to replace key not in set";
1540 Replace_Element
(Container
, Node
, New_Item
);
1545 end Ada
.Containers
.Formal_Hashed_Sets
;