1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.FUNCTIONAL_SETS --
9 -- Copyright (C) 2016-2017, Free Software Foundation, Inc. --
11 -- This specification is derived from the Ada Reference Manual for use with --
12 -- GNAT. The copyright notice above, and the license provisions that follow --
13 -- apply solely to the contents of the part following the private keyword. --
15 -- GNAT is free software; you can redistribute it and/or modify it under --
16 -- terms of the GNU General Public License as published by the Free Soft- --
17 -- ware Foundation; either version 3, or (at your option) any later ver- --
18 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
19 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
20 -- or FITNESS FOR A PARTICULAR PURPOSE. --
22 -- As a special exception under Section 7 of GPL version 3, you are granted --
23 -- additional permissions described in the GCC Runtime Library Exception, --
24 -- version 3.1, as published by the Free Software Foundation. --
26 -- You should have received a copy of the GNU General Public License and --
27 -- a copy of the GCC Runtime Library Exception along with this program; --
28 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
29 -- <http://www.gnu.org/licenses/>. --
30 ------------------------------------------------------------------------------
33 private with Ada
.Containers
.Functional_Base
;
36 type Element_Type
(<>) is private;
38 with function Equivalent_Elements
40 Right
: Element_Type
) return Boolean is "=";
42 Enable_Handling_Of_Equivalence
: Boolean := True;
43 -- This constant should only be set to False when no particular handling
44 -- of equivalence over elements is needed, that is, Equivalent_Elements
45 -- defines an element uniquely.
47 package Ada
.Containers
.Functional_Sets
with SPARK_Mode
is
49 type Set
is private with
50 Default_Initial_Condition
=> Is_Empty
(Set
),
51 Iterable
=> (First
=> Iter_First
,
53 Has_Element
=> Iter_Has_Element
,
54 Element
=> Iter_Element
);
55 -- Sets are empty when default initialized.
56 -- "For in" quantification over sets should not be used.
57 -- "For of" quantification over sets iterates over elements.
58 -- Note that, for proof, "for of" quantification is understood modulo
59 -- equivalence (the range of quantification comprises all the elements that
60 -- are equivalent to any element of the set).
62 -----------------------
63 -- Basic operations --
64 -----------------------
66 -- Sets are axiomatized using Contains, which encodes whether an element is
67 -- contained in a set. The length of a set is also added to protect Add
68 -- against overflows but it is not actually modeled.
70 function Contains
(Container
: Set
; Item
: Element_Type
) return Boolean with
71 -- Return True if Item is contained in Container
75 (if Enable_Handling_Of_Equivalence
then
77 -- Contains returns the same result on all equivalent elements
79 (if (for some E
of Container
=> Equivalent_Elements
(E
, Item
)) then
82 function Length
(Container
: Set
) return Count_Type
with
84 -- Return the number of elements in Container
86 ------------------------
87 -- Property Functions --
88 ------------------------
90 function "<=" (Left
: Set
; Right
: Set
) return Boolean with
94 Post
=> "<="'Result = (for all Item of Left => Contains (Right, Item));
96 function "=" (Left : Set; Right : Set) return Boolean with
97 -- Extensional equality over sets
100 Post => "="'Result
= (Left
<= Right
and Right
<= Left
);
102 pragma Warnings
(Off
, "unused variable ""Item""");
103 function Is_Empty
(Container
: Set
) return Boolean with
104 -- A set is empty if it contains no element
108 Is_Empty
'Result = (for all Item
of Container
=> False)
109 and Is_Empty
'Result = (Length
(Container
) = 0);
110 pragma Warnings
(On
, "unused variable ""Item""");
112 function Included_Except
115 Item
: Element_Type
) return Boolean
116 -- Return True if Left contains only elements of Right except possibly
122 Included_Except
'Result =
123 (for all E
of Left
=>
124 Contains
(Right
, E
) or Equivalent_Elements
(E
, Item
));
126 function Includes_Intersection
129 Right
: Set
) return Boolean
131 -- Return True if every element of the intersection of Left and Right is
136 Includes_Intersection
'Result =
137 (for all Item
of Left
=>
138 (if Contains
(Right
, Item
) then Contains
(Container
, Item
)));
140 function Included_In_Union
143 Right
: Set
) return Boolean
145 -- Return True if every element of Container is the union of Left and Right
149 Included_In_Union
'Result =
150 (for all Item
of Container
=>
151 Contains
(Left
, Item
) or Contains
(Right
, Item
));
153 function Is_Singleton
155 New_Item
: Element_Type
) return Boolean
157 -- Return True Container only contains New_Item
161 Is_Singleton
'Result =
162 (for all Item
of Container
=> Equivalent_Elements
(Item
, New_Item
));
167 Right
: Set
) return Boolean
168 -- Return True if there are no elements in Container that are in Left and
175 (for all Item
of Container
=>
176 not Contains
(Left
, Item
) or not Contains
(Right
, Item
));
178 function No_Overlap
(Left
: Set
; Right
: Set
) return Boolean with
179 -- Return True if there are no equivalent elements in Left and Right
184 (for all Item
of Left
=> not Contains
(Right
, Item
));
186 function Num_Overlaps
(Left
: Set
; Right
: Set
) return Count_Type
with
187 -- Number of elements that are both in Left and Right
191 Num_Overlaps
'Result = Length
(Intersection
(Left
, Right
))
192 and (if Left
<= Right
then Num_Overlaps
'Result = Length
(Left
)
193 else Num_Overlaps
'Result < Length
(Left
))
194 and (if Right
<= Left
then Num_Overlaps
'Result = Length
(Right
)
195 else Num_Overlaps
'Result < Length
(Right
))
196 and (Num_Overlaps
'Result = 0) = No_Overlap
(Left
, Right
);
198 ----------------------------
199 -- Construction Functions --
200 ----------------------------
202 -- For better efficiency of both proofs and execution, avoid using
203 -- construction functions in annotations and rather use property functions.
205 function Add
(Container
: Set
; Item
: Element_Type
) return Set
with
206 -- Return a new set containing all the elements of Container plus E
210 not Contains
(Container
, Item
)
211 and Length
(Container
) < Count_Type
'Last,
213 Length
(Add
'Result) = Length
(Container
) + 1
214 and Contains
(Add
'Result, Item
)
215 and Container
<= Add
'Result
216 and Included_Except
(Add
'Result, Container
, Item
);
218 function Remove
(Container
: Set
; Item
: Element_Type
) return Set
with
219 -- Return a new set containing all the elements of Container except E
222 Pre
=> Contains
(Container
, Item
),
224 Length
(Remove
'Result) = Length
(Container
) - 1
225 and not Contains
(Remove
'Result, Item
)
226 and Remove
'Result <= Container
227 and Included_Except
(Container
, Remove
'Result, Item
);
229 function Intersection
(Left
: Set
; Right
: Set
) return Set
with
230 -- Returns the intersection of Left and Right
234 Intersection
'Result <= Left
235 and Intersection
'Result <= Right
236 and Includes_Intersection
(Intersection
'Result, Left
, Right
);
238 function Union
(Left
: Set
; Right
: Set
) return Set
with
239 -- Returns the union of Left and Right
243 Length
(Left
) - Num_Overlaps
(Left
, Right
) <=
244 Count_Type
'Last - Length
(Right
),
246 Length
(Union
'Result) =
247 Length
(Left
) - Num_Overlaps
(Left
, Right
) + Length
(Right
)
248 and Left
<= Union
'Result
249 and Right
<= Union
'Result
250 and Included_In_Union
(Union
'Result, Left
, Right
);
252 ---------------------------
253 -- Iteration Primitives --
254 ---------------------------
256 type Private_Key
is private;
258 function Iter_First
(Container
: Set
) return Private_Key
with
261 function Iter_Has_Element
263 Key
: Private_Key
) return Boolean
269 Key
: Private_Key
) return Private_Key
272 Pre
=> Iter_Has_Element
(Container
, Key
);
274 function Iter_Element
276 Key
: Private_Key
) return Element_Type
279 Pre
=> Iter_Has_Element
(Container
, Key
);
280 pragma Annotate
(GNATprove
, Iterable_For_Proof
, "Contains", Contains
);
284 pragma SPARK_Mode
(Off
);
286 subtype Positive_Count_Type
is Count_Type
range 1 .. Count_Type
'Last;
289 (Left
: Element_Type
;
290 Right
: Element_Type
) return Boolean renames Equivalent_Elements
;
292 package Containers
is new Ada
.Containers
.Functional_Base
293 (Element_Type
=> Element_Type
,
294 Index_Type
=> Positive_Count_Type
);
297 Content
: Containers
.Container
;
300 type Private_Key
is new Count_Type
;
302 function Iter_First
(Container
: Set
) return Private_Key
is (1);
304 function Iter_Has_Element
306 Key
: Private_Key
) return Boolean
308 (Count_Type
(Key
) in 1 .. Containers
.Length
(Container
.Content
));
312 Key
: Private_Key
) return Private_Key
314 (if Key
= Private_Key
'Last then 0 else Key
+ 1);
316 function Iter_Element
318 Key
: Private_Key
) return Element_Type
320 (Containers
.Get
(Container
.Content
, Count_Type
(Key
)));
322 end Ada
.Containers
.Functional_Sets
;