summaryrefslogtreecommitdiff
path: root/gcc/ada/a-cfdlli.ads
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/a-cfdlli.ads')
-rw-r--r--gcc/ada/a-cfdlli.ads1316
1 files changed, 1177 insertions, 139 deletions
diff --git a/gcc/ada/a-cfdlli.ads b/gcc/ada/a-cfdlli.ads
index 8e17479fc3a..62cdf52028e 100644
--- a/gcc/ada/a-cfdlli.ads
+++ b/gcc/ada/a-cfdlli.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 2004-2015, Free Software Foundation, Inc. --
+-- Copyright (C) 2004-2017, Free Software Foundation, Inc. --
-- --
-- This specification is derived from the Ada Reference Manual for use with --
-- GNAT. The copyright notice above, and the license provisions that follow --
@@ -29,43 +29,14 @@
-- <http://www.gnu.org/licenses/>. --
------------------------------------------------------------------------------
--- This spec is derived from Ada.Containers.Bounded_Doubly_Linked_Lists in the
--- Ada 2012 RM. The modifications are meant to facilitate formal proofs by
--- making it easier to express properties, and by making the specification of
--- this unit compatible with SPARK 2014. Note that the API of this unit may be
--- subject to incompatible changes as SPARK 2014 evolves.
-
--- The modifications are:
-
--- A parameter for the container is added to every function reading the
--- contents of a container: Next, Previous, Query_Element, Has_Element,
--- Iterate, Reverse_Iterate, Element. This change is motivated by the need
--- to have cursors which are valid on different containers (typically a
--- container C and its previous version C'Old) for expressing properties,
--- which is not possible if cursors encapsulate an access to the underlying
--- container.
-
--- There are three new functions:
-
--- function Strict_Equal (Left, Right : List) return Boolean;
--- function First_To_Previous (Container : List; Current : Cursor)
--- return List;
--- function Current_To_Last (Container : List; Current : Cursor)
--- return List;
-
--- See subprogram specifications that follow for details
+with Ada.Containers.Functional_Vectors;
+with Ada.Containers.Functional_Maps;
generic
type Element_Type is private;
-
- with function "=" (Left, Right : Element_Type)
- return Boolean is <>;
-
package Ada.Containers.Formal_Doubly_Linked_Lists with
- Pure,
SPARK_Mode
is
- pragma Annotate (GNATprove, External_Axiomatization);
pragma Annotate (CodePeer, Skip_Analysis);
type List (Capacity : Count_Type) is private with
@@ -76,39 +47,334 @@ is
Default_Initial_Condition => Is_Empty (List);
pragma Preelaborable_Initialization (List);
- type Cursor is private;
- pragma Preelaborable_Initialization (Cursor);
+ type Cursor is record
+ Node : Count_Type := 0;
+ end record;
+
+ No_Element : constant Cursor := Cursor'(Node => 0);
Empty_List : constant List;
- No_Element : constant Cursor;
+ function Length (Container : List) return Count_Type with
+ Global => null,
+ Post => Length'Result <= Container.Capacity;
+
+ pragma Unevaluated_Use_Of_Old (Allow);
+
+ package Formal_Model with Ghost is
+ subtype Positive_Count_Type is Count_Type range 1 .. Count_Type'Last;
+
+ package M is new Ada.Containers.Functional_Vectors
+ (Index_Type => Positive_Count_Type,
+ Element_Type => Element_Type);
+ function "=" (Left, Right : M.Sequence) return Boolean renames M."=";
+ function "<" (Left, Right : M.Sequence) return Boolean renames M."<";
+ function "<=" (Left, Right : M.Sequence) return Boolean renames M."<=";
+
+ function M_Elements_Contains
+ (S : M.Sequence;
+ Fst : Positive_Count_Type;
+ Lst : Count_Type;
+ E : Element_Type)
+ return Boolean
+ -- E appears in the slice from Fst to Lst in S
+ with
+ Global => null,
+ Pre => Lst <= M.Length (S),
+ Post =>
+ M_Elements_Contains'Result =
+ (for some I in Fst .. Lst => Element (S, I) = E);
+ pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Contains);
+
+ function M_Elements_Cst
+ (S : M.Sequence;
+ Fst : Positive_Count_Type;
+ Lst : Count_Type;
+ E : Element_Type)
+ return Boolean
+ -- Every element of the slice from Fst to Lst in S is E.
+ with
+ Global => null,
+ Pre => Lst <= M.Length (S),
+ Post =>
+ M_Elements_Cst'Result =
+ (for all I in Fst .. Lst => Element (S, I) = E);
+ pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Cst);
+
+ function M_Elements_Equal
+ (S1, S2 : M.Sequence;
+ Fst : Positive_Count_Type;
+ Lst : Count_Type)
+ return Boolean
+ -- The slice from Fst to Lst is the same in S1 and S2
+ with
+ Global => null,
+ Pre => Lst <= M.Length (S1) and Lst <= M.Length (S2),
+ Post =>
+ M_Elements_Equal'Result =
+ (for all I in Fst .. Lst => Element (S1, I) = Element (S2, I));
+ pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Equal);
+
+ function M_Elements_Shuffle
+ (S1, S2 : M.Sequence;
+ Fst : Positive_Count_Type;
+ Lst : Count_Type;
+ Offset : Count_Type'Base)
+ return Boolean
+ -- The slice from Fst to Lst in S1 contains the same elements than the
+ -- same slide shifted by Offset in S2
+ with
+ Global => null,
+ Pre =>
+ Lst <= M.Length (S1)
+ and Offset in 1 - Fst .. M.Length (S2) - Lst,
+ Post =>
+ M_Elements_Shuffle'Result =
+ (for all J in Fst + Offset .. Lst + Offset =>
+ (for some I in Fst .. Lst =>
+ Element (S1, I) = Element (S2, J)));
+ pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Shuffle);
+
+ function M_Elements_Reversed (S1, S2 : M.Sequence) return Boolean
+ -- S2 is S1 in reverse order
+ with
+ Global => null,
+ Post =>
+ M_Elements_Reversed'Result =
+ (M.Length (S1) = M.Length (S2)
+ and (for all I in 1 .. M.Length (S1) =>
+ Element (S1, I) = Element (S2, M.Length (S1) - I + 1))
+ and (for all I in 1 .. M.Length (S1) =>
+ Element (S2, I) = Element (S1, M.Length (S1) - I + 1)));
+ pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Reversed);
+
+ function M_Elements_Shifted
+ (S1, S2 : M.Sequence;
+ Fst : Positive_Count_Type;
+ Lst : Count_Type;
+ Offset : Count_Type'Base := 1)
+ return Boolean
+ -- The slice from Fst to Lst in S1 has been shifted by Offset in S2.
+ with
+ Global => null,
+ Pre =>
+ Lst <= M.Length (S1)
+ and Offset in 1 - Fst .. M.Length (S2) - Lst,
+ Post =>
+ M_Elements_Shifted'Result =
+ ((for all I in Fst .. Lst =>
+ Element (S1, I) = Element (S2, I + Offset))
+ and (for all I in Fst + Offset .. Lst + Offset =>
+ Element (S1, I - Offset) = Element (S2, I)));
+ pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Shifted);
+
+ function M_Elements_Swapped
+ (S1, S2 : M.Sequence;
+ X, Y : Positive_Count_Type)
+ return Boolean
+ -- Elements stored at X and Y are reversed in S1 and S2
+ with
+ Global => null,
+ Pre => X <= M.Length (S1) and Y <= M.Length (S1),
+ Post =>
+ M_Elements_Swapped'Result =
+ (M.Length (S1) = M.Length (S2)
+ and Element (S1, X) = Element (S2, Y)
+ and Element (S1, Y) = Element (S2, X)
+ and
+ (for all I in 1 .. M.Length (S1) =>
+ (if I /= X and I /= Y
+ then Element (S1, I) = Element (S2, I))));
+ pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Swapped);
+
+ package P is new Ada.Containers.Functional_Maps
+ (Key_Type => Cursor,
+ Element_Type => Positive_Count_Type,
+ Equivalent_Keys => "=");
+ function "=" (Left, Right : P.Map) return Boolean renames P."=";
+ function "<=" (Left, Right : P.Map) return Boolean renames P."<=";
+
+ function P_Positions_Shifted
+ (Small : P.Map;
+ Big : P.Map;
+ Cut : Positive_Count_Type;
+ Count : Count_Type := 1) return Boolean
+ with
+ Global => null,
+ Post =>
+ P_Positions_Shifted'Result =
+
+ -- Big contains all cursors of Small
+ ((for all I of Small => P.Mem (Big, I))
+
+ -- Cursors located before Cut are not moved, cursors located after
+ -- are shifted by Count.
+ and
+ (for all I of Small =>
+ (if P.Get (Small, I) < Cut
+ then P.Get (Big, I) = P.Get (Small, I)
+ else P.Get (Big, I) - Count = P.Get (Small, I)))
+
+ -- New cursors of Big (if any) are between Cut and Cut - 1 + Count
+ and
+ (for all I of Big =>
+ P.Mem (Small, I)
+ or P.Get (Big, I) - Count in Cut - Count .. Cut - 1));
+
+ function P_Positions_Swapped
+ (M1, M2 : P.Map;
+ C1, C2 : Cursor) return Boolean
+ -- M1 and M2 contain the same cursors, but the positions of C1 and C2
+ -- are reversed.
+ with
+ Ghost,
+ Global => null,
+ Post =>
+ P_Positions_Swapped'Result =
+ ((for all C of M1 => P.Mem (M2, C))
+ and (for all C of M2 => P.Mem (M1, C))
+ and
+ (for all C of M1 =>
+ (if C /= C1 and C /= C2
+ then P.Get (M1, C) = P.Get (M2, C)))
+ and P.Mem (M1, C1) and P.Mem (M1, C2)
+ and P.Get (M1, C1) = P.Get (M2, C2)
+ and P.Get (M1, C2) = P.Get (M2, C1));
+
+ function P_Positions_Truncated
+ (Small : P.Map;
+ Big : P.Map;
+ Cut : Positive_Count_Type;
+ Count : Count_Type := 1) return Boolean
+ with
+ Ghost,
+ Global => null,
+ Post =>
+ P_Positions_Truncated'Result =
+
+ -- Big contains all cursors of Small
+ ((for all I of Small => P.Mem (Big, I))
+
+ -- The cursors of Small are all bellow Cut
+ and (for all I of Small => P.Get (Small, I) < Cut)
+
+ -- The cursors have the same position in Big and Small
+ and (for all I of Small => P.Get (Big, I) = P.Get (Small, I))
+
+ -- New cursors of Big (if any) are between Cut and Cut - 1 + Count
+ and
+ (for all I of Big =>
+ P.Mem (Small, I)
+ or P.Get (Big, I) - Count in Cut - Count .. Cut - 1));
+
+ function Mapping_Preserved
+ (S1, S2 : M.Sequence;
+ M1, M2 : P.Map) return Boolean
+ with
+ Ghost,
+ Global => null,
+ Post =>
+ (if Mapping_Preserved'Result then
+
+ -- M1 contains all cursors of M2
+ (for all I of M2 => P.Mem (M1, I))
+
+ -- M2 contains all cursors of M1
+ and (for all I of M1 => P.Mem (M2, I))
+
+ -- Mappings from cursors to elements induced by S1, M1 and S2, M2
+ -- are the same.
+ and (for all I of M1 =>
+ M.Get (S1, P.Get (M1, I)) = M.Get (S2, P.Get (M2, I))));
+
+ function Model (Container : List) return M.Sequence with
+ -- The highlevel model of a list is a sequence of elements. Cursors are
+ -- not represented in this model.
+
+ Ghost,
+ Global => null,
+ Post => M.Length (Model'Result) = Length (Container);
+ pragma Annotate (GNATprove, Iterable_For_Proof, "Model", Model);
+
+ function Positions (Container : List) return P.Map with
+ -- The Positions map is used to model cursors. It only contains valid
+ -- cursors and map them to their position in the container.
+
+ Ghost,
+ Global => null,
+ Post => not P.Mem (Positions'Result, No_Element)
+ -- Positions of cursors are smaller than the container's length.
+ and then
+ (for all I of Positions'Result =>
+ P.Get (Positions'Result, I) in 1 .. Length (Container)
+
+ -- No two cursors have the same position. Note that we do not
+ -- state that there is a cursor in the map for each position,
+ -- as it is rarely needed.
+ and then
+ (for all J of Positions'Result =>
+ (if P.Get (Positions'Result, I) = P.Get (Positions'Result, J)
+ then I = J)));
+
+ procedure Lift_Abstraction_Level (Container : List) with
+ -- Lift_Abstraction_Level is a ghost procedure that does nothing but
+ -- assume that we can access to the same elements by iterating over
+ -- positions or cursors.
+ -- This information is not generally useful except when switching from
+ -- a lowlevel, cursor aware view of a container, to a highlevel
+ -- position based view.
+
+ Ghost,
+ Global => null,
+ Post =>
+ (for all Elt of Model (Container) =>
+ (for some I of Positions (Container) =>
+ M.Get (Model (Container), P.Get (Positions (Container), I))
+ = Elt));
+
+ function Element (S : M.Sequence; I : Count_Type) return Element_Type
+ renames M.Get;
+ -- To improve readability of contracts, we rename the function used to
+ -- access an element in the model to Element.
+ end Formal_Model;
+ use Formal_Model;
function "=" (Left, Right : List) return Boolean with
- Global => null;
-
- function Length (Container : List) return Count_Type with
- Global => null;
+ Global => null,
+ Post => "="'Result = (Model (Left) = Model (Right));
function Is_Empty (Container : List) return Boolean with
- Global => null;
+ Global => null,
+ Post => Is_Empty'Result = (Length (Container) = 0);
procedure Clear (Container : in out List) with
- Global => null;
+ Global => null,
+ Post => Length (Container) = 0;
procedure Assign (Target : in out List; Source : List) with
Global => null,
- Pre => Target.Capacity >= Length (Source);
+ Pre => Target.Capacity >= Length (Source),
+ Post => Model (Target) = Model (Source);
function Copy (Source : List; Capacity : Count_Type := 0) return List with
Global => null,
- Pre => Capacity = 0 or else Capacity >= Source.Capacity;
+ Pre => Capacity = 0 or else Capacity >= Source.Capacity,
+ Post => Model (Copy'Result) = Model (Source)
+ and Positions (Copy'Result) = Positions (Source)
+ and (if Capacity = 0 then Copy'Result.Capacity = Source.Capacity
+ else Copy'Result.Capacity = Capacity);
function Element
(Container : List;
Position : Cursor) return Element_Type
with
Global => null,
- Pre => Has_Element (Container, Position);
+ Pre => Has_Element (Container, Position),
+ Post =>
+ Element'Result =
+ Element (Model (Container),
+ P.Get (Positions (Container), Position));
+ pragma Annotate (GNATprove, Inline_For_Proof, Element);
procedure Replace_Element
(Container : in out List;
@@ -116,229 +382,1007 @@ is
New_Item : Element_Type)
with
Global => null,
- Pre => Has_Element (Container, Position);
+ Pre => Has_Element (Container, Position),
+ Post => Length (Container) = Length (Container)'Old
+
+ -- Cursors are preserved.
+ and Positions (Container)'Old = Positions (Container)
+
+ -- The element at the position of Position in Container is replaced by
+ -- New_Item.
+ and M.Is_Set (Model (Container)'Old,
+ P.Get (Positions (Container), Position),
+ New_Item,
+ Model (Container));
procedure Move (Target : in out List; Source : in out List) with
Global => null,
- Pre => Target.Capacity >= Length (Source);
+ Pre => Target.Capacity >= Length (Source),
+ Post => Model (Target) = Model (Source'Old)
+ and Length (Source) = 0;
+
+ procedure Insert
+ (Container : in out List;
+ Before : Cursor;
+ New_Item : Element_Type)
+ with
+ Global => null,
+ Pre =>
+ Length (Container) < Container.Capacity
+ and then (Has_Element (Container, Before)
+ or else Before = No_Element),
+ Post => Length (Container) = Length (Container)'Old + 1,
+ Contract_Cases =>
+ (Before = No_Element =>
+
+ -- Positions contains a new mapping from the last cursor of
+ -- Container to its length.
+ P.Is_Add
+ (Positions (Container)'Old, Last (Container), Length (Container),
+ Result => Positions (Container))
+
+ -- Model contains a new element New_Item at the end
+ and M.Is_Add (Model (Container)'Old, New_Item, Model (Container)),
+ others =>
+
+ -- The elements of Container located before Before are preserved.
+ M_Elements_Equal
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 1,
+ Lst => P.Get (Positions (Container)'Old, Before) - 1)
+
+ -- Other elements are shifted by 1.
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => P.Get (Positions (Container)'Old, Before),
+ Lst => Length (Container)'Old,
+ Offset => 1)
+
+ -- New_Item is stored at the previous position of Before in
+ -- Container
+ and Element
+ (Model (Container), P.Get (Positions (Container)'Old, Before))
+ = New_Item
+
+ -- A new cursor has been inserted at position Before in Container
+ and P_Positions_Shifted
+ (Positions (Container)'Old,
+ Positions (Container),
+ Cut => P.Get (Positions (Container)'Old, Before)));
procedure Insert
(Container : in out List;
Before : Cursor;
New_Item : Element_Type;
- Count : Count_Type := 1)
+ Count : Count_Type)
with
Global => null,
- Pre => Length (Container) + Count <= Container.Capacity
- and then (Has_Element (Container, Before)
- or else Before = No_Element);
+ Pre =>
+ Length (Container) <= Container.Capacity - Count
+ and then (Has_Element (Container, Before)
+ or else Before = No_Element),
+ Post => Length (Container) = Length (Container)'Old + Count,
+ Contract_Cases =>
+ (Before = No_Element =>
+
+ -- The elements of Container are preserved
+ M_Elements_Equal
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 1,
+ Lst => Length (Container)'Old)
+
+ -- Container contains Count times New_Item at the end
+ and M_Elements_Cst
+ (S => Model (Container),
+ Fst => Length (Container)'Old + 1,
+ Lst => Length (Container),
+ E => New_Item)
+
+ -- A Count cursors have been inserted at the end of Container
+ and P_Positions_Truncated
+ (Positions (Container)'Old,
+ Positions (Container),
+ Cut => Length (Container)'Old + 1,
+ Count => Count),
+ others =>
+
+ -- The elements of Container located before Before are preserved
+ M_Elements_Equal
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 1,
+ Lst => P.Get (Positions (Container)'Old, Before) - 1)
+
+ -- Other elements are shifted by Count.
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => P.Get (Positions (Container)'Old, Before),
+ Lst => Length (Container)'Old,
+ Offset => Count)
+
+ -- Container contains Count times New_Item after position Before
+ and M_Elements_Cst
+ (S => Model (Container),
+ Fst => P.Get (Positions (Container)'Old, Before),
+ Lst => P.Get (Positions (Container)'Old, Before) - 1 + Count,
+ E => New_Item)
+
+ -- Count cursors have been inserted at position Before in Container
+ and P_Positions_Shifted
+ (Positions (Container)'Old,
+ Positions (Container),
+ Cut => P.Get (Positions (Container)'Old, Before),
+ Count => Count));
procedure Insert
(Container : in out List;
Before : Cursor;
New_Item : Element_Type;
- Position : out Cursor;
- Count : Count_Type := 1)
+ Position : out Cursor)
with
Global => null,
- Pre => Length (Container) + Count <= Container.Capacity
- and then (Has_Element (Container, Before)
- or else Before = No_Element);
+ Pre =>
+ Length (Container) < Container.Capacity
+ and then (Has_Element (Container, Before)
+ or else Before = No_Element),
+ Post =>
+ Length (Container) = Length (Container)'Old + 1
+
+ -- Positions is valid in Container and it is located either before
+ -- Before if it is valid in Container or at the end if it is
+ -- No_Element.
+ and P.Mem (Positions (Container), Position)
+ and (if Before = No_Element
+ then P.Get (Positions (Container), Position)
+ = Length (Container)
+ else P.Get (Positions (Container), Position)
+ = P.Get (Positions (Container)'Old, Before))
+
+ -- The elements of Container located before Position are preserved.
+ and M_Elements_Equal
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 1,
+ Lst => P.Get (Positions (Container), Position) - 1)
+
+ -- Other elements are shifted by 1.
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => P.Get (Positions (Container), Position),
+ Lst => Length (Container)'Old,
+ Offset => 1)
+
+ -- New_Item is stored at Position in Container
+ and Element
+ (Model (Container), P.Get (Positions (Container), Position))
+ = New_Item
+
+ -- A new cursor has been inserted at position Position in Container
+ and P_Positions_Shifted
+ (Positions (Container)'Old,
+ Positions (Container),
+ Cut => P.Get (Positions (Container), Position));
procedure Insert
(Container : in out List;
Before : Cursor;
+ New_Item : Element_Type;
Position : out Cursor;
- Count : Count_Type := 1)
+ Count : Count_Type)
+ with
+ Global => null,
+ Pre =>
+ Length (Container) <= Container.Capacity - Count
+ and then (Has_Element (Container, Before)
+ or else Before = No_Element),
+ Post => Length (Container) = Length (Container)'Old + Count,
+ Contract_Cases =>
+ (Count = 0 => Position = Before
+ and Model (Container) = Model (Container)'Old
+ and Positions (Container) = Positions (Container)'Old,
+
+ others =>
+ -- Positions is valid in Container and it is located either before
+ -- Before if it is valid in Container or at the end if it is
+ -- No_Element.
+ P.Mem (Positions (Container), Position)
+ and (if Before = No_Element
+ then P.Get (Positions (Container), Position)
+ = Length (Container)'Old + 1
+ else P.Get (Positions (Container), Position)
+ = P.Get (Positions (Container)'Old, Before))
+
+ -- The elements of Container located before Position are preserved.
+ and M_Elements_Equal
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 1,
+ Lst => P.Get (Positions (Container), Position) - 1)
+
+ -- Other elements are shifted by Count.
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => P.Get (Positions (Container), Position),
+ Lst => Length (Container)'Old,
+ Offset => Count)
+
+ -- Container contains Count times New_Item after position Position
+ and M_Elements_Cst
+ (S => Model (Container),
+ Fst => P.Get (Positions (Container), Position),
+ Lst => P.Get (Positions (Container), Position) - 1 + Count,
+ E => New_Item)
+
+ -- Count cursor have been inserted at Position in Container
+ and P_Positions_Shifted
+ (Positions (Container)'Old,
+ Positions (Container),
+ Cut => P.Get (Positions (Container), Position),
+ Count => Count));
+
+ procedure Prepend
+ (Container : in out List;
+ New_Item : Element_Type)
with
Global => null,
- Pre => Length (Container) + Count <= Container.Capacity
- and then (Has_Element (Container, Before)
- or else Before = No_Element);
+ Pre => Length (Container) < Container.Capacity,
+ Post =>
+ Length (Container) = Length (Container)'Old + 1
+
+ -- Elements are shifted by 1
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 1,
+ Lst => Length (Container)'Old,
+ Offset => 1)
+
+ -- New_Item is the first element of Container
+ and Element (Model (Container), 1) = New_Item
+
+ -- A new cursor has been inserted at the beginning of Container
+ and P_Positions_Shifted
+ (Positions (Container)'Old,
+ Positions (Container),
+ Cut => 1);
procedure Prepend
(Container : in out List;
New_Item : Element_Type;
- Count : Count_Type := 1)
+ Count : Count_Type)
+ with
+ Global => null,
+ Pre => Length (Container) <= Container.Capacity - Count,
+ Post =>
+ Length (Container) = Length (Container)'Old + Count
+
+ -- Elements are shifted by Count.
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 1,
+ Lst => Length (Container)'Old,
+ Offset => Count)
+
+ -- Container starts with Count times New_Item
+ and M_Elements_Cst
+ (S => Model (Container),
+ Fst => 1,
+ Lst => Count,
+ E => New_Item)
+
+ -- Count cursors have been inserted at the beginning of Container
+ and P_Positions_Shifted
+ (Positions (Container)'Old,
+ Positions (Container),
+ Cut => 1,
+ Count => Count);
+
+ procedure Append
+ (Container : in out List;
+ New_Item : Element_Type)
with
Global => null,
- Pre => Length (Container) + Count <= Container.Capacity;
+ Pre => Length (Container) < Container.Capacity,
+ Post => Length (Container) = Length (Container)'Old + 1
+
+ -- Positions contains a new mapping from the last cursor of
+ -- Container to its length.
+ and P.Is_Add
+ (Positions (Container)'Old, Last (Container), Length (Container),
+ Result => Positions (Container))
+
+ -- Model contains a new element New_Item at the end
+ and M.Is_Add (Model (Container)'Old, New_Item, Model (Container));
procedure Append
(Container : in out List;
New_Item : Element_Type;
- Count : Count_Type := 1)
+ Count : Count_Type)
+ with
+ Global => null,
+ Pre => Length (Container) <= Container.Capacity - Count,
+ Post =>
+ Length (Container) = Length (Container)'Old + Count
+
+ -- The elements of Container are preserved
+ and Model (Container)'Old <= Model (Container)
+
+ -- Container contains Count times New_Item at the end
+ and M_Elements_Cst
+ (S => Model (Container),
+ Fst => Length (Container)'Old + 1,
+ Lst => Length (Container),
+ E => New_Item)
+
+ -- Count cursors have been inserted at the end of Container
+ and P_Positions_Truncated
+ (Positions (Container)'Old,
+ Positions (Container),
+ Cut => Length (Container)'Old + 1,
+ Count => Count);
+
+ procedure Delete
+ (Container : in out List;
+ Position : in out Cursor)
with
Global => null,
- Pre => Length (Container) + Count <= Container.Capacity;
+ Pre => Has_Element (Container, Position),
+ Post =>
+ Length (Container) = Length (Container)'Old - 1
+
+ -- Position is set to No_Element
+ and Position = No_Element
+
+ -- The elements of Container located before Position are preserved.
+ and M_Elements_Equal
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 1,
+ Lst => P.Get (Positions (Container)'Old, Position'Old) - 1)
+
+ -- The elements located after Position are shifted by 1
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => P.Get (Positions (Container)'Old, Position'Old) + 1,
+ Lst => Length (Container)'Old,
+ Offset => -1)
+
+ -- Position has been removed from Container
+ and P_Positions_Shifted
+ (Positions (Container),
+ Positions (Container)'Old,
+ Cut => P.Get (Positions (Container)'Old, Position'Old));
procedure Delete
(Container : in out List;
Position : in out Cursor;
- Count : Count_Type := 1)
+ Count : Count_Type)
+ with
+ Global => null,
+ Pre => Has_Element (Container, Position),
+ Post =>
+ Length (Container) in Length (Container)'Old - Count
+ .. Length (Container)'Old
+
+ -- Position is set to No_Element
+ and Position = No_Element
+
+ -- The elements of Container located before Position are preserved.
+ and M_Elements_Equal
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 1,
+ Lst => P.Get (Positions (Container)'Old, Position'Old) - 1),
+ Contract_Cases =>
+
+ -- All the elements after Position have been erased
+ (Length (Container) - Count < P.Get (Positions (Container), Position)
+ =>
+
+ Length (Container) =
+ P.Get (Positions (Container)'Old, Position'Old) - 1
+
+ -- At most Count cursors have been removed at the end of Container
+ and P_Positions_Truncated
+ (Positions (Container),
+ Positions (Container)'Old,
+ Cut => P.Get (Positions (Container)'Old, Position'Old),
+ Count => Count),
+ others =>
+ Length (Container) = Length (Container)'Old - Count
+
+ -- Other elements are shifted by Count
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst =>
+ P.Get (Positions (Container)'Old, Position'Old) + Count,
+ Lst => Length (Container)'Old,
+ Offset => -Count)
+
+ -- Count cursors have been removed from Container at Position
+ and P_Positions_Shifted
+ (Positions (Container),
+ Positions (Container)'Old,
+ Cut => P.Get (Positions (Container)'Old, Position'Old),
+ Count => Count));
+
+ procedure Delete_First (Container : in out List)
with
Global => null,
- Pre => Has_Element (Container, Position);
+ Pre => not Is_Empty (Container),
+ Post =>
+ Length (Container) = Length (Container)'Old - 1
+
+ -- The elements of Container are shifted by 1
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 2,
+ Lst => Length (Container)'Old,
+ Offset => -1)
+
+ -- The first cursor of Container has been removed
+ and P_Positions_Shifted
+ (Positions (Container),
+ Positions (Container)'Old,
+ Cut => 1);
procedure Delete_First
(Container : in out List;
- Count : Count_Type := 1)
+ Count : Count_Type)
+ with
+ Global => null,
+ Contract_Cases =>
+
+ -- All the elements of Container have been erased
+ (Length (Container) <= Count => Length (Container) = 0,
+ others =>
+ Length (Container) = Length (Container)'Old - Count
+
+ -- Elements of Container are shifted by Count
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => Count + 1,
+ Lst => Length (Container)'Old,
+ Offset => -Count)
+
+ -- The first Count cursors have been removed from Container
+ and P_Positions_Shifted
+ (Positions (Container),
+ Positions (Container)'Old,
+ Cut => 1,
+ Count => Count));
+
+ procedure Delete_Last (Container : in out List)
with
- Global => null;
+ Global => null,
+ Pre => not Is_Empty (Container),
+ Post =>
+ Length (Container) = Length (Container)'Old - 1
+
+ -- The elements of Container are preserved.
+ and Model (Container) <= Model (Container)'Old
+
+ -- The last cursor of Container has been removed
+ and P.Is_Add (Positions (Container), Last (Container)'Old,
+ Length (Container)'Old, Positions (Container)'Old);
procedure Delete_Last
(Container : in out List;
- Count : Count_Type := 1)
+ Count : Count_Type)
with
- Global => null;
+ Global => null,
+ Contract_Cases =>
+
+ -- All the elements of Container have been erased
+ (Length (Container) <= Count => Length (Container) = 0,
+ others =>
+
+ Length (Container) = Length (Container)'Old - Count
+
+ -- The elements of Container are preserved.
+ and Model (Container) <= Model (Container)'Old
+
+ -- At most Count cursors have been removed at the end of Container
+ and P_Positions_Truncated
+ (Positions (Container),
+ Positions (Container)'Old,
+ Cut => Length (Container) + 1,
+ Count => Count));
procedure Reverse_Elements (Container : in out List) with
- Global => null;
+ Global => null,
+ Post => M_Elements_Reversed (Model (Container'Old), Model (Container));
procedure Swap
(Container : in out List;
I, J : Cursor)
with
Global => null,
- Pre => Has_Element (Container, I) and then Has_Element (Container, J);
+ Pre => Has_Element (Container, I) and then Has_Element (Container, J),
+ Post =>
+ M_Elements_Swapped
+ (Model (Container)'Old, Model (Container),
+ X => P.Get (Positions (Container)'Old, I),
+ Y => P.Get (Positions (Container)'Old, J))
+ and Positions (Container) = Positions (Container)'Old;
procedure Swap_Links
(Container : in out List;
I, J : Cursor)
with
Global => null,
- Pre => Has_Element (Container, I) and then Has_Element (Container, J);
+ Pre => Has_Element (Container, I) and then Has_Element (Container, J),
+ Post =>
+ M_Elements_Swapped
+ (Model (Container'Old), Model (Container),
+ X => P.Get (Positions (Container)'Old, I),
+ Y => P.Get (Positions (Container)'Old, J))
+ and P_Positions_Swapped
+ (Positions (Container)'Old, Positions (Container), I, J);
procedure Splice
(Target : in out List;
Before : Cursor;
Source : in out List)
+ -- Target and Source should not be aliased
with
- Global => null,
- Pre => Length (Source) + Length (Target) <= Target.Capacity
- and then (Has_Element (Target, Before)
- or else Before = No_Element);
+ Global => null,
+ Pre =>
+ Length (Source) <= Target.Capacity - Length (Target)
+ and then (Has_Element (Target, Before)
+ or else Before = No_Element),
+ Post =>
+ Length (Source) = 0
+ and Length (Target) = Length (Target)'Old + Length (Source)'Old,
+ Contract_Cases =>
+ (Before = No_Element =>
+
+ -- The elements of Target are preserved
+ M_Elements_Equal
+ (S1 => Model (Target)'Old,
+ S2 => Model (Target),
+ Fst => 1,
+ Lst => Length (Target)'Old)
+
+ -- The elements of Source are appended to target, the order is not
+ -- specified.
+ and M_Elements_Shuffle
+ (S1 => Model (Source)'Old,
+ S2 => Model (Target),
+ Fst => 1,
+ Lst => Length (Source)'Old,
+ Offset => Length (Target)'Old)
+
+ -- Cursors have been inserted at the end of Target
+ and P_Positions_Truncated
+ (Positions (Target)'Old,
+ Positions (Target),
+ Cut => Length (Target)'Old + 1,
+ Count => Length (Source)'Old),
+ others =>
+
+ -- The elements of Target located before Before are preserved
+ M_Elements_Equal
+ (S1 => Model (Target)'Old,
+ S2 => Model (Target),
+ Fst => 1,
+ Lst => P.Get (Positions (Target)'Old, Before) - 1)
+
+ -- The elements of Source are inserted before Before, the order is
+ -- not specified.
+ and M_Elements_Shuffle
+ (S1 => Model (Source)'Old,
+ S2 => Model (Target),
+ Fst => 1,
+ Lst => Length (Source)'Old,
+ Offset => P.Get (Positions (Target)'Old, Before) - 1)
+
+ -- Other elements are shifted by the length of Source
+ and M_Elements_Shifted
+ (S1 => Model (Target)'Old,
+ S2 => Model (Target),
+ Fst => P.Get (Positions (Target)'Old, Before),
+ Lst => Length (Target)'Old,
+ Offset => Length (Source)'Old)
+
+ -- Cursors have been inserted at position Before in Target
+ and P_Positions_Shifted
+ (Positions (Target)'Old,
+ Positions (Target),
+ Cut => P.Get (Positions (Target)'Old, Before),
+ Count => Length (Source)'Old));
procedure Splice
(Target : in out List;
Before : Cursor;
Source : in out List;
Position : in out Cursor)
+ -- Target and Source should not be aliased
with
Global => null,
- Pre => Length (Source) + Length (Target) <= Target.Capacity
- and then (Has_Element (Target, Before)
- or else Before = No_Element)
- and then Has_Element (Source, Position);
+ Pre =>
+ (Has_Element (Target, Before)
+ or else Before = No_Element)
+ and then Has_Element (Source, Position)
+ and then Length (Target) < Target.Capacity,
+ Post =>
+ Length (Target) = Length (Target)'Old + 1
+ and Length (Source) = Length (Source)'Old - 1
+
+ -- The elements of Source located before Position are preserved.
+ and M_Elements_Equal
+ (S1 => Model (Source)'Old,
+ S2 => Model (Source),
+ Fst => 1,
+ Lst => P.Get (Positions (Source)'Old, Position'Old) - 1)
+
+ -- The elements located after Position are shifted by 1
+ and M_Elements_Shifted
+ (S1 => Model (Source)'Old,
+ S2 => Model (Source),
+ Fst => P.Get (Positions (Source)'Old, Position'Old) + 1,
+ Lst => Length (Source)'Old,
+ Offset => -1)
+
+ -- Position has been removed from Source
+ and P_Positions_Shifted
+ (Positions (Source),
+ Positions (Source)'Old,
+ Cut => P.Get (Positions (Source)'Old, Position'Old))
+
+ -- Positions is valid in Target and it is located either before
+ -- Before if it is valid in Target or at the end if it is
+ -- No_Element.
+ and P.Mem (Positions (Target), Position)
+ and (if Before = No_Element
+ then P.Get (Positions (Target), Position)
+ = Length (Target)
+ else P.Get (Positions (Target), Position)
+ = P.Get (Positions (Target)'Old, Before))
+
+ -- The elements of Target located before Position are preserved.
+ and M_Elements_Equal
+ (S1 => Model (Target)'Old,
+ S2 => Model (Target),
+ Fst => 1,
+ Lst => P.Get (Positions (Target), Position) - 1)
+
+ -- Other elements are shifted by 1.
+ and M_Elements_Shifted
+ (S1 => Model (Target)'Old,
+ S2 => Model (Target),
+ Fst => P.Get (Positions (Target), Position),
+ Lst => Length (Target)'Old,
+ Offset => 1)
+
+ -- The element located at Position in Source is moved to Target
+ and Element (Model (Target), P.Get (Positions (Target), Position))
+ = Element (Model (Source)'Old,
+ P.Get (Positions (Source)'Old, Position'Old))
+
+ -- A new cursor has been inserted at position Position in Target
+ and P_Positions_Shifted
+ (Positions (Target)'Old,
+ Positions (Target),
+ Cut => P.Get (Positions (Target), Position));
procedure Splice
(Container : in out List;
Before : Cursor;
Position : Cursor)
with
- Global => null,
- Pre => 2 * Length (Container) <= Container.Capacity
- and then (Has_Element (Container, Before)
- or else Before = No_Element)
- and then Has_Element (Container, Position);
+ Global => null,
+ Pre =>
+ (Has_Element (Container, Before) or else Before = No_Element)
+ and then Has_Element (Container, Position),
+ Post => Length (Container) = Length (Container)'Old,
+ Contract_Cases =>
+ (Before = Position =>
+ Model (Container) = Model (Container)'Old
+ and Positions (Container) = Positions (Container)'Old,
+
+ Before = No_Element =>
+
+ -- The elements located before Position are preserved
+ M_Elements_Equal
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 1,
+ Lst => P.Get (Positions (Container)'Old, Position) - 1)
+
+ -- The elements located after Position are shifted by 1
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => P.Get (Positions (Container)'Old, Position) + 1,
+ Lst => Length (Container)'Old,
+ Offset => -1)
+
+ -- The last element of Container is the one that was previously
+ -- at Position.
+ and Element (Model (Container), Length (Container))
+ = Element (Model (Container)'Old,
+ P.Get (Positions (Container)'Old, Position))
+
+ -- Cursors from Container continue designating the same elements
+ and Mapping_Preserved
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ M1 => Positions (Container)'Old,
+ M2 => Positions (Container)),
+
+ others =>
+
+ -- The elements located before Position and Before are preserved
+ M_Elements_Equal
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => 1,
+ Lst => Count_Type'Min
+ (P.Get (Positions (Container)'Old, Position) - 1,
+ P.Get (Positions (Container)'Old, Before) - 1))
+
+ -- The elements located after Position and Before are preserved
+ and M_Elements_Equal
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => Count_Type'Max
+ (P.Get (Positions (Container)'Old, Position) + 1,
+ P.Get (Positions (Container)'Old, Before) + 1),
+ Lst => Length (Container))
+
+ -- The elements located after Before and before Position are shifted
+ -- by 1 to the right.
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => P.Get (Positions (Container)'Old, Before) + 1,
+ Lst => P.Get (Positions (Container)'Old, Position) - 1,
+ Offset => 1)
+
+ -- The elements located after Position and before Before are shifted
+ -- by 1 to the left.
+ and M_Elements_Shifted
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ Fst => P.Get (Positions (Container)'Old, Position) + 1,
+ Lst => P.Get (Positions (Container)'Old, Before) - 1,
+ Offset => -1)
+
+ -- The element previously at Position is now before Before
+ and Element (Model (Container),
+ P.Get (Positions (Container)'Old, Before))
+ = Element (Model (Container)'Old,
+ P.Get (Positions (Container)'Old, Position))
+
+ -- Cursors from Container continue designating the same elements
+ and Mapping_Preserved
+ (S1 => Model (Container)'Old,
+ S2 => Model (Container),
+ M1 => Positions (Container)'Old,
+ M2 => Positions (Container)));
function First (Container : List) return Cursor with
- Global => null;
+ Global => null,
+ Contract_Cases =>
+ (Length (Container) = 0 => First'Result = No_Element,
+ others => Has_Element (Container, First'Result)
+ and P.Get (Positions (Container), First'Result) = 1);
function First_Element (Container : List) return Element_Type with
Global => null,
- Pre => not Is_Empty (Container);
+ Pre => not Is_Empty (Container),
+ Post => First_Element'Result = M.Get (Model (Container), 1);
function Last (Container : List) return Cursor with
- Global => null;
+ Global => null,
+ Contract_Cases =>
+ (Length (Container) = 0 => Last'Result = No_Element,
+ others => Has_Element (Container, Last'Result)
+ and P.Get (Positions (Container), Last'Result) = Length (Container));
function Last_Element (Container : List) return Element_Type with
Global => null,
- Pre => not Is_Empty (Container);
+ Pre => not Is_Empty (Container),
+ Post => Last_Element'Result
+ = M.Get (Model (Container), Length (Container));
function Next (Container : List; Position : Cursor) return Cursor with
- Global => null,
- Pre => Has_Element (Container, Position) or else Position = No_Element;
+ Global => null,
+ Pre => Has_Element (Container, Position)
+ or else Position = No_Element,
+ Contract_Cases =>
+ (Position = No_Element
+ or else P.Get (Positions (Container), Position) = Length (Container) =>
+ Next'Result = No_Element,
+ others => Has_Element (Container, Next'Result)
+ and then P.Get (Positions (Container), Next'Result) =
+ P.Get (Positions (Container), Position) + 1);
procedure Next (Container : List; Position : in out Cursor) with
- Global => null,
- Pre => Has_Element (Container, Position) or else Position = No_Element;
+ Global => null,
+ Pre => Has_Element (Container, Position)
+ or else Position = No_Element,
+ Contract_Cases =>
+ (Position = No_Element
+ or else P.Get (Positions (Container), Position) = Length (Container) =>
+ Position = No_Element,
+ others => Has_Element (Container, Position)
+ and then P.Get (Positions (Container), Position) =
+ P.Get (Positions (Container), Position'Old) + 1);
function Previous (Container : List; Position : Cursor) return Cursor with
- Global => null,
- Pre => Has_Element (Container, Position) or else Position = No_Element;
+ Global => null,
+ Pre => Has_Element (Container, Position)
+ or else Position = No_Element,
+ Contract_Cases =>
+ (Position = No_Element
+ or else P.Get (Positions (Container), Position) = 1 =>
+ Previous'Result = No_Element,
+ others =>
+ Has_Element (Container, Previous'Result)
+ and then P.Get (Positions (Container), Previous'Result) =
+ P.Get (Positions (Container), Position) - 1);
procedure Previous (Container : List; Position : in out Cursor) with
- Global => null,
- Pre => Has_Element (Container, Position) or else Position = No_Element;
+ Global => null,
+ Pre => Has_Element (Container, Position)
+ or else Position = No_Element,
+ Contract_Cases =>
+ (Position = No_Element
+ or else P.Get (Positions (Container), Position) = 1 =>
+ Position = No_Element,
+ others =>
+ Has_Element (Container, Position)
+ and then P.Get (Positions (Container), Position) =
+ P.Get (Positions (Container), Position'Old) - 1);
function Find
(Container : List;
Item : Element_Type;
Position : Cursor := No_Element) return Cursor
with
- Global => null,
- Pre => Has_Element (Container, Position) or else Position = No_Element;
+ Global => null,
+ Pre =>
+ Has_Element (Container, Position) or else Position = No_Element,
+ Contract_Cases =>
+
+ -- If Item is not is not contained in Container after Position, Find
+ -- returns No_Element.
+ (not M_Elements_Contains
+ (S => Model (Container),
+ Fst => (if Position = No_Element then 1
+ else P.Get (Positions (Container), Position)),
+ Lst => Length (Container),
+ E => Item)
+ =>
+ Find'Result = No_Element,
+
+ -- Otherwise, Find returns a valid cusror in Container
+ others =>
+ P.Mem (Positions (Container), Find'Result)
+
+ -- The element designated by the result of Find is Item
+ and Element (Model (Container),
+ P.Get (Positions (Container), Find'Result)) = Item
+
+ -- The result of Find is located after Position
+ and (if Position /= No_Element
+ then P.Get (Positions (Container), Find'Result)
+ >= P.Get (Positions (Container), Position))
+
+ -- It is the first occurence of Item in this slice
+ and not M_Elements_Contains
+ (S => Model (Container),
+ Fst => (if Position = No_Element then 1
+ else P.Get (Positions (Container), Position)),
+ Lst => P.Get (Positions (Container), Find'Result) - 1,
+ E => Item));
function Reverse_Find
(Container : List;
Item : Element_Type;
Position : Cursor := No_Element) return Cursor
with
- Global => null,
- Pre => Has_Element (Container, Position) or else Position = No_Element;
+ Global => null,
+ Pre =>
+ Has_Element (Container, Position) or else Position = No_Element,
+ Contract_Cases =>
+
+ -- If Item is not is not contained in Container before Position, Find
+ -- returns No_Element.
+ (not M_Elements_Contains
+ (S => Model (Container),
+ Fst => 1,
+ Lst => (if Position = No_Element then Length (Container)
+ else P.Get (Positions (Container), Position)),
+ E => Item)
+ =>
+ Reverse_Find'Result = No_Element,
+
+ -- Otherwise, Find returns a valid cusror in Container
+ others =>
+ P.Mem (Positions (Container), Reverse_Find'Result)
+
+ -- The element designated by the result of Find is Item
+ and Element (Model (Container),
+ P.Get (Positions (Container), Reverse_Find'Result)) = Item
+
+ -- The result of Find is located before Position
+ and (if Position /= No_Element
+ then P.Get (Positions (Container), Reverse_Find'Result)
+ <= P.Get (Positions (Container), Position))
+
+ -- It is the last occurence of Item in this slice
+ and not M_Elements_Contains
+ (S => Model (Container),
+ Fst => P.Get (Positions (Container), Reverse_Find'Result) + 1,
+ Lst => (if Position = No_Element then Length (Container)
+ else P.Get (Positions (Container), Position)),
+ E => Item));
function Contains
(Container : List;
Item : Element_Type) return Boolean
with
- Global => null;
+ Global => null,
+ Post => Contains'Result =
+ M_Elements_Contains
+ (S => Model (Container),
+ Fst => 1,
+ Lst => Length (Container),
+ E => Item);
function Has_Element (Container : List; Position : Cursor) return Boolean
with
- Global => null;
+ Global => null,
+ Post => Has_Element'Result = P.Mem (Positions (Container), Position);
+ pragma Annotate (GNATprove, Inline_For_Proof, Has_Element);
generic
with function "<" (Left, Right : Element_Type) return Boolean is <>;
package Generic_Sorting with SPARK_Mode is
+ function M_Elements_Sorted (S : M.Sequence) return Boolean with
+ Ghost,
+ Global => null,
+ Post => M_Elements_Sorted'Result =
+ (for all I in 1 .. M.Length (S) =>
+ (for all J in I + 1 .. M.Length (S) =>
+ Element (S, I) = Element (S, J)
+ or Element (S, I) < Element (S, J)));
+ pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Sorted);
function Is_Sorted (Container : List) return Boolean with
- Global => null;
+ Global => null,
+ Post => Is_Sorted'Result = M_Elements_Sorted (Model (Container));
procedure Sort (Container : in out List) with
- Global => null;
+ Global => null,
+ Post => Length (Container) = Length (Container)'Old
+ and M_Elements_Sorted (Model (Container));
procedure Merge (Target, Source : in out List) with
- Global => null;
-
+ -- Target and Source should not be aliased
+ Global => null,
+ Pre => Length (Source) <= Target.Capacity - Length (Target),
+ Post => Length (Target) = Length (Target)'Old + Length (Source)'Old
+ and Length (Source) = 0
+ and (if M_Elements_Sorted (Model (Target)'Old)
+ and M_Elements_Sorted (Model (Source)'Old)
+ then M_Elements_Sorted (Model (Target)));
end Generic_Sorting;
- function Strict_Equal (Left, Right : List) return Boolean with
- Ghost,
- Global => null;
- -- Strict_Equal returns True if the containers are physically equal, i.e.
- -- they are structurally equal (function "=" returns True) and that they
- -- have the same set of cursors.
-
- function First_To_Previous (Container : List; Current : Cursor) return List
- with
- Ghost,
- Global => null,
- Pre => Has_Element (Container, Current) or else Current = No_Element;
-
- function Current_To_Last (Container : List; Current : Cursor) return List
- with
- Ghost,
- Global => null,
- Pre => Has_Element (Container, Current) or else Current = No_Element;
- -- First_To_Previous returns a container containing all elements preceding
- -- Current (excluded) in Container. Current_To_Last returns a container
- -- containing all elements following Current (included) in Container.
- -- These two new functions can be used to express invariant properties in
- -- loops which iterate over containers. First_To_Previous returns the part
- -- of the container already scanned and Current_To_Last the part not
- -- scanned yet.
-
private
pragma SPARK_Mode (Off);
@@ -361,12 +1405,6 @@ private
Nodes : Node_Array (1 .. Capacity) := (others => <>);
end record;
- type Cursor is record
- Node : Count_Type := 0;
- end record;
-
Empty_List : constant List := (0, others => <>);
- No_Element : constant Cursor := (Node => 0);
-
end Ada.Containers.Formal_Doubly_Linked_Lists;