1------------------------------------------------------------------------------
2--                                                                          --
3--                         GNAT LIBRARY COMPONENTS                          --
4--                                                                          --
5--                 ADA.CONTAINERS.FORMAL_DOUBLY_LINKED_LISTS                --
6--                                                                          --
7--                                 S p e c                                  --
8--                                                                          --
9--          Copyright (C) 2004-2015, 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--  This spec is derived from Ada.Containers.Bounded_Doubly_Linked_Lists in the
33--  Ada 2012 RM. The modifications are meant to facilitate formal proofs by
34--  making it easier to express properties, and by making the specification of
35--  this unit compatible with SPARK 2014. Note that the API of this unit may be
36--  subject to incompatible changes as SPARK 2014 evolves.
37
38--  The modifications are:
39
40--    A parameter for the container is added to every function reading the
41--    contents of a container: Next, Previous, Query_Element, Has_Element,
42--    Iterate, Reverse_Iterate, Element. This change is motivated by the need
43--    to have cursors which are valid on different containers (typically a
44--    container C and its previous version C'Old) for expressing properties,
45--    which is not possible if cursors encapsulate an access to the underlying
46--    container.
47
48--    There are three new functions:
49
50--      function Strict_Equal (Left, Right : List) return Boolean;
51--      function First_To_Previous  (Container : List; Current : Cursor)
52--         return List;
53--      function Current_To_Last (Container : List; Current : Cursor)
54--         return List;
55
56--    See subprogram specifications that follow for details
57
58generic
59   type Element_Type is private;
60
61   with function "=" (Left, Right : Element_Type)
62                      return Boolean is <>;
63
64package Ada.Containers.Formal_Doubly_Linked_Lists with
65  Pure,
66  SPARK_Mode
67is
68   pragma Annotate (GNATprove, External_Axiomatization);
69   pragma Annotate (CodePeer, Skip_Analysis);
70
71   type List (Capacity : Count_Type) is private with
72     Iterable => (First       => First,
73                  Next        => Next,
74                  Has_Element => Has_Element,
75                  Element     => Element),
76     Default_Initial_Condition => Is_Empty (List);
77   pragma Preelaborable_Initialization (List);
78
79   type Cursor is private;
80   pragma Preelaborable_Initialization (Cursor);
81
82   Empty_List : constant List;
83
84   No_Element : constant Cursor;
85
86   function "=" (Left, Right : List) return Boolean with
87     Global => null;
88
89   function Length (Container : List) return Count_Type with
90     Global => null;
91
92   function Is_Empty (Container : List) return Boolean with
93     Global => null;
94
95   procedure Clear (Container : in out List) with
96     Global => null;
97
98   procedure Assign (Target : in out List; Source : List) with
99     Global => null,
100     Pre    => Target.Capacity >= Length (Source);
101
102   function Copy (Source : List; Capacity : Count_Type := 0) return List with
103     Global => null,
104     Pre    => Capacity = 0 or else Capacity >= Source.Capacity;
105
106   function Element
107     (Container : List;
108      Position : Cursor) return Element_Type
109   with
110     Global => null,
111     Pre    => Has_Element (Container, Position);
112
113   procedure Replace_Element
114     (Container : in out List;
115      Position  : Cursor;
116      New_Item  : Element_Type)
117   with
118     Global => null,
119     Pre    => Has_Element (Container, Position);
120
121   procedure Move (Target : in out List; Source : in out List) with
122     Global => null,
123     Pre    => Target.Capacity >= Length (Source);
124
125   procedure Insert
126     (Container : in out List;
127      Before    : Cursor;
128      New_Item  : Element_Type;
129      Count     : Count_Type := 1)
130   with
131     Global => null,
132     Pre    => Length (Container) + Count <= Container.Capacity
133                 and then (Has_Element (Container, Before)
134                            or else Before = No_Element);
135
136   procedure Insert
137     (Container : in out List;
138      Before    : Cursor;
139      New_Item  : Element_Type;
140      Position  : out Cursor;
141      Count     : Count_Type := 1)
142   with
143     Global => null,
144     Pre    => Length (Container) + Count <= Container.Capacity
145                 and then (Has_Element (Container, Before)
146                            or else Before = No_Element);
147
148   procedure Insert
149     (Container : in out List;
150      Before    : Cursor;
151      Position  : out Cursor;
152      Count     : Count_Type := 1)
153   with
154     Global => null,
155     Pre    => Length (Container) + Count <= Container.Capacity
156                 and then (Has_Element (Container, Before)
157                            or else Before = No_Element);
158
159   procedure Prepend
160     (Container : in out List;
161      New_Item  : Element_Type;
162      Count     : Count_Type := 1)
163   with
164     Global => null,
165     Pre    => Length (Container) + Count <= Container.Capacity;
166
167   procedure Append
168     (Container : in out List;
169      New_Item  : Element_Type;
170      Count     : Count_Type := 1)
171   with
172     Global => null,
173     Pre    => Length (Container) + Count <= Container.Capacity;
174
175   procedure Delete
176     (Container : in out List;
177      Position  : in out Cursor;
178      Count     : Count_Type := 1)
179   with
180     Global => null,
181     Pre    => Has_Element (Container, Position);
182
183   procedure Delete_First
184     (Container : in out List;
185      Count     : Count_Type := 1)
186   with
187     Global => null;
188
189   procedure Delete_Last
190     (Container : in out List;
191      Count     : Count_Type := 1)
192   with
193     Global => null;
194
195   procedure Reverse_Elements (Container : in out List) with
196     Global => null;
197
198   procedure Swap
199     (Container : in out List;
200      I, J      : Cursor)
201   with
202     Global => null,
203     Pre    => Has_Element (Container, I) and then Has_Element (Container, J);
204
205   procedure Swap_Links
206     (Container : in out List;
207      I, J      : Cursor)
208   with
209     Global => null,
210     Pre    => Has_Element (Container, I) and then Has_Element (Container, J);
211
212   procedure Splice
213     (Target : in out List;
214      Before : Cursor;
215      Source : in out List)
216   with
217     Global => null,
218     Pre    => Length (Source) + Length (Target) <= Target.Capacity
219                 and then (Has_Element (Target, Before)
220                            or else Before = No_Element);
221
222   procedure Splice
223     (Target   : in out List;
224      Before   : Cursor;
225      Source   : in out List;
226      Position : in out Cursor)
227   with
228     Global => null,
229     Pre    => Length (Source) + Length (Target) <= Target.Capacity
230                 and then (Has_Element (Target, Before)
231                            or else Before = No_Element)
232                 and then Has_Element (Source, Position);
233
234   procedure Splice
235     (Container : in out List;
236      Before    : Cursor;
237      Position  : Cursor)
238   with
239     Global => null,
240     Pre    => 2 * Length (Container) <= Container.Capacity
241                 and then (Has_Element (Container, Before)
242                            or else Before = No_Element)
243                 and then Has_Element (Container, Position);
244
245   function First (Container : List) return Cursor with
246     Global => null;
247
248   function First_Element (Container : List) return Element_Type with
249     Global => null,
250     Pre    => not Is_Empty (Container);
251
252   function Last (Container : List) return Cursor with
253     Global => null;
254
255   function Last_Element (Container : List) return Element_Type with
256     Global => null,
257     Pre    => not Is_Empty (Container);
258
259   function Next (Container : List; Position : Cursor) return Cursor with
260     Global => null,
261     Pre    => Has_Element (Container, Position) or else Position = No_Element;
262
263   procedure Next (Container : List; Position : in out Cursor) with
264     Global => null,
265     Pre    => Has_Element (Container, Position) or else Position = No_Element;
266
267   function Previous (Container : List; Position : Cursor) return Cursor with
268     Global => null,
269     Pre    => Has_Element (Container, Position) or else Position = No_Element;
270
271   procedure Previous (Container : List; Position : in out Cursor) with
272     Global => null,
273     Pre    => Has_Element (Container, Position) or else Position = No_Element;
274
275   function Find
276     (Container : List;
277      Item      : Element_Type;
278      Position  : Cursor := No_Element) return Cursor
279   with
280     Global => null,
281     Pre    => Has_Element (Container, Position) or else Position = No_Element;
282
283   function Reverse_Find
284     (Container : List;
285      Item      : Element_Type;
286      Position  : Cursor := No_Element) return Cursor
287   with
288     Global => null,
289     Pre    => Has_Element (Container, Position) or else Position = No_Element;
290
291   function Contains
292     (Container : List;
293      Item      : Element_Type) return Boolean
294   with
295     Global => null;
296
297   function Has_Element (Container : List; Position : Cursor) return Boolean
298   with
299     Global => null;
300
301   generic
302      with function "<" (Left, Right : Element_Type) return Boolean is <>;
303   package Generic_Sorting with SPARK_Mode is
304
305      function Is_Sorted (Container : List) return Boolean with
306        Global => null;
307
308      procedure Sort (Container : in out List) with
309        Global => null;
310
311      procedure Merge (Target, Source : in out List) with
312        Global => null;
313
314   end Generic_Sorting;
315
316   function Strict_Equal (Left, Right : List) return Boolean with
317     Ghost,
318     Global => null;
319   --  Strict_Equal returns True if the containers are physically equal, i.e.
320   --  they are structurally equal (function "=" returns True) and that they
321   --  have the same set of cursors.
322
323   function First_To_Previous (Container : List; Current : Cursor) return List
324   with
325     Ghost,
326     Global => null,
327     Pre    => Has_Element (Container, Current) or else Current = No_Element;
328
329   function Current_To_Last (Container : List; Current : Cursor) return List
330   with
331     Ghost,
332     Global => null,
333     Pre    => Has_Element (Container, Current) or else Current = No_Element;
334   --  First_To_Previous returns a container containing all elements preceding
335   --  Current (excluded) in Container. Current_To_Last returns a container
336   --  containing all elements following Current (included) in Container.
337   --  These two new functions can be used to express invariant properties in
338   --  loops which iterate over containers. First_To_Previous returns the part
339   --  of the container already scanned and Current_To_Last the part not
340   --  scanned yet.
341
342private
343   pragma SPARK_Mode (Off);
344
345   type Node_Type is record
346      Prev    : Count_Type'Base := -1;
347      Next    : Count_Type;
348      Element : Element_Type;
349   end record;
350
351   function "=" (L, R : Node_Type) return Boolean is abstract;
352
353   type Node_Array is array (Count_Type range <>) of Node_Type;
354   function "=" (L, R : Node_Array) return Boolean is abstract;
355
356   type List (Capacity : Count_Type) is tagged record
357      Nodes  : Node_Array (1 .. Capacity) := (others => <>);
358      Free   : Count_Type'Base := -1;
359      Length : Count_Type := 0;
360      First  : Count_Type := 0;
361      Last   : Count_Type := 0;
362   end record;
363
364   type Cursor is record
365      Node : Count_Type := 0;
366   end record;
367
368   Empty_List : constant List := (0, others => <>);
369
370   No_Element : constant Cursor := (Node => 0);
371
372end Ada.Containers.Formal_Doubly_Linked_Lists;
373