1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.FUNCTIONAL_MAPS --
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 Key_Type
(<>) is private;
37 type Element_Type
(<>) is private;
39 with function Equivalent_Keys
41 Right
: Key_Type
) return Boolean is "=";
43 Enable_Handling_Of_Equivalence
: Boolean := True;
44 -- This constant should only be set to False when no particular handling
45 -- of equivalence over keys is needed, that is, Equivalent_Keys defines a
48 package Ada
.Containers
.Functional_Maps
with SPARK_Mode
is
50 type Map
is private with
51 Default_Initial_Condition
=> Is_Empty
(Map
) and Length
(Map
) = 0,
52 Iterable
=> (First
=> Iter_First
,
54 Has_Element
=> Iter_Has_Element
,
55 Element
=> Iter_Element
);
56 -- Maps are empty when default initialized.
57 -- "For in" quantification over maps should not be used.
58 -- "For of" quantification over maps iterates over keys.
59 -- Note that, for proof, "for of" quantification is understood modulo
60 -- equivalence (the range of quantification comprises all the keys that are
61 -- equivalent to any key of the map).
63 -----------------------
64 -- Basic operations --
65 -----------------------
67 -- Maps are axiomatized using Has_Key and Get, encoding respectively the
68 -- presence of a key in a map and an accessor to elements associated with
69 -- its keys. The length of a map is also added to protect Add against
70 -- overflows but it is not actually modeled.
72 function Has_Key
(Container
: Map
; Key
: Key_Type
) return Boolean with
73 -- Return True if Key is present in Container
77 (if Enable_Handling_Of_Equivalence
then
79 -- Has_Key returns the same result on all equivalent keys
81 (if (for some K
of Container
=> Equivalent_Keys
(K
, Key
)) then
84 function Get
(Container
: Map
; Key
: Key_Type
) return Element_Type
with
85 -- Return the element associated with Key in Container
88 Pre
=> Has_Key
(Container
, Key
),
90 (if Enable_Handling_Of_Equivalence
then
92 -- Get returns the same result on all equivalent keys
94 Get
'Result = W_Get
(Container
, Witness
(Container
, Key
))
95 and (for all K
of Container
=>
96 (Equivalent_Keys
(K
, Key
) =
97 (Witness
(Container
, Key
) = Witness
(Container
, K
)))));
99 function Length
(Container
: Map
) return Count_Type
with
101 -- Return the number of mappings in Container
103 ------------------------
104 -- Property Functions --
105 ------------------------
107 function "<=" (Left
: Map
; Right
: Map
) return Boolean with
113 (for all Key of Left =>
114 Has_Key (Right, Key) and then Get (Right, Key) = Get (Left, Key));
116 function "=" (Left : Map; Right : Map) return Boolean with
117 -- Extensional equality over maps
122 ((for all Key
of Left
=>
124 and then Get
(Right
, Key
) = Get
(Left
, Key
))
125 and (for all Key
of Right
=> Has_Key
(Left
, Key
)));
127 pragma Warnings
(Off
, "unused variable ""Key""");
128 function Is_Empty
(Container
: Map
) return Boolean with
129 -- A map is empty if it contains no key
132 Post
=> Is_Empty
'Result = (for all Key
of Container
=> False);
133 pragma Warnings
(On
, "unused variable ""Key""");
135 function Keys_Included
(Left
: Map
; Right
: Map
) return Boolean
136 -- Returns True if every Key of Left is in Right
141 Keys_Included
'Result = (for all Key
of Left
=> Has_Key
(Right
, Key
));
143 function Same_Keys
(Left
: Map
; Right
: Map
) return Boolean
144 -- Returns True if Left and Right have the same keys
150 (Keys_Included
(Left
, Right
)
151 and Keys_Included
(Left
=> Right
, Right
=> Left
));
152 pragma Annotate
(GNATprove
, Inline_For_Proof
, Same_Keys
);
154 function Keys_Included_Except
157 New_Key
: Key_Type
) return Boolean
158 -- Returns True if Left contains only keys of Right and possibly New_Key
163 Keys_Included_Except
'Result =
164 (for all Key
of Left
=>
165 (if not Equivalent_Keys
(Key
, New_Key
) then
166 Has_Key
(Right
, Key
)));
168 function Keys_Included_Except
172 Y
: Key_Type
) return Boolean
173 -- Returns True if Left contains only keys of Right and possibly X and Y
178 Keys_Included_Except
'Result =
179 (for all Key
of Left
=>
180 (if not Equivalent_Keys
(Key
, X
)
181 and not Equivalent_Keys
(Key
, Y
)
183 Has_Key
(Right
, Key
)));
185 function Elements_Equal_Except
188 New_Key
: Key_Type
) return Boolean
189 -- Returns True if all the keys of Left are mapped to the same elements in
190 -- Left and Right except New_Key.
195 Elements_Equal_Except
'Result =
196 (for all Key
of Left
=>
197 (if not Equivalent_Keys
(Key
, New_Key
) then
199 and then Get
(Left
, Key
) = Get
(Right
, Key
)));
201 function Elements_Equal_Except
205 Y
: Key_Type
) return Boolean
206 -- Returns True if all the keys of Left are mapped to the same elements in
207 -- Left and Right except X and Y.
212 Elements_Equal_Except
'Result =
213 (for all Key
of Left
=>
214 (if not Equivalent_Keys
(Key
, X
)
215 and not Equivalent_Keys
(Key
, Y
)
218 and then Get
(Left
, Key
) = Get
(Right
, Key
)));
220 ----------------------------
221 -- Construction Functions --
222 ----------------------------
224 -- For better efficiency of both proofs and execution, avoid using
225 -- construction functions in annotations and rather use property functions.
230 New_Item
: Element_Type
) return Map
231 -- Returns Container augmented with the mapping Key -> New_Item
236 not Has_Key
(Container
, New_Key
)
237 and Length
(Container
) < Count_Type
'Last,
239 Length
(Container
) + 1 = Length
(Add
'Result)
240 and Has_Key
(Add
'Result, New_Key
)
241 and Get
(Add
'Result, New_Key
) = New_Item
242 and Container
<= Add
'Result
243 and Keys_Included_Except
(Add
'Result, Container
, New_Key
);
248 New_Item
: Element_Type
) return Map
249 -- Returns Container, where the element associated with Key has been
250 -- replaced by New_Item.
254 Pre
=> Has_Key
(Container
, Key
),
256 Length
(Container
) = Length
(Set
'Result)
257 and Get
(Set
'Result, Key
) = New_Item
258 and Same_Keys
(Container
, Set
'Result)
259 and Elements_Equal_Except
(Container
, Set
'Result, Key
);
261 ------------------------------
262 -- Handling of Equivalence --
263 ------------------------------
265 -- These functions are used to specify that Get returns the same value on
266 -- equivalent keys. They should not be used directly in user code.
268 function Has_Witness
(Container
: Map
; Witness
: Count_Type
) return Boolean
272 -- Returns True if there is a key with witness Witness in Container
274 function Witness
(Container
: Map
; Key
: Key_Type
) return Count_Type
with
275 -- Returns the witness of Key in Container
279 Pre
=> Has_Key
(Container
, Key
),
280 Post
=> Has_Witness
(Container
, Witness
'Result);
282 function W_Get
(Container
: Map
; Witness
: Count_Type
) return Element_Type
284 -- Returns the element associated with a witness in Container
288 Pre
=> Has_Witness
(Container
, Witness
);
290 ---------------------------
291 -- Iteration Primitives --
292 ---------------------------
294 type Private_Key
is private;
296 function Iter_First
(Container
: Map
) return Private_Key
with
299 function Iter_Has_Element
301 Key
: Private_Key
) return Boolean
305 function Iter_Next
(Container
: Map
; Key
: Private_Key
) return Private_Key
308 Pre
=> Iter_Has_Element
(Container
, Key
);
310 function Iter_Element
(Container
: Map
; Key
: Private_Key
) return Key_Type
313 Pre
=> Iter_Has_Element
(Container
, Key
);
314 pragma Annotate
(GNATprove
, Iterable_For_Proof
, "Contains", Has_Key
);
318 pragma SPARK_Mode
(Off
);
322 Right
: Key_Type
) return Boolean renames Equivalent_Keys
;
324 subtype Positive_Count_Type
is Count_Type
range 1 .. Count_Type
'Last;
326 package Element_Containers
is new Ada
.Containers
.Functional_Base
327 (Element_Type
=> Element_Type
,
328 Index_Type
=> Positive_Count_Type
);
330 package Key_Containers
is new Ada
.Containers
.Functional_Base
331 (Element_Type
=> Key_Type
,
332 Index_Type
=> Positive_Count_Type
);
335 Keys
: Key_Containers
.Container
;
336 Elements
: Element_Containers
.Container
;
339 type Private_Key
is new Count_Type
;
341 function Iter_First
(Container
: Map
) return Private_Key
is (1);
343 function Iter_Has_Element
345 Key
: Private_Key
) return Boolean
347 (Count_Type
(Key
) in 1 .. Key_Containers
.Length
(Container
.Keys
));
351 Key
: Private_Key
) return Private_Key
353 (if Key
= Private_Key
'Last then 0 else Key
+ 1);
355 function Iter_Element
357 Key
: Private_Key
) return Key_Type
359 (Key_Containers
.Get
(Container
.Keys
, Count_Type
(Key
)));
361 end Ada
.Containers
.Functional_Maps
;