]>
Commit | Line | Data |
---|---|---|
bd65a2d7 AC |
1 | ------------------------------------------------------------------------------ |
2 | -- -- | |
3 | -- GNAT LIBRARY COMPONENTS -- | |
4 | -- -- | |
5 | -- ADA.CONTAINERS.FORMAL_DOUBLY_LINKED_LISTS -- | |
6 | -- -- | |
7 | -- S p e c -- | |
8 | -- -- | |
e77e2429 | 9 | -- Copyright (C) 2004-2017, Free Software Foundation, Inc. -- |
bd65a2d7 AC |
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 | ||
e77e2429 AC |
32 | with Ada.Containers.Functional_Vectors; |
33 | with Ada.Containers.Functional_Maps; | |
bd65a2d7 AC |
34 | |
35 | generic | |
36 | type Element_Type is private; | |
5fde9688 | 37 | package Ada.Containers.Formal_Doubly_Linked_Lists with |
5fde9688 AC |
38 | SPARK_Mode |
39 | is | |
6031f544 | 40 | pragma Annotate (CodePeer, Skip_Analysis); |
bd65a2d7 | 41 | |
edbd98c4 AC |
42 | type List (Capacity : Count_Type) is private with |
43 | Iterable => (First => First, | |
44 | Next => Next, | |
45 | Has_Element => Has_Element, | |
9ceeaf9d | 46 | Element => Element), |
203876fc | 47 | Default_Initial_Condition => Is_Empty (List); |
9686dbc7 | 48 | pragma Preelaborable_Initialization (List); |
bd65a2d7 | 49 | |
e77e2429 AC |
50 | type Cursor is record |
51 | Node : Count_Type := 0; | |
52 | end record; | |
53 | ||
54 | No_Element : constant Cursor := Cursor'(Node => 0); | |
bd65a2d7 AC |
55 | |
56 | Empty_List : constant List; | |
57 | ||
e77e2429 AC |
58 | function Length (Container : List) return Count_Type with |
59 | Global => null, | |
60 | Post => Length'Result <= Container.Capacity; | |
61 | ||
62 | pragma Unevaluated_Use_Of_Old (Allow); | |
63 | ||
64 | package Formal_Model with Ghost is | |
65 | subtype Positive_Count_Type is Count_Type range 1 .. Count_Type'Last; | |
66 | ||
67 | package M is new Ada.Containers.Functional_Vectors | |
68 | (Index_Type => Positive_Count_Type, | |
69 | Element_Type => Element_Type); | |
70 | function "=" (Left, Right : M.Sequence) return Boolean renames M."="; | |
71 | function "<" (Left, Right : M.Sequence) return Boolean renames M."<"; | |
72 | function "<=" (Left, Right : M.Sequence) return Boolean renames M."<="; | |
73 | ||
e77e2429 | 74 | function M_Elements_Shuffle |
6cbfce7e AC |
75 | (Left : M.Sequence; |
76 | Right : M.Sequence; | |
e77e2429 AC |
77 | Fst : Positive_Count_Type; |
78 | Lst : Count_Type; | |
79 | Offset : Count_Type'Base) | |
80 | return Boolean | |
6cbfce7e AC |
81 | -- The slice from Fst to Lst in Left contains the same elements than the |
82 | -- same slide shifted by Offset in Right | |
e77e2429 AC |
83 | with |
84 | Global => null, | |
85 | Pre => | |
6cbfce7e AC |
86 | Lst <= M.Length (Left) |
87 | and Offset in 1 - Fst .. M.Length (Right) - Lst, | |
e77e2429 AC |
88 | Post => |
89 | M_Elements_Shuffle'Result = | |
90 | (for all J in Fst + Offset .. Lst + Offset => | |
91 | (for some I in Fst .. Lst => | |
6cbfce7e | 92 | Element (Left, I) = Element (Right, J))); |
e77e2429 AC |
93 | pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Shuffle); |
94 | ||
6cbfce7e AC |
95 | function M_Elements_Reversed (Left, Right : M.Sequence) return Boolean |
96 | -- Right is Left in reverse order | |
e77e2429 AC |
97 | with |
98 | Global => null, | |
99 | Post => | |
100 | M_Elements_Reversed'Result = | |
6cbfce7e AC |
101 | (M.Length (Left) = M.Length (Right) |
102 | and | |
103 | (for all I in 1 .. M.Length (Left) => | |
104 | Element (Left, I) | |
105 | = Element (Right, M.Length (Left) - I + 1)) | |
106 | and | |
107 | (for all I in 1 .. M.Length (Left) => | |
108 | Element (Right, I) | |
109 | = Element (Left, M.Length (Left) - I + 1))); | |
e77e2429 AC |
110 | pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Reversed); |
111 | ||
e77e2429 | 112 | function M_Elements_Swapped |
6cbfce7e AC |
113 | (Left : M.Sequence; |
114 | Right : M.Sequence; | |
115 | X, Y : Positive_Count_Type) | |
e77e2429 | 116 | return Boolean |
6cbfce7e | 117 | -- Elements stored at X and Y are reversed in Left and Right |
e77e2429 AC |
118 | with |
119 | Global => null, | |
6cbfce7e | 120 | Pre => X <= M.Length (Left) and Y <= M.Length (Left), |
e77e2429 AC |
121 | Post => |
122 | M_Elements_Swapped'Result = | |
6cbfce7e AC |
123 | (M.Length (Left) = M.Length (Right) |
124 | and Element (Left, X) = Element (Right, Y) | |
125 | and Element (Left, Y) = Element (Right, X) | |
126 | and M.Equal_Except (Left, Right, X, Y)); | |
e77e2429 AC |
127 | pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Swapped); |
128 | ||
129 | package P is new Ada.Containers.Functional_Maps | |
130 | (Key_Type => Cursor, | |
131 | Element_Type => Positive_Count_Type, | |
132 | Equivalent_Keys => "="); | |
133 | function "=" (Left, Right : P.Map) return Boolean renames P."="; | |
134 | function "<=" (Left, Right : P.Map) return Boolean renames P."<="; | |
135 | ||
136 | function P_Positions_Shifted | |
137 | (Small : P.Map; | |
138 | Big : P.Map; | |
139 | Cut : Positive_Count_Type; | |
140 | Count : Count_Type := 1) return Boolean | |
141 | with | |
142 | Global => null, | |
143 | Post => | |
144 | P_Positions_Shifted'Result = | |
145 | ||
146 | -- Big contains all cursors of Small | |
6cbfce7e | 147 | (P.Keys_Included (Small, Big) |
e77e2429 AC |
148 | |
149 | -- Cursors located before Cut are not moved, cursors located after | |
150 | -- are shifted by Count. | |
151 | and | |
152 | (for all I of Small => | |
153 | (if P.Get (Small, I) < Cut | |
154 | then P.Get (Big, I) = P.Get (Small, I) | |
155 | else P.Get (Big, I) - Count = P.Get (Small, I))) | |
156 | ||
157 | -- New cursors of Big (if any) are between Cut and Cut - 1 + Count | |
158 | and | |
159 | (for all I of Big => | |
6cbfce7e | 160 | P.Has_Key (Small, I) |
e77e2429 AC |
161 | or P.Get (Big, I) - Count in Cut - Count .. Cut - 1)); |
162 | ||
163 | function P_Positions_Swapped | |
6cbfce7e AC |
164 | (Left : P.Map; |
165 | Right : P.Map; | |
166 | X, Y : Cursor) return Boolean | |
167 | -- Left and Right contain the same cursors, but the positions of X and Y | |
e77e2429 AC |
168 | -- are reversed. |
169 | with | |
170 | Ghost, | |
171 | Global => null, | |
172 | Post => | |
173 | P_Positions_Swapped'Result = | |
6cbfce7e AC |
174 | (P.Same_Keys (Left, Right) |
175 | and P.Elements_Equal_Except (Left, Right, X, Y) | |
176 | and P.Has_Key (Left, X) and P.Has_Key (Left, Y) | |
177 | and P.Get (Left, X) = P.Get (Right, Y) | |
178 | and P.Get (Left, Y) = P.Get (Right, X)); | |
e77e2429 AC |
179 | |
180 | function P_Positions_Truncated | |
181 | (Small : P.Map; | |
182 | Big : P.Map; | |
183 | Cut : Positive_Count_Type; | |
184 | Count : Count_Type := 1) return Boolean | |
185 | with | |
186 | Ghost, | |
187 | Global => null, | |
188 | Post => | |
189 | P_Positions_Truncated'Result = | |
190 | ||
6cbfce7e AC |
191 | -- Big contains all cursors of Small at the same position |
192 | (Small <= Big | |
e77e2429 AC |
193 | |
194 | -- New cursors of Big (if any) are between Cut and Cut - 1 + Count | |
195 | and | |
196 | (for all I of Big => | |
6cbfce7e | 197 | P.Has_Key (Small, I) |
e77e2429 AC |
198 | or P.Get (Big, I) - Count in Cut - Count .. Cut - 1)); |
199 | ||
200 | function Mapping_Preserved | |
6cbfce7e AC |
201 | (M_Left : M.Sequence; |
202 | M_Right : M.Sequence; | |
203 | P_Left : P.Map; | |
204 | P_Right : P.Map) return Boolean | |
e77e2429 AC |
205 | with |
206 | Ghost, | |
207 | Global => null, | |
208 | Post => | |
209 | (if Mapping_Preserved'Result then | |
210 | ||
6cbfce7e AC |
211 | -- Left and Right contain the same cursors |
212 | P.Same_Keys (P_Left, P_Right) | |
e77e2429 | 213 | |
6cbfce7e AC |
214 | -- Mappings from cursors to elements induced by M_Left, P_Left |
215 | -- and M_Right, P_Right are the same. | |
216 | and (for all C of P_Left => | |
217 | M.Get (M_Left, P.Get (P_Left, C)) | |
218 | = M.Get (M_Right, P.Get (P_Right, C)))); | |
e77e2429 AC |
219 | |
220 | function Model (Container : List) return M.Sequence with | |
221 | -- The highlevel model of a list is a sequence of elements. Cursors are | |
222 | -- not represented in this model. | |
223 | ||
224 | Ghost, | |
225 | Global => null, | |
226 | Post => M.Length (Model'Result) = Length (Container); | |
227 | pragma Annotate (GNATprove, Iterable_For_Proof, "Model", Model); | |
228 | ||
229 | function Positions (Container : List) return P.Map with | |
230 | -- The Positions map is used to model cursors. It only contains valid | |
231 | -- cursors and map them to their position in the container. | |
232 | ||
233 | Ghost, | |
234 | Global => null, | |
6cbfce7e | 235 | Post => not P.Has_Key (Positions'Result, No_Element) |
e77e2429 AC |
236 | -- Positions of cursors are smaller than the container's length. |
237 | and then | |
238 | (for all I of Positions'Result => | |
239 | P.Get (Positions'Result, I) in 1 .. Length (Container) | |
240 | ||
241 | -- No two cursors have the same position. Note that we do not | |
242 | -- state that there is a cursor in the map for each position, | |
243 | -- as it is rarely needed. | |
244 | and then | |
245 | (for all J of Positions'Result => | |
246 | (if P.Get (Positions'Result, I) = P.Get (Positions'Result, J) | |
247 | then I = J))); | |
248 | ||
249 | procedure Lift_Abstraction_Level (Container : List) with | |
250 | -- Lift_Abstraction_Level is a ghost procedure that does nothing but | |
251 | -- assume that we can access to the same elements by iterating over | |
252 | -- positions or cursors. | |
253 | -- This information is not generally useful except when switching from | |
254 | -- a lowlevel, cursor aware view of a container, to a highlevel | |
255 | -- position based view. | |
256 | ||
257 | Ghost, | |
258 | Global => null, | |
259 | Post => | |
260 | (for all Elt of Model (Container) => | |
261 | (for some I of Positions (Container) => | |
262 | M.Get (Model (Container), P.Get (Positions (Container), I)) | |
263 | = Elt)); | |
264 | ||
265 | function Element (S : M.Sequence; I : Count_Type) return Element_Type | |
266 | renames M.Get; | |
267 | -- To improve readability of contracts, we rename the function used to | |
268 | -- access an element in the model to Element. | |
269 | end Formal_Model; | |
270 | use Formal_Model; | |
bd65a2d7 | 271 | |
47fb6ca8 | 272 | function "=" (Left, Right : List) return Boolean with |
e77e2429 AC |
273 | Global => null, |
274 | Post => "="'Result = (Model (Left) = Model (Right)); | |
bd65a2d7 | 275 | |
47fb6ca8 | 276 | function Is_Empty (Container : List) return Boolean with |
e77e2429 AC |
277 | Global => null, |
278 | Post => Is_Empty'Result = (Length (Container) = 0); | |
bd65a2d7 | 279 | |
47fb6ca8 | 280 | procedure Clear (Container : in out List) with |
e77e2429 AC |
281 | Global => null, |
282 | Post => Length (Container) = 0; | |
bd65a2d7 | 283 | |
16788d44 | 284 | procedure Assign (Target : in out List; Source : List) with |
47fb6ca8 | 285 | Global => null, |
e77e2429 AC |
286 | Pre => Target.Capacity >= Length (Source), |
287 | Post => Model (Target) = Model (Source); | |
bd65a2d7 | 288 | |
b1d12996 | 289 | function Copy (Source : List; Capacity : Count_Type := 0) return List with |
47fb6ca8 | 290 | Global => null, |
e77e2429 AC |
291 | Pre => Capacity = 0 or else Capacity >= Source.Capacity, |
292 | Post => Model (Copy'Result) = Model (Source) | |
293 | and Positions (Copy'Result) = Positions (Source) | |
294 | and (if Capacity = 0 then Copy'Result.Capacity = Source.Capacity | |
295 | else Copy'Result.Capacity = Capacity); | |
bd65a2d7 | 296 | |
16788d44 RD |
297 | function Element |
298 | (Container : List; | |
299 | Position : Cursor) return Element_Type | |
300 | with | |
47fb6ca8 | 301 | Global => null, |
e77e2429 AC |
302 | Pre => Has_Element (Container, Position), |
303 | Post => | |
304 | Element'Result = | |
305 | Element (Model (Container), | |
306 | P.Get (Positions (Container), Position)); | |
307 | pragma Annotate (GNATprove, Inline_For_Proof, Element); | |
bd65a2d7 AC |
308 | |
309 | procedure Replace_Element | |
310 | (Container : in out List; | |
311 | Position : Cursor; | |
67a90476 | 312 | New_Item : Element_Type) |
16788d44 | 313 | with |
47fb6ca8 | 314 | Global => null, |
e77e2429 AC |
315 | Pre => Has_Element (Container, Position), |
316 | Post => Length (Container) = Length (Container)'Old | |
317 | ||
318 | -- Cursors are preserved. | |
319 | and Positions (Container)'Old = Positions (Container) | |
320 | ||
6cbfce7e AC |
321 | -- The element at the position of Position in Container is New_Item |
322 | and Element (Model (Container), P.Get (Positions (Container), Position)) | |
323 | = New_Item | |
324 | ||
325 | -- Other elements are preserved | |
326 | and M.Equal_Except (Model (Container)'Old, | |
327 | Model (Container), | |
328 | P.Get (Positions (Container), Position)); | |
bd65a2d7 | 329 | |
16788d44 | 330 | procedure Move (Target : in out List; Source : in out List) with |
47fb6ca8 | 331 | Global => null, |
e77e2429 AC |
332 | Pre => Target.Capacity >= Length (Source), |
333 | Post => Model (Target) = Model (Source'Old) | |
334 | and Length (Source) = 0; | |
335 | ||
336 | procedure Insert | |
337 | (Container : in out List; | |
338 | Before : Cursor; | |
339 | New_Item : Element_Type) | |
340 | with | |
341 | Global => null, | |
342 | Pre => | |
343 | Length (Container) < Container.Capacity | |
344 | and then (Has_Element (Container, Before) | |
345 | or else Before = No_Element), | |
346 | Post => Length (Container) = Length (Container)'Old + 1, | |
347 | Contract_Cases => | |
348 | (Before = No_Element => | |
349 | ||
350 | -- Positions contains a new mapping from the last cursor of | |
351 | -- Container to its length. | |
6cbfce7e AC |
352 | P.Get (Positions (Container), Last (Container)) = Length (Container) |
353 | ||
354 | -- Other cursors come from Container'Old | |
355 | and P.Keys_Included_Except | |
356 | (Left => Positions (Container), | |
357 | Right => Positions (Container)'Old, | |
358 | New_Key => Last (Container)) | |
359 | ||
360 | -- Cursors of Container'Old keep the same position | |
361 | and Positions (Container)'Old <= Positions (Container) | |
e77e2429 AC |
362 | |
363 | -- Model contains a new element New_Item at the end | |
6cbfce7e AC |
364 | and Element (Model (Container), Length (Container)) = New_Item |
365 | ||
366 | -- Elements of Container'Old are preserved | |
367 | and Model (Container)'Old <= Model (Container), | |
e77e2429 AC |
368 | others => |
369 | ||
370 | -- The elements of Container located before Before are preserved. | |
6cbfce7e AC |
371 | M.Range_Equal |
372 | (Left => Model (Container)'Old, | |
373 | Right => Model (Container), | |
374 | Fst => 1, | |
375 | Lst => P.Get (Positions (Container)'Old, Before) - 1) | |
e77e2429 AC |
376 | |
377 | -- Other elements are shifted by 1. | |
6cbfce7e AC |
378 | and M.Range_Shifted |
379 | (Left => Model (Container)'Old, | |
380 | Right => Model (Container), | |
e77e2429 AC |
381 | Fst => P.Get (Positions (Container)'Old, Before), |
382 | Lst => Length (Container)'Old, | |
383 | Offset => 1) | |
384 | ||
385 | -- New_Item is stored at the previous position of Before in | |
386 | -- Container | |
387 | and Element | |
388 | (Model (Container), P.Get (Positions (Container)'Old, Before)) | |
389 | = New_Item | |
390 | ||
391 | -- A new cursor has been inserted at position Before in Container | |
392 | and P_Positions_Shifted | |
393 | (Positions (Container)'Old, | |
394 | Positions (Container), | |
395 | Cut => P.Get (Positions (Container)'Old, Before))); | |
bd65a2d7 AC |
396 | |
397 | procedure Insert | |
398 | (Container : in out List; | |
399 | Before : Cursor; | |
400 | New_Item : Element_Type; | |
e77e2429 | 401 | Count : Count_Type) |
16788d44 | 402 | with |
47fb6ca8 | 403 | Global => null, |
e77e2429 AC |
404 | Pre => |
405 | Length (Container) <= Container.Capacity - Count | |
406 | and then (Has_Element (Container, Before) | |
407 | or else Before = No_Element), | |
408 | Post => Length (Container) = Length (Container)'Old + Count, | |
409 | Contract_Cases => | |
410 | (Before = No_Element => | |
411 | ||
412 | -- The elements of Container are preserved | |
6cbfce7e AC |
413 | M.Range_Equal |
414 | (Left => Model (Container)'Old, | |
415 | Right => Model (Container), | |
416 | Fst => 1, | |
417 | Lst => Length (Container)'Old) | |
e77e2429 AC |
418 | |
419 | -- Container contains Count times New_Item at the end | |
6cbfce7e AC |
420 | and M.Constant_Range |
421 | (Container => Model (Container), | |
422 | Fst => Length (Container)'Old + 1, | |
423 | Lst => Length (Container), | |
424 | Item => New_Item) | |
e77e2429 AC |
425 | |
426 | -- A Count cursors have been inserted at the end of Container | |
427 | and P_Positions_Truncated | |
428 | (Positions (Container)'Old, | |
429 | Positions (Container), | |
430 | Cut => Length (Container)'Old + 1, | |
431 | Count => Count), | |
432 | others => | |
433 | ||
434 | -- The elements of Container located before Before are preserved | |
6cbfce7e AC |
435 | M.Range_Equal |
436 | (Left => Model (Container)'Old, | |
437 | Right => Model (Container), | |
438 | Fst => 1, | |
439 | Lst => P.Get (Positions (Container)'Old, Before) - 1) | |
e77e2429 AC |
440 | |
441 | -- Other elements are shifted by Count. | |
6cbfce7e AC |
442 | and M.Range_Shifted |
443 | (Left => Model (Container)'Old, | |
444 | Right => Model (Container), | |
e77e2429 AC |
445 | Fst => P.Get (Positions (Container)'Old, Before), |
446 | Lst => Length (Container)'Old, | |
447 | Offset => Count) | |
448 | ||
449 | -- Container contains Count times New_Item after position Before | |
6cbfce7e AC |
450 | and M.Constant_Range |
451 | (Container => Model (Container), | |
452 | Fst => P.Get (Positions (Container)'Old, Before), | |
453 | Lst => | |
454 | P.Get (Positions (Container)'Old, Before) - 1 + Count, | |
455 | Item => New_Item) | |
e77e2429 AC |
456 | |
457 | -- Count cursors have been inserted at position Before in Container | |
458 | and P_Positions_Shifted | |
459 | (Positions (Container)'Old, | |
460 | Positions (Container), | |
461 | Cut => P.Get (Positions (Container)'Old, Before), | |
462 | Count => Count)); | |
bd65a2d7 AC |
463 | |
464 | procedure Insert | |
465 | (Container : in out List; | |
466 | Before : Cursor; | |
467 | New_Item : Element_Type; | |
e77e2429 | 468 | Position : out Cursor) |
16788d44 | 469 | with |
47fb6ca8 | 470 | Global => null, |
e77e2429 AC |
471 | Pre => |
472 | Length (Container) < Container.Capacity | |
473 | and then (Has_Element (Container, Before) | |
474 | or else Before = No_Element), | |
475 | Post => | |
476 | Length (Container) = Length (Container)'Old + 1 | |
477 | ||
478 | -- Positions is valid in Container and it is located either before | |
479 | -- Before if it is valid in Container or at the end if it is | |
480 | -- No_Element. | |
6cbfce7e | 481 | and P.Has_Key (Positions (Container), Position) |
e77e2429 AC |
482 | and (if Before = No_Element |
483 | then P.Get (Positions (Container), Position) | |
484 | = Length (Container) | |
485 | else P.Get (Positions (Container), Position) | |
486 | = P.Get (Positions (Container)'Old, Before)) | |
487 | ||
488 | -- The elements of Container located before Position are preserved. | |
6cbfce7e AC |
489 | and M.Range_Equal |
490 | (Left => Model (Container)'Old, | |
491 | Right => Model (Container), | |
492 | Fst => 1, | |
493 | Lst => P.Get (Positions (Container), Position) - 1) | |
e77e2429 AC |
494 | |
495 | -- Other elements are shifted by 1. | |
6cbfce7e AC |
496 | and M.Range_Shifted |
497 | (Left => Model (Container)'Old, | |
498 | Right => Model (Container), | |
e77e2429 AC |
499 | Fst => P.Get (Positions (Container), Position), |
500 | Lst => Length (Container)'Old, | |
501 | Offset => 1) | |
502 | ||
503 | -- New_Item is stored at Position in Container | |
504 | and Element | |
505 | (Model (Container), P.Get (Positions (Container), Position)) | |
506 | = New_Item | |
507 | ||
508 | -- A new cursor has been inserted at position Position in Container | |
509 | and P_Positions_Shifted | |
510 | (Positions (Container)'Old, | |
511 | Positions (Container), | |
512 | Cut => P.Get (Positions (Container), Position)); | |
bd65a2d7 AC |
513 | |
514 | procedure Insert | |
515 | (Container : in out List; | |
516 | Before : Cursor; | |
e77e2429 | 517 | New_Item : Element_Type; |
bd65a2d7 | 518 | Position : out Cursor; |
e77e2429 AC |
519 | Count : Count_Type) |
520 | with | |
521 | Global => null, | |
522 | Pre => | |
523 | Length (Container) <= Container.Capacity - Count | |
524 | and then (Has_Element (Container, Before) | |
525 | or else Before = No_Element), | |
526 | Post => Length (Container) = Length (Container)'Old + Count, | |
527 | Contract_Cases => | |
528 | (Count = 0 => Position = Before | |
529 | and Model (Container) = Model (Container)'Old | |
530 | and Positions (Container) = Positions (Container)'Old, | |
531 | ||
532 | others => | |
533 | -- Positions is valid in Container and it is located either before | |
534 | -- Before if it is valid in Container or at the end if it is | |
535 | -- No_Element. | |
6cbfce7e | 536 | P.Has_Key (Positions (Container), Position) |
e77e2429 AC |
537 | and (if Before = No_Element |
538 | then P.Get (Positions (Container), Position) | |
539 | = Length (Container)'Old + 1 | |
540 | else P.Get (Positions (Container), Position) | |
541 | = P.Get (Positions (Container)'Old, Before)) | |
542 | ||
543 | -- The elements of Container located before Position are preserved. | |
6cbfce7e AC |
544 | and M.Range_Equal |
545 | (Left => Model (Container)'Old, | |
546 | Right => Model (Container), | |
547 | Fst => 1, | |
548 | Lst => P.Get (Positions (Container), Position) - 1) | |
e77e2429 AC |
549 | |
550 | -- Other elements are shifted by Count. | |
6cbfce7e AC |
551 | and M.Range_Shifted |
552 | (Left => Model (Container)'Old, | |
553 | Right => Model (Container), | |
e77e2429 AC |
554 | Fst => P.Get (Positions (Container), Position), |
555 | Lst => Length (Container)'Old, | |
556 | Offset => Count) | |
557 | ||
558 | -- Container contains Count times New_Item after position Position | |
6cbfce7e AC |
559 | and M.Constant_Range |
560 | (Container => Model (Container), | |
561 | Fst => P.Get (Positions (Container), Position), | |
562 | Lst => P.Get (Positions (Container), Position) - 1 + Count, | |
563 | Item => New_Item) | |
e77e2429 AC |
564 | |
565 | -- Count cursor have been inserted at Position in Container | |
566 | and P_Positions_Shifted | |
567 | (Positions (Container)'Old, | |
568 | Positions (Container), | |
569 | Cut => P.Get (Positions (Container), Position), | |
570 | Count => Count)); | |
571 | ||
572 | procedure Prepend | |
573 | (Container : in out List; | |
574 | New_Item : Element_Type) | |
16788d44 | 575 | with |
47fb6ca8 | 576 | Global => null, |
e77e2429 AC |
577 | Pre => Length (Container) < Container.Capacity, |
578 | Post => | |
579 | Length (Container) = Length (Container)'Old + 1 | |
580 | ||
581 | -- Elements are shifted by 1 | |
6cbfce7e AC |
582 | and M.Range_Shifted |
583 | (Left => Model (Container)'Old, | |
584 | Right => Model (Container), | |
e77e2429 AC |
585 | Fst => 1, |
586 | Lst => Length (Container)'Old, | |
587 | Offset => 1) | |
588 | ||
589 | -- New_Item is the first element of Container | |
590 | and Element (Model (Container), 1) = New_Item | |
591 | ||
592 | -- A new cursor has been inserted at the beginning of Container | |
593 | and P_Positions_Shifted | |
594 | (Positions (Container)'Old, | |
595 | Positions (Container), | |
596 | Cut => 1); | |
bd65a2d7 AC |
597 | |
598 | procedure Prepend | |
599 | (Container : in out List; | |
600 | New_Item : Element_Type; | |
e77e2429 AC |
601 | Count : Count_Type) |
602 | with | |
603 | Global => null, | |
604 | Pre => Length (Container) <= Container.Capacity - Count, | |
605 | Post => | |
606 | Length (Container) = Length (Container)'Old + Count | |
607 | ||
608 | -- Elements are shifted by Count. | |
6cbfce7e AC |
609 | and M.Range_Shifted |
610 | (Left => Model (Container)'Old, | |
611 | Right => Model (Container), | |
e77e2429 AC |
612 | Fst => 1, |
613 | Lst => Length (Container)'Old, | |
614 | Offset => Count) | |
615 | ||
616 | -- Container starts with Count times New_Item | |
6cbfce7e AC |
617 | and M.Constant_Range |
618 | (Container => Model (Container), | |
619 | Fst => 1, | |
620 | Lst => Count, | |
621 | Item => New_Item) | |
e77e2429 AC |
622 | |
623 | -- Count cursors have been inserted at the beginning of Container | |
624 | and P_Positions_Shifted | |
625 | (Positions (Container)'Old, | |
626 | Positions (Container), | |
627 | Cut => 1, | |
628 | Count => Count); | |
629 | ||
630 | procedure Append | |
631 | (Container : in out List; | |
632 | New_Item : Element_Type) | |
16788d44 | 633 | with |
47fb6ca8 | 634 | Global => null, |
e77e2429 AC |
635 | Pre => Length (Container) < Container.Capacity, |
636 | Post => Length (Container) = Length (Container)'Old + 1 | |
637 | ||
638 | -- Positions contains a new mapping from the last cursor of | |
639 | -- Container to its length. | |
6cbfce7e AC |
640 | and P.Get (Positions (Container), Last (Container)) |
641 | = Length (Container) | |
642 | ||
643 | -- Other cursors come from Container'Old | |
644 | and P.Keys_Included_Except | |
645 | (Left => Positions (Container), | |
646 | Right => Positions (Container)'Old, | |
647 | New_Key => Last (Container)) | |
648 | ||
649 | -- Cursors of Container'Old keep the same position | |
650 | and Positions (Container)'Old <= Positions (Container) | |
e77e2429 AC |
651 | |
652 | -- Model contains a new element New_Item at the end | |
6cbfce7e AC |
653 | and Element (Model (Container), Length (Container)) = New_Item |
654 | ||
655 | -- Elements of Container'Old are preserved | |
656 | and Model (Container)'Old <= Model (Container); | |
bd65a2d7 AC |
657 | |
658 | procedure Append | |
659 | (Container : in out List; | |
660 | New_Item : Element_Type; | |
e77e2429 AC |
661 | Count : Count_Type) |
662 | with | |
663 | Global => null, | |
664 | Pre => Length (Container) <= Container.Capacity - Count, | |
665 | Post => | |
666 | Length (Container) = Length (Container)'Old + Count | |
667 | ||
668 | -- The elements of Container are preserved | |
669 | and Model (Container)'Old <= Model (Container) | |
670 | ||
671 | -- Container contains Count times New_Item at the end | |
6cbfce7e AC |
672 | and M.Constant_Range |
673 | (Container => Model (Container), | |
674 | Fst => Length (Container)'Old + 1, | |
675 | Lst => Length (Container), | |
676 | Item => New_Item) | |
e77e2429 AC |
677 | |
678 | -- Count cursors have been inserted at the end of Container | |
679 | and P_Positions_Truncated | |
680 | (Positions (Container)'Old, | |
681 | Positions (Container), | |
682 | Cut => Length (Container)'Old + 1, | |
683 | Count => Count); | |
684 | ||
685 | procedure Delete | |
686 | (Container : in out List; | |
687 | Position : in out Cursor) | |
16788d44 | 688 | with |
47fb6ca8 | 689 | Global => null, |
e77e2429 AC |
690 | Pre => Has_Element (Container, Position), |
691 | Post => | |
692 | Length (Container) = Length (Container)'Old - 1 | |
693 | ||
694 | -- Position is set to No_Element | |
695 | and Position = No_Element | |
696 | ||
697 | -- The elements of Container located before Position are preserved. | |
6cbfce7e AC |
698 | and M.Range_Equal |
699 | (Left => Model (Container)'Old, | |
700 | Right => Model (Container), | |
701 | Fst => 1, | |
702 | Lst => P.Get (Positions (Container)'Old, Position'Old) - 1) | |
e77e2429 AC |
703 | |
704 | -- The elements located after Position are shifted by 1 | |
6cbfce7e AC |
705 | and M.Range_Shifted |
706 | (Left => Model (Container)'Old, | |
707 | Right => Model (Container), | |
e77e2429 AC |
708 | Fst => P.Get (Positions (Container)'Old, Position'Old) + 1, |
709 | Lst => Length (Container)'Old, | |
710 | Offset => -1) | |
711 | ||
712 | -- Position has been removed from Container | |
713 | and P_Positions_Shifted | |
714 | (Positions (Container), | |
715 | Positions (Container)'Old, | |
716 | Cut => P.Get (Positions (Container)'Old, Position'Old)); | |
bd65a2d7 AC |
717 | |
718 | procedure Delete | |
719 | (Container : in out List; | |
720 | Position : in out Cursor; | |
e77e2429 AC |
721 | Count : Count_Type) |
722 | with | |
723 | Global => null, | |
724 | Pre => Has_Element (Container, Position), | |
725 | Post => | |
726 | Length (Container) in Length (Container)'Old - Count | |
727 | .. Length (Container)'Old | |
728 | ||
729 | -- Position is set to No_Element | |
730 | and Position = No_Element | |
731 | ||
732 | -- The elements of Container located before Position are preserved. | |
6cbfce7e AC |
733 | and M.Range_Equal |
734 | (Left => Model (Container)'Old, | |
735 | Right => Model (Container), | |
736 | Fst => 1, | |
737 | Lst => P.Get (Positions (Container)'Old, Position'Old) - 1), | |
e77e2429 AC |
738 | Contract_Cases => |
739 | ||
740 | -- All the elements after Position have been erased | |
741 | (Length (Container) - Count < P.Get (Positions (Container), Position) | |
742 | => | |
743 | ||
744 | Length (Container) = | |
745 | P.Get (Positions (Container)'Old, Position'Old) - 1 | |
746 | ||
747 | -- At most Count cursors have been removed at the end of Container | |
748 | and P_Positions_Truncated | |
749 | (Positions (Container), | |
750 | Positions (Container)'Old, | |
751 | Cut => P.Get (Positions (Container)'Old, Position'Old), | |
752 | Count => Count), | |
753 | others => | |
754 | Length (Container) = Length (Container)'Old - Count | |
755 | ||
756 | -- Other elements are shifted by Count | |
6cbfce7e AC |
757 | and M.Range_Shifted |
758 | (Left => Model (Container)'Old, | |
759 | Right => Model (Container), | |
e77e2429 AC |
760 | Fst => |
761 | P.Get (Positions (Container)'Old, Position'Old) + Count, | |
762 | Lst => Length (Container)'Old, | |
763 | Offset => -Count) | |
764 | ||
765 | -- Count cursors have been removed from Container at Position | |
766 | and P_Positions_Shifted | |
767 | (Positions (Container), | |
768 | Positions (Container)'Old, | |
769 | Cut => P.Get (Positions (Container)'Old, Position'Old), | |
770 | Count => Count)); | |
771 | ||
772 | procedure Delete_First (Container : in out List) | |
16788d44 | 773 | with |
47fb6ca8 | 774 | Global => null, |
e77e2429 AC |
775 | Pre => not Is_Empty (Container), |
776 | Post => | |
777 | Length (Container) = Length (Container)'Old - 1 | |
778 | ||
779 | -- The elements of Container are shifted by 1 | |
6cbfce7e AC |
780 | and M.Range_Shifted |
781 | (Left => Model (Container)'Old, | |
782 | Right => Model (Container), | |
e77e2429 AC |
783 | Fst => 2, |
784 | Lst => Length (Container)'Old, | |
785 | Offset => -1) | |
786 | ||
787 | -- The first cursor of Container has been removed | |
788 | and P_Positions_Shifted | |
789 | (Positions (Container), | |
790 | Positions (Container)'Old, | |
791 | Cut => 1); | |
bd65a2d7 AC |
792 | |
793 | procedure Delete_First | |
794 | (Container : in out List; | |
e77e2429 AC |
795 | Count : Count_Type) |
796 | with | |
797 | Global => null, | |
798 | Contract_Cases => | |
799 | ||
800 | -- All the elements of Container have been erased | |
801 | (Length (Container) <= Count => Length (Container) = 0, | |
802 | others => | |
803 | Length (Container) = Length (Container)'Old - Count | |
804 | ||
805 | -- Elements of Container are shifted by Count | |
6cbfce7e AC |
806 | and M.Range_Shifted |
807 | (Left => Model (Container)'Old, | |
808 | Right => Model (Container), | |
e77e2429 AC |
809 | Fst => Count + 1, |
810 | Lst => Length (Container)'Old, | |
811 | Offset => -Count) | |
812 | ||
813 | -- The first Count cursors have been removed from Container | |
814 | and P_Positions_Shifted | |
815 | (Positions (Container), | |
816 | Positions (Container)'Old, | |
817 | Cut => 1, | |
818 | Count => Count)); | |
819 | ||
820 | procedure Delete_Last (Container : in out List) | |
47fb6ca8 | 821 | with |
e77e2429 AC |
822 | Global => null, |
823 | Pre => not Is_Empty (Container), | |
824 | Post => | |
825 | Length (Container) = Length (Container)'Old - 1 | |
826 | ||
827 | -- The elements of Container are preserved. | |
828 | and Model (Container) <= Model (Container)'Old | |
829 | ||
830 | -- The last cursor of Container has been removed | |
6cbfce7e AC |
831 | and not P.Has_Key (Positions (Container), Last (Container)'Old) |
832 | ||
833 | -- Other cursors are still valid | |
834 | and P.Keys_Included_Except | |
835 | (Left => Positions (Container)'Old, | |
836 | Right => Positions (Container)'Old, | |
837 | New_Key => Last (Container)'Old) | |
838 | ||
839 | -- The positions of other cursors are preserved | |
840 | and Positions (Container) <= Positions (Container)'Old; | |
bd65a2d7 AC |
841 | |
842 | procedure Delete_Last | |
843 | (Container : in out List; | |
e77e2429 | 844 | Count : Count_Type) |
47fb6ca8 | 845 | with |
e77e2429 AC |
846 | Global => null, |
847 | Contract_Cases => | |
848 | ||
849 | -- All the elements of Container have been erased | |
850 | (Length (Container) <= Count => Length (Container) = 0, | |
851 | others => | |
852 | ||
853 | Length (Container) = Length (Container)'Old - Count | |
854 | ||
855 | -- The elements of Container are preserved. | |
856 | and Model (Container) <= Model (Container)'Old | |
857 | ||
858 | -- At most Count cursors have been removed at the end of Container | |
859 | and P_Positions_Truncated | |
860 | (Positions (Container), | |
861 | Positions (Container)'Old, | |
862 | Cut => Length (Container) + 1, | |
863 | Count => Count)); | |
bd65a2d7 | 864 | |
47fb6ca8 | 865 | procedure Reverse_Elements (Container : in out List) with |
e77e2429 AC |
866 | Global => null, |
867 | Post => M_Elements_Reversed (Model (Container'Old), Model (Container)); | |
bd65a2d7 AC |
868 | |
869 | procedure Swap | |
870 | (Container : in out List; | |
67a90476 | 871 | I, J : Cursor) |
16788d44 | 872 | with |
47fb6ca8 | 873 | Global => null, |
e77e2429 AC |
874 | Pre => Has_Element (Container, I) and then Has_Element (Container, J), |
875 | Post => | |
876 | M_Elements_Swapped | |
877 | (Model (Container)'Old, Model (Container), | |
878 | X => P.Get (Positions (Container)'Old, I), | |
879 | Y => P.Get (Positions (Container)'Old, J)) | |
880 | and Positions (Container) = Positions (Container)'Old; | |
bd65a2d7 AC |
881 | |
882 | procedure Swap_Links | |
883 | (Container : in out List; | |
67a90476 | 884 | I, J : Cursor) |
16788d44 | 885 | with |
47fb6ca8 | 886 | Global => null, |
e77e2429 AC |
887 | Pre => Has_Element (Container, I) and then Has_Element (Container, J), |
888 | Post => | |
889 | M_Elements_Swapped | |
890 | (Model (Container'Old), Model (Container), | |
891 | X => P.Get (Positions (Container)'Old, I), | |
892 | Y => P.Get (Positions (Container)'Old, J)) | |
893 | and P_Positions_Swapped | |
894 | (Positions (Container)'Old, Positions (Container), I, J); | |
bd65a2d7 AC |
895 | |
896 | procedure Splice | |
897 | (Target : in out List; | |
898 | Before : Cursor; | |
67a90476 | 899 | Source : in out List) |
e77e2429 | 900 | -- Target and Source should not be aliased |
16788d44 | 901 | with |
e77e2429 AC |
902 | Global => null, |
903 | Pre => | |
904 | Length (Source) <= Target.Capacity - Length (Target) | |
905 | and then (Has_Element (Target, Before) | |
906 | or else Before = No_Element), | |
907 | Post => | |
908 | Length (Source) = 0 | |
909 | and Length (Target) = Length (Target)'Old + Length (Source)'Old, | |
910 | Contract_Cases => | |
911 | (Before = No_Element => | |
912 | ||
913 | -- The elements of Target are preserved | |
6cbfce7e AC |
914 | M.Range_Equal |
915 | (Left => Model (Target)'Old, | |
916 | Right => Model (Target), | |
917 | Fst => 1, | |
918 | Lst => Length (Target)'Old) | |
e77e2429 AC |
919 | |
920 | -- The elements of Source are appended to target, the order is not | |
921 | -- specified. | |
922 | and M_Elements_Shuffle | |
6cbfce7e AC |
923 | (Left => Model (Source)'Old, |
924 | Right => Model (Target), | |
e77e2429 AC |
925 | Fst => 1, |
926 | Lst => Length (Source)'Old, | |
927 | Offset => Length (Target)'Old) | |
928 | ||
929 | -- Cursors have been inserted at the end of Target | |
930 | and P_Positions_Truncated | |
931 | (Positions (Target)'Old, | |
932 | Positions (Target), | |
933 | Cut => Length (Target)'Old + 1, | |
934 | Count => Length (Source)'Old), | |
935 | others => | |
936 | ||
937 | -- The elements of Target located before Before are preserved | |
6cbfce7e AC |
938 | M.Range_Equal |
939 | (Left => Model (Target)'Old, | |
940 | Right => Model (Target), | |
941 | Fst => 1, | |
942 | Lst => P.Get (Positions (Target)'Old, Before) - 1) | |
e77e2429 AC |
943 | |
944 | -- The elements of Source are inserted before Before, the order is | |
945 | -- not specified. | |
946 | and M_Elements_Shuffle | |
6cbfce7e AC |
947 | (Left => Model (Source)'Old, |
948 | Right => Model (Target), | |
e77e2429 AC |
949 | Fst => 1, |
950 | Lst => Length (Source)'Old, | |
951 | Offset => P.Get (Positions (Target)'Old, Before) - 1) | |
952 | ||
953 | -- Other elements are shifted by the length of Source | |
6cbfce7e AC |
954 | and M.Range_Shifted |
955 | (Left => Model (Target)'Old, | |
956 | Right => Model (Target), | |
e77e2429 AC |
957 | Fst => P.Get (Positions (Target)'Old, Before), |
958 | Lst => Length (Target)'Old, | |
959 | Offset => Length (Source)'Old) | |
960 | ||
961 | -- Cursors have been inserted at position Before in Target | |
962 | and P_Positions_Shifted | |
963 | (Positions (Target)'Old, | |
964 | Positions (Target), | |
965 | Cut => P.Get (Positions (Target)'Old, Before), | |
966 | Count => Length (Source)'Old)); | |
bd65a2d7 AC |
967 | |
968 | procedure Splice | |
969 | (Target : in out List; | |
970 | Before : Cursor; | |
971 | Source : in out List; | |
67a90476 | 972 | Position : in out Cursor) |
e77e2429 | 973 | -- Target and Source should not be aliased |
16788d44 | 974 | with |
47fb6ca8 | 975 | Global => null, |
e77e2429 AC |
976 | Pre => |
977 | (Has_Element (Target, Before) | |
978 | or else Before = No_Element) | |
979 | and then Has_Element (Source, Position) | |
980 | and then Length (Target) < Target.Capacity, | |
981 | Post => | |
982 | Length (Target) = Length (Target)'Old + 1 | |
983 | and Length (Source) = Length (Source)'Old - 1 | |
984 | ||
985 | -- The elements of Source located before Position are preserved. | |
6cbfce7e AC |
986 | and M.Range_Equal |
987 | (Left => Model (Source)'Old, | |
988 | Right => Model (Source), | |
989 | Fst => 1, | |
990 | Lst => P.Get (Positions (Source)'Old, Position'Old) - 1) | |
e77e2429 AC |
991 | |
992 | -- The elements located after Position are shifted by 1 | |
6cbfce7e AC |
993 | and M.Range_Shifted |
994 | (Left => Model (Source)'Old, | |
995 | Right => Model (Source), | |
e77e2429 AC |
996 | Fst => P.Get (Positions (Source)'Old, Position'Old) + 1, |
997 | Lst => Length (Source)'Old, | |
998 | Offset => -1) | |
999 | ||
1000 | -- Position has been removed from Source | |
1001 | and P_Positions_Shifted | |
1002 | (Positions (Source), | |
1003 | Positions (Source)'Old, | |
1004 | Cut => P.Get (Positions (Source)'Old, Position'Old)) | |
1005 | ||
1006 | -- Positions is valid in Target and it is located either before | |
1007 | -- Before if it is valid in Target or at the end if it is | |
1008 | -- No_Element. | |
6cbfce7e | 1009 | and P.Has_Key (Positions (Target), Position) |
e77e2429 AC |
1010 | and (if Before = No_Element |
1011 | then P.Get (Positions (Target), Position) | |
1012 | = Length (Target) | |
1013 | else P.Get (Positions (Target), Position) | |
1014 | = P.Get (Positions (Target)'Old, Before)) | |
1015 | ||
1016 | -- The elements of Target located before Position are preserved. | |
6cbfce7e AC |
1017 | and M.Range_Equal |
1018 | (Left => Model (Target)'Old, | |
1019 | Right => Model (Target), | |
1020 | Fst => 1, | |
1021 | Lst => P.Get (Positions (Target), Position) - 1) | |
e77e2429 AC |
1022 | |
1023 | -- Other elements are shifted by 1. | |
6cbfce7e AC |
1024 | and M.Range_Shifted |
1025 | (Left => Model (Target)'Old, | |
1026 | Right => Model (Target), | |
e77e2429 AC |
1027 | Fst => P.Get (Positions (Target), Position), |
1028 | Lst => Length (Target)'Old, | |
1029 | Offset => 1) | |
1030 | ||
1031 | -- The element located at Position in Source is moved to Target | |
1032 | and Element (Model (Target), P.Get (Positions (Target), Position)) | |
1033 | = Element (Model (Source)'Old, | |
1034 | P.Get (Positions (Source)'Old, Position'Old)) | |
1035 | ||
1036 | -- A new cursor has been inserted at position Position in Target | |
1037 | and P_Positions_Shifted | |
1038 | (Positions (Target)'Old, | |
1039 | Positions (Target), | |
1040 | Cut => P.Get (Positions (Target), Position)); | |
bd65a2d7 AC |
1041 | |
1042 | procedure Splice | |
1043 | (Container : in out List; | |
1044 | Before : Cursor; | |
67a90476 | 1045 | Position : Cursor) |
16788d44 | 1046 | with |
e77e2429 AC |
1047 | Global => null, |
1048 | Pre => | |
1049 | (Has_Element (Container, Before) or else Before = No_Element) | |
1050 | and then Has_Element (Container, Position), | |
1051 | Post => Length (Container) = Length (Container)'Old, | |
1052 | Contract_Cases => | |
1053 | (Before = Position => | |
1054 | Model (Container) = Model (Container)'Old | |
1055 | and Positions (Container) = Positions (Container)'Old, | |
1056 | ||
1057 | Before = No_Element => | |
1058 | ||
1059 | -- The elements located before Position are preserved | |
6cbfce7e AC |
1060 | M.Range_Equal |
1061 | (Left => Model (Container)'Old, | |
1062 | Right => Model (Container), | |
1063 | Fst => 1, | |
1064 | Lst => P.Get (Positions (Container)'Old, Position) - 1) | |
e77e2429 AC |
1065 | |
1066 | -- The elements located after Position are shifted by 1 | |
6cbfce7e AC |
1067 | and M.Range_Shifted |
1068 | (Left => Model (Container)'Old, | |
1069 | Right => Model (Container), | |
e77e2429 AC |
1070 | Fst => P.Get (Positions (Container)'Old, Position) + 1, |
1071 | Lst => Length (Container)'Old, | |
1072 | Offset => -1) | |
1073 | ||
1074 | -- The last element of Container is the one that was previously | |
1075 | -- at Position. | |
1076 | and Element (Model (Container), Length (Container)) | |
1077 | = Element (Model (Container)'Old, | |
1078 | P.Get (Positions (Container)'Old, Position)) | |
1079 | ||
1080 | -- Cursors from Container continue designating the same elements | |
1081 | and Mapping_Preserved | |
6cbfce7e AC |
1082 | (M_Left => Model (Container)'Old, |
1083 | M_Right => Model (Container), | |
1084 | P_Left => Positions (Container)'Old, | |
1085 | P_Right => Positions (Container)), | |
e77e2429 AC |
1086 | |
1087 | others => | |
1088 | ||
1089 | -- The elements located before Position and Before are preserved | |
6cbfce7e AC |
1090 | M.Range_Equal |
1091 | (Left => Model (Container)'Old, | |
1092 | Right => Model (Container), | |
1093 | Fst => 1, | |
1094 | Lst => Count_Type'Min | |
1095 | (P.Get (Positions (Container)'Old, Position) - 1, | |
1096 | P.Get (Positions (Container)'Old, Before) - 1)) | |
e77e2429 AC |
1097 | |
1098 | -- The elements located after Position and Before are preserved | |
6cbfce7e AC |
1099 | and M.Range_Equal |
1100 | (Left => Model (Container)'Old, | |
1101 | Right => Model (Container), | |
1102 | Fst => Count_Type'Max | |
1103 | (P.Get (Positions (Container)'Old, Position) + 1, | |
1104 | P.Get (Positions (Container)'Old, Before) + 1), | |
1105 | Lst => Length (Container)) | |
e77e2429 AC |
1106 | |
1107 | -- The elements located after Before and before Position are shifted | |
1108 | -- by 1 to the right. | |
6cbfce7e AC |
1109 | and M.Range_Shifted |
1110 | (Left => Model (Container)'Old, | |
1111 | Right => Model (Container), | |
e77e2429 AC |
1112 | Fst => P.Get (Positions (Container)'Old, Before) + 1, |
1113 | Lst => P.Get (Positions (Container)'Old, Position) - 1, | |
1114 | Offset => 1) | |
1115 | ||
1116 | -- The elements located after Position and before Before are shifted | |
1117 | -- by 1 to the left. | |
6cbfce7e AC |
1118 | and M.Range_Shifted |
1119 | (Left => Model (Container)'Old, | |
1120 | Right => Model (Container), | |
e77e2429 AC |
1121 | Fst => P.Get (Positions (Container)'Old, Position) + 1, |
1122 | Lst => P.Get (Positions (Container)'Old, Before) - 1, | |
1123 | Offset => -1) | |
1124 | ||
1125 | -- The element previously at Position is now before Before | |
1126 | and Element (Model (Container), | |
1127 | P.Get (Positions (Container)'Old, Before)) | |
1128 | = Element (Model (Container)'Old, | |
1129 | P.Get (Positions (Container)'Old, Position)) | |
1130 | ||
1131 | -- Cursors from Container continue designating the same elements | |
1132 | and Mapping_Preserved | |
6cbfce7e AC |
1133 | (M_Left => Model (Container)'Old, |
1134 | M_Right => Model (Container), | |
1135 | P_Left => Positions (Container)'Old, | |
1136 | P_Right => Positions (Container))); | |
bd65a2d7 | 1137 | |
47fb6ca8 | 1138 | function First (Container : List) return Cursor with |
e77e2429 AC |
1139 | Global => null, |
1140 | Contract_Cases => | |
1141 | (Length (Container) = 0 => First'Result = No_Element, | |
1142 | others => Has_Element (Container, First'Result) | |
1143 | and P.Get (Positions (Container), First'Result) = 1); | |
bd65a2d7 | 1144 | |
16788d44 | 1145 | function First_Element (Container : List) return Element_Type with |
47fb6ca8 | 1146 | Global => null, |
e77e2429 AC |
1147 | Pre => not Is_Empty (Container), |
1148 | Post => First_Element'Result = M.Get (Model (Container), 1); | |
bd65a2d7 | 1149 | |
47fb6ca8 | 1150 | function Last (Container : List) return Cursor with |
e77e2429 AC |
1151 | Global => null, |
1152 | Contract_Cases => | |
1153 | (Length (Container) = 0 => Last'Result = No_Element, | |
1154 | others => Has_Element (Container, Last'Result) | |
1155 | and P.Get (Positions (Container), Last'Result) = Length (Container)); | |
bd65a2d7 | 1156 | |
16788d44 | 1157 | function Last_Element (Container : List) return Element_Type with |
47fb6ca8 | 1158 | Global => null, |
e77e2429 AC |
1159 | Pre => not Is_Empty (Container), |
1160 | Post => Last_Element'Result | |
1161 | = M.Get (Model (Container), Length (Container)); | |
bd65a2d7 | 1162 | |
16788d44 | 1163 | function Next (Container : List; Position : Cursor) return Cursor with |
e77e2429 AC |
1164 | Global => null, |
1165 | Pre => Has_Element (Container, Position) | |
1166 | or else Position = No_Element, | |
1167 | Contract_Cases => | |
1168 | (Position = No_Element | |
1169 | or else P.Get (Positions (Container), Position) = Length (Container) => | |
1170 | Next'Result = No_Element, | |
1171 | others => Has_Element (Container, Next'Result) | |
1172 | and then P.Get (Positions (Container), Next'Result) = | |
1173 | P.Get (Positions (Container), Position) + 1); | |
bd65a2d7 | 1174 | |
16788d44 | 1175 | procedure Next (Container : List; Position : in out Cursor) with |
e77e2429 AC |
1176 | Global => null, |
1177 | Pre => Has_Element (Container, Position) | |
1178 | or else Position = No_Element, | |
1179 | Contract_Cases => | |
1180 | (Position = No_Element | |
1181 | or else P.Get (Positions (Container), Position) = Length (Container) => | |
1182 | Position = No_Element, | |
1183 | others => Has_Element (Container, Position) | |
1184 | and then P.Get (Positions (Container), Position) = | |
1185 | P.Get (Positions (Container), Position'Old) + 1); | |
bd65a2d7 | 1186 | |
16788d44 | 1187 | function Previous (Container : List; Position : Cursor) return Cursor with |
e77e2429 AC |
1188 | Global => null, |
1189 | Pre => Has_Element (Container, Position) | |
1190 | or else Position = No_Element, | |
1191 | Contract_Cases => | |
1192 | (Position = No_Element | |
1193 | or else P.Get (Positions (Container), Position) = 1 => | |
1194 | Previous'Result = No_Element, | |
1195 | others => | |
1196 | Has_Element (Container, Previous'Result) | |
1197 | and then P.Get (Positions (Container), Previous'Result) = | |
1198 | P.Get (Positions (Container), Position) - 1); | |
bd65a2d7 | 1199 | |
16788d44 | 1200 | procedure Previous (Container : List; Position : in out Cursor) with |
e77e2429 AC |
1201 | Global => null, |
1202 | Pre => Has_Element (Container, Position) | |
1203 | or else Position = No_Element, | |
1204 | Contract_Cases => | |
1205 | (Position = No_Element | |
1206 | or else P.Get (Positions (Container), Position) = 1 => | |
1207 | Position = No_Element, | |
1208 | others => | |
1209 | Has_Element (Container, Position) | |
1210 | and then P.Get (Positions (Container), Position) = | |
1211 | P.Get (Positions (Container), Position'Old) - 1); | |
bd65a2d7 AC |
1212 | |
1213 | function Find | |
1214 | (Container : List; | |
1215 | Item : Element_Type; | |
67a90476 | 1216 | Position : Cursor := No_Element) return Cursor |
16788d44 | 1217 | with |
e77e2429 AC |
1218 | Global => null, |
1219 | Pre => | |
1220 | Has_Element (Container, Position) or else Position = No_Element, | |
1221 | Contract_Cases => | |
1222 | ||
1223 | -- If Item is not is not contained in Container after Position, Find | |
1224 | -- returns No_Element. | |
6cbfce7e AC |
1225 | (not M.Contains |
1226 | (Container => Model (Container), | |
1227 | Fst => (if Position = No_Element then 1 | |
1228 | else P.Get (Positions (Container), Position)), | |
1229 | Lst => Length (Container), | |
1230 | Item => Item) | |
e77e2429 AC |
1231 | => |
1232 | Find'Result = No_Element, | |
1233 | ||
1234 | -- Otherwise, Find returns a valid cusror in Container | |
1235 | others => | |
6cbfce7e | 1236 | P.Has_Key (Positions (Container), Find'Result) |
e77e2429 AC |
1237 | |
1238 | -- The element designated by the result of Find is Item | |
1239 | and Element (Model (Container), | |
1240 | P.Get (Positions (Container), Find'Result)) = Item | |
1241 | ||
1242 | -- The result of Find is located after Position | |
1243 | and (if Position /= No_Element | |
1244 | then P.Get (Positions (Container), Find'Result) | |
1245 | >= P.Get (Positions (Container), Position)) | |
1246 | ||
1247 | -- It is the first occurence of Item in this slice | |
6cbfce7e AC |
1248 | and not M.Contains |
1249 | (Container => Model (Container), | |
1250 | Fst => (if Position = No_Element then 1 | |
1251 | else P.Get (Positions (Container), Position)), | |
1252 | Lst => P.Get (Positions (Container), Find'Result) - 1, | |
1253 | Item => Item)); | |
bd65a2d7 AC |
1254 | |
1255 | function Reverse_Find | |
1256 | (Container : List; | |
1257 | Item : Element_Type; | |
67a90476 | 1258 | Position : Cursor := No_Element) return Cursor |
16788d44 | 1259 | with |
e77e2429 AC |
1260 | Global => null, |
1261 | Pre => | |
1262 | Has_Element (Container, Position) or else Position = No_Element, | |
1263 | Contract_Cases => | |
1264 | ||
1265 | -- If Item is not is not contained in Container before Position, Find | |
1266 | -- returns No_Element. | |
6cbfce7e AC |
1267 | (not M.Contains |
1268 | (Container => Model (Container), | |
1269 | Fst => 1, | |
1270 | Lst => (if Position = No_Element then Length (Container) | |
1271 | else P.Get (Positions (Container), Position)), | |
1272 | Item => Item) | |
e77e2429 AC |
1273 | => |
1274 | Reverse_Find'Result = No_Element, | |
1275 | ||
1276 | -- Otherwise, Find returns a valid cusror in Container | |
1277 | others => | |
6cbfce7e | 1278 | P.Has_Key (Positions (Container), Reverse_Find'Result) |
e77e2429 AC |
1279 | |
1280 | -- The element designated by the result of Find is Item | |
1281 | and Element (Model (Container), | |
1282 | P.Get (Positions (Container), Reverse_Find'Result)) = Item | |
1283 | ||
1284 | -- The result of Find is located before Position | |
1285 | and (if Position /= No_Element | |
1286 | then P.Get (Positions (Container), Reverse_Find'Result) | |
1287 | <= P.Get (Positions (Container), Position)) | |
1288 | ||
1289 | -- It is the last occurence of Item in this slice | |
6cbfce7e AC |
1290 | and not M.Contains |
1291 | (Container => Model (Container), | |
1292 | Fst => P.Get (Positions (Container), Reverse_Find'Result) + 1, | |
1293 | Lst => (if Position = No_Element then Length (Container) | |
1294 | else P.Get (Positions (Container), Position)), | |
1295 | Item => Item)); | |
bd65a2d7 AC |
1296 | |
1297 | function Contains | |
1298 | (Container : List; | |
47fb6ca8 AC |
1299 | Item : Element_Type) return Boolean |
1300 | with | |
e77e2429 | 1301 | Global => null, |
6cbfce7e AC |
1302 | Post => |
1303 | Contains'Result = M.Contains (Container => Model (Container), | |
1304 | Fst => 1, | |
1305 | Lst => Length (Container), | |
1306 | Item => Item); | |
bd65a2d7 | 1307 | |
47fb6ca8 AC |
1308 | function Has_Element (Container : List; Position : Cursor) return Boolean |
1309 | with | |
e77e2429 | 1310 | Global => null, |
6cbfce7e AC |
1311 | Post => |
1312 | Has_Element'Result = P.Has_Key (Positions (Container), Position); | |
e77e2429 | 1313 | pragma Annotate (GNATprove, Inline_For_Proof, Has_Element); |
bd65a2d7 | 1314 | |
bd65a2d7 AC |
1315 | generic |
1316 | with function "<" (Left, Right : Element_Type) return Boolean is <>; | |
c96c518f | 1317 | package Generic_Sorting with SPARK_Mode is |
6cbfce7e | 1318 | function M_Elements_Sorted (Container : M.Sequence) return Boolean with |
e77e2429 AC |
1319 | Ghost, |
1320 | Global => null, | |
1321 | Post => M_Elements_Sorted'Result = | |
6cbfce7e AC |
1322 | (for all I in 1 .. M.Length (Container) => |
1323 | (for all J in I + 1 .. M.Length (Container) => | |
1324 | Element (Container, I) = Element (Container, J) | |
1325 | or Element (Container, I) < Element (Container, J))); | |
e77e2429 | 1326 | pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Sorted); |
bd65a2d7 | 1327 | |
47fb6ca8 | 1328 | function Is_Sorted (Container : List) return Boolean with |
e77e2429 AC |
1329 | Global => null, |
1330 | Post => Is_Sorted'Result = M_Elements_Sorted (Model (Container)); | |
bd65a2d7 | 1331 | |
47fb6ca8 | 1332 | procedure Sort (Container : in out List) with |
e77e2429 AC |
1333 | Global => null, |
1334 | Post => Length (Container) = Length (Container)'Old | |
1335 | and M_Elements_Sorted (Model (Container)); | |
bd65a2d7 | 1336 | |
47fb6ca8 | 1337 | procedure Merge (Target, Source : in out List) with |
e77e2429 AC |
1338 | -- Target and Source should not be aliased |
1339 | Global => null, | |
1340 | Pre => Length (Source) <= Target.Capacity - Length (Target), | |
1341 | Post => Length (Target) = Length (Target)'Old + Length (Source)'Old | |
1342 | and Length (Source) = 0 | |
1343 | and (if M_Elements_Sorted (Model (Target)'Old) | |
1344 | and M_Elements_Sorted (Model (Source)'Old) | |
1345 | then M_Elements_Sorted (Model (Target))); | |
bd65a2d7 AC |
1346 | end Generic_Sorting; |
1347 | ||
bd65a2d7 | 1348 | private |
5fde9688 | 1349 | pragma SPARK_Mode (Off); |
bd65a2d7 AC |
1350 | |
1351 | type Node_Type is record | |
1352 | Prev : Count_Type'Base := -1; | |
1353 | Next : Count_Type; | |
9686dbc7 | 1354 | Element : Element_Type; |
bd65a2d7 | 1355 | end record; |
88115c2a | 1356 | |
bd65a2d7 AC |
1357 | function "=" (L, R : Node_Type) return Boolean is abstract; |
1358 | ||
1359 | type Node_Array is array (Count_Type range <>) of Node_Type; | |
1360 | function "=" (L, R : Node_Array) return Boolean is abstract; | |
1361 | ||
0f8b3e5d | 1362 | type List (Capacity : Count_Type) is record |
bd65a2d7 | 1363 | Free : Count_Type'Base := -1; |
bd65a2d7 AC |
1364 | Length : Count_Type := 0; |
1365 | First : Count_Type := 0; | |
1366 | Last : Count_Type := 0; | |
0f8b3e5d | 1367 | Nodes : Node_Array (1 .. Capacity) := (others => <>); |
bd65a2d7 AC |
1368 | end record; |
1369 | ||
bd65a2d7 AC |
1370 | Empty_List : constant List := (0, others => <>); |
1371 | ||
bd65a2d7 | 1372 | end Ada.Containers.Formal_Doubly_Linked_Lists; |