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-2013, 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 is
65   pragma Annotate (GNATprove, External_Axiomatization);
66   pragma Pure;
67
68   type List (Capacity : Count_Type) is private with
69     Iterable => (First       => First,
70                  Next        => Next,
71                  Has_Element => Has_Element,
72                  Element     => Element);
73   pragma Preelaborable_Initialization (List);
74
75   type Cursor is private;
76   pragma Preelaborable_Initialization (Cursor);
77
78   Empty_List : constant List;
79
80   No_Element : constant Cursor;
81
82   function "=" (Left, Right : List) return Boolean with
83     Global => null;
84
85   function Length (Container : List) return Count_Type with
86     Global => null;
87
88   function Is_Empty (Container : List) return Boolean with
89     Global => null;
90
91   procedure Clear (Container : in out List) with
92     Global => null;
93
94   procedure Assign (Target : in out List; Source : List) with
95     Global => null,
96     Pre    => Target.Capacity >= Length (Source);
97
98   function Copy (Source : List; Capacity : Count_Type := 0) return List with
99     Global => null,
100     Pre    => Capacity = 0 or else Capacity >= Source.Capacity;
101
102   function Element
103     (Container : List;
104      Position : Cursor) return Element_Type
105   with
106     Global => null,
107     Pre    => Has_Element (Container, Position);
108
109   procedure Replace_Element
110     (Container : in out List;
111      Position  : Cursor;
112      New_Item  : Element_Type)
113   with
114     Global => null,
115     Pre    => Has_Element (Container, Position);
116
117   procedure Move (Target : in out List; Source : in out List) with
118     Global => null,
119     Pre    => Target.Capacity >= Length (Source);
120
121   procedure Insert
122     (Container : in out List;
123      Before    : Cursor;
124      New_Item  : Element_Type;
125      Count     : Count_Type := 1)
126   with
127     Global => null,
128     Pre    => Length (Container) + Count <= Container.Capacity
129                 and then (Has_Element (Container, Before)
130                            or else Before = No_Element);
131
132   procedure Insert
133     (Container : in out List;
134      Before    : Cursor;
135      New_Item  : Element_Type;
136      Position  : out Cursor;
137      Count     : Count_Type := 1)
138   with
139     Global => null,
140     Pre    => Length (Container) + Count <= Container.Capacity
141                 and then (Has_Element (Container, Before)
142                            or else Before = No_Element);
143
144   procedure Insert
145     (Container : in out List;
146      Before    : Cursor;
147      Position  : out Cursor;
148      Count     : Count_Type := 1)
149   with
150     Global => null,
151     Pre    => Length (Container) + Count <= Container.Capacity
152                 and then (Has_Element (Container, Before)
153                            or else Before = No_Element);
154
155   procedure Prepend
156     (Container : in out List;
157      New_Item  : Element_Type;
158      Count     : Count_Type := 1)
159   with
160     Global => null,
161     Pre    => Length (Container) + Count <= Container.Capacity;
162
163   procedure Append
164     (Container : in out List;
165      New_Item  : Element_Type;
166      Count     : Count_Type := 1)
167   with
168     Global => null,
169     Pre    => Length (Container) + Count <= Container.Capacity;
170
171   procedure Delete
172     (Container : in out List;
173      Position  : in out Cursor;
174      Count     : Count_Type := 1)
175   with
176     Global => null,
177     Pre    => Has_Element (Container, Position);
178
179   procedure Delete_First
180     (Container : in out List;
181      Count     : Count_Type := 1)
182   with
183     Global => null;
184
185   procedure Delete_Last
186     (Container : in out List;
187      Count     : Count_Type := 1)
188   with
189     Global => null;
190
191   procedure Reverse_Elements (Container : in out List) with
192     Global => null;
193
194   procedure Swap
195     (Container : in out List;
196      I, J      : Cursor)
197   with
198     Global => null,
199     Pre    => Has_Element (Container, I) and then Has_Element (Container, J);
200
201   procedure Swap_Links
202     (Container : in out List;
203      I, J      : Cursor)
204   with
205     Global => null,
206     Pre    => Has_Element (Container, I) and then Has_Element (Container, J);
207
208   procedure Splice
209     (Target : in out List;
210      Before : Cursor;
211      Source : in out List)
212   with
213     Global => null,
214     Pre    => Length (Source) + Length (Target) <= Target.Capacity
215                 and then (Has_Element (Target, Before)
216                            or else Before = No_Element);
217
218   procedure Splice
219     (Target   : in out List;
220      Before   : Cursor;
221      Source   : in out List;
222      Position : in out Cursor)
223   with
224     Global => null,
225     Pre    => Length (Source) + Length (Target) <= Target.Capacity
226                 and then (Has_Element (Target, Before)
227                            or else Before = No_Element)
228                 and then Has_Element (Source, Position);
229
230   procedure Splice
231     (Container : in out List;
232      Before    : Cursor;
233      Position  : Cursor)
234   with
235     Global => null,
236     Pre    => 2 * Length (Container) <= Container.Capacity
237                 and then (Has_Element (Container, Before)
238                            or else Before = No_Element)
239                 and then Has_Element (Container, Position);
240
241   function First (Container : List) return Cursor with
242     Global => null;
243
244   function First_Element (Container : List) return Element_Type with
245     Global => null,
246     Pre    => not Is_Empty (Container);
247
248   function Last (Container : List) return Cursor with
249     Global => null;
250
251   function Last_Element (Container : List) return Element_Type with
252     Global => null,
253     Pre    => not Is_Empty (Container);
254
255   function Next (Container : List; Position : Cursor) return Cursor with
256     Global => null,
257     Pre    => Has_Element (Container, Position) or else Position = No_Element;
258
259   procedure Next (Container : List; Position : in out Cursor) with
260     Global => null,
261     Pre    => Has_Element (Container, Position) or else Position = No_Element;
262
263   function Previous (Container : List; Position : Cursor) return Cursor with
264     Global => null,
265     Pre    => Has_Element (Container, Position) or else Position = No_Element;
266
267   procedure Previous (Container : List; Position : in out Cursor) with
268     Global => null,
269     Pre    => Has_Element (Container, Position) or else Position = No_Element;
270
271   function Find
272     (Container : List;
273      Item      : Element_Type;
274      Position  : Cursor := No_Element) return Cursor
275   with
276     Global => null,
277     Pre    => Has_Element (Container, Position) or else Position = No_Element;
278
279   function Reverse_Find
280     (Container : List;
281      Item      : Element_Type;
282      Position  : Cursor := No_Element) return Cursor
283   with
284     Global => null,
285     Pre    => Has_Element (Container, Position) or else Position = No_Element;
286
287   function Contains
288     (Container : List;
289      Item      : Element_Type) return Boolean
290   with
291     Global => null;
292
293   function Has_Element (Container : List; Position : Cursor) return Boolean
294   with
295     Global => null;
296
297   generic
298      with function "<" (Left, Right : Element_Type) return Boolean is <>;
299   package Generic_Sorting is
300
301      function Is_Sorted (Container : List) return Boolean with
302        Global => null;
303
304      procedure Sort (Container : in out List) with
305        Global => null;
306
307      procedure Merge (Target, Source : in out List) with
308        Global => null;
309
310   end Generic_Sorting;
311
312   function Strict_Equal (Left, Right : List) return Boolean with
313     Global => null;
314   --  Strict_Equal returns True if the containers are physically equal, i.e.
315   --  they are structurally equal (function "=" returns True) and that they
316   --  have the same set of cursors.
317
318   function First_To_Previous (Container : List; Current : Cursor) return List
319   with
320     Global => null,
321     Pre    => Has_Element (Container, Current) or else Current = No_Element;
322   function Current_To_Last (Container : List; Current : Cursor) return List
323   with
324     Global => null,
325     Pre    => Has_Element (Container, Current) or else Current = No_Element;
326   --  First_To_Previous returns a container containing all elements preceding
327   --  Current (excluded) in Container. Current_To_Last returns a container
328   --  containing all elements following Current (included) in Container.
329   --  These two new functions can be used to express invariant properties in
330   --  loops which iterate over containers. First_To_Previous returns the part
331   --  of the container already scanned and Current_To_Last the part not
332   --  scanned yet.
333
334private
335
336   type Node_Type is record
337      Prev    : Count_Type'Base := -1;
338      Next    : Count_Type;
339      Element : Element_Type;
340   end record;
341
342   function "=" (L, R : Node_Type) return Boolean is abstract;
343
344   type Node_Array is array (Count_Type range <>) of Node_Type;
345   function "=" (L, R : Node_Array) return Boolean is abstract;
346
347   type List (Capacity : Count_Type) is tagged record
348      Nodes  : Node_Array (1 .. Capacity) := (others => <>);
349      Free   : Count_Type'Base := -1;
350      Length : Count_Type := 0;
351      First  : Count_Type := 0;
352      Last   : Count_Type := 0;
353   end record;
354
355   type Cursor is record
356      Node : Count_Type := 0;
357   end record;
358
359   Empty_List : constant List := (0, others => <>);
360
361   No_Element : constant Cursor := (Node => 0);
362
363end Ada.Containers.Formal_Doubly_Linked_Lists;
364