]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/ada/libgnat/a-cofuse.ads
c91a1d177513c62533bf7d60020ada9b70d53e39
[thirdparty/gcc.git] / gcc / ada / libgnat / a-cofuse.ads
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.FUNCTIONAL_SETS --
6 -- --
7 -- S p e c --
8 -- --
9 -- Copyright (C) 2016-2019, Free Software Foundation, Inc. --
10 -- --
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. --
14 -- --
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. --
21 -- --
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. --
25 -- --
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 ------------------------------------------------------------------------------
31
32 pragma Ada_2012;
33 private with Ada.Containers.Functional_Base;
34
35 generic
36 type Element_Type (<>) is private;
37
38 with function Equivalent_Elements
39 (Left : Element_Type;
40 Right : Element_Type) return Boolean is "=";
41
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.
46
47 package Ada.Containers.Functional_Sets with SPARK_Mode is
48
49 type Set is private with
50 Default_Initial_Condition => Is_Empty (Set),
51 Iterable => (First => Iter_First,
52 Next => Iter_Next,
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).
61
62 -----------------------
63 -- Basic operations --
64 -----------------------
65
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.
69
70 function Contains (Container : Set; Item : Element_Type) return Boolean with
71 -- Return True if Item is contained in Container
72
73 Global => null,
74 Post =>
75 (if Enable_Handling_Of_Equivalence then
76
77 -- Contains returns the same result on all equivalent elements
78
79 (if (for some E of Container => Equivalent_Elements (E, Item)) then
80 Contains'Result));
81
82 function Length (Container : Set) return Count_Type with
83 Global => null;
84 -- Return the number of elements in Container
85
86 ------------------------
87 -- Property Functions --
88 ------------------------
89
90 function "<=" (Left : Set; Right : Set) return Boolean with
91 -- Set inclusion
92
93 Global => null,
94 Post => "<="'Result = (for all Item of Left => Contains (Right, Item));
95
96 function "=" (Left : Set; Right : Set) return Boolean with
97 -- Extensional equality over sets
98
99 Global => null,
100 Post => "="'Result = (Left <= Right and Right <= Left);
101
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
105
106 Global => null,
107 Post =>
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""");
111
112 function Included_Except
113 (Left : Set;
114 Right : Set;
115 Item : Element_Type) return Boolean
116 -- Return True if Left contains only elements of Right except possibly
117 -- Item.
118
119 with
120 Global => null,
121 Post =>
122 Included_Except'Result =
123 (for all E of Left =>
124 Contains (Right, E) or Equivalent_Elements (E, Item));
125
126 function Includes_Intersection
127 (Container : Set;
128 Left : Set;
129 Right : Set) return Boolean
130 with
131 -- Return True if every element of the intersection of Left and Right is
132 -- in Container.
133
134 Global => null,
135 Post =>
136 Includes_Intersection'Result =
137 (for all Item of Left =>
138 (if Contains (Right, Item) then Contains (Container, Item)));
139
140 function Included_In_Union
141 (Container : Set;
142 Left : Set;
143 Right : Set) return Boolean
144 with
145 -- Return True if every element of Container is the union of Left and Right
146
147 Global => null,
148 Post =>
149 Included_In_Union'Result =
150 (for all Item of Container =>
151 Contains (Left, Item) or Contains (Right, Item));
152
153 function Is_Singleton
154 (Container : Set;
155 New_Item : Element_Type) return Boolean
156 with
157 -- Return True Container only contains New_Item
158
159 Global => null,
160 Post =>
161 Is_Singleton'Result =
162 (for all Item of Container => Equivalent_Elements (Item, New_Item));
163
164 function Not_In_Both
165 (Container : Set;
166 Left : Set;
167 Right : Set) return Boolean
168 -- Return True if there are no elements in Container that are in Left and
169 -- Right.
170
171 with
172 Global => null,
173 Post =>
174 Not_In_Both'Result =
175 (for all Item of Container =>
176 not Contains (Left, Item) or not Contains (Right, Item));
177
178 function No_Overlap (Left : Set; Right : Set) return Boolean with
179 -- Return True if there are no equivalent elements in Left and Right
180
181 Global => null,
182 Post =>
183 No_Overlap'Result =
184 (for all Item of Left => not Contains (Right, Item));
185
186 function Num_Overlaps (Left : Set; Right : Set) return Count_Type with
187 -- Number of elements that are both in Left and Right
188
189 Global => null,
190 Post =>
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);
197
198 ----------------------------
199 -- Construction Functions --
200 ----------------------------
201
202 -- For better efficiency of both proofs and execution, avoid using
203 -- construction functions in annotations and rather use property functions.
204
205 function Add (Container : Set; Item : Element_Type) return Set with
206 -- Return a new set containing all the elements of Container plus E
207
208 Global => null,
209 Pre =>
210 not Contains (Container, Item)
211 and Length (Container) < Count_Type'Last,
212 Post =>
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);
217
218 function Remove (Container : Set; Item : Element_Type) return Set with
219 -- Return a new set containing all the elements of Container except E
220
221 Global => null,
222 Pre => Contains (Container, Item),
223 Post =>
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);
228
229 function Intersection (Left : Set; Right : Set) return Set with
230 -- Returns the intersection of Left and Right
231
232 Global => null,
233 Post =>
234 Intersection'Result <= Left
235 and Intersection'Result <= Right
236 and Includes_Intersection (Intersection'Result, Left, Right);
237
238 function Union (Left : Set; Right : Set) return Set with
239 -- Returns the union of Left and Right
240
241 Global => null,
242 Pre =>
243 Length (Left) - Num_Overlaps (Left, Right) <=
244 Count_Type'Last - Length (Right),
245 Post =>
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);
251
252 ---------------------------
253 -- Iteration Primitives --
254 ---------------------------
255
256 type Private_Key is private;
257
258 function Iter_First (Container : Set) return Private_Key with
259 Global => null;
260
261 function Iter_Has_Element
262 (Container : Set;
263 Key : Private_Key) return Boolean
264 with
265 Global => null;
266
267 function Iter_Next
268 (Container : Set;
269 Key : Private_Key) return Private_Key
270 with
271 Global => null,
272 Pre => Iter_Has_Element (Container, Key);
273
274 function Iter_Element
275 (Container : Set;
276 Key : Private_Key) return Element_Type
277 with
278 Global => null,
279 Pre => Iter_Has_Element (Container, Key);
280 pragma Annotate (GNATprove, Iterable_For_Proof, "Contains", Contains);
281
282 private
283
284 pragma SPARK_Mode (Off);
285
286 subtype Positive_Count_Type is Count_Type range 1 .. Count_Type'Last;
287
288 function "="
289 (Left : Element_Type;
290 Right : Element_Type) return Boolean renames Equivalent_Elements;
291
292 package Containers is new Ada.Containers.Functional_Base
293 (Element_Type => Element_Type,
294 Index_Type => Positive_Count_Type);
295
296 type Set is record
297 Content : Containers.Container;
298 end record;
299
300 type Private_Key is new Count_Type;
301
302 function Iter_First (Container : Set) return Private_Key is (1);
303
304 function Iter_Has_Element
305 (Container : Set;
306 Key : Private_Key) return Boolean
307 is
308 (Count_Type (Key) in 1 .. Containers.Length (Container.Content));
309
310 function Iter_Next
311 (Container : Set;
312 Key : Private_Key) return Private_Key
313 is
314 (if Key = Private_Key'Last then 0 else Key + 1);
315
316 function Iter_Element
317 (Container : Set;
318 Key : Private_Key) return Element_Type
319 is
320 (Containers.Get (Container.Content, Count_Type (Key)));
321
322 end Ada.Containers.Functional_Sets;