mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-02 08:40:26 +08:00
[Ada] Replace SPARK containers implementation by Compile_Time_Error
The SPARK containers are now maintained under the spark2014 repository. This change replaces the implementation of SPARK containers by a pragma Compile_Time_Error, pointing the users WITHing the libraries to their new location. gcc/ada/ * Makefile.rtl: Remove SPARK containers filenames. * impunit.adb: Remove SPARK containers packages names. * libgnat/a-cfdlli.adb, libgnat/a-cfdlli.ads: Remove content and add pragma Compile_Time_Error with suitable message. * libgnat/a-cfhama.adb, libgnat/a-cfhama.ads: Likewise. * libgnat/a-cfhase.adb, libgnat/a-cfhase.ads: Likewise. * libgnat/a-cfidll.adb, libgnat/a-cfidll.ads: Likewise. * libgnat/a-cfinse.adb, libgnat/a-cfinse.ads: Likewise. * libgnat/a-cfinve.adb, libgnat/a-cfinve.ads: Likewise. * libgnat/a-cforma.adb, libgnat/a-cforma.ads: Likewise. * libgnat/a-cforse.adb, libgnat/a-cforse.ads: Likewise. * libgnat/a-cofove.adb, libgnat/a-cofove.ads: Likewise. * libgnat/a-cofuma.adb, libgnat/a-cofuma.ads: Likewise. * libgnat/a-cofuse.adb, libgnat/a-cofuse.ads: Likewise. * libgnat/a-cofuve.adb, libgnat/a-cofuve.ads: Likewise. * libgnat/a-cofuba.adb, libgnat/a-cofuba.ads: Remove package. gcc/testsuite/ * gnat.dg/aspect2.adb: Removed. * gnat.dg/aspect2.ads: Removed. * gnat.dg/config_pragma1.adb: Removed. * gnat.dg/config_pragma1_pkg.ads: Removed. * gnat.dg/equal8.adb: Removed. * gnat.dg/equal8.ads: Removed. * gnat.dg/equal8_pkg.ads: Removed. * gnat.dg/formal_containers.adb: Removed. * gnat.dg/iter1.adb: Removed. * gnat.dg/iter1.ads: Removed.
This commit is contained in:
parent
cf8af60f6a
commit
4a7312f7ce
@ -110,14 +110,6 @@ GNATRTL_NONTASKING_OBJS= \
|
||||
a-cbprqu$(objext) \
|
||||
a-cbsyqu$(objext) \
|
||||
a-cdlili$(objext) \
|
||||
a-cfdlli$(objext) \
|
||||
a-cfhama$(objext) \
|
||||
a-cfhase$(objext) \
|
||||
a-cfidll$(objext) \
|
||||
a-cfinve$(objext) \
|
||||
a-cfinse$(objext) \
|
||||
a-cforma$(objext) \
|
||||
a-cforse$(objext) \
|
||||
a-cgaaso$(objext) \
|
||||
a-cgarso$(objext) \
|
||||
a-cgcaso$(objext) \
|
||||
@ -144,14 +136,7 @@ GNATRTL_NONTASKING_OBJS= \
|
||||
a-clrefi$(objext) \
|
||||
a-coboho$(objext) \
|
||||
a-cobove$(objext) \
|
||||
a-cofove$(objext) \
|
||||
a-cofuba$(objext) \
|
||||
a-cofuma$(objext) \
|
||||
a-cofuse$(objext) \
|
||||
a-cofuve$(objext) \
|
||||
a-cogeso$(objext) \
|
||||
a-cohama$(objext) \
|
||||
a-cohase$(objext) \
|
||||
a-cohata$(objext) \
|
||||
a-coinho$(objext) \
|
||||
a-coinve$(objext) \
|
||||
|
@ -605,19 +605,7 @@ package body Impunit is
|
||||
-- GNAT Defined Additions to Ada 2012 --
|
||||
----------------------------------------
|
||||
|
||||
("a-cfidll", F), -- Ada.Containers.Formal_Indefinite_Doubly_Linked_Lists
|
||||
("a-cfinse", F), -- Ada.Containers.Functional_Infinite_Sequences
|
||||
("a-cfinve", F), -- Ada.Containers.Formal_Indefinite_Vectors
|
||||
("a-coboho", F), -- Ada.Containers.Bounded_Holders
|
||||
("a-cofove", F), -- Ada.Containers.Formal_Vectors
|
||||
("a-cofuma", F), -- Ada.Containers.Functional_Maps
|
||||
("a-cofuse", F), -- Ada.Containers.Functional_Sets
|
||||
("a-cofuve", F), -- Ada.Containers.Functional_Vectors
|
||||
("a-cfdlli", F), -- Ada.Containers.Formal_Doubly_Linked_Lists
|
||||
("a-cforse", F), -- Ada.Containers.Formal_Ordered_Sets
|
||||
("a-cforma", F), -- Ada.Containers.Formal_Ordered_Maps
|
||||
("a-cfhase", F), -- Ada.Containers.Formal_Hashed_Sets
|
||||
("a-cfhama", F), -- Ada.Containers.Formal_Hashed_Maps
|
||||
("a-cvgpso", F) -- Ada.Containers.Vectors.Generic_Parallel_Sorting from
|
||||
); -- GNATCOLL.OMP
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,976 +0,0 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- --
|
||||
-- GNAT LIBRARY COMPONENTS --
|
||||
-- --
|
||||
-- A D A . C O N T A I N E R S . F O R M A L _ H A S H E D _ M A P S --
|
||||
-- --
|
||||
-- B o d y --
|
||||
-- --
|
||||
-- Copyright (C) 2010-2022, Free Software Foundation, Inc. --
|
||||
-- --
|
||||
-- GNAT is free software; you can redistribute it and/or modify it under --
|
||||
-- terms of the GNU General Public License as published by the Free Soft- --
|
||||
-- ware Foundation; either version 3, or (at your option) any later ver- --
|
||||
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
||||
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
||||
-- or FITNESS FOR A PARTICULAR PURPOSE. --
|
||||
-- --
|
||||
-- As a special exception under Section 7 of GPL version 3, you are granted --
|
||||
-- additional permissions described in the GCC Runtime Library Exception, --
|
||||
-- version 3.1, as published by the Free Software Foundation. --
|
||||
-- --
|
||||
-- You should have received a copy of the GNU General Public License and --
|
||||
-- a copy of the GCC Runtime Library Exception along with this program; --
|
||||
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
with Ada.Containers.Hash_Tables.Generic_Formal_Operations;
|
||||
pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Formal_Operations);
|
||||
|
||||
with Ada.Containers.Hash_Tables.Generic_Formal_Keys;
|
||||
pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Formal_Keys);
|
||||
|
||||
with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
|
||||
|
||||
with Ada.Numerics.Big_Numbers.Big_Integers;
|
||||
use Ada.Numerics.Big_Numbers.Big_Integers;
|
||||
|
||||
with System; use type System.Address;
|
||||
|
||||
package body Ada.Containers.Formal_Hashed_Maps with
|
||||
SPARK_Mode => Off
|
||||
is
|
||||
-----------------------
|
||||
-- Local Subprograms --
|
||||
-----------------------
|
||||
|
||||
-- All local subprograms require comments ???
|
||||
|
||||
function Equivalent_Keys
|
||||
(Key : Key_Type;
|
||||
Node : Node_Type) return Boolean;
|
||||
pragma Inline (Equivalent_Keys);
|
||||
|
||||
procedure Free
|
||||
(HT : in out Map;
|
||||
X : Count_Type);
|
||||
|
||||
generic
|
||||
with procedure Set_Element (Node : in out Node_Type);
|
||||
procedure Generic_Allocate
|
||||
(HT : in out HT_Types.Hash_Table_Type;
|
||||
Node : out Count_Type);
|
||||
|
||||
function Hash_Node (Node : Node_Type) return Hash_Type;
|
||||
pragma Inline (Hash_Node);
|
||||
|
||||
function Next (Node : Node_Type) return Count_Type;
|
||||
pragma Inline (Next);
|
||||
|
||||
procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
|
||||
pragma Inline (Set_Next);
|
||||
|
||||
function Vet (Container : Map; Position : Cursor) return Boolean
|
||||
with Inline;
|
||||
|
||||
-- Convert Count_Type to Big_Interger
|
||||
|
||||
package Conversions is new Signed_Conversions (Int => Count_Type);
|
||||
|
||||
function Big (J : Count_Type) return Big_Integer renames
|
||||
Conversions.To_Big_Integer;
|
||||
|
||||
--------------------------
|
||||
-- Local Instantiations --
|
||||
--------------------------
|
||||
|
||||
package HT_Ops is
|
||||
new Hash_Tables.Generic_Formal_Operations
|
||||
(HT_Types => HT_Types,
|
||||
Hash_Node => Hash_Node,
|
||||
Next => Next,
|
||||
Set_Next => Set_Next);
|
||||
|
||||
package Key_Ops is
|
||||
new Hash_Tables.Generic_Formal_Keys
|
||||
(HT_Types => HT_Types,
|
||||
Next => Next,
|
||||
Set_Next => Set_Next,
|
||||
Key_Type => Key_Type,
|
||||
Hash => Hash,
|
||||
Equivalent_Keys => Equivalent_Keys);
|
||||
|
||||
---------
|
||||
-- "=" --
|
||||
---------
|
||||
|
||||
function "=" (Left, Right : Map) return Boolean is
|
||||
begin
|
||||
if Length (Left) /= Length (Right) then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
if Length (Left) = 0 then
|
||||
return True;
|
||||
end if;
|
||||
|
||||
declare
|
||||
Node : Count_Type;
|
||||
ENode : Count_Type;
|
||||
|
||||
begin
|
||||
Node := First (Left).Node;
|
||||
while Node /= 0 loop
|
||||
ENode :=
|
||||
Find
|
||||
(Container => Right,
|
||||
Key => Left.Content.Nodes (Node).Key).Node;
|
||||
|
||||
if ENode = 0 or else
|
||||
Right.Content.Nodes (ENode).Element /=
|
||||
Left.Content.Nodes (Node).Element
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
Node := HT_Ops.Next (Left.Content, Node);
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end;
|
||||
end "=";
|
||||
|
||||
------------
|
||||
-- Assign --
|
||||
------------
|
||||
|
||||
procedure Assign (Target : in out Map; Source : Map) is
|
||||
procedure Insert_Element (Source_Node : Count_Type);
|
||||
pragma Inline (Insert_Element);
|
||||
|
||||
procedure Insert_Elements is
|
||||
new HT_Ops.Generic_Iteration (Insert_Element);
|
||||
|
||||
--------------------
|
||||
-- Insert_Element --
|
||||
--------------------
|
||||
|
||||
procedure Insert_Element (Source_Node : Count_Type) is
|
||||
N : Node_Type renames Source.Content.Nodes (Source_Node);
|
||||
begin
|
||||
Insert (Target, N.Key, N.Element);
|
||||
end Insert_Element;
|
||||
|
||||
-- Start of processing for Assign
|
||||
|
||||
begin
|
||||
if Target.Capacity < Length (Source) then
|
||||
raise Constraint_Error with -- correct exception ???
|
||||
"Source length exceeds Target capacity";
|
||||
end if;
|
||||
|
||||
Clear (Target);
|
||||
|
||||
Insert_Elements (Source.Content);
|
||||
end Assign;
|
||||
|
||||
--------------
|
||||
-- Capacity --
|
||||
--------------
|
||||
|
||||
function Capacity (Container : Map) return Count_Type is
|
||||
begin
|
||||
return Container.Content.Nodes'Length;
|
||||
end Capacity;
|
||||
|
||||
-----------
|
||||
-- Clear --
|
||||
-----------
|
||||
|
||||
procedure Clear (Container : in out Map) is
|
||||
begin
|
||||
HT_Ops.Clear (Container.Content);
|
||||
end Clear;
|
||||
|
||||
------------------------
|
||||
-- Constant_Reference --
|
||||
------------------------
|
||||
|
||||
function Constant_Reference
|
||||
(Container : aliased Map;
|
||||
Position : Cursor) return not null access constant Element_Type
|
||||
is
|
||||
begin
|
||||
if not Has_Element (Container, Position) then
|
||||
raise Constraint_Error with "Position cursor has no element";
|
||||
end if;
|
||||
|
||||
pragma Assert
|
||||
(Vet (Container, Position),
|
||||
"bad cursor in function Constant_Reference");
|
||||
|
||||
return Container.Content.Nodes (Position.Node).Element'Access;
|
||||
end Constant_Reference;
|
||||
|
||||
function Constant_Reference
|
||||
(Container : aliased Map;
|
||||
Key : Key_Type) return not null access constant Element_Type
|
||||
is
|
||||
Node : constant Count_Type := Find (Container, Key).Node;
|
||||
|
||||
begin
|
||||
if Node = 0 then
|
||||
raise Constraint_Error with
|
||||
"no element available because key not in map";
|
||||
end if;
|
||||
|
||||
return Container.Content.Nodes (Node).Element'Access;
|
||||
end Constant_Reference;
|
||||
|
||||
--------------
|
||||
-- Contains --
|
||||
--------------
|
||||
|
||||
function Contains (Container : Map; Key : Key_Type) return Boolean is
|
||||
begin
|
||||
return Find (Container, Key) /= No_Element;
|
||||
end Contains;
|
||||
|
||||
----------
|
||||
-- Copy --
|
||||
----------
|
||||
|
||||
function Copy
|
||||
(Source : Map;
|
||||
Capacity : Count_Type := 0) return Map
|
||||
is
|
||||
C : constant Count_Type :=
|
||||
Count_Type'Max (Capacity, Source.Capacity);
|
||||
Cu : Cursor;
|
||||
H : Hash_Type;
|
||||
N : Count_Type;
|
||||
Target : Map (C, Source.Modulus);
|
||||
|
||||
begin
|
||||
if 0 < Capacity and then Capacity < Source.Capacity then
|
||||
raise Capacity_Error;
|
||||
end if;
|
||||
|
||||
Target.Content.Length := Source.Content.Length;
|
||||
Target.Content.Free := Source.Content.Free;
|
||||
|
||||
H := 1;
|
||||
while H <= Source.Modulus loop
|
||||
Target.Content.Buckets (H) := Source.Content.Buckets (H);
|
||||
H := H + 1;
|
||||
end loop;
|
||||
|
||||
N := 1;
|
||||
while N <= Source.Capacity loop
|
||||
Target.Content.Nodes (N) := Source.Content.Nodes (N);
|
||||
N := N + 1;
|
||||
end loop;
|
||||
|
||||
while N <= C loop
|
||||
Cu := (Node => N);
|
||||
Free (Target, Cu.Node);
|
||||
N := N + 1;
|
||||
end loop;
|
||||
|
||||
return Target;
|
||||
end Copy;
|
||||
|
||||
---------------------
|
||||
-- Default_Modulus --
|
||||
---------------------
|
||||
|
||||
function Default_Modulus (Capacity : Count_Type) return Hash_Type is
|
||||
begin
|
||||
return To_Prime (Capacity);
|
||||
end Default_Modulus;
|
||||
|
||||
------------
|
||||
-- Delete --
|
||||
------------
|
||||
|
||||
procedure Delete (Container : in out Map; Key : Key_Type) is
|
||||
X : Count_Type;
|
||||
|
||||
begin
|
||||
Key_Ops.Delete_Key_Sans_Free (Container.Content, Key, X);
|
||||
|
||||
if X = 0 then
|
||||
raise Constraint_Error with "attempt to delete key not in map";
|
||||
end if;
|
||||
|
||||
Free (Container, X);
|
||||
end Delete;
|
||||
|
||||
procedure Delete (Container : in out Map; Position : in out Cursor) is
|
||||
begin
|
||||
if not Has_Element (Container, Position) then
|
||||
raise Constraint_Error with
|
||||
"Position cursor of Delete has no element";
|
||||
end if;
|
||||
|
||||
pragma Assert (Vet (Container, Position), "bad cursor in Delete");
|
||||
|
||||
HT_Ops.Delete_Node_Sans_Free (Container.Content, Position.Node);
|
||||
|
||||
Free (Container, Position.Node);
|
||||
Position := No_Element;
|
||||
end Delete;
|
||||
|
||||
-------------
|
||||
-- Element --
|
||||
-------------
|
||||
|
||||
function Element (Container : Map; Key : Key_Type) return Element_Type is
|
||||
Node : constant Count_Type := Find (Container, Key).Node;
|
||||
|
||||
begin
|
||||
if Node = 0 then
|
||||
raise Constraint_Error with
|
||||
"no element available because key not in map";
|
||||
end if;
|
||||
|
||||
return Container.Content.Nodes (Node).Element;
|
||||
end Element;
|
||||
|
||||
function Element (Container : Map; Position : Cursor) return Element_Type is
|
||||
begin
|
||||
if not Has_Element (Container, Position) then
|
||||
raise Constraint_Error with "Position cursor equals No_Element";
|
||||
end if;
|
||||
|
||||
pragma Assert
|
||||
(Vet (Container, Position), "bad cursor in function Element");
|
||||
|
||||
return Container.Content.Nodes (Position.Node).Element;
|
||||
end Element;
|
||||
|
||||
---------------------
|
||||
-- Equivalent_Keys --
|
||||
---------------------
|
||||
|
||||
function Equivalent_Keys
|
||||
(Key : Key_Type;
|
||||
Node : Node_Type) return Boolean
|
||||
is
|
||||
begin
|
||||
return Equivalent_Keys (Key, Node.Key);
|
||||
end Equivalent_Keys;
|
||||
|
||||
-------------
|
||||
-- Exclude --
|
||||
-------------
|
||||
|
||||
procedure Exclude (Container : in out Map; Key : Key_Type) is
|
||||
X : Count_Type;
|
||||
begin
|
||||
Key_Ops.Delete_Key_Sans_Free (Container.Content, Key, X);
|
||||
Free (Container, X);
|
||||
end Exclude;
|
||||
|
||||
----------
|
||||
-- Find --
|
||||
----------
|
||||
|
||||
function Find (Container : Map; Key : Key_Type) return Cursor is
|
||||
Node : constant Count_Type := Key_Ops.Find (Container.Content, Key);
|
||||
|
||||
begin
|
||||
if Node = 0 then
|
||||
return No_Element;
|
||||
end if;
|
||||
|
||||
return (Node => Node);
|
||||
end Find;
|
||||
|
||||
-----------
|
||||
-- First --
|
||||
-----------
|
||||
|
||||
function First (Container : Map) return Cursor is
|
||||
Node : constant Count_Type := HT_Ops.First (Container.Content);
|
||||
|
||||
begin
|
||||
if Node = 0 then
|
||||
return No_Element;
|
||||
end if;
|
||||
|
||||
return (Node => Node);
|
||||
end First;
|
||||
|
||||
------------------
|
||||
-- Formal_Model --
|
||||
------------------
|
||||
|
||||
package body Formal_Model is
|
||||
|
||||
----------
|
||||
-- Find --
|
||||
----------
|
||||
|
||||
function Find
|
||||
(Container : K.Sequence;
|
||||
Key : Key_Type) return Count_Type
|
||||
is
|
||||
begin
|
||||
for I in 1 .. K.Length (Container) loop
|
||||
if Equivalent_Keys (Key, K.Get (Container, I)) then
|
||||
return I;
|
||||
end if;
|
||||
end loop;
|
||||
return 0;
|
||||
end Find;
|
||||
|
||||
---------------------
|
||||
-- K_Keys_Included --
|
||||
---------------------
|
||||
|
||||
function K_Keys_Included
|
||||
(Left : K.Sequence;
|
||||
Right : K.Sequence) return Boolean
|
||||
is
|
||||
begin
|
||||
for I in 1 .. K.Length (Left) loop
|
||||
if not K.Contains (Right, 1, K.Length (Right), K.Get (Left, I))
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end K_Keys_Included;
|
||||
|
||||
----------
|
||||
-- Keys --
|
||||
----------
|
||||
|
||||
function Keys (Container : Map) return K.Sequence is
|
||||
Position : Count_Type := HT_Ops.First (Container.Content);
|
||||
R : K.Sequence;
|
||||
|
||||
begin
|
||||
-- Can't use First, Next or Element here, since they depend on models
|
||||
-- for their postconditions.
|
||||
|
||||
while Position /= 0 loop
|
||||
R := K.Add (R, Container.Content.Nodes (Position).Key);
|
||||
Position := HT_Ops.Next (Container.Content, Position);
|
||||
end loop;
|
||||
|
||||
return R;
|
||||
end Keys;
|
||||
|
||||
----------------------------
|
||||
-- Lift_Abstraction_Level --
|
||||
----------------------------
|
||||
|
||||
procedure Lift_Abstraction_Level (Container : Map) is null;
|
||||
|
||||
-----------------------
|
||||
-- Mapping_Preserved --
|
||||
-----------------------
|
||||
|
||||
function Mapping_Preserved
|
||||
(K_Left : K.Sequence;
|
||||
K_Right : K.Sequence;
|
||||
P_Left : P.Map;
|
||||
P_Right : P.Map) return Boolean
|
||||
is
|
||||
begin
|
||||
for C of P_Left loop
|
||||
if not P.Has_Key (P_Right, C)
|
||||
or else P.Get (P_Left, C) > K.Length (K_Left)
|
||||
or else P.Get (P_Right, C) > K.Length (K_Right)
|
||||
or else K.Get (K_Left, P.Get (P_Left, C)) /=
|
||||
K.Get (K_Right, P.Get (P_Right, C))
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Mapping_Preserved;
|
||||
|
||||
-----------
|
||||
-- Model --
|
||||
-----------
|
||||
|
||||
function Model (Container : Map) return M.Map is
|
||||
Position : Count_Type := HT_Ops.First (Container.Content);
|
||||
R : M.Map;
|
||||
|
||||
begin
|
||||
-- Can't use First, Next or Element here, since they depend on models
|
||||
-- for their postconditions.
|
||||
|
||||
while Position /= 0 loop
|
||||
R :=
|
||||
M.Add
|
||||
(Container => R,
|
||||
New_Key => Container.Content.Nodes (Position).Key,
|
||||
New_Item => Container.Content.Nodes (Position).Element);
|
||||
|
||||
Position := HT_Ops.Next (Container.Content, Position);
|
||||
end loop;
|
||||
|
||||
return R;
|
||||
end Model;
|
||||
|
||||
---------------
|
||||
-- Positions --
|
||||
---------------
|
||||
|
||||
function Positions (Container : Map) return P.Map is
|
||||
I : Count_Type := 1;
|
||||
Position : Count_Type := HT_Ops.First (Container.Content);
|
||||
R : P.Map;
|
||||
|
||||
begin
|
||||
-- Can't use First, Next or Element here, since they depend on models
|
||||
-- for their postconditions.
|
||||
|
||||
while Position /= 0 loop
|
||||
R := P.Add (R, (Node => Position), I);
|
||||
pragma Assert (P.Length (R) = Big (I));
|
||||
Position := HT_Ops.Next (Container.Content, Position);
|
||||
I := I + 1;
|
||||
end loop;
|
||||
|
||||
return R;
|
||||
end Positions;
|
||||
|
||||
end Formal_Model;
|
||||
|
||||
----------
|
||||
-- Free --
|
||||
----------
|
||||
|
||||
procedure Free (HT : in out Map; X : Count_Type) is
|
||||
begin
|
||||
if X /= 0 then
|
||||
pragma Assert (X <= HT.Capacity);
|
||||
HT.Content.Nodes (X).Has_Element := False;
|
||||
HT_Ops.Free (HT.Content, X);
|
||||
end if;
|
||||
end Free;
|
||||
|
||||
----------------------
|
||||
-- Generic_Allocate --
|
||||
----------------------
|
||||
|
||||
procedure Generic_Allocate
|
||||
(HT : in out HT_Types.Hash_Table_Type;
|
||||
Node : out Count_Type)
|
||||
is
|
||||
procedure Allocate is
|
||||
new HT_Ops.Generic_Allocate (Set_Element);
|
||||
|
||||
begin
|
||||
Allocate (HT, Node);
|
||||
HT.Nodes (Node).Has_Element := True;
|
||||
end Generic_Allocate;
|
||||
|
||||
-----------------
|
||||
-- Has_Element --
|
||||
-----------------
|
||||
|
||||
function Has_Element (Container : Map; Position : Cursor) return Boolean is
|
||||
begin
|
||||
if Position.Node = 0
|
||||
or else not Container.Content.Nodes (Position.Node).Has_Element
|
||||
then
|
||||
return False;
|
||||
else
|
||||
return True;
|
||||
end if;
|
||||
end Has_Element;
|
||||
|
||||
---------------
|
||||
-- Hash_Node --
|
||||
---------------
|
||||
|
||||
function Hash_Node (Node : Node_Type) return Hash_Type is
|
||||
begin
|
||||
return Hash (Node.Key);
|
||||
end Hash_Node;
|
||||
|
||||
-------------
|
||||
-- Include --
|
||||
-------------
|
||||
|
||||
procedure Include
|
||||
(Container : in out Map;
|
||||
Key : Key_Type;
|
||||
New_Item : Element_Type)
|
||||
is
|
||||
Position : Cursor;
|
||||
Inserted : Boolean;
|
||||
|
||||
begin
|
||||
Insert (Container, Key, New_Item, Position, Inserted);
|
||||
|
||||
if not Inserted then
|
||||
declare
|
||||
P : constant Count_Type := Position.Node;
|
||||
N : Node_Type renames Container.Content.Nodes (P);
|
||||
begin
|
||||
N.Key := Key;
|
||||
N.Element := New_Item;
|
||||
end;
|
||||
end if;
|
||||
end Include;
|
||||
|
||||
------------
|
||||
-- Insert --
|
||||
------------
|
||||
|
||||
procedure Insert
|
||||
(Container : in out Map;
|
||||
Key : Key_Type;
|
||||
New_Item : Element_Type;
|
||||
Position : out Cursor;
|
||||
Inserted : out Boolean)
|
||||
is
|
||||
procedure Assign_Key (Node : in out Node_Type);
|
||||
pragma Inline (Assign_Key);
|
||||
|
||||
procedure New_Node
|
||||
(HT : in out HT_Types.Hash_Table_Type;
|
||||
Node : out Count_Type);
|
||||
pragma Inline (New_Node);
|
||||
|
||||
procedure Local_Insert is
|
||||
new Key_Ops.Generic_Conditional_Insert (New_Node);
|
||||
|
||||
procedure Allocate is
|
||||
new Generic_Allocate (Assign_Key);
|
||||
|
||||
-----------------
|
||||
-- Assign_Key --
|
||||
-----------------
|
||||
|
||||
procedure Assign_Key (Node : in out Node_Type) is
|
||||
begin
|
||||
Node.Key := Key;
|
||||
Node.Element := New_Item;
|
||||
end Assign_Key;
|
||||
|
||||
--------------
|
||||
-- New_Node --
|
||||
--------------
|
||||
|
||||
procedure New_Node
|
||||
(HT : in out HT_Types.Hash_Table_Type;
|
||||
Node : out Count_Type)
|
||||
is
|
||||
begin
|
||||
Allocate (HT, Node);
|
||||
end New_Node;
|
||||
|
||||
-- Start of processing for Insert
|
||||
|
||||
begin
|
||||
Local_Insert (Container.Content, Key, Position.Node, Inserted);
|
||||
end Insert;
|
||||
|
||||
procedure Insert
|
||||
(Container : in out Map;
|
||||
Key : Key_Type;
|
||||
New_Item : Element_Type)
|
||||
is
|
||||
Unused_Position : Cursor;
|
||||
Inserted : Boolean;
|
||||
|
||||
begin
|
||||
Insert (Container, Key, New_Item, Unused_Position, Inserted);
|
||||
|
||||
if not Inserted then
|
||||
raise Constraint_Error with "attempt to insert key already in map";
|
||||
end if;
|
||||
end Insert;
|
||||
|
||||
--------------
|
||||
-- Is_Empty --
|
||||
--------------
|
||||
|
||||
function Is_Empty (Container : Map) return Boolean is
|
||||
begin
|
||||
return Length (Container) = 0;
|
||||
end Is_Empty;
|
||||
|
||||
---------
|
||||
-- Key --
|
||||
---------
|
||||
|
||||
function Key (Container : Map; Position : Cursor) return Key_Type is
|
||||
begin
|
||||
if not Has_Element (Container, Position) then
|
||||
raise Constraint_Error with
|
||||
"Position cursor of function Key has no element";
|
||||
end if;
|
||||
|
||||
pragma Assert (Vet (Container, Position), "bad cursor in function Key");
|
||||
|
||||
return Container.Content.Nodes (Position.Node).Key;
|
||||
end Key;
|
||||
|
||||
------------
|
||||
-- Length --
|
||||
------------
|
||||
|
||||
function Length (Container : Map) return Count_Type is
|
||||
begin
|
||||
return Container.Content.Length;
|
||||
end Length;
|
||||
|
||||
----------
|
||||
-- Move --
|
||||
----------
|
||||
|
||||
procedure Move
|
||||
(Target : in out Map;
|
||||
Source : in out Map)
|
||||
is
|
||||
NN : HT_Types.Nodes_Type renames Source.Content.Nodes;
|
||||
X : Count_Type;
|
||||
Y : Count_Type;
|
||||
|
||||
begin
|
||||
if Target.Capacity < Length (Source) then
|
||||
raise Constraint_Error with -- ???
|
||||
"Source length exceeds Target capacity";
|
||||
end if;
|
||||
|
||||
Clear (Target);
|
||||
|
||||
if Source.Content.Length = 0 then
|
||||
return;
|
||||
end if;
|
||||
|
||||
X := HT_Ops.First (Source.Content);
|
||||
while X /= 0 loop
|
||||
Insert (Target, NN (X).Key, NN (X).Element); -- optimize???
|
||||
|
||||
Y := HT_Ops.Next (Source.Content, X);
|
||||
|
||||
HT_Ops.Delete_Node_Sans_Free (Source.Content, X);
|
||||
Free (Source, X);
|
||||
|
||||
X := Y;
|
||||
end loop;
|
||||
end Move;
|
||||
|
||||
----------
|
||||
-- Next --
|
||||
----------
|
||||
|
||||
function Next (Node : Node_Type) return Count_Type is
|
||||
begin
|
||||
return Node.Next;
|
||||
end Next;
|
||||
|
||||
function Next (Container : Map; Position : Cursor) return Cursor is
|
||||
begin
|
||||
if Position.Node = 0 then
|
||||
return No_Element;
|
||||
end if;
|
||||
|
||||
if not Has_Element (Container, Position) then
|
||||
raise Constraint_Error with "Position has no element";
|
||||
end if;
|
||||
|
||||
pragma Assert (Vet (Container, Position), "bad cursor in function Next");
|
||||
|
||||
declare
|
||||
Node : constant Count_Type :=
|
||||
HT_Ops.Next (Container.Content, Position.Node);
|
||||
|
||||
begin
|
||||
if Node = 0 then
|
||||
return No_Element;
|
||||
end if;
|
||||
|
||||
return (Node => Node);
|
||||
end;
|
||||
end Next;
|
||||
|
||||
procedure Next (Container : Map; Position : in out Cursor) is
|
||||
begin
|
||||
Position := Next (Container, Position);
|
||||
end Next;
|
||||
|
||||
---------------
|
||||
-- Reference --
|
||||
---------------
|
||||
|
||||
function Reference
|
||||
(Container : not null access Map;
|
||||
Position : Cursor) return not null access Element_Type
|
||||
is
|
||||
begin
|
||||
if not Has_Element (Container.all, Position) then
|
||||
raise Constraint_Error with "Position cursor has no element";
|
||||
end if;
|
||||
|
||||
pragma Assert
|
||||
(Vet (Container.all, Position), "bad cursor in function Reference");
|
||||
|
||||
return Container.Content.Nodes (Position.Node).Element'Access;
|
||||
end Reference;
|
||||
|
||||
function Reference
|
||||
(Container : not null access Map;
|
||||
Key : Key_Type) return not null access Element_Type
|
||||
is
|
||||
Node : constant Count_Type := Find (Container.all, Key).Node;
|
||||
|
||||
begin
|
||||
if Node = 0 then
|
||||
raise Constraint_Error with
|
||||
"no element available because key not in map";
|
||||
end if;
|
||||
|
||||
return Container.Content.Nodes (Node).Element'Access;
|
||||
end Reference;
|
||||
|
||||
-------------
|
||||
-- Replace --
|
||||
-------------
|
||||
|
||||
procedure Replace
|
||||
(Container : in out Map;
|
||||
Key : Key_Type;
|
||||
New_Item : Element_Type)
|
||||
is
|
||||
Node : constant Count_Type := Key_Ops.Find (Container.Content, Key);
|
||||
|
||||
begin
|
||||
if Node = 0 then
|
||||
raise Constraint_Error with "attempt to replace key not in map";
|
||||
end if;
|
||||
|
||||
declare
|
||||
N : Node_Type renames Container.Content.Nodes (Node);
|
||||
begin
|
||||
N.Key := Key;
|
||||
N.Element := New_Item;
|
||||
end;
|
||||
end Replace;
|
||||
|
||||
---------------------
|
||||
-- Replace_Element --
|
||||
---------------------
|
||||
|
||||
procedure Replace_Element
|
||||
(Container : in out Map;
|
||||
Position : Cursor;
|
||||
New_Item : Element_Type)
|
||||
is
|
||||
begin
|
||||
if not Has_Element (Container, Position) then
|
||||
raise Constraint_Error with
|
||||
"Position cursor of Replace_Element has no element";
|
||||
end if;
|
||||
|
||||
pragma Assert
|
||||
(Vet (Container, Position), "bad cursor in Replace_Element");
|
||||
|
||||
Container.Content.Nodes (Position.Node).Element := New_Item;
|
||||
end Replace_Element;
|
||||
|
||||
----------------------
|
||||
-- Reserve_Capacity --
|
||||
----------------------
|
||||
|
||||
procedure Reserve_Capacity
|
||||
(Container : in out Map;
|
||||
Capacity : Count_Type)
|
||||
is
|
||||
begin
|
||||
if Capacity > Container.Capacity then
|
||||
raise Capacity_Error with "requested capacity is too large";
|
||||
end if;
|
||||
end Reserve_Capacity;
|
||||
|
||||
--------------
|
||||
-- Set_Next --
|
||||
--------------
|
||||
|
||||
procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
|
||||
begin
|
||||
Node.Next := Next;
|
||||
end Set_Next;
|
||||
|
||||
---------
|
||||
-- Vet --
|
||||
---------
|
||||
|
||||
function Vet (Container : Map; Position : Cursor) return Boolean is
|
||||
begin
|
||||
if not Container_Checks'Enabled then
|
||||
return True;
|
||||
end if;
|
||||
|
||||
if Position.Node = 0 then
|
||||
return True;
|
||||
end if;
|
||||
|
||||
declare
|
||||
X : Count_Type;
|
||||
|
||||
begin
|
||||
if Container.Content.Length = 0 then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
if Container.Capacity = 0 then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
if Container.Content.Buckets'Length = 0 then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
if Position.Node > Container.Capacity then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
if Container.Content.Nodes (Position.Node).Next = Position.Node then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
X :=
|
||||
Container.Content.Buckets
|
||||
(Key_Ops.Index
|
||||
(Container.Content,
|
||||
Container.Content.Nodes (Position.Node).Key));
|
||||
|
||||
for J in 1 .. Container.Content.Length loop
|
||||
if X = Position.Node then
|
||||
return True;
|
||||
end if;
|
||||
|
||||
if X = 0 then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
if X = Container.Content.Nodes (X).Next then
|
||||
|
||||
-- Prevent unnecessary looping
|
||||
|
||||
return False;
|
||||
end if;
|
||||
|
||||
X := Container.Content.Nodes (X).Next;
|
||||
end loop;
|
||||
|
||||
return False;
|
||||
end;
|
||||
end Vet;
|
||||
|
||||
end Ada.Containers.Formal_Hashed_Maps;
|
@ -29,885 +29,12 @@
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- This spec is derived from package Ada.Containers.Bounded_Hashed_Maps 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: Key, Element, Next, Query_Element, Has_Element,
|
||||
-- Iterate, Equivalent_Keys. 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.
|
||||
|
||||
-- Iteration over maps is done using the Iterable aspect, which is SPARK
|
||||
-- compatible. "For of" iteration ranges over keys instead of elements.
|
||||
|
||||
with Ada.Containers.Functional_Vectors;
|
||||
with Ada.Containers.Functional_Maps;
|
||||
private with Ada.Containers.Hash_Tables;
|
||||
|
||||
generic
|
||||
type Key_Type is private;
|
||||
type Element_Type is private;
|
||||
package Ada.Containers.Formal_Hashed_Maps with SPARK_Mode is
|
||||
|
||||
with function Hash (Key : Key_Type) return Hash_Type;
|
||||
with function Equivalent_Keys
|
||||
(Left : Key_Type;
|
||||
Right : Key_Type) return Boolean is "=";
|
||||
with function "=" (Left, Right : Element_Type) return Boolean is <>;
|
||||
|
||||
package Ada.Containers.Formal_Hashed_Maps with
|
||||
SPARK_Mode,
|
||||
Annotate => (GNATprove, Always_Return)
|
||||
is
|
||||
|
||||
-- Contracts in this unit are meant for analysis only, not for run-time
|
||||
-- checking.
|
||||
|
||||
pragma Assertion_Policy (Pre => Ignore);
|
||||
pragma Assertion_Policy (Post => Ignore);
|
||||
pragma Assertion_Policy (Contract_Cases => Ignore);
|
||||
pragma Annotate (CodePeer, Skip_Analysis);
|
||||
|
||||
type Map (Capacity : Count_Type; Modulus : Hash_Type) is private with
|
||||
Iterable => (First => First,
|
||||
Next => Next,
|
||||
Has_Element => Has_Element,
|
||||
Element => Key),
|
||||
Default_Initial_Condition => Is_Empty (Map);
|
||||
pragma Preelaborable_Initialization (Map);
|
||||
|
||||
Empty_Map : constant Map;
|
||||
|
||||
type Cursor is record
|
||||
Node : Count_Type;
|
||||
end record;
|
||||
|
||||
No_Element : constant Cursor := (Node => 0);
|
||||
|
||||
function Length (Container : Map) 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_Maps
|
||||
(Element_Type => Element_Type,
|
||||
Key_Type => Key_Type,
|
||||
Equivalent_Keys => Equivalent_Keys);
|
||||
|
||||
function "="
|
||||
(Left : M.Map;
|
||||
Right : M.Map) return Boolean renames M."=";
|
||||
|
||||
function "<="
|
||||
(Left : M.Map;
|
||||
Right : M.Map) return Boolean renames M."<=";
|
||||
|
||||
package K is new Ada.Containers.Functional_Vectors
|
||||
(Element_Type => Key_Type,
|
||||
Index_Type => Positive_Count_Type);
|
||||
|
||||
function "="
|
||||
(Left : K.Sequence;
|
||||
Right : K.Sequence) return Boolean renames K."=";
|
||||
|
||||
function "<"
|
||||
(Left : K.Sequence;
|
||||
Right : K.Sequence) return Boolean renames K."<";
|
||||
|
||||
function "<="
|
||||
(Left : K.Sequence;
|
||||
Right : K.Sequence) return Boolean renames K."<=";
|
||||
|
||||
function Find (Container : K.Sequence; Key : Key_Type) return Count_Type
|
||||
-- Search for Key in Container
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
(if Find'Result > 0 then
|
||||
Find'Result <= K.Length (Container)
|
||||
and Equivalent_Keys (Key, K.Get (Container, Find'Result)));
|
||||
|
||||
function K_Keys_Included
|
||||
(Left : K.Sequence;
|
||||
Right : K.Sequence) return Boolean
|
||||
-- Return True if Right contains all the keys of Left
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
K_Keys_Included'Result =
|
||||
(for all I in 1 .. K.Length (Left) =>
|
||||
Find (Right, K.Get (Left, I)) > 0
|
||||
and then K.Get (Right, Find (Right, K.Get (Left, I))) =
|
||||
K.Get (Left, I));
|
||||
|
||||
package P is new Ada.Containers.Functional_Maps
|
||||
(Key_Type => Cursor,
|
||||
Element_Type => Positive_Count_Type,
|
||||
Equivalent_Keys => "=",
|
||||
Enable_Handling_Of_Equivalence => False);
|
||||
|
||||
function "="
|
||||
(Left : P.Map;
|
||||
Right : P.Map) return Boolean renames P."=";
|
||||
|
||||
function "<="
|
||||
(Left : P.Map;
|
||||
Right : P.Map) return Boolean renames P."<=";
|
||||
|
||||
function Mapping_Preserved
|
||||
(K_Left : K.Sequence;
|
||||
K_Right : K.Sequence;
|
||||
P_Left : P.Map;
|
||||
P_Right : P.Map) return Boolean
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
(if Mapping_Preserved'Result then
|
||||
|
||||
-- Right contains all the cursors of Left
|
||||
|
||||
P.Keys_Included (P_Left, P_Right)
|
||||
|
||||
-- Right contains all the keys of Left
|
||||
|
||||
and K_Keys_Included (K_Left, K_Right)
|
||||
|
||||
-- Mappings from cursors to elements induced by K_Left, P_Left
|
||||
-- and K_Right, P_Right are the same.
|
||||
|
||||
and (for all C of P_Left =>
|
||||
K.Get (K_Left, P.Get (P_Left, C)) =
|
||||
K.Get (K_Right, P.Get (P_Right, C))));
|
||||
|
||||
function Model (Container : Map) return M.Map with
|
||||
-- The high-level model of a map is a map from keys to elements. Neither
|
||||
-- cursors nor order of elements are represented in this model. Keys are
|
||||
-- modeled up to equivalence.
|
||||
|
||||
Ghost,
|
||||
Global => null;
|
||||
|
||||
function Keys (Container : Map) return K.Sequence with
|
||||
-- The Keys sequence represents the underlying list structure of maps
|
||||
-- that is used for iteration. It stores the actual values of keys in
|
||||
-- the map. It does not model cursors nor elements.
|
||||
|
||||
Ghost,
|
||||
Global => null,
|
||||
Post =>
|
||||
K.Length (Keys'Result) = Length (Container)
|
||||
|
||||
-- It only contains keys contained in Model
|
||||
|
||||
and (for all Key of Keys'Result =>
|
||||
M.Has_Key (Model (Container), Key))
|
||||
|
||||
-- It contains all the keys contained in Model
|
||||
|
||||
and (for all Key of Model (Container) =>
|
||||
(Find (Keys'Result, Key) > 0
|
||||
and then Equivalent_Keys
|
||||
(K.Get (Keys'Result, Find (Keys'Result, Key)),
|
||||
Key)))
|
||||
|
||||
-- It has no duplicate
|
||||
|
||||
and (for all I in 1 .. Length (Container) =>
|
||||
Find (Keys'Result, K.Get (Keys'Result, I)) = I)
|
||||
|
||||
and (for all I in 1 .. Length (Container) =>
|
||||
(for all J in 1 .. Length (Container) =>
|
||||
(if Equivalent_Keys
|
||||
(K.Get (Keys'Result, I), K.Get (Keys'Result, J))
|
||||
then
|
||||
I = J)));
|
||||
pragma Annotate (GNATprove, Iterable_For_Proof, "Model", Keys);
|
||||
|
||||
function Positions (Container : Map) return P.Map with
|
||||
-- The Positions map is used to model cursors. It only contains valid
|
||||
-- cursors and maps them to their position in the container.
|
||||
|
||||
Ghost,
|
||||
Global => null,
|
||||
Post =>
|
||||
not P.Has_Key (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 : Map) with
|
||||
-- Lift_Abstraction_Level is a ghost procedure that does nothing but
|
||||
-- assume that we can access the same elements by iterating over
|
||||
-- positions or cursors.
|
||||
-- This information is not generally useful except when switching from
|
||||
-- a low-level, cursor-aware view of a container, to a high-level,
|
||||
-- position-based view.
|
||||
|
||||
Ghost,
|
||||
Global => null,
|
||||
Post =>
|
||||
(for all Key of Keys (Container) =>
|
||||
(for some I of Positions (Container) =>
|
||||
K.Get (Keys (Container), P.Get (Positions (Container), I)) =
|
||||
Key));
|
||||
|
||||
function Contains
|
||||
(C : M.Map;
|
||||
K : Key_Type) return Boolean renames M.Has_Key;
|
||||
-- To improve readability of contracts, we rename the function used to
|
||||
-- search for a key in the model to Contains.
|
||||
|
||||
function Element
|
||||
(C : M.Map;
|
||||
K : Key_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 : Map) return Boolean with
|
||||
Global => null,
|
||||
Post => "="'Result = (Model (Left) = Model (Right));
|
||||
|
||||
function Capacity (Container : Map) return Count_Type with
|
||||
Global => null,
|
||||
Post => Capacity'Result = Container.Capacity;
|
||||
|
||||
procedure Reserve_Capacity
|
||||
(Container : in out Map;
|
||||
Capacity : Count_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre => Capacity <= Container.Capacity,
|
||||
Post =>
|
||||
Model (Container) = Model (Container)'Old
|
||||
and Length (Container)'Old = Length (Container)
|
||||
|
||||
-- Actual keys are preserved
|
||||
|
||||
and K_Keys_Included (Keys (Container), Keys (Container)'Old)
|
||||
and K_Keys_Included (Keys (Container)'Old, Keys (Container));
|
||||
|
||||
function Is_Empty (Container : Map) return Boolean with
|
||||
Global => null,
|
||||
Post => Is_Empty'Result = (Length (Container) = 0);
|
||||
|
||||
procedure Clear (Container : in out Map) with
|
||||
Global => null,
|
||||
Post => Length (Container) = 0 and M.Is_Empty (Model (Container));
|
||||
|
||||
procedure Assign (Target : in out Map; Source : Map) with
|
||||
Global => null,
|
||||
Pre => Target.Capacity >= Length (Source),
|
||||
Post =>
|
||||
Model (Target) = Model (Source)
|
||||
and Length (Source) = Length (Target)
|
||||
|
||||
-- Actual keys are preserved
|
||||
|
||||
and K_Keys_Included (Keys (Target), Keys (Source))
|
||||
and K_Keys_Included (Keys (Source), Keys (Target));
|
||||
|
||||
function Copy
|
||||
(Source : Map;
|
||||
Capacity : Count_Type := 0) return Map
|
||||
with
|
||||
Global => null,
|
||||
Pre => Capacity = 0 or else Capacity >= Source.Capacity,
|
||||
Post =>
|
||||
Model (Copy'Result) = Model (Source)
|
||||
and Keys (Copy'Result) = Keys (Source)
|
||||
and Positions (Copy'Result) = Positions (Source)
|
||||
and (if Capacity = 0 then
|
||||
Copy'Result.Capacity = Source.Capacity
|
||||
else
|
||||
Copy'Result.Capacity = Capacity);
|
||||
-- Copy returns a container stricty equal to Source. It must have the same
|
||||
-- cursors associated with each element. Therefore:
|
||||
-- - capacity=0 means use Source.Capacity as capacity of target
|
||||
-- - the modulus cannot be changed.
|
||||
|
||||
function Key (Container : Map; Position : Cursor) return Key_Type with
|
||||
Global => null,
|
||||
Pre => Has_Element (Container, Position),
|
||||
Post =>
|
||||
Key'Result =
|
||||
K.Get (Keys (Container), P.Get (Positions (Container), Position));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Key);
|
||||
|
||||
function Element
|
||||
(Container : Map;
|
||||
Position : Cursor) return Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre => Has_Element (Container, Position),
|
||||
Post =>
|
||||
Element'Result = Element (Model (Container), Key (Container, Position));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Element);
|
||||
|
||||
procedure Replace_Element
|
||||
(Container : in out Map;
|
||||
Position : Cursor;
|
||||
New_Item : Element_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre => Has_Element (Container, Position),
|
||||
Post =>
|
||||
|
||||
-- Order of keys and cursors is preserved
|
||||
|
||||
Keys (Container) = Keys (Container)'Old
|
||||
and Positions (Container) = Positions (Container)'Old
|
||||
|
||||
-- New_Item is now associated with the key at position Position in
|
||||
-- Container.
|
||||
|
||||
and Element (Container, Position) = New_Item
|
||||
|
||||
-- Elements associated with other keys are preserved
|
||||
|
||||
and M.Same_Keys (Model (Container), Model (Container)'Old)
|
||||
and M.Elements_Equal_Except
|
||||
(Model (Container),
|
||||
Model (Container)'Old,
|
||||
Key (Container, Position));
|
||||
|
||||
function At_End
|
||||
(E : not null access constant Map) return not null access constant Map
|
||||
is (E)
|
||||
with Ghost,
|
||||
Annotate => (GNATprove, At_End_Borrow);
|
||||
|
||||
function At_End
|
||||
(E : access constant Element_Type) return access constant Element_Type
|
||||
is (E)
|
||||
with Ghost,
|
||||
Annotate => (GNATprove, At_End_Borrow);
|
||||
|
||||
function Constant_Reference
|
||||
(Container : aliased Map;
|
||||
Position : Cursor) return not null access constant Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre => Has_Element (Container, Position),
|
||||
Post =>
|
||||
Constant_Reference'Result.all =
|
||||
Element (Model (Container), Key (Container, Position));
|
||||
|
||||
function Reference
|
||||
(Container : not null access Map;
|
||||
Position : Cursor) return not null access Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre => Has_Element (Container.all, Position),
|
||||
Post =>
|
||||
|
||||
-- Order of keys and cursors is preserved
|
||||
|
||||
Keys (At_End (Container).all) = Keys (Container.all)
|
||||
and Positions (At_End (Container).all) = Positions (Container.all)
|
||||
|
||||
-- The value designated by the result of Reference is now associated
|
||||
-- with the key at position Position in Container.
|
||||
|
||||
and Element (At_End (Container).all, Position) =
|
||||
At_End (Reference'Result).all
|
||||
|
||||
-- Elements associated with other keys are preserved
|
||||
|
||||
and M.Same_Keys
|
||||
(Model (At_End (Container).all),
|
||||
Model (Container.all))
|
||||
and M.Elements_Equal_Except
|
||||
(Model (At_End (Container).all),
|
||||
Model (Container.all),
|
||||
Key (At_End (Container).all, Position));
|
||||
|
||||
function Constant_Reference
|
||||
(Container : aliased Map;
|
||||
Key : Key_Type) return not null access constant Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre => Contains (Container, Key),
|
||||
Post =>
|
||||
Constant_Reference'Result.all = Element (Model (Container), Key);
|
||||
|
||||
function Reference
|
||||
(Container : not null access Map;
|
||||
Key : Key_Type) return not null access Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre => Contains (Container.all, Key),
|
||||
Post =>
|
||||
|
||||
-- Order of keys and cursors is preserved
|
||||
|
||||
Keys (At_End (Container).all) = Keys (Container.all)
|
||||
and Positions (At_End (Container).all) = Positions (Container.all)
|
||||
|
||||
-- The value designated by the result of Reference is now associated
|
||||
-- with Key in Container.
|
||||
|
||||
and Element (Model (At_End (Container).all), Key) =
|
||||
At_End (Reference'Result).all
|
||||
|
||||
-- Elements associated with other keys are preserved
|
||||
|
||||
and M.Same_Keys
|
||||
(Model (At_End (Container).all),
|
||||
Model (Container.all))
|
||||
and M.Elements_Equal_Except
|
||||
(Model (At_End (Container).all),
|
||||
Model (Container.all),
|
||||
Key);
|
||||
|
||||
procedure Move (Target : in out Map; Source : in out Map) with
|
||||
Global => null,
|
||||
Pre => Target.Capacity >= Length (Source),
|
||||
Post =>
|
||||
Model (Target) = Model (Source)'Old
|
||||
and Length (Source)'Old = Length (Target)
|
||||
and Length (Source) = 0
|
||||
|
||||
-- Actual keys are preserved
|
||||
|
||||
and K_Keys_Included (Keys (Target), Keys (Source)'Old)
|
||||
and K_Keys_Included (Keys (Source)'Old, Keys (Target));
|
||||
|
||||
procedure Insert
|
||||
(Container : in out Map;
|
||||
Key : Key_Type;
|
||||
New_Item : Element_Type;
|
||||
Position : out Cursor;
|
||||
Inserted : out Boolean)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) < Container.Capacity or Contains (Container, Key),
|
||||
Post =>
|
||||
Contains (Container, Key)
|
||||
and Has_Element (Container, Position)
|
||||
and Equivalent_Keys
|
||||
(Formal_Hashed_Maps.Key (Container, Position), Key),
|
||||
Contract_Cases =>
|
||||
|
||||
-- If Key is already in Container, it is not modified and Inserted is
|
||||
-- set to False.
|
||||
|
||||
(Contains (Container, Key) =>
|
||||
not Inserted
|
||||
and Model (Container) = Model (Container)'Old
|
||||
and Keys (Container) = Keys (Container)'Old
|
||||
and Positions (Container) = Positions (Container)'Old,
|
||||
|
||||
-- Otherwise, Key is inserted in Container and Inserted is set to True
|
||||
|
||||
others =>
|
||||
Inserted
|
||||
and Length (Container) = Length (Container)'Old + 1
|
||||
|
||||
-- Key now maps to New_Item
|
||||
|
||||
and Formal_Hashed_Maps.Key (Container, Position) = Key
|
||||
and Element (Model (Container), Key) = New_Item
|
||||
|
||||
-- Other keys are preserved
|
||||
|
||||
and Model (Container)'Old <= Model (Container)
|
||||
and M.Keys_Included_Except
|
||||
(Model (Container),
|
||||
Model (Container)'Old,
|
||||
Key)
|
||||
|
||||
-- Mapping from cursors to keys is preserved
|
||||
|
||||
and Mapping_Preserved
|
||||
(K_Left => Keys (Container)'Old,
|
||||
K_Right => Keys (Container),
|
||||
P_Left => Positions (Container)'Old,
|
||||
P_Right => Positions (Container))
|
||||
and P.Keys_Included_Except
|
||||
(Positions (Container),
|
||||
Positions (Container)'Old,
|
||||
Position));
|
||||
|
||||
procedure Insert
|
||||
(Container : in out Map;
|
||||
Key : Key_Type;
|
||||
New_Item : Element_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) < Container.Capacity
|
||||
and then (not Contains (Container, Key)),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + 1
|
||||
and Contains (Container, Key)
|
||||
|
||||
-- Key now maps to New_Item
|
||||
|
||||
and Formal_Hashed_Maps.Key (Container, Find (Container, Key)) = Key
|
||||
and Element (Model (Container), Key) = New_Item
|
||||
|
||||
-- Other keys are preserved
|
||||
|
||||
and Model (Container)'Old <= Model (Container)
|
||||
and M.Keys_Included_Except
|
||||
(Model (Container),
|
||||
Model (Container)'Old,
|
||||
Key)
|
||||
|
||||
-- Mapping from cursors to keys is preserved
|
||||
|
||||
and Mapping_Preserved
|
||||
(K_Left => Keys (Container)'Old,
|
||||
K_Right => Keys (Container),
|
||||
P_Left => Positions (Container)'Old,
|
||||
P_Right => Positions (Container))
|
||||
and P.Keys_Included_Except
|
||||
(Positions (Container),
|
||||
Positions (Container)'Old,
|
||||
Find (Container, Key));
|
||||
|
||||
procedure Include
|
||||
(Container : in out Map;
|
||||
Key : Key_Type;
|
||||
New_Item : Element_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) < Container.Capacity or Contains (Container, Key),
|
||||
Post =>
|
||||
Contains (Container, Key) and Element (Container, Key) = New_Item,
|
||||
Contract_Cases =>
|
||||
|
||||
-- If Key is already in Container, Key is mapped to New_Item
|
||||
|
||||
(Contains (Container, Key) =>
|
||||
|
||||
-- Cursors are preserved
|
||||
|
||||
Positions (Container) = Positions (Container)'Old
|
||||
|
||||
-- The key equivalent to Key in Container is replaced by Key
|
||||
|
||||
and K.Get
|
||||
(Keys (Container),
|
||||
P.Get (Positions (Container), Find (Container, Key))) = Key
|
||||
and K.Equal_Except
|
||||
(Keys (Container)'Old,
|
||||
Keys (Container),
|
||||
P.Get (Positions (Container), Find (Container, Key)))
|
||||
|
||||
-- Elements associated with other keys are preserved
|
||||
|
||||
and M.Same_Keys (Model (Container), Model (Container)'Old)
|
||||
and M.Elements_Equal_Except
|
||||
(Model (Container),
|
||||
Model (Container)'Old,
|
||||
Key),
|
||||
|
||||
-- Otherwise, Key is inserted in Container
|
||||
|
||||
others =>
|
||||
Length (Container) = Length (Container)'Old + 1
|
||||
|
||||
-- Other keys are preserved
|
||||
|
||||
and Model (Container)'Old <= Model (Container)
|
||||
and M.Keys_Included_Except
|
||||
(Model (Container),
|
||||
Model (Container)'Old,
|
||||
Key)
|
||||
|
||||
-- Key is inserted in Container
|
||||
|
||||
and K.Get
|
||||
(Keys (Container),
|
||||
P.Get (Positions (Container), Find (Container, Key))) = Key
|
||||
|
||||
-- Mapping from cursors to keys is preserved
|
||||
|
||||
and Mapping_Preserved
|
||||
(K_Left => Keys (Container)'Old,
|
||||
K_Right => Keys (Container),
|
||||
P_Left => Positions (Container)'Old,
|
||||
P_Right => Positions (Container))
|
||||
and P.Keys_Included_Except
|
||||
(Positions (Container),
|
||||
Positions (Container)'Old,
|
||||
Find (Container, Key)));
|
||||
|
||||
procedure Replace
|
||||
(Container : in out Map;
|
||||
Key : Key_Type;
|
||||
New_Item : Element_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre => Contains (Container, Key),
|
||||
Post =>
|
||||
|
||||
-- Cursors are preserved
|
||||
|
||||
Positions (Container) = Positions (Container)'Old
|
||||
|
||||
-- The key equivalent to Key in Container is replaced by Key
|
||||
|
||||
and K.Get
|
||||
(Keys (Container),
|
||||
P.Get (Positions (Container), Find (Container, Key))) = Key
|
||||
and K.Equal_Except
|
||||
(Keys (Container)'Old,
|
||||
Keys (Container),
|
||||
P.Get (Positions (Container), Find (Container, Key)))
|
||||
|
||||
-- New_Item is now associated with the Key in Container
|
||||
|
||||
and Element (Model (Container), Key) = New_Item
|
||||
|
||||
-- Elements associated with other keys are preserved
|
||||
|
||||
and M.Same_Keys (Model (Container), Model (Container)'Old)
|
||||
and M.Elements_Equal_Except
|
||||
(Model (Container),
|
||||
Model (Container)'Old,
|
||||
Key);
|
||||
|
||||
procedure Exclude (Container : in out Map; Key : Key_Type) with
|
||||
Global => null,
|
||||
Post => not Contains (Container, Key),
|
||||
Contract_Cases =>
|
||||
|
||||
-- If Key is not in Container, nothing is changed
|
||||
|
||||
(not Contains (Container, Key) =>
|
||||
Model (Container) = Model (Container)'Old
|
||||
and Keys (Container) = Keys (Container)'Old
|
||||
and Positions (Container) = Positions (Container)'Old,
|
||||
|
||||
-- Otherwise, Key is removed from Container
|
||||
|
||||
others =>
|
||||
Length (Container) = Length (Container)'Old - 1
|
||||
|
||||
-- Other keys are preserved
|
||||
|
||||
and Model (Container) <= Model (Container)'Old
|
||||
and M.Keys_Included_Except
|
||||
(Model (Container)'Old,
|
||||
Model (Container),
|
||||
Key)
|
||||
|
||||
-- Mapping from cursors to keys is preserved
|
||||
|
||||
and Mapping_Preserved
|
||||
(K_Left => Keys (Container),
|
||||
K_Right => Keys (Container)'Old,
|
||||
P_Left => Positions (Container),
|
||||
P_Right => Positions (Container)'Old)
|
||||
and P.Keys_Included_Except
|
||||
(Positions (Container)'Old,
|
||||
Positions (Container),
|
||||
Find (Container, Key)'Old));
|
||||
|
||||
procedure Delete (Container : in out Map; Key : Key_Type) with
|
||||
Global => null,
|
||||
Pre => Contains (Container, Key),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old - 1
|
||||
|
||||
-- Key is no longer in Container
|
||||
|
||||
and not Contains (Container, Key)
|
||||
|
||||
-- Other keys are preserved
|
||||
|
||||
and Model (Container) <= Model (Container)'Old
|
||||
and M.Keys_Included_Except
|
||||
(Model (Container)'Old,
|
||||
Model (Container),
|
||||
Key)
|
||||
|
||||
-- Mapping from cursors to keys is preserved
|
||||
|
||||
and Mapping_Preserved
|
||||
(K_Left => Keys (Container),
|
||||
K_Right => Keys (Container)'Old,
|
||||
P_Left => Positions (Container),
|
||||
P_Right => Positions (Container)'Old)
|
||||
and P.Keys_Included_Except
|
||||
(Positions (Container)'Old,
|
||||
Positions (Container),
|
||||
Find (Container, Key)'Old);
|
||||
|
||||
procedure Delete (Container : in out Map; Position : in out Cursor) with
|
||||
Global => null,
|
||||
Depends => (Container =>+ Position, Position => null),
|
||||
Pre => Has_Element (Container, Position),
|
||||
Post =>
|
||||
Position = No_Element
|
||||
and Length (Container) = Length (Container)'Old - 1
|
||||
|
||||
-- The key at position Position is no longer in Container
|
||||
|
||||
and not Contains (Container, Key (Container, Position)'Old)
|
||||
and not P.Has_Key (Positions (Container), Position'Old)
|
||||
|
||||
-- Other keys are preserved
|
||||
|
||||
and Model (Container) <= Model (Container)'Old
|
||||
and M.Keys_Included_Except
|
||||
(Model (Container)'Old,
|
||||
Model (Container),
|
||||
Key (Container, Position)'Old)
|
||||
|
||||
-- Mapping from cursors to keys is preserved
|
||||
|
||||
and Mapping_Preserved
|
||||
(K_Left => Keys (Container),
|
||||
K_Right => Keys (Container)'Old,
|
||||
P_Left => Positions (Container),
|
||||
P_Right => Positions (Container)'Old)
|
||||
and P.Keys_Included_Except
|
||||
(Positions (Container)'Old,
|
||||
Positions (Container),
|
||||
Position'Old);
|
||||
|
||||
function First (Container : Map) return Cursor with
|
||||
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 Next (Container : Map; Position : Cursor) return Cursor with
|
||||
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 : Map; Position : in out Cursor) with
|
||||
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 Find (Container : Map; Key : Key_Type) return Cursor with
|
||||
Global => null,
|
||||
Contract_Cases =>
|
||||
|
||||
-- If Key is not contained in Container, Find returns No_Element
|
||||
|
||||
(not Contains (Model (Container), Key) =>
|
||||
Find'Result = No_Element,
|
||||
|
||||
-- Otherwise, Find returns a valid cursor in Container
|
||||
|
||||
others =>
|
||||
P.Has_Key (Positions (Container), Find'Result)
|
||||
and P.Get (Positions (Container), Find'Result) =
|
||||
Find (Keys (Container), Key)
|
||||
|
||||
-- The key designated by the result of Find is Key
|
||||
|
||||
and Equivalent_Keys
|
||||
(Formal_Hashed_Maps.Key (Container, Find'Result), Key));
|
||||
|
||||
function Contains (Container : Map; Key : Key_Type) return Boolean with
|
||||
Global => null,
|
||||
Post => Contains'Result = Contains (Model (Container), Key);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Contains);
|
||||
|
||||
function Element (Container : Map; Key : Key_Type) return Element_Type with
|
||||
Global => null,
|
||||
Pre => Contains (Container, Key),
|
||||
Post => Element'Result = Element (Model (Container), Key);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Element);
|
||||
|
||||
function Has_Element (Container : Map; Position : Cursor) return Boolean
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Has_Element'Result = P.Has_Key (Positions (Container), Position);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Has_Element);
|
||||
|
||||
function Default_Modulus (Capacity : Count_Type) return Hash_Type with
|
||||
Global => null;
|
||||
|
||||
private
|
||||
pragma SPARK_Mode (Off);
|
||||
|
||||
pragma Inline (Length);
|
||||
pragma Inline (Is_Empty);
|
||||
pragma Inline (Clear);
|
||||
pragma Inline (Key);
|
||||
pragma Inline (Element);
|
||||
pragma Inline (Contains);
|
||||
pragma Inline (Capacity);
|
||||
pragma Inline (Has_Element);
|
||||
pragma Inline (Equivalent_Keys);
|
||||
pragma Inline (Next);
|
||||
|
||||
type Node_Type is record
|
||||
Key : Key_Type;
|
||||
Element : aliased Element_Type;
|
||||
Next : Count_Type;
|
||||
Has_Element : Boolean := False;
|
||||
end record;
|
||||
|
||||
package HT_Types is new
|
||||
Ada.Containers.Hash_Tables.Generic_Formal_Hash_Table_Types (Node_Type);
|
||||
|
||||
type Map (Capacity : Count_Type; Modulus : Hash_Type) is record
|
||||
Content : HT_Types.Hash_Table_Type (Capacity, Modulus);
|
||||
end record;
|
||||
|
||||
Empty_Map : constant Map := (Capacity => 0, Modulus => 0, others => <>);
|
||||
pragma Compile_Time_Error
|
||||
(True,
|
||||
"This package has been moved to the SPARK library shipped with any"
|
||||
& " SPARK release starting with version 23.");
|
||||
|
||||
end Ada.Containers.Formal_Hashed_Maps;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,304 +0,0 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- --
|
||||
-- GNAT LIBRARY COMPONENTS --
|
||||
-- --
|
||||
-- ADA.CONTAINERS.FUNCTIONAL_INFINITE_SEQUENCE --
|
||||
-- --
|
||||
-- B o d y --
|
||||
-- --
|
||||
-- Copyright (C) 2022-2022, 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 --
|
||||
-- apply solely to the contents of the part following the private keyword. --
|
||||
-- --
|
||||
-- GNAT is free software; you can redistribute it and/or modify it under --
|
||||
-- terms of the GNU General Public License as published by the Free Soft- --
|
||||
-- ware Foundation; either version 3, or (at your option) any later ver- --
|
||||
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
||||
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
||||
-- or FITNESS FOR A PARTICULAR PURPOSE. --
|
||||
-- --
|
||||
-- As a special exception under Section 7 of GPL version 3, you are granted --
|
||||
-- additional permissions described in the GCC Runtime Library Exception, --
|
||||
-- version 3.1, as published by the Free Software Foundation. --
|
||||
-- --
|
||||
-- You should have received a copy of the GNU General Public License and --
|
||||
-- a copy of the GCC Runtime Library Exception along with this program; --
|
||||
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
pragma Ada_2012;
|
||||
|
||||
package body Ada.Containers.Functional_Infinite_Sequences
|
||||
with SPARK_Mode => Off
|
||||
is
|
||||
use Containers;
|
||||
|
||||
-----------------------
|
||||
-- Local Subprograms --
|
||||
-----------------------
|
||||
|
||||
package Big_From_Count is new Signed_Conversions
|
||||
(Int => Count_Type);
|
||||
|
||||
function Big (C : Count_Type) return Big_Integer renames
|
||||
Big_From_Count.To_Big_Integer;
|
||||
|
||||
-- Store Count_Type'Last as a Big Natural because it is often used
|
||||
|
||||
Count_Type_Big_Last : constant Big_Natural := Big (Count_Type'Last);
|
||||
|
||||
function To_Count (C : Big_Natural) return Count_Type;
|
||||
-- Convert Big_Natural to Count_Type
|
||||
|
||||
---------
|
||||
-- "<" --
|
||||
---------
|
||||
|
||||
function "<" (Left : Sequence; Right : Sequence) return Boolean is
|
||||
(Length (Left) < Length (Right)
|
||||
and then (for all N in Left =>
|
||||
Get (Left, N) = Get (Right, N)));
|
||||
|
||||
----------
|
||||
-- "<=" --
|
||||
----------
|
||||
|
||||
function "<=" (Left : Sequence; Right : Sequence) return Boolean is
|
||||
(Length (Left) <= Length (Right)
|
||||
and then (for all N in Left =>
|
||||
Get (Left, N) = Get (Right, N)));
|
||||
|
||||
---------
|
||||
-- "=" --
|
||||
---------
|
||||
|
||||
function "=" (Left : Sequence; Right : Sequence) return Boolean is
|
||||
(Left.Content = Right.Content);
|
||||
|
||||
---------
|
||||
-- Add --
|
||||
---------
|
||||
|
||||
function Add (Container : Sequence; New_Item : Element_Type) return Sequence
|
||||
is
|
||||
(Add (Container, Last (Container) + 1, New_Item));
|
||||
|
||||
function Add
|
||||
(Container : Sequence;
|
||||
Position : Big_Positive;
|
||||
New_Item : Element_Type) return Sequence is
|
||||
(Content => Add (Container.Content, To_Count (Position), New_Item));
|
||||
|
||||
--------------------
|
||||
-- Constant_Range --
|
||||
--------------------
|
||||
|
||||
function Constant_Range
|
||||
(Container : Sequence;
|
||||
Fst : Big_Positive;
|
||||
Lst : Big_Natural;
|
||||
Item : Element_Type) return Boolean
|
||||
is
|
||||
Count_Fst : constant Count_Type := To_Count (Fst);
|
||||
Count_Lst : constant Count_Type := To_Count (Lst);
|
||||
|
||||
begin
|
||||
for J in Count_Fst .. Count_Lst loop
|
||||
if Get (Container.Content, J) /= Item then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Constant_Range;
|
||||
|
||||
--------------
|
||||
-- Contains --
|
||||
--------------
|
||||
|
||||
function Contains
|
||||
(Container : Sequence;
|
||||
Fst : Big_Positive;
|
||||
Lst : Big_Natural;
|
||||
Item : Element_Type) return Boolean
|
||||
is
|
||||
Count_Fst : constant Count_Type := To_Count (Fst);
|
||||
Count_Lst : constant Count_Type := To_Count (Lst);
|
||||
|
||||
begin
|
||||
for J in Count_Fst .. Count_Lst loop
|
||||
if Get (Container.Content, J) = Item then
|
||||
return True;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return False;
|
||||
end Contains;
|
||||
|
||||
--------------------
|
||||
-- Empty_Sequence --
|
||||
--------------------
|
||||
|
||||
function Empty_Sequence return Sequence is
|
||||
(Content => <>);
|
||||
|
||||
------------------
|
||||
-- Equal_Except --
|
||||
------------------
|
||||
|
||||
function Equal_Except
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Position : Big_Positive) return Boolean
|
||||
is
|
||||
Count_Pos : constant Count_Type := To_Count (Position);
|
||||
Count_Lst : constant Count_Type := To_Count (Last (Left));
|
||||
|
||||
begin
|
||||
if Length (Left) /= Length (Right) then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
for J in 1 .. Count_Lst loop
|
||||
if J /= Count_Pos
|
||||
and then Get (Left.Content, J) /= Get (Right.Content, J)
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Equal_Except;
|
||||
|
||||
function Equal_Except
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
X : Big_Positive;
|
||||
Y : Big_Positive) return Boolean
|
||||
is
|
||||
Count_X : constant Count_Type := To_Count (X);
|
||||
Count_Y : constant Count_Type := To_Count (Y);
|
||||
Count_Lst : constant Count_Type := To_Count (Last (Left));
|
||||
|
||||
begin
|
||||
if Length (Left) /= Length (Right) then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
for J in 1 .. Count_Lst loop
|
||||
if J /= Count_X
|
||||
and then J /= Count_Y
|
||||
and then Get (Left.Content, J) /= Get (Right.Content, J)
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Equal_Except;
|
||||
|
||||
---------
|
||||
-- Get --
|
||||
---------
|
||||
|
||||
function Get
|
||||
(Container : Sequence;
|
||||
Position : Big_Integer) return Element_Type is
|
||||
(Get (Container.Content, To_Count (Position)));
|
||||
|
||||
----------
|
||||
-- Last --
|
||||
----------
|
||||
|
||||
function Last (Container : Sequence) return Big_Natural is
|
||||
(Length (Container));
|
||||
|
||||
------------
|
||||
-- Length --
|
||||
------------
|
||||
|
||||
function Length (Container : Sequence) return Big_Natural is
|
||||
(Big (Length (Container.Content)));
|
||||
|
||||
-----------------
|
||||
-- Range_Equal --
|
||||
-----------------
|
||||
|
||||
function Range_Equal
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Fst : Big_Positive;
|
||||
Lst : Big_Natural) return Boolean
|
||||
is
|
||||
Count_Fst : constant Count_Type := To_Count (Fst);
|
||||
Count_Lst : constant Count_Type := To_Count (Lst);
|
||||
|
||||
begin
|
||||
for J in Count_Fst .. Count_Lst loop
|
||||
if Get (Left.Content, J) /= Get (Right.Content, J) then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Range_Equal;
|
||||
|
||||
-------------------
|
||||
-- Range_Shifted --
|
||||
-------------------
|
||||
|
||||
function Range_Shifted
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Fst : Big_Positive;
|
||||
Lst : Big_Natural;
|
||||
Offset : Big_Integer) return Boolean
|
||||
is
|
||||
Count_Fst : constant Count_Type := To_Count (Fst);
|
||||
Count_Lst : constant Count_Type := To_Count (Lst);
|
||||
|
||||
begin
|
||||
for J in Count_Fst .. Count_Lst loop
|
||||
if Get (Left.Content, J) /= Get (Right, Big (J) + Offset) then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Range_Shifted;
|
||||
|
||||
------------
|
||||
-- Remove --
|
||||
------------
|
||||
|
||||
function Remove
|
||||
(Container : Sequence;
|
||||
Position : Big_Positive) return Sequence is
|
||||
(Content => Remove (Container.Content, To_Count (Position)));
|
||||
|
||||
---------
|
||||
-- Set --
|
||||
---------
|
||||
|
||||
function Set
|
||||
(Container : Sequence;
|
||||
Position : Big_Positive;
|
||||
New_Item : Element_Type) return Sequence is
|
||||
(Content => Set (Container.Content, To_Count (Position), New_Item));
|
||||
|
||||
--------------
|
||||
-- To_Count --
|
||||
--------------
|
||||
|
||||
function To_Count (C : Big_Natural) return Count_Type is
|
||||
begin
|
||||
if C > Count_Type_Big_Last then
|
||||
raise Program_Error with "Big_Integer too large for Count_Type";
|
||||
end if;
|
||||
return Big_From_Count.From_Big_Integer (C);
|
||||
end To_Count;
|
||||
|
||||
end Ada.Containers.Functional_Infinite_Sequences;
|
@ -29,352 +29,12 @@
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
pragma Ada_2012;
|
||||
private with Ada.Containers.Functional_Base;
|
||||
with Ada.Numerics.Big_Numbers.Big_Integers;
|
||||
use Ada.Numerics.Big_Numbers.Big_Integers;
|
||||
|
||||
generic
|
||||
type Element_Type (<>) is private;
|
||||
with function "=" (Left, Right : Element_Type) return Boolean is <>;
|
||||
package Ada.Containers.Functional_Infinite_Sequences with SPARK_Mode is
|
||||
|
||||
package Ada.Containers.Functional_Infinite_Sequences with
|
||||
SPARK_Mode,
|
||||
Annotate => (GNATprove, Always_Return)
|
||||
is
|
||||
pragma Compile_Time_Error
|
||||
(True,
|
||||
"This package has been moved to the SPARK library shipped with any"
|
||||
& " SPARK release starting with version 23.");
|
||||
|
||||
type Sequence is private
|
||||
with Default_Initial_Condition => Length (Sequence) = 0,
|
||||
Iterable => (First => Iter_First,
|
||||
Has_Element => Iter_Has_Element,
|
||||
Next => Iter_Next,
|
||||
Element => Get);
|
||||
-- Sequences are empty when default initialized.
|
||||
-- Quantification over sequences can be done using the regular
|
||||
-- quantification over its range or directly on its elements with "for of".
|
||||
|
||||
-----------------------
|
||||
-- Basic operations --
|
||||
-----------------------
|
||||
|
||||
-- Sequences are axiomatized using Length and Get, providing respectively
|
||||
-- the length of a sequence and an accessor to its Nth element:
|
||||
|
||||
function Length (Container : Sequence) return Big_Natural with
|
||||
-- Length of a sequence
|
||||
|
||||
Global => null;
|
||||
|
||||
function Get
|
||||
(Container : Sequence;
|
||||
Position : Big_Integer) return Element_Type
|
||||
-- Access the Element at position Position in Container
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Iter_Has_Element (Container, Position);
|
||||
|
||||
function Last (Container : Sequence) return Big_Natural with
|
||||
-- Last index of a sequence
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
Last'Result = Length (Container);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Last);
|
||||
|
||||
function First return Big_Positive is (1) with
|
||||
-- First index of a sequence
|
||||
|
||||
Global => null;
|
||||
|
||||
------------------------
|
||||
-- Property Functions --
|
||||
------------------------
|
||||
|
||||
function "=" (Left : Sequence; Right : Sequence) return Boolean with
|
||||
-- Extensional equality over sequences
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
"="'Result =
|
||||
(Length (Left) = Length (Right)
|
||||
and then (for all N in Left => Get (Left, N) = Get (Right, N)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, "=");
|
||||
|
||||
function "<" (Left : Sequence; Right : Sequence) return Boolean with
|
||||
-- Left is a strict subsequence of Right
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
"<"'Result =
|
||||
(Length (Left) < Length (Right)
|
||||
and then (for all N in Left => Get (Left, N) = Get (Right, N)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, "<");
|
||||
|
||||
function "<=" (Left : Sequence; Right : Sequence) return Boolean with
|
||||
-- Left is a subsequence of Right
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
"<="'Result =
|
||||
(Length (Left) <= Length (Right)
|
||||
and then (for all N in Left => Get (Left, N) = Get (Right, N)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, "<=");
|
||||
|
||||
function Contains
|
||||
(Container : Sequence;
|
||||
Fst : Big_Positive;
|
||||
Lst : Big_Natural;
|
||||
Item : Element_Type) return Boolean
|
||||
-- Returns True if Item occurs in the range from Fst to Lst of Container
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Lst <= Last (Container),
|
||||
Post =>
|
||||
Contains'Result =
|
||||
(for some J in Container =>
|
||||
Fst <= J and J <= Lst and Get (Container, J) = Item);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Contains);
|
||||
|
||||
function Constant_Range
|
||||
(Container : Sequence;
|
||||
Fst : Big_Positive;
|
||||
Lst : Big_Natural;
|
||||
Item : Element_Type) return Boolean
|
||||
-- Returns True if every element of the range from Fst to Lst of Container
|
||||
-- is equal to Item.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Lst <= Last (Container),
|
||||
Post =>
|
||||
Constant_Range'Result =
|
||||
(for all J in Container =>
|
||||
(if Fst <= J and J <= Lst then Get (Container, J) = Item));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Constant_Range);
|
||||
|
||||
function Equal_Except
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Position : Big_Positive) return Boolean
|
||||
-- Returns True is Left and Right are the same except at position Position
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Position <= Last (Left),
|
||||
Post =>
|
||||
Equal_Except'Result =
|
||||
(Length (Left) = Length (Right)
|
||||
and then (for all J in Left =>
|
||||
(if J /= Position then
|
||||
Get (Left, J) = Get (Right, J))));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Equal_Except);
|
||||
|
||||
function Equal_Except
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
X : Big_Positive;
|
||||
Y : Big_Positive) return Boolean
|
||||
-- Returns True is Left and Right are the same except at positions X and Y
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => X <= Last (Left) and Y <= Last (Left),
|
||||
Post =>
|
||||
Equal_Except'Result =
|
||||
(Length (Left) = Length (Right)
|
||||
and then (for all J in Left =>
|
||||
(if J /= X and J /= Y then
|
||||
Get (Left, J) = Get (Right, J))));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Equal_Except);
|
||||
|
||||
function Range_Equal
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Fst : Big_Positive;
|
||||
Lst : Big_Natural) return Boolean
|
||||
-- Returns True if the ranges from Fst to Lst contain the same elements in
|
||||
-- Left and Right.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Lst <= Last (Left) and Lst <= Last (Right),
|
||||
Post =>
|
||||
Range_Equal'Result =
|
||||
(for all J in Left =>
|
||||
(if Fst <= J and J <= Lst then Get (Left, J) = Get (Right, J)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Range_Equal);
|
||||
|
||||
function Range_Shifted
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Fst : Big_Positive;
|
||||
Lst : Big_Natural;
|
||||
Offset : Big_Integer) return Boolean
|
||||
-- Returns True if the range from Fst to Lst in Left contains the same
|
||||
-- elements as the range from Fst + Offset to Lst + Offset in Right.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Lst <= Last (Left)
|
||||
and then
|
||||
(if Fst <= Lst then
|
||||
Offset + Fst >= 1 and Offset + Lst <= Length (Right)),
|
||||
Post =>
|
||||
Range_Shifted'Result =
|
||||
((for all J in Left =>
|
||||
(if Fst <= J and J <= Lst then
|
||||
Get (Left, J) = Get (Right, J + Offset)))
|
||||
and
|
||||
(for all J in Right =>
|
||||
(if Fst + Offset <= J and J <= Lst + Offset then
|
||||
Get (Left, J - Offset) = Get (Right, J))));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Range_Shifted);
|
||||
|
||||
----------------------------
|
||||
-- Construction Functions --
|
||||
----------------------------
|
||||
|
||||
-- For better efficiency of both proofs and execution, avoid using
|
||||
-- construction functions in annotations and rather use property functions.
|
||||
|
||||
function Set
|
||||
(Container : Sequence;
|
||||
Position : Big_Positive;
|
||||
New_Item : Element_Type) return Sequence
|
||||
-- Returns a new sequence which contains the same elements as Container
|
||||
-- except for the one at position Position which is replaced by New_Item.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Position <= Last (Container),
|
||||
Post =>
|
||||
Get (Set'Result, Position) = New_Item
|
||||
and then Equal_Except (Container, Set'Result, Position);
|
||||
|
||||
function Add (Container : Sequence; New_Item : Element_Type) return Sequence
|
||||
-- Returns a new sequence which contains the same elements as Container
|
||||
-- plus New_Item at the end.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Length (Add'Result) = Length (Container) + 1
|
||||
and then Get (Add'Result, Last (Add'Result)) = New_Item
|
||||
and then Container <= Add'Result;
|
||||
|
||||
function Add
|
||||
(Container : Sequence;
|
||||
Position : Big_Positive;
|
||||
New_Item : Element_Type) return Sequence
|
||||
with
|
||||
-- Returns a new sequence which contains the same elements as Container
|
||||
-- except that New_Item has been inserted at position Position.
|
||||
|
||||
Global => null,
|
||||
Pre => Position <= Last (Container) + 1,
|
||||
Post =>
|
||||
Length (Add'Result) = Length (Container) + 1
|
||||
and then Get (Add'Result, Position) = New_Item
|
||||
and then Range_Equal
|
||||
(Left => Container,
|
||||
Right => Add'Result,
|
||||
Fst => 1,
|
||||
Lst => Position - 1)
|
||||
and then Range_Shifted
|
||||
(Left => Container,
|
||||
Right => Add'Result,
|
||||
Fst => Position,
|
||||
Lst => Last (Container),
|
||||
Offset => 1);
|
||||
|
||||
function Remove
|
||||
(Container : Sequence;
|
||||
Position : Big_Positive) return Sequence
|
||||
-- Returns a new sequence which contains the same elements as Container
|
||||
-- except that the element at position Position has been removed.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Position <= Last (Container),
|
||||
Post =>
|
||||
Length (Remove'Result) = Length (Container) - 1
|
||||
and then Range_Equal
|
||||
(Left => Container,
|
||||
Right => Remove'Result,
|
||||
Fst => 1,
|
||||
Lst => Position - 1)
|
||||
and then Range_Shifted
|
||||
(Left => Remove'Result,
|
||||
Right => Container,
|
||||
Fst => Position,
|
||||
Lst => Last (Remove'Result),
|
||||
Offset => 1);
|
||||
|
||||
function Copy_Element (Item : Element_Type) return Element_Type is (Item);
|
||||
-- Elements of containers are copied by numerous primitives in this
|
||||
-- package. This function causes GNATprove to verify that such a copy is
|
||||
-- valid (in particular, it does not break the ownership policy of SPARK,
|
||||
-- i.e. it does not contain pointers that could be used to alias mutable
|
||||
-- data).
|
||||
|
||||
function Empty_Sequence return Sequence with
|
||||
-- Return an empty Sequence
|
||||
|
||||
Global => null,
|
||||
Post => Length (Empty_Sequence'Result) = 0;
|
||||
|
||||
---------------------------
|
||||
-- Iteration Primitives --
|
||||
---------------------------
|
||||
|
||||
function Iter_First (Container : Sequence) return Big_Integer with
|
||||
Global => null,
|
||||
Post => Iter_First'Result = 1;
|
||||
|
||||
function Iter_Has_Element
|
||||
(Container : Sequence;
|
||||
Position : Big_Integer) return Boolean
|
||||
with
|
||||
Global => null,
|
||||
Post => Iter_Has_Element'Result =
|
||||
In_Range (Position, 1, Length (Container));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Iter_Has_Element);
|
||||
|
||||
function Iter_Next
|
||||
(Container : Sequence;
|
||||
Position : Big_Integer) return Big_Integer
|
||||
with
|
||||
Global => null,
|
||||
Pre => Iter_Has_Element (Container, Position),
|
||||
Post => Iter_Next'Result = Position + 1;
|
||||
|
||||
private
|
||||
pragma SPARK_Mode (Off);
|
||||
|
||||
subtype Positive_Count_Type is Count_Type range 1 .. Count_Type'Last;
|
||||
|
||||
package Containers is new Ada.Containers.Functional_Base
|
||||
(Index_Type => Positive_Count_Type,
|
||||
Element_Type => Element_Type);
|
||||
|
||||
type Sequence is record
|
||||
Content : Containers.Container;
|
||||
end record;
|
||||
|
||||
function Iter_First (Container : Sequence) return Big_Integer is (1);
|
||||
|
||||
function Iter_Next
|
||||
(Container : Sequence;
|
||||
Position : Big_Integer) return Big_Integer
|
||||
is
|
||||
(Position + 1);
|
||||
|
||||
function Iter_Has_Element
|
||||
(Container : Sequence;
|
||||
Position : Big_Integer) return Boolean
|
||||
is
|
||||
(In_Range (Position, 1, Length (Container)));
|
||||
end Ada.Containers.Functional_Infinite_Sequences;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,959 +29,12 @@
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Similar to Ada.Containers.Formal_Vectors. The main difference is that
|
||||
-- Element_Type may be indefinite (but not an unconstrained array).
|
||||
|
||||
with Ada.Containers.Bounded_Holders;
|
||||
with Ada.Containers.Functional_Vectors;
|
||||
|
||||
generic
|
||||
type Index_Type is range <>;
|
||||
type Element_Type (<>) is private;
|
||||
with function "=" (Left, Right : Element_Type) return Boolean is <>;
|
||||
Max_Size_In_Storage_Elements : Natural;
|
||||
-- Maximum size of Vector elements in bytes. This has the same meaning as
|
||||
-- in Ada.Containers.Bounded_Holders, with the same restrictions. Note that
|
||||
-- setting this too small can lead to erroneous execution; see comments in
|
||||
-- Ada.Containers.Bounded_Holders. If Element_Type is class-wide, it is the
|
||||
-- responsibility of clients to calculate the maximum size of all types in
|
||||
-- the class.
|
||||
package Ada.Containers.Formal_Indefinite_Vectors with SPARK_Mode is
|
||||
|
||||
Bounded : Boolean := True;
|
||||
-- If True, the containers are bounded; the initial capacity is the maximum
|
||||
-- size, and heap allocation will be avoided. If False, the containers can
|
||||
-- grow via heap allocation.
|
||||
|
||||
package Ada.Containers.Formal_Indefinite_Vectors with
|
||||
SPARK_Mode,
|
||||
Annotate => (GNATprove, Always_Return)
|
||||
is
|
||||
|
||||
-- Contracts in this unit are meant for analysis only, not for run-time
|
||||
-- checking.
|
||||
|
||||
pragma Assertion_Policy (Pre => Ignore);
|
||||
pragma Assertion_Policy (Post => Ignore);
|
||||
pragma Assertion_Policy (Contract_Cases => Ignore);
|
||||
pragma Annotate (CodePeer, Skip_Analysis);
|
||||
|
||||
subtype Extended_Index is Index_Type'Base
|
||||
range Index_Type'First - 1 ..
|
||||
Index_Type'Min (Index_Type'Base'Last - 1, Index_Type'Last) + 1;
|
||||
|
||||
No_Index : constant Extended_Index := Extended_Index'First;
|
||||
|
||||
Last_Count : constant Count_Type :=
|
||||
(if Index_Type'Last < Index_Type'First then
|
||||
0
|
||||
elsif Index_Type'Last < -1
|
||||
or else Index_Type'Pos (Index_Type'First) >
|
||||
Index_Type'Pos (Index_Type'Last) - Count_Type'Last
|
||||
then
|
||||
Index_Type'Pos (Index_Type'Last) -
|
||||
Index_Type'Pos (Index_Type'First) + 1
|
||||
else
|
||||
Count_Type'Last);
|
||||
-- Maximal capacity of any vector. It is the minimum of the size of the
|
||||
-- index range and the last possible Count_Type.
|
||||
|
||||
subtype Capacity_Range is Count_Type range 0 .. Last_Count;
|
||||
|
||||
type Vector (Capacity : Capacity_Range) is limited private with
|
||||
Default_Initial_Condition => Is_Empty (Vector);
|
||||
-- In the bounded case, Capacity is the capacity of the container, which
|
||||
-- never changes. In the unbounded case, Capacity is the initial capacity
|
||||
-- of the container, and operations such as Reserve_Capacity and Append can
|
||||
-- increase the capacity. The capacity never shrinks, except in the case of
|
||||
-- Clear.
|
||||
--
|
||||
-- Note that all objects of type Vector are constrained, including in the
|
||||
-- unbounded case; you can't assign from one object to another if the
|
||||
-- Capacity is different.
|
||||
|
||||
function Length (Container : Vector) return Capacity_Range with
|
||||
Global => null,
|
||||
Post => Length'Result <= Capacity (Container);
|
||||
|
||||
pragma Unevaluated_Use_Of_Old (Allow);
|
||||
|
||||
package Formal_Model with Ghost is
|
||||
|
||||
package M is new Ada.Containers.Functional_Vectors
|
||||
(Index_Type => Index_Type,
|
||||
Element_Type => Element_Type);
|
||||
|
||||
function "="
|
||||
(Left : M.Sequence;
|
||||
Right : M.Sequence) return Boolean renames M."=";
|
||||
|
||||
function "<"
|
||||
(Left : M.Sequence;
|
||||
Right : M.Sequence) return Boolean renames M."<";
|
||||
|
||||
function "<="
|
||||
(Left : M.Sequence;
|
||||
Right : M.Sequence) return Boolean renames M."<=";
|
||||
|
||||
function M_Elements_In_Union
|
||||
(Container : M.Sequence;
|
||||
Left : M.Sequence;
|
||||
Right : M.Sequence) return Boolean
|
||||
-- The elements of Container are contained in either Left or Right
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
M_Elements_In_Union'Result =
|
||||
(for all I in Index_Type'First .. M.Last (Container) =>
|
||||
(for some J in Index_Type'First .. M.Last (Left) =>
|
||||
Element (Container, I) = Element (Left, J))
|
||||
or (for some J in Index_Type'First .. M.Last (Right) =>
|
||||
Element (Container, I) = Element (Right, J)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_In_Union);
|
||||
|
||||
function M_Elements_Included
|
||||
(Left : M.Sequence;
|
||||
L_Fst : Index_Type := Index_Type'First;
|
||||
L_Lst : Extended_Index;
|
||||
Right : M.Sequence;
|
||||
R_Fst : Index_Type := Index_Type'First;
|
||||
R_Lst : Extended_Index) return Boolean
|
||||
-- The elements of the slice from L_Fst to L_Lst in Left are contained
|
||||
-- in the slide from R_Fst to R_Lst in Right.
|
||||
with
|
||||
Global => null,
|
||||
Pre => L_Lst <= M.Last (Left) and R_Lst <= M.Last (Right),
|
||||
Post =>
|
||||
M_Elements_Included'Result =
|
||||
(for all I in L_Fst .. L_Lst =>
|
||||
(for some J in R_Fst .. R_Lst =>
|
||||
Element (Left, I) = Element (Right, J)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Included);
|
||||
|
||||
function M_Elements_Reversed
|
||||
(Left : M.Sequence;
|
||||
Right : M.Sequence) return Boolean
|
||||
-- Right is Left in reverse order
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
M_Elements_Reversed'Result =
|
||||
(M.Length (Left) = M.Length (Right)
|
||||
and (for all I in Index_Type'First .. M.Last (Left) =>
|
||||
Element (Left, I) =
|
||||
Element (Right, M.Last (Left) - I + 1))
|
||||
and (for all I in Index_Type'First .. M.Last (Right) =>
|
||||
Element (Right, I) =
|
||||
Element (Left, M.Last (Left) - I + 1)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Reversed);
|
||||
|
||||
function M_Elements_Swapped
|
||||
(Left : M.Sequence;
|
||||
Right : M.Sequence;
|
||||
X : Index_Type;
|
||||
Y : Index_Type) return Boolean
|
||||
-- Elements stored at X and Y are reversed in Left and Right
|
||||
with
|
||||
Global => null,
|
||||
Pre => X <= M.Last (Left) and Y <= M.Last (Left),
|
||||
Post =>
|
||||
M_Elements_Swapped'Result =
|
||||
(M.Length (Left) = M.Length (Right)
|
||||
and Element (Left, X) = Element (Right, Y)
|
||||
and Element (Left, Y) = Element (Right, X)
|
||||
and M.Equal_Except (Left, Right, X, Y));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Swapped);
|
||||
|
||||
function Model (Container : Vector) return M.Sequence with
|
||||
-- The high-level model of a vector is a sequence of elements. The
|
||||
-- sequence really is similar to the vector itself. However, it is not
|
||||
-- limited which allows usage of 'Old and 'Loop_Entry attributes.
|
||||
|
||||
Ghost,
|
||||
Global => null,
|
||||
Post => M.Length (Model'Result) = Length (Container);
|
||||
|
||||
function Element
|
||||
(S : M.Sequence;
|
||||
I : Index_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 Empty_Vector return Vector with
|
||||
Global => null,
|
||||
Post => Length (Empty_Vector'Result) = 0;
|
||||
|
||||
function "=" (Left, Right : Vector) return Boolean with
|
||||
Global => null,
|
||||
Post => "="'Result = (Model (Left) = Model (Right));
|
||||
|
||||
function To_Vector
|
||||
(New_Item : Element_Type;
|
||||
Length : Capacity_Range) return Vector
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Formal_Indefinite_Vectors.Length (To_Vector'Result) = Length
|
||||
and M.Constant_Range
|
||||
(Container => Model (To_Vector'Result),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (To_Vector'Result),
|
||||
Item => New_Item);
|
||||
|
||||
function Capacity (Container : Vector) return Capacity_Range with
|
||||
Global => null,
|
||||
Post =>
|
||||
Capacity'Result =
|
||||
(if Bounded then
|
||||
Container.Capacity
|
||||
else
|
||||
Capacity_Range'Last);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Capacity);
|
||||
|
||||
procedure Reserve_Capacity
|
||||
(Container : in out Vector;
|
||||
Capacity : Capacity_Range)
|
||||
with
|
||||
Global => null,
|
||||
Pre => (if Bounded then Capacity <= Container.Capacity),
|
||||
Post => Model (Container) = Model (Container)'Old;
|
||||
|
||||
function Is_Empty (Container : Vector) return Boolean with
|
||||
Global => null,
|
||||
Post => Is_Empty'Result = (Length (Container) = 0);
|
||||
|
||||
procedure Clear (Container : in out Vector) with
|
||||
Global => null,
|
||||
Post => Length (Container) = 0;
|
||||
-- Note that this reclaims storage in the unbounded case. You need to call
|
||||
-- this before a container goes out of scope in order to avoid storage
|
||||
-- leaks. In addition, "X := ..." can leak unless you Clear(X) first.
|
||||
|
||||
procedure Assign (Target : in out Vector; Source : Vector) with
|
||||
Global => null,
|
||||
Pre => (if Bounded then Length (Source) <= Target.Capacity),
|
||||
Post => Model (Target) = Model (Source);
|
||||
|
||||
function Copy
|
||||
(Source : Vector;
|
||||
Capacity : Capacity_Range := 0) return Vector
|
||||
with
|
||||
Global => null,
|
||||
Pre => (if Bounded then (Capacity = 0 or Length (Source) <= Capacity)),
|
||||
Post =>
|
||||
Model (Copy'Result) = Model (Source)
|
||||
and (if Capacity = 0 then
|
||||
Copy'Result.Capacity = Length (Source)
|
||||
else
|
||||
Copy'Result.Capacity = Capacity);
|
||||
|
||||
procedure Move (Target : in out Vector; Source : in out Vector)
|
||||
with
|
||||
Global => null,
|
||||
Pre => (if Bounded then Length (Source) <= Capacity (Target)),
|
||||
Post => Model (Target) = Model (Source)'Old and Length (Source) = 0;
|
||||
|
||||
function Element
|
||||
(Container : Vector;
|
||||
Index : Extended_Index) return Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre => Index in First_Index (Container) .. Last_Index (Container),
|
||||
Post => Element'Result = Element (Model (Container), Index);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Element);
|
||||
|
||||
procedure Replace_Element
|
||||
(Container : in out Vector;
|
||||
Index : Index_Type;
|
||||
New_Item : Element_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre => Index in First_Index (Container) .. Last_Index (Container),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old
|
||||
|
||||
-- Container now has New_Item at index Index
|
||||
|
||||
and Element (Model (Container), Index) = New_Item
|
||||
|
||||
-- All other elements are preserved
|
||||
|
||||
and M.Equal_Except
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Position => Index);
|
||||
|
||||
function At_End (E : access constant Vector) return access constant Vector
|
||||
is (E)
|
||||
with Ghost,
|
||||
Annotate => (GNATprove, At_End_Borrow);
|
||||
|
||||
function At_End
|
||||
(E : access constant Element_Type) return access constant Element_Type
|
||||
is (E)
|
||||
with Ghost,
|
||||
Annotate => (GNATprove, At_End_Borrow);
|
||||
|
||||
function Constant_Reference
|
||||
(Container : aliased Vector;
|
||||
Index : Index_Type) return not null access constant Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre => Index in First_Index (Container) .. Last_Index (Container),
|
||||
Post =>
|
||||
Constant_Reference'Result.all = Element (Model (Container), Index);
|
||||
|
||||
function Reference
|
||||
(Container : not null access Vector;
|
||||
Index : Index_Type) return not null access Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Index in First_Index (Container.all) .. Last_Index (Container.all),
|
||||
Post =>
|
||||
Length (Container.all) = Length (At_End (Container).all)
|
||||
|
||||
-- Container will have Result.all at index Index
|
||||
|
||||
and At_End (Reference'Result).all =
|
||||
Element (Model (At_End (Container).all), Index)
|
||||
|
||||
-- All other elements are preserved
|
||||
|
||||
and M.Equal_Except
|
||||
(Left => Model (Container.all),
|
||||
Right => Model (At_End (Container).all),
|
||||
Position => Index);
|
||||
|
||||
procedure Insert
|
||||
(Container : in out Vector;
|
||||
Before : Extended_Index;
|
||||
New_Item : Vector)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) <= Capacity (Container) - Length (New_Item)
|
||||
and (Before in Index_Type'First .. Last_Index (Container)
|
||||
or (Before /= No_Index
|
||||
and then Before - 1 = Last_Index (Container))),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Length (New_Item)
|
||||
|
||||
-- Elements located before Before in Container are preserved
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Before - 1)
|
||||
|
||||
-- Elements of New_Item are inserted at position Before
|
||||
|
||||
and (if Length (New_Item) > 0 then
|
||||
M.Range_Shifted
|
||||
(Left => Model (New_Item),
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (New_Item),
|
||||
Offset => Count_Type (Before - Index_Type'First)))
|
||||
|
||||
-- Elements located after Before in Container are shifted
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Before,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => Length (New_Item));
|
||||
|
||||
procedure Insert
|
||||
(Container : in out Vector;
|
||||
Before : Extended_Index;
|
||||
New_Item : Element_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) < Capacity (Container)
|
||||
and then (Before in Index_Type'First .. Last_Index (Container) + 1),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + 1
|
||||
|
||||
-- Elements located before Before in Container are preserved
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Before - 1)
|
||||
|
||||
-- Container now has New_Item at index Before
|
||||
|
||||
and Element (Model (Container), Before) = New_Item
|
||||
|
||||
-- Elements located after Before in Container are shifted by 1
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Before,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => 1);
|
||||
|
||||
procedure Insert
|
||||
(Container : in out Vector;
|
||||
Before : Extended_Index;
|
||||
New_Item : Element_Type;
|
||||
Count : Count_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) <= Capacity (Container) - Count
|
||||
and (Before in Index_Type'First .. Last_Index (Container)
|
||||
or (Before /= No_Index
|
||||
and then Before - 1 = Last_Index (Container))),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Count
|
||||
|
||||
-- Elements located before Before in Container are preserved
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Before - 1)
|
||||
|
||||
-- New_Item is inserted Count times at position Before
|
||||
|
||||
and (if Count > 0 then
|
||||
M.Constant_Range
|
||||
(Container => Model (Container),
|
||||
Fst => Before,
|
||||
Lst => Before + Index_Type'Base (Count - 1),
|
||||
Item => New_Item))
|
||||
|
||||
-- Elements located after Before in Container are shifted
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Before,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => Count);
|
||||
|
||||
procedure Prepend (Container : in out Vector; New_Item : Vector) with
|
||||
Global => null,
|
||||
Pre => Length (Container) <= Capacity (Container) - Length (New_Item),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Length (New_Item)
|
||||
|
||||
-- Elements of New_Item are inserted at the beginning of Container
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (New_Item),
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (New_Item))
|
||||
|
||||
-- Elements of Container are shifted
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => Length (New_Item));
|
||||
|
||||
procedure Prepend (Container : in out Vector; New_Item : Element_Type) with
|
||||
Global => null,
|
||||
Pre => Length (Container) < Capacity (Container),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + 1
|
||||
|
||||
-- Container now has New_Item at Index_Type'First
|
||||
|
||||
and Element (Model (Container), Index_Type'First) = New_Item
|
||||
|
||||
-- Elements of Container are shifted by 1
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => 1);
|
||||
|
||||
procedure Prepend
|
||||
(Container : in out Vector;
|
||||
New_Item : Element_Type;
|
||||
Count : Count_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre => Length (Container) <= Capacity (Container) - Count,
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Count
|
||||
|
||||
-- New_Item is inserted Count times at the beginning of Container
|
||||
|
||||
and M.Constant_Range
|
||||
(Container => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Index_Type'First + Index_Type'Base (Count - 1),
|
||||
Item => New_Item)
|
||||
|
||||
-- Elements of Container are shifted
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => Count);
|
||||
|
||||
procedure Append (Container : in out Vector; New_Item : Vector) with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) <= Capacity (Container) - Length (New_Item),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Length (New_Item)
|
||||
|
||||
-- The elements of Container are preserved
|
||||
|
||||
and Model (Container)'Old <= Model (Container)
|
||||
|
||||
-- Elements of New_Item are inserted at the end of Container
|
||||
|
||||
and (if Length (New_Item) > 0 then
|
||||
M.Range_Shifted
|
||||
(Left => Model (New_Item),
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (New_Item),
|
||||
Offset =>
|
||||
Count_Type
|
||||
(Last_Index (Container)'Old - Index_Type'First + 1)));
|
||||
|
||||
procedure Append (Container : in out Vector; New_Item : Element_Type) with
|
||||
Global => null,
|
||||
Pre => Length (Container) < Capacity (Container),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + 1
|
||||
|
||||
-- Elements of Container are preserved
|
||||
|
||||
and Model (Container)'Old < Model (Container)
|
||||
|
||||
-- Container now has New_Item at the end of Container
|
||||
|
||||
and Element
|
||||
(Model (Container), Last_Index (Container)'Old + 1) = New_Item;
|
||||
|
||||
procedure Append
|
||||
(Container : in out Vector;
|
||||
New_Item : Element_Type;
|
||||
Count : Count_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre => Length (Container) <= Capacity (Container) - Count,
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Count
|
||||
|
||||
-- Elements of Container are preserved
|
||||
|
||||
and Model (Container)'Old <= Model (Container)
|
||||
|
||||
-- New_Item is inserted Count times at the end of Container
|
||||
|
||||
and (if Count > 0 then
|
||||
M.Constant_Range
|
||||
(Container => Model (Container),
|
||||
Fst => Last_Index (Container)'Old + 1,
|
||||
Lst =>
|
||||
Last_Index (Container)'Old + Index_Type'Base (Count),
|
||||
Item => New_Item));
|
||||
|
||||
procedure Delete (Container : in out Vector; Index : Extended_Index) with
|
||||
Global => null,
|
||||
Pre => Index in First_Index (Container) .. Last_Index (Container),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old - 1
|
||||
|
||||
-- Elements located before Index in Container are preserved
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Index - 1)
|
||||
|
||||
-- Elements located after Index in Container are shifted by 1
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container),
|
||||
Right => Model (Container)'Old,
|
||||
Fst => Index,
|
||||
Lst => Last_Index (Container),
|
||||
Offset => 1);
|
||||
|
||||
procedure Delete
|
||||
(Container : in out Vector;
|
||||
Index : Extended_Index;
|
||||
Count : Count_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Index in First_Index (Container) .. Last_Index (Container),
|
||||
Post =>
|
||||
Length (Container) in
|
||||
Length (Container)'Old - Count .. Length (Container)'Old
|
||||
|
||||
-- The elements of Container located before Index are preserved.
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Index - 1),
|
||||
|
||||
Contract_Cases =>
|
||||
|
||||
-- All the elements after Position have been erased
|
||||
|
||||
(Length (Container) - Count <= Count_Type (Index - Index_Type'First) =>
|
||||
Length (Container) = Count_Type (Index - Index_Type'First),
|
||||
|
||||
others =>
|
||||
Length (Container) = Length (Container)'Old - Count
|
||||
|
||||
-- Other elements are shifted by Count
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container),
|
||||
Right => Model (Container)'Old,
|
||||
Fst => Index,
|
||||
Lst => Last_Index (Container),
|
||||
Offset => Count));
|
||||
|
||||
procedure Delete_First (Container : in out Vector) with
|
||||
Global => null,
|
||||
Pre => Length (Container) > 0,
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old - 1
|
||||
|
||||
-- Elements of Container are shifted by 1
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container),
|
||||
Right => Model (Container)'Old,
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container),
|
||||
Offset => 1);
|
||||
|
||||
procedure Delete_First (Container : in out Vector; 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.Range_Shifted
|
||||
(Left => Model (Container),
|
||||
Right => Model (Container)'Old,
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container),
|
||||
Offset => Count));
|
||||
|
||||
procedure Delete_Last (Container : in out Vector) with
|
||||
Global => null,
|
||||
Pre => Length (Container) > 0,
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old - 1
|
||||
|
||||
-- Elements of Container are preserved
|
||||
|
||||
and Model (Container) < Model (Container)'Old;
|
||||
|
||||
procedure Delete_Last (Container : in out Vector; Count : Count_Type) with
|
||||
Global => null,
|
||||
Contract_Cases =>
|
||||
|
||||
-- All the elements after Position 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);
|
||||
|
||||
procedure Reverse_Elements (Container : in out Vector) with
|
||||
Global => null,
|
||||
Post => M_Elements_Reversed (Model (Container)'Old, Model (Container));
|
||||
|
||||
procedure Swap
|
||||
(Container : in out Vector;
|
||||
I : Index_Type;
|
||||
J : Index_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
I in First_Index (Container) .. Last_Index (Container)
|
||||
and then J in First_Index (Container) .. Last_Index (Container),
|
||||
Post =>
|
||||
M_Elements_Swapped (Model (Container)'Old, Model (Container), I, J);
|
||||
|
||||
function First_Index (Container : Vector) return Index_Type with
|
||||
Global => null,
|
||||
Post => First_Index'Result = Index_Type'First;
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, First_Index);
|
||||
|
||||
function First_Element (Container : Vector) return Element_Type with
|
||||
Global => null,
|
||||
Pre => not Is_Empty (Container),
|
||||
Post =>
|
||||
First_Element'Result = Element (Model (Container), Index_Type'First);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, First_Element);
|
||||
|
||||
function Last_Index (Container : Vector) return Extended_Index with
|
||||
Global => null,
|
||||
Post => Last_Index'Result = M.Last (Model (Container));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Last_Index);
|
||||
|
||||
function Last_Element (Container : Vector) return Element_Type with
|
||||
Global => null,
|
||||
Pre => not Is_Empty (Container),
|
||||
Post =>
|
||||
Last_Element'Result =
|
||||
Element (Model (Container), Last_Index (Container));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Last_Element);
|
||||
|
||||
function Find_Index
|
||||
(Container : Vector;
|
||||
Item : Element_Type;
|
||||
Index : Index_Type := Index_Type'First) return Extended_Index
|
||||
with
|
||||
Global => null,
|
||||
Contract_Cases =>
|
||||
|
||||
-- If Item is not contained in Container after Index, Find_Index
|
||||
-- returns No_Index.
|
||||
|
||||
(Index > Last_Index (Container)
|
||||
or else not M.Contains
|
||||
(Container => Model (Container),
|
||||
Fst => Index,
|
||||
Lst => Last_Index (Container),
|
||||
Item => Item)
|
||||
=>
|
||||
Find_Index'Result = No_Index,
|
||||
|
||||
-- Otherwise, Find_Index returns a valid index greater than Index
|
||||
|
||||
others =>
|
||||
Find_Index'Result in Index .. Last_Index (Container)
|
||||
|
||||
-- The element at this index in Container is Item
|
||||
|
||||
and Element (Model (Container), Find_Index'Result) = Item
|
||||
|
||||
-- It is the first occurrence of Item after Index in Container
|
||||
|
||||
and not M.Contains
|
||||
(Container => Model (Container),
|
||||
Fst => Index,
|
||||
Lst => Find_Index'Result - 1,
|
||||
Item => Item));
|
||||
|
||||
function Reverse_Find_Index
|
||||
(Container : Vector;
|
||||
Item : Element_Type;
|
||||
Index : Index_Type := Index_Type'Last) return Extended_Index
|
||||
with
|
||||
Global => null,
|
||||
Contract_Cases =>
|
||||
|
||||
-- If Item is not contained in Container before Index,
|
||||
-- Reverse_Find_Index returns No_Index.
|
||||
|
||||
(not M.Contains
|
||||
(Container => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => (if Index <= Last_Index (Container) then Index
|
||||
else Last_Index (Container)),
|
||||
Item => Item)
|
||||
=>
|
||||
Reverse_Find_Index'Result = No_Index,
|
||||
|
||||
-- Otherwise, Reverse_Find_Index returns a valid index smaller than
|
||||
-- Index
|
||||
|
||||
others =>
|
||||
Reverse_Find_Index'Result in Index_Type'First .. Index
|
||||
and Reverse_Find_Index'Result <= Last_Index (Container)
|
||||
|
||||
-- The element at this index in Container is Item
|
||||
|
||||
and Element (Model (Container), Reverse_Find_Index'Result) = Item
|
||||
|
||||
-- It is the last occurrence of Item before Index in Container
|
||||
|
||||
and not M.Contains
|
||||
(Container => Model (Container),
|
||||
Fst => Reverse_Find_Index'Result + 1,
|
||||
Lst =>
|
||||
(if Index <= Last_Index (Container) then
|
||||
Index
|
||||
else
|
||||
Last_Index (Container)),
|
||||
Item => Item));
|
||||
|
||||
function Contains
|
||||
(Container : Vector;
|
||||
Item : Element_Type) return Boolean
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Contains'Result =
|
||||
M.Contains
|
||||
(Container => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container),
|
||||
Item => Item);
|
||||
|
||||
function Has_Element
|
||||
(Container : Vector;
|
||||
Position : Extended_Index) return Boolean
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Has_Element'Result =
|
||||
(Position in Index_Type'First .. Last_Index (Container));
|
||||
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
|
||||
|
||||
package Formal_Model with Ghost is
|
||||
|
||||
function M_Elements_Sorted (Container : M.Sequence) return Boolean
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
M_Elements_Sorted'Result =
|
||||
(for all I in Index_Type'First .. M.Last (Container) =>
|
||||
(for all J in I .. M.Last (Container) =>
|
||||
Element (Container, I) = Element (Container, J)
|
||||
or Element (Container, I) < Element (Container, J)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Sorted);
|
||||
|
||||
end Formal_Model;
|
||||
use Formal_Model;
|
||||
|
||||
function Is_Sorted (Container : Vector) return Boolean with
|
||||
Global => null,
|
||||
Post => Is_Sorted'Result = M_Elements_Sorted (Model (Container));
|
||||
|
||||
procedure Sort (Container : in out Vector) with
|
||||
Global => null,
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old
|
||||
and M_Elements_Sorted (Model (Container))
|
||||
and M_Elements_Included
|
||||
(Left => Model (Container)'Old,
|
||||
L_Lst => Last_Index (Container),
|
||||
Right => Model (Container),
|
||||
R_Lst => Last_Index (Container))
|
||||
and M_Elements_Included
|
||||
(Left => Model (Container),
|
||||
L_Lst => Last_Index (Container),
|
||||
Right => Model (Container)'Old,
|
||||
R_Lst => Last_Index (Container));
|
||||
|
||||
procedure Merge (Target : in out Vector; Source : in out Vector) with
|
||||
-- Target and Source should not be aliased
|
||||
Global => null,
|
||||
Pre => Length (Source) <= Capacity (Target) - 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)))
|
||||
and M_Elements_Included
|
||||
(Left => Model (Target)'Old,
|
||||
L_Lst => Last_Index (Target)'Old,
|
||||
Right => Model (Target),
|
||||
R_Lst => Last_Index (Target))
|
||||
and M_Elements_Included
|
||||
(Left => Model (Source)'Old,
|
||||
L_Lst => Last_Index (Source)'Old,
|
||||
Right => Model (Target),
|
||||
R_Lst => Last_Index (Target))
|
||||
and M_Elements_In_Union
|
||||
(Model (Target),
|
||||
Model (Source)'Old,
|
||||
Model (Target)'Old);
|
||||
end Generic_Sorting;
|
||||
|
||||
private
|
||||
pragma SPARK_Mode (Off);
|
||||
|
||||
pragma Inline (First_Index);
|
||||
pragma Inline (Last_Index);
|
||||
pragma Inline (Element);
|
||||
pragma Inline (First_Element);
|
||||
pragma Inline (Last_Element);
|
||||
pragma Inline (Replace_Element);
|
||||
pragma Inline (Contains);
|
||||
|
||||
-- The implementation method is to instantiate Bounded_Holders to get a
|
||||
-- definite type for Element_Type.
|
||||
|
||||
package Holders is new Bounded_Holders
|
||||
(Element_Type, Max_Size_In_Storage_Elements, "=");
|
||||
use Holders;
|
||||
|
||||
subtype Array_Index is Capacity_Range range 1 .. Capacity_Range'Last;
|
||||
type Elements_Array is array (Array_Index range <>) of aliased Holder;
|
||||
function "=" (L, R : Elements_Array) return Boolean is abstract;
|
||||
|
||||
type Elements_Array_Ptr is access all Elements_Array;
|
||||
|
||||
type Vector (Capacity : Capacity_Range) is limited record
|
||||
|
||||
-- In the bounded case, the elements are stored in Elements. In the
|
||||
-- unbounded case, the elements are initially stored in Elements, until
|
||||
-- we run out of room, then we switch to Elements_Ptr.
|
||||
|
||||
Last : Extended_Index := No_Index;
|
||||
Elements_Ptr : Elements_Array_Ptr := null;
|
||||
Elements : aliased Elements_Array (1 .. Capacity);
|
||||
end record;
|
||||
|
||||
-- The primary reason Vector is limited is that in the unbounded case, once
|
||||
-- Elements_Ptr is in use, assignment statements won't work. "X := Y;" will
|
||||
-- cause X and Y to share state; that is, X.Elements_Ptr = Y.Elements_Ptr,
|
||||
-- so for example "Append (X, ...);" will modify BOTH X and Y. That would
|
||||
-- allow SPARK to "prove" things that are false. We could fix that by
|
||||
-- making Vector a controlled type, and override Adjust to make a deep
|
||||
-- copy, but finalization is not allowed in SPARK.
|
||||
--
|
||||
-- Note that (unfortunately) this means that 'Old and 'Loop_Entry are not
|
||||
-- allowed on Vectors.
|
||||
|
||||
function Empty_Vector return Vector is
|
||||
((Capacity => 0, others => <>));
|
||||
pragma Compile_Time_Error
|
||||
(True,
|
||||
"This package has been moved to the SPARK library shipped with any"
|
||||
& " SPARK release starting with version 23.");
|
||||
|
||||
end Ada.Containers.Formal_Indefinite_Vectors;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -29,954 +29,12 @@
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- This spec is derived from package Ada.Containers.Bounded_Vectors 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.
|
||||
|
||||
with Ada.Containers.Functional_Vectors;
|
||||
|
||||
generic
|
||||
type Index_Type is range <>;
|
||||
type Element_Type is private;
|
||||
with function "=" (Left, Right : Element_Type) return Boolean is <>;
|
||||
package Ada.Containers.Formal_Vectors with SPARK_Mode is
|
||||
|
||||
package Ada.Containers.Formal_Vectors with
|
||||
SPARK_Mode
|
||||
is
|
||||
pragma Annotate (GNATprove, Always_Return, Formal_Vectors);
|
||||
|
||||
-- Contracts in this unit are meant for analysis only, not for run-time
|
||||
-- checking.
|
||||
|
||||
pragma Assertion_Policy (Pre => Ignore);
|
||||
pragma Assertion_Policy (Post => Ignore);
|
||||
pragma Assertion_Policy (Contract_Cases => Ignore);
|
||||
pragma Annotate (CodePeer, Skip_Analysis);
|
||||
|
||||
subtype Extended_Index is Index_Type'Base
|
||||
range Index_Type'First - 1 ..
|
||||
Index_Type'Min (Index_Type'Base'Last - 1, Index_Type'Last) + 1;
|
||||
|
||||
No_Index : constant Extended_Index := Extended_Index'First;
|
||||
|
||||
Last_Count : constant Count_Type :=
|
||||
(if Index_Type'Last < Index_Type'First then
|
||||
0
|
||||
elsif Index_Type'Last < -1
|
||||
or else Index_Type'Pos (Index_Type'First) >
|
||||
Index_Type'Pos (Index_Type'Last) - Count_Type'Last
|
||||
then
|
||||
Index_Type'Pos (Index_Type'Last) -
|
||||
Index_Type'Pos (Index_Type'First) + 1
|
||||
else
|
||||
Count_Type'Last);
|
||||
-- Maximal capacity of any vector. It is the minimum of the size of the
|
||||
-- index range and the last possible Count_Type.
|
||||
|
||||
subtype Capacity_Range is Count_Type range 0 .. Last_Count;
|
||||
|
||||
type Vector (Capacity : Capacity_Range) is private with
|
||||
Default_Initial_Condition => Is_Empty (Vector),
|
||||
Iterable => (First => Iter_First,
|
||||
Has_Element => Iter_Has_Element,
|
||||
Next => Iter_Next,
|
||||
Element => Element);
|
||||
|
||||
function Length (Container : Vector) return Capacity_Range with
|
||||
Global => null,
|
||||
Post => Length'Result <= Capacity (Container);
|
||||
|
||||
pragma Unevaluated_Use_Of_Old (Allow);
|
||||
|
||||
package Formal_Model with Ghost is
|
||||
|
||||
package M is new Ada.Containers.Functional_Vectors
|
||||
(Index_Type => Index_Type,
|
||||
Element_Type => Element_Type);
|
||||
|
||||
function "="
|
||||
(Left : M.Sequence;
|
||||
Right : M.Sequence) return Boolean renames M."=";
|
||||
|
||||
function "<"
|
||||
(Left : M.Sequence;
|
||||
Right : M.Sequence) return Boolean renames M."<";
|
||||
|
||||
function "<="
|
||||
(Left : M.Sequence;
|
||||
Right : M.Sequence) return Boolean renames M."<=";
|
||||
|
||||
function M_Elements_In_Union
|
||||
(Container : M.Sequence;
|
||||
Left : M.Sequence;
|
||||
Right : M.Sequence) return Boolean
|
||||
-- The elements of Container are contained in either Left or Right
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
M_Elements_In_Union'Result =
|
||||
(for all I in Index_Type'First .. M.Last (Container) =>
|
||||
(for some J in Index_Type'First .. M.Last (Left) =>
|
||||
Element (Container, I) = Element (Left, J))
|
||||
or (for some J in Index_Type'First .. M.Last (Right) =>
|
||||
Element (Container, I) = Element (Right, J)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_In_Union);
|
||||
|
||||
function M_Elements_Included
|
||||
(Left : M.Sequence;
|
||||
L_Fst : Index_Type := Index_Type'First;
|
||||
L_Lst : Extended_Index;
|
||||
Right : M.Sequence;
|
||||
R_Fst : Index_Type := Index_Type'First;
|
||||
R_Lst : Extended_Index) return Boolean
|
||||
-- The elements of the slice from L_Fst to L_Lst in Left are contained
|
||||
-- in the slide from R_Fst to R_Lst in Right.
|
||||
with
|
||||
Global => null,
|
||||
Pre => L_Lst <= M.Last (Left) and R_Lst <= M.Last (Right),
|
||||
Post =>
|
||||
M_Elements_Included'Result =
|
||||
(for all I in L_Fst .. L_Lst =>
|
||||
(for some J in R_Fst .. R_Lst =>
|
||||
Element (Left, I) = Element (Right, J)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Included);
|
||||
|
||||
function M_Elements_Reversed
|
||||
(Left : M.Sequence;
|
||||
Right : M.Sequence) return Boolean
|
||||
-- Right is Left in reverse order
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
M_Elements_Reversed'Result =
|
||||
(M.Length (Left) = M.Length (Right)
|
||||
and (for all I in Index_Type'First .. M.Last (Left) =>
|
||||
Element (Left, I) =
|
||||
Element (Right, M.Last (Left) - I + 1))
|
||||
and (for all I in Index_Type'First .. M.Last (Right) =>
|
||||
Element (Right, I) =
|
||||
Element (Left, M.Last (Left) - I + 1)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Reversed);
|
||||
|
||||
function M_Elements_Swapped
|
||||
(Left : M.Sequence;
|
||||
Right : M.Sequence;
|
||||
X : Index_Type;
|
||||
Y : Index_Type) return Boolean
|
||||
-- Elements stored at X and Y are reversed in Left and Right
|
||||
with
|
||||
Global => null,
|
||||
Pre => X <= M.Last (Left) and Y <= M.Last (Left),
|
||||
Post =>
|
||||
M_Elements_Swapped'Result =
|
||||
(M.Length (Left) = M.Length (Right)
|
||||
and Element (Left, X) = Element (Right, Y)
|
||||
and Element (Left, Y) = Element (Right, X)
|
||||
and M.Equal_Except (Left, Right, X, Y));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Swapped);
|
||||
|
||||
function Model (Container : Vector) return M.Sequence with
|
||||
-- The high-level model of a vector is a sequence of elements. The
|
||||
-- sequence really is similar to the vector itself. However, it is not
|
||||
-- limited which allows usage of 'Old and 'Loop_Entry attributes.
|
||||
|
||||
Ghost,
|
||||
Global => null,
|
||||
Post => M.Length (Model'Result) = Length (Container);
|
||||
pragma Annotate (GNATprove, Iterable_For_Proof, "Model", Model);
|
||||
|
||||
function Element
|
||||
(S : M.Sequence;
|
||||
I : Index_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 Empty_Vector return Vector with
|
||||
Global => null,
|
||||
Post => Length (Empty_Vector'Result) = 0;
|
||||
|
||||
function "=" (Left, Right : Vector) return Boolean with
|
||||
Global => null,
|
||||
Post => "="'Result = (Model (Left) = Model (Right));
|
||||
|
||||
function To_Vector
|
||||
(New_Item : Element_Type;
|
||||
Length : Capacity_Range) return Vector
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Formal_Vectors.Length (To_Vector'Result) = Length
|
||||
and M.Constant_Range
|
||||
(Container => Model (To_Vector'Result),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (To_Vector'Result),
|
||||
Item => New_Item);
|
||||
|
||||
function Capacity (Container : Vector) return Capacity_Range with
|
||||
Global => null,
|
||||
Post =>
|
||||
Capacity'Result = Container.Capacity;
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Capacity);
|
||||
|
||||
procedure Reserve_Capacity
|
||||
(Container : in out Vector;
|
||||
Capacity : Capacity_Range)
|
||||
with
|
||||
Global => null,
|
||||
Pre => Capacity <= Container.Capacity,
|
||||
Post => Model (Container) = Model (Container)'Old;
|
||||
|
||||
function Is_Empty (Container : Vector) return Boolean with
|
||||
Global => null,
|
||||
Post => Is_Empty'Result = (Length (Container) = 0);
|
||||
|
||||
procedure Clear (Container : in out Vector) with
|
||||
Global => null,
|
||||
Post => Length (Container) = 0;
|
||||
|
||||
procedure Assign (Target : in out Vector; Source : Vector) with
|
||||
Global => null,
|
||||
Pre => Length (Source) <= Target.Capacity,
|
||||
Post => Model (Target) = Model (Source);
|
||||
|
||||
function Copy
|
||||
(Source : Vector;
|
||||
Capacity : Capacity_Range := 0) return Vector
|
||||
with
|
||||
Global => null,
|
||||
Pre => (Capacity = 0 or Length (Source) <= Capacity),
|
||||
Post =>
|
||||
Model (Copy'Result) = Model (Source)
|
||||
and (if Capacity = 0 then
|
||||
Copy'Result.Capacity = Length (Source)
|
||||
else
|
||||
Copy'Result.Capacity = Capacity);
|
||||
|
||||
procedure Move (Target : in out Vector; Source : in out Vector)
|
||||
with
|
||||
Global => null,
|
||||
Pre => Length (Source) <= Capacity (Target),
|
||||
Post => Model (Target) = Model (Source)'Old and Length (Source) = 0;
|
||||
|
||||
function Element
|
||||
(Container : Vector;
|
||||
Index : Extended_Index) return Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre => Index in First_Index (Container) .. Last_Index (Container),
|
||||
Post => Element'Result = Element (Model (Container), Index);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Element);
|
||||
|
||||
procedure Replace_Element
|
||||
(Container : in out Vector;
|
||||
Index : Index_Type;
|
||||
New_Item : Element_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre => Index in First_Index (Container) .. Last_Index (Container),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old
|
||||
|
||||
-- Container now has New_Item at index Index
|
||||
|
||||
and Element (Model (Container), Index) = New_Item
|
||||
|
||||
-- All other elements are preserved
|
||||
|
||||
and M.Equal_Except
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Position => Index);
|
||||
|
||||
function At_End (E : access constant Vector) return access constant Vector
|
||||
is (E)
|
||||
with Ghost,
|
||||
Annotate => (GNATprove, At_End_Borrow);
|
||||
|
||||
function At_End
|
||||
(E : access constant Element_Type) return access constant Element_Type
|
||||
is (E)
|
||||
with Ghost,
|
||||
Annotate => (GNATprove, At_End_Borrow);
|
||||
|
||||
function Constant_Reference
|
||||
(Container : aliased Vector;
|
||||
Index : Index_Type) return not null access constant Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre => Index in First_Index (Container) .. Last_Index (Container),
|
||||
Post =>
|
||||
Constant_Reference'Result.all = Element (Model (Container), Index);
|
||||
|
||||
function Reference
|
||||
(Container : not null access Vector;
|
||||
Index : Index_Type) return not null access Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Index in First_Index (Container.all) .. Last_Index (Container.all),
|
||||
Post =>
|
||||
Length (Container.all) = Length (At_End (Container).all)
|
||||
|
||||
-- Container will have Result.all at index Index
|
||||
|
||||
and At_End (Reference'Result).all =
|
||||
Element (Model (At_End (Container).all), Index)
|
||||
|
||||
-- All other elements are preserved
|
||||
|
||||
and M.Equal_Except
|
||||
(Left => Model (Container.all),
|
||||
Right => Model (At_End (Container).all),
|
||||
Position => Index);
|
||||
|
||||
procedure Insert
|
||||
(Container : in out Vector;
|
||||
Before : Extended_Index;
|
||||
New_Item : Vector)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) <= Capacity (Container) - Length (New_Item)
|
||||
and (Before in Index_Type'First .. Last_Index (Container)
|
||||
or (Before /= No_Index
|
||||
and then Before - 1 = Last_Index (Container))),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Length (New_Item)
|
||||
|
||||
-- Elements located before Before in Container are preserved
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Before - 1)
|
||||
|
||||
-- Elements of New_Item are inserted at position Before
|
||||
|
||||
and (if Length (New_Item) > 0 then
|
||||
M.Range_Shifted
|
||||
(Left => Model (New_Item),
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (New_Item),
|
||||
Offset => Count_Type (Before - Index_Type'First)))
|
||||
|
||||
-- Elements located after Before in Container are shifted
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Before,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => Length (New_Item));
|
||||
|
||||
procedure Insert
|
||||
(Container : in out Vector;
|
||||
Before : Extended_Index;
|
||||
New_Item : Element_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) < Capacity (Container)
|
||||
and then (Before in Index_Type'First .. Last_Index (Container) + 1),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + 1
|
||||
|
||||
-- Elements located before Before in Container are preserved
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Before - 1)
|
||||
|
||||
-- Container now has New_Item at index Before
|
||||
|
||||
and Element (Model (Container), Before) = New_Item
|
||||
|
||||
-- Elements located after Before in Container are shifted by 1
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Before,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => 1);
|
||||
|
||||
procedure Insert
|
||||
(Container : in out Vector;
|
||||
Before : Extended_Index;
|
||||
New_Item : Element_Type;
|
||||
Count : Count_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) <= Capacity (Container) - Count
|
||||
and (Before in Index_Type'First .. Last_Index (Container)
|
||||
or (Before /= No_Index
|
||||
and then Before - 1 = Last_Index (Container))),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Count
|
||||
|
||||
-- Elements located before Before in Container are preserved
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Before - 1)
|
||||
|
||||
-- New_Item is inserted Count times at position Before
|
||||
|
||||
and (if Count > 0 then
|
||||
M.Constant_Range
|
||||
(Container => Model (Container),
|
||||
Fst => Before,
|
||||
Lst => Before + Index_Type'Base (Count - 1),
|
||||
Item => New_Item))
|
||||
|
||||
-- Elements located after Before in Container are shifted
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Before,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => Count);
|
||||
|
||||
procedure Prepend (Container : in out Vector; New_Item : Vector) with
|
||||
Global => null,
|
||||
Pre => Length (Container) <= Capacity (Container) - Length (New_Item),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Length (New_Item)
|
||||
|
||||
-- Elements of New_Item are inserted at the beginning of Container
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (New_Item),
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (New_Item))
|
||||
|
||||
-- Elements of Container are shifted
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => Length (New_Item));
|
||||
|
||||
procedure Prepend (Container : in out Vector; New_Item : Element_Type) with
|
||||
Global => null,
|
||||
Pre => Length (Container) < Capacity (Container),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + 1
|
||||
|
||||
-- Container now has New_Item at Index_Type'First
|
||||
|
||||
and Element (Model (Container), Index_Type'First) = New_Item
|
||||
|
||||
-- Elements of Container are shifted by 1
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => 1);
|
||||
|
||||
procedure Prepend
|
||||
(Container : in out Vector;
|
||||
New_Item : Element_Type;
|
||||
Count : Count_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre => Length (Container) <= Capacity (Container) - Count,
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Count
|
||||
|
||||
-- New_Item is inserted Count times at the beginning of Container
|
||||
|
||||
and M.Constant_Range
|
||||
(Container => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Index_Type'First + Index_Type'Base (Count - 1),
|
||||
Item => New_Item)
|
||||
|
||||
-- Elements of Container are shifted
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container)'Old,
|
||||
Offset => Count);
|
||||
|
||||
procedure Append (Container : in out Vector; New_Item : Vector) with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) <= Capacity (Container) - Length (New_Item),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Length (New_Item)
|
||||
|
||||
-- The elements of Container are preserved
|
||||
|
||||
and Model (Container)'Old <= Model (Container)
|
||||
|
||||
-- Elements of New_Item are inserted at the end of Container
|
||||
|
||||
and (if Length (New_Item) > 0 then
|
||||
M.Range_Shifted
|
||||
(Left => Model (New_Item),
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (New_Item),
|
||||
Offset =>
|
||||
Count_Type
|
||||
(Last_Index (Container)'Old - Index_Type'First + 1)));
|
||||
|
||||
procedure Append (Container : in out Vector; New_Item : Element_Type) with
|
||||
Global => null,
|
||||
Pre => Length (Container) < Capacity (Container),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + 1
|
||||
|
||||
-- Elements of Container are preserved
|
||||
|
||||
and Model (Container)'Old < Model (Container)
|
||||
|
||||
-- Container now has New_Item at the end of Container
|
||||
|
||||
and Element
|
||||
(Model (Container), Last_Index (Container)'Old + 1) = New_Item;
|
||||
|
||||
procedure Append
|
||||
(Container : in out Vector;
|
||||
New_Item : Element_Type;
|
||||
Count : Count_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre => Length (Container) <= Capacity (Container) - Count,
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old + Count
|
||||
|
||||
-- Elements of Container are preserved
|
||||
|
||||
and Model (Container)'Old <= Model (Container)
|
||||
|
||||
-- New_Item is inserted Count times at the end of Container
|
||||
|
||||
and (if Count > 0 then
|
||||
M.Constant_Range
|
||||
(Container => Model (Container),
|
||||
Fst => Last_Index (Container)'Old + 1,
|
||||
Lst =>
|
||||
Last_Index (Container)'Old + Index_Type'Base (Count),
|
||||
Item => New_Item));
|
||||
|
||||
procedure Delete (Container : in out Vector; Index : Extended_Index) with
|
||||
Global => null,
|
||||
Pre => Index in First_Index (Container) .. Last_Index (Container),
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old - 1
|
||||
|
||||
-- Elements located before Index in Container are preserved
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Index - 1)
|
||||
|
||||
-- Elements located after Index in Container are shifted by 1
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container),
|
||||
Right => Model (Container)'Old,
|
||||
Fst => Index,
|
||||
Lst => Last_Index (Container),
|
||||
Offset => 1);
|
||||
|
||||
procedure Delete
|
||||
(Container : in out Vector;
|
||||
Index : Extended_Index;
|
||||
Count : Count_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Index in First_Index (Container) .. Last_Index (Container),
|
||||
Post =>
|
||||
Length (Container) in
|
||||
Length (Container)'Old - Count .. Length (Container)'Old
|
||||
|
||||
-- The elements of Container located before Index are preserved.
|
||||
|
||||
and M.Range_Equal
|
||||
(Left => Model (Container)'Old,
|
||||
Right => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Index - 1),
|
||||
|
||||
Contract_Cases =>
|
||||
|
||||
-- All the elements after Position have been erased
|
||||
|
||||
(Length (Container) - Count <= Count_Type (Index - Index_Type'First) =>
|
||||
Length (Container) = Count_Type (Index - Index_Type'First),
|
||||
|
||||
others =>
|
||||
Length (Container) = Length (Container)'Old - Count
|
||||
|
||||
-- Other elements are shifted by Count
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container),
|
||||
Right => Model (Container)'Old,
|
||||
Fst => Index,
|
||||
Lst => Last_Index (Container),
|
||||
Offset => Count));
|
||||
|
||||
procedure Delete_First (Container : in out Vector) with
|
||||
Global => null,
|
||||
Pre => Length (Container) > 0,
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old - 1
|
||||
|
||||
-- Elements of Container are shifted by 1
|
||||
|
||||
and M.Range_Shifted
|
||||
(Left => Model (Container),
|
||||
Right => Model (Container)'Old,
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container),
|
||||
Offset => 1);
|
||||
|
||||
procedure Delete_First (Container : in out Vector; 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.Range_Shifted
|
||||
(Left => Model (Container),
|
||||
Right => Model (Container)'Old,
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container),
|
||||
Offset => Count));
|
||||
|
||||
procedure Delete_Last (Container : in out Vector) with
|
||||
Global => null,
|
||||
Pre => Length (Container) > 0,
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old - 1
|
||||
|
||||
-- Elements of Container are preserved
|
||||
|
||||
and Model (Container) < Model (Container)'Old;
|
||||
|
||||
procedure Delete_Last (Container : in out Vector; Count : Count_Type) with
|
||||
Global => null,
|
||||
Contract_Cases =>
|
||||
|
||||
-- All the elements after Position 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);
|
||||
|
||||
procedure Reverse_Elements (Container : in out Vector) with
|
||||
Global => null,
|
||||
Post => M_Elements_Reversed (Model (Container)'Old, Model (Container));
|
||||
|
||||
procedure Swap
|
||||
(Container : in out Vector;
|
||||
I : Index_Type;
|
||||
J : Index_Type)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
I in First_Index (Container) .. Last_Index (Container)
|
||||
and then J in First_Index (Container) .. Last_Index (Container),
|
||||
Post =>
|
||||
M_Elements_Swapped (Model (Container)'Old, Model (Container), I, J);
|
||||
|
||||
function First_Index (Container : Vector) return Index_Type with
|
||||
Global => null,
|
||||
Post => First_Index'Result = Index_Type'First;
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, First_Index);
|
||||
|
||||
function First_Element (Container : Vector) return Element_Type with
|
||||
Global => null,
|
||||
Pre => not Is_Empty (Container),
|
||||
Post =>
|
||||
First_Element'Result = Element (Model (Container), Index_Type'First);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, First_Element);
|
||||
|
||||
function Last_Index (Container : Vector) return Extended_Index with
|
||||
Global => null,
|
||||
Post => Last_Index'Result = M.Last (Model (Container));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Last_Index);
|
||||
|
||||
function Last_Element (Container : Vector) return Element_Type with
|
||||
Global => null,
|
||||
Pre => not Is_Empty (Container),
|
||||
Post =>
|
||||
Last_Element'Result =
|
||||
Element (Model (Container), Last_Index (Container));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Last_Element);
|
||||
|
||||
function Find_Index
|
||||
(Container : Vector;
|
||||
Item : Element_Type;
|
||||
Index : Index_Type := Index_Type'First) return Extended_Index
|
||||
with
|
||||
Global => null,
|
||||
Contract_Cases =>
|
||||
|
||||
-- If Item is not contained in Container after Index, Find_Index
|
||||
-- returns No_Index.
|
||||
|
||||
(Index > Last_Index (Container)
|
||||
or else not M.Contains
|
||||
(Container => Model (Container),
|
||||
Fst => Index,
|
||||
Lst => Last_Index (Container),
|
||||
Item => Item)
|
||||
=>
|
||||
Find_Index'Result = No_Index,
|
||||
|
||||
-- Otherwise, Find_Index returns a valid index greater than Index
|
||||
|
||||
others =>
|
||||
Find_Index'Result in Index .. Last_Index (Container)
|
||||
|
||||
-- The element at this index in Container is Item
|
||||
|
||||
and Element (Model (Container), Find_Index'Result) = Item
|
||||
|
||||
-- It is the first occurrence of Item after Index in Container
|
||||
|
||||
and not M.Contains
|
||||
(Container => Model (Container),
|
||||
Fst => Index,
|
||||
Lst => Find_Index'Result - 1,
|
||||
Item => Item));
|
||||
|
||||
function Reverse_Find_Index
|
||||
(Container : Vector;
|
||||
Item : Element_Type;
|
||||
Index : Index_Type := Index_Type'Last) return Extended_Index
|
||||
with
|
||||
Global => null,
|
||||
Contract_Cases =>
|
||||
|
||||
-- If Item is not contained in Container before Index,
|
||||
-- Reverse_Find_Index returns No_Index.
|
||||
|
||||
(not M.Contains
|
||||
(Container => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => (if Index <= Last_Index (Container) then Index
|
||||
else Last_Index (Container)),
|
||||
Item => Item)
|
||||
=>
|
||||
Reverse_Find_Index'Result = No_Index,
|
||||
|
||||
-- Otherwise, Reverse_Find_Index returns a valid index smaller than
|
||||
-- Index
|
||||
|
||||
others =>
|
||||
Reverse_Find_Index'Result in Index_Type'First .. Index
|
||||
and Reverse_Find_Index'Result <= Last_Index (Container)
|
||||
|
||||
-- The element at this index in Container is Item
|
||||
|
||||
and Element (Model (Container), Reverse_Find_Index'Result) = Item
|
||||
|
||||
-- It is the last occurrence of Item before Index in Container
|
||||
|
||||
and not M.Contains
|
||||
(Container => Model (Container),
|
||||
Fst => Reverse_Find_Index'Result + 1,
|
||||
Lst =>
|
||||
(if Index <= Last_Index (Container) then
|
||||
Index
|
||||
else
|
||||
Last_Index (Container)),
|
||||
Item => Item));
|
||||
|
||||
function Contains
|
||||
(Container : Vector;
|
||||
Item : Element_Type) return Boolean
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Contains'Result =
|
||||
M.Contains
|
||||
(Container => Model (Container),
|
||||
Fst => Index_Type'First,
|
||||
Lst => Last_Index (Container),
|
||||
Item => Item);
|
||||
|
||||
function Has_Element
|
||||
(Container : Vector;
|
||||
Position : Extended_Index) return Boolean
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Has_Element'Result =
|
||||
(Position in Index_Type'First .. Last_Index (Container));
|
||||
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
|
||||
|
||||
package Formal_Model with Ghost is
|
||||
|
||||
function M_Elements_Sorted (Container : M.Sequence) return Boolean
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
M_Elements_Sorted'Result =
|
||||
(for all I in Index_Type'First .. M.Last (Container) =>
|
||||
(for all J in I .. M.Last (Container) =>
|
||||
Element (Container, I) = Element (Container, J)
|
||||
or Element (Container, I) < Element (Container, J)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Sorted);
|
||||
|
||||
end Formal_Model;
|
||||
use Formal_Model;
|
||||
|
||||
function Is_Sorted (Container : Vector) return Boolean with
|
||||
Global => null,
|
||||
Post => Is_Sorted'Result = M_Elements_Sorted (Model (Container));
|
||||
|
||||
procedure Sort (Container : in out Vector) with
|
||||
Global => null,
|
||||
Post =>
|
||||
Length (Container) = Length (Container)'Old
|
||||
and M_Elements_Sorted (Model (Container))
|
||||
and M_Elements_Included
|
||||
(Left => Model (Container)'Old,
|
||||
L_Lst => Last_Index (Container),
|
||||
Right => Model (Container),
|
||||
R_Lst => Last_Index (Container))
|
||||
and M_Elements_Included
|
||||
(Left => Model (Container),
|
||||
L_Lst => Last_Index (Container),
|
||||
Right => Model (Container)'Old,
|
||||
R_Lst => Last_Index (Container));
|
||||
|
||||
procedure Merge (Target : in out Vector; Source : in out Vector) with
|
||||
-- Target and Source should not be aliased
|
||||
Global => null,
|
||||
Pre => Length (Source) <= Capacity (Target) - 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)))
|
||||
and M_Elements_Included
|
||||
(Left => Model (Target)'Old,
|
||||
L_Lst => Last_Index (Target)'Old,
|
||||
Right => Model (Target),
|
||||
R_Lst => Last_Index (Target))
|
||||
and M_Elements_Included
|
||||
(Left => Model (Source)'Old,
|
||||
L_Lst => Last_Index (Source)'Old,
|
||||
Right => Model (Target),
|
||||
R_Lst => Last_Index (Target))
|
||||
and M_Elements_In_Union
|
||||
(Model (Target),
|
||||
Model (Source)'Old,
|
||||
Model (Target)'Old);
|
||||
end Generic_Sorting;
|
||||
|
||||
---------------------------
|
||||
-- Iteration Primitives --
|
||||
---------------------------
|
||||
|
||||
function Iter_First (Container : Vector) return Extended_Index with
|
||||
Global => null;
|
||||
|
||||
function Iter_Has_Element
|
||||
(Container : Vector;
|
||||
Position : Extended_Index) return Boolean
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Iter_Has_Element'Result =
|
||||
(Position in Index_Type'First .. Last_Index (Container));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Iter_Has_Element);
|
||||
|
||||
function Iter_Next
|
||||
(Container : Vector;
|
||||
Position : Extended_Index) return Extended_Index
|
||||
with
|
||||
Global => null,
|
||||
Pre => Iter_Has_Element (Container, Position);
|
||||
|
||||
private
|
||||
pragma SPARK_Mode (Off);
|
||||
|
||||
pragma Inline (First_Index);
|
||||
pragma Inline (Last_Index);
|
||||
pragma Inline (Element);
|
||||
pragma Inline (First_Element);
|
||||
pragma Inline (Last_Element);
|
||||
pragma Inline (Replace_Element);
|
||||
pragma Inline (Contains);
|
||||
|
||||
subtype Array_Index is Capacity_Range range 1 .. Capacity_Range'Last;
|
||||
type Elements_Array is array (Array_Index range <>) of aliased Element_Type;
|
||||
function "=" (L, R : Elements_Array) return Boolean is abstract;
|
||||
|
||||
type Vector (Capacity : Capacity_Range) is record
|
||||
Last : Extended_Index := No_Index;
|
||||
Elements : Elements_Array (1 .. Capacity);
|
||||
end record;
|
||||
|
||||
function Empty_Vector return Vector is
|
||||
((Capacity => 0, others => <>));
|
||||
|
||||
function Iter_First (Container : Vector) return Extended_Index is
|
||||
(Index_Type'First);
|
||||
|
||||
function Iter_Next
|
||||
(Container : Vector;
|
||||
Position : Extended_Index) return Extended_Index
|
||||
is
|
||||
(if Position = Extended_Index'Last then
|
||||
Extended_Index'First
|
||||
else
|
||||
Extended_Index'Succ (Position));
|
||||
|
||||
function Iter_Has_Element
|
||||
(Container : Vector;
|
||||
Position : Extended_Index) return Boolean
|
||||
is
|
||||
(Position in Index_Type'First .. Container.Last);
|
||||
pragma Compile_Time_Error
|
||||
(True,
|
||||
"This package has been moved to the SPARK library shipped with any"
|
||||
& " SPARK release starting with version 23.");
|
||||
|
||||
end Ada.Containers.Formal_Vectors;
|
||||
|
@ -1,432 +0,0 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- --
|
||||
-- GNAT LIBRARY COMPONENTS --
|
||||
-- --
|
||||
-- ADA.CONTAINERS.FUNCTIONAL_BASE --
|
||||
-- --
|
||||
-- B o d y --
|
||||
-- --
|
||||
-- Copyright (C) 2016-2022, 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 --
|
||||
-- apply solely to the contents of the part following the private keyword. --
|
||||
-- --
|
||||
-- GNAT is free software; you can redistribute it and/or modify it under --
|
||||
-- terms of the GNU General Public License as published by the Free Soft- --
|
||||
-- ware Foundation; either version 3, or (at your option) any later ver- --
|
||||
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
||||
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
||||
-- or FITNESS FOR A PARTICULAR PURPOSE. --
|
||||
-- --
|
||||
-- As a special exception under Section 7 of GPL version 3, you are granted --
|
||||
-- additional permissions described in the GCC Runtime Library Exception, --
|
||||
-- version 3.1, as published by the Free Software Foundation. --
|
||||
-- --
|
||||
-- You should have received a copy of the GNU General Public License and --
|
||||
-- a copy of the GCC Runtime Library Exception along with this program; --
|
||||
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
pragma Ada_2012;
|
||||
with Ada.Unchecked_Deallocation;
|
||||
|
||||
package body Ada.Containers.Functional_Base with SPARK_Mode => Off is
|
||||
|
||||
function To_Count (Idx : Extended_Index) return Count_Type is
|
||||
(Count_Type
|
||||
(Extended_Index'Pos (Idx) -
|
||||
Extended_Index'Pos (Extended_Index'First)));
|
||||
|
||||
function To_Index (Position : Count_Type) return Extended_Index is
|
||||
(Extended_Index'Val
|
||||
(Position + Extended_Index'Pos (Extended_Index'First)));
|
||||
-- Conversion functions between Index_Type and Count_Type
|
||||
|
||||
function Find (C : Container; E : access Element_Type) return Count_Type;
|
||||
-- Search a container C for an element equal to E.all, returning the
|
||||
-- position in the underlying array.
|
||||
|
||||
procedure Resize (Base : Array_Base_Access);
|
||||
-- Resize the underlying array if needed so that it can contain one more
|
||||
-- element.
|
||||
|
||||
function Elements (C : Container) return Element_Array_Access is
|
||||
(C.Controlled_Base.Base.Elements)
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
C.Controlled_Base.Base /= null
|
||||
and then C.Controlled_Base.Base.Elements /= null;
|
||||
|
||||
function Get
|
||||
(C_E : Element_Array_Access;
|
||||
I : Count_Type)
|
||||
return Element_Access
|
||||
is
|
||||
(C_E (I).Ref.E_Access)
|
||||
with
|
||||
Global => null,
|
||||
Pre => C_E /= null and then C_E (I).Ref /= null;
|
||||
|
||||
---------
|
||||
-- "=" --
|
||||
---------
|
||||
|
||||
function "=" (C1 : Container; C2 : Container) return Boolean is
|
||||
begin
|
||||
if C1.Length /= C2.Length then
|
||||
return False;
|
||||
end if;
|
||||
for I in 1 .. C1.Length loop
|
||||
if Get (Elements (C1), I).all /= Get (Elements (C2), I).all then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end "=";
|
||||
|
||||
----------
|
||||
-- "<=" --
|
||||
----------
|
||||
|
||||
function "<=" (C1 : Container; C2 : Container) return Boolean is
|
||||
begin
|
||||
for I in 1 .. C1.Length loop
|
||||
if Find (C2, Get (Elements (C1), I)) = 0 then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end "<=";
|
||||
|
||||
---------
|
||||
-- Add --
|
||||
---------
|
||||
|
||||
function Add
|
||||
(C : Container;
|
||||
I : Index_Type;
|
||||
E : Element_Type) return Container
|
||||
is
|
||||
C_B : Array_Base_Access renames C.Controlled_Base.Base;
|
||||
begin
|
||||
if To_Count (I) = C.Length + 1 and then C.Length = C_B.Max_Length then
|
||||
Resize (C_B);
|
||||
C_B.Max_Length := C_B.Max_Length + 1;
|
||||
C_B.Elements (C_B.Max_Length) := Element_Init (E);
|
||||
|
||||
return Container'(Length => C_B.Max_Length,
|
||||
Controlled_Base => C.Controlled_Base);
|
||||
else
|
||||
declare
|
||||
A : constant Array_Base_Controlled_Access :=
|
||||
Content_Init (C.Length);
|
||||
P : Count_Type := 0;
|
||||
begin
|
||||
A.Base.Max_Length := C.Length + 1;
|
||||
for J in 1 .. C.Length + 1 loop
|
||||
if J /= To_Count (I) then
|
||||
P := P + 1;
|
||||
A.Base.Elements (J) := C_B.Elements (P);
|
||||
else
|
||||
A.Base.Elements (J) := Element_Init (E);
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return Container'(Length => A.Base.Max_Length,
|
||||
Controlled_Base => A);
|
||||
end;
|
||||
end if;
|
||||
end Add;
|
||||
|
||||
------------
|
||||
-- Adjust --
|
||||
------------
|
||||
|
||||
procedure Adjust (Controlled_Base : in out Array_Base_Controlled_Access) is
|
||||
C_B : Array_Base_Access renames Controlled_Base.Base;
|
||||
begin
|
||||
if C_B /= null then
|
||||
C_B.Reference_Count := C_B.Reference_Count + 1;
|
||||
end if;
|
||||
end Adjust;
|
||||
|
||||
procedure Adjust (Ctrl_E : in out Controlled_Element_Access) is
|
||||
begin
|
||||
if Ctrl_E.Ref /= null then
|
||||
Ctrl_E.Ref.Reference_Count := Ctrl_E.Ref.Reference_Count + 1;
|
||||
end if;
|
||||
end Adjust;
|
||||
|
||||
------------------
|
||||
-- Content_Init --
|
||||
------------------
|
||||
|
||||
function Content_Init
|
||||
(L : Count_Type := 0) return Array_Base_Controlled_Access
|
||||
is
|
||||
Max_Init : constant Count_Type := 100;
|
||||
Size : constant Count_Type :=
|
||||
(if L < Count_Type'Last - Max_Init then L + Max_Init
|
||||
else Count_Type'Last);
|
||||
|
||||
-- The Access in the array will be initialized to null
|
||||
|
||||
Elements : constant Element_Array_Access :=
|
||||
new Element_Array'(1 .. Size => <>);
|
||||
B : constant Array_Base_Access :=
|
||||
new Array_Base'(Reference_Count => 1,
|
||||
Max_Length => 0,
|
||||
Elements => Elements);
|
||||
begin
|
||||
return (Ada.Finalization.Controlled with Base => B);
|
||||
end Content_Init;
|
||||
|
||||
------------------
|
||||
-- Element_Init --
|
||||
------------------
|
||||
|
||||
function Element_Init (E : Element_Type) return Controlled_Element_Access
|
||||
is
|
||||
Refcounted_E : constant Refcounted_Element_Access :=
|
||||
new Refcounted_Element'(Reference_Count => 1,
|
||||
E_Access => new Element_Type'(E));
|
||||
begin
|
||||
return (Ada.Finalization.Controlled with Ref => Refcounted_E);
|
||||
end Element_Init;
|
||||
|
||||
--------------
|
||||
-- Finalize --
|
||||
--------------
|
||||
|
||||
procedure Finalize (Controlled_Base : in out Array_Base_Controlled_Access)
|
||||
is
|
||||
procedure Unchecked_Free_Base is new Ada.Unchecked_Deallocation
|
||||
(Object => Array_Base,
|
||||
Name => Array_Base_Access);
|
||||
procedure Unchecked_Free_Array is new Ada.Unchecked_Deallocation
|
||||
(Object => Element_Array,
|
||||
Name => Element_Array_Access);
|
||||
|
||||
C_B : Array_Base_Access renames Controlled_Base.Base;
|
||||
begin
|
||||
if C_B /= null then
|
||||
C_B.Reference_Count := C_B.Reference_Count - 1;
|
||||
if C_B.Reference_Count = 0 then
|
||||
Unchecked_Free_Array (Controlled_Base.Base.Elements);
|
||||
Unchecked_Free_Base (Controlled_Base.Base);
|
||||
end if;
|
||||
C_B := null;
|
||||
end if;
|
||||
end Finalize;
|
||||
|
||||
procedure Finalize (Ctrl_E : in out Controlled_Element_Access) is
|
||||
procedure Unchecked_Free_Ref is new Ada.Unchecked_Deallocation
|
||||
(Object => Refcounted_Element,
|
||||
Name => Refcounted_Element_Access);
|
||||
|
||||
procedure Unchecked_Free_Element is new Ada.Unchecked_Deallocation
|
||||
(Object => Element_Type,
|
||||
Name => Element_Access);
|
||||
|
||||
begin
|
||||
if Ctrl_E.Ref /= null then
|
||||
Ctrl_E.Ref.Reference_Count := Ctrl_E.Ref.Reference_Count - 1;
|
||||
if Ctrl_E.Ref.Reference_Count = 0 then
|
||||
Unchecked_Free_Element (Ctrl_E.Ref.E_Access);
|
||||
Unchecked_Free_Ref (Ctrl_E.Ref);
|
||||
end if;
|
||||
Ctrl_E.Ref := null;
|
||||
end if;
|
||||
end Finalize;
|
||||
|
||||
----------
|
||||
-- Find --
|
||||
----------
|
||||
|
||||
function Find (C : Container; E : access Element_Type) return Count_Type is
|
||||
begin
|
||||
for I in 1 .. C.Length loop
|
||||
if Get (Elements (C), I).all = E.all then
|
||||
return I;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return 0;
|
||||
end Find;
|
||||
|
||||
function Find (C : Container; E : Element_Type) return Extended_Index is
|
||||
(To_Index (Find (C, E'Unrestricted_Access)));
|
||||
|
||||
---------
|
||||
-- Get --
|
||||
---------
|
||||
|
||||
function Get (C : Container; I : Index_Type) return Element_Type is
|
||||
(Get (Elements (C), To_Count (I)).all);
|
||||
|
||||
------------------
|
||||
-- Intersection --
|
||||
------------------
|
||||
|
||||
function Intersection (C1 : Container; C2 : Container) return Container is
|
||||
L : constant Count_Type := Num_Overlaps (C1, C2);
|
||||
A : constant Array_Base_Controlled_Access := Content_Init (L);
|
||||
P : Count_Type := 0;
|
||||
|
||||
begin
|
||||
A.Base.Max_Length := L;
|
||||
for I in 1 .. C1.Length loop
|
||||
if Find (C2, Get (Elements (C1), I)) > 0 then
|
||||
P := P + 1;
|
||||
A.Base.Elements (P) := Elements (C1) (I);
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return Container'(Length => P, Controlled_Base => A);
|
||||
end Intersection;
|
||||
|
||||
------------
|
||||
-- Length --
|
||||
------------
|
||||
|
||||
function Length (C : Container) return Count_Type is (C.Length);
|
||||
---------------------
|
||||
-- Num_Overlaps --
|
||||
---------------------
|
||||
|
||||
function Num_Overlaps (C1 : Container; C2 : Container) return Count_Type is
|
||||
P : Count_Type := 0;
|
||||
|
||||
begin
|
||||
for I in 1 .. C1.Length loop
|
||||
if Find (C2, Get (Elements (C1), I)) > 0 then
|
||||
P := P + 1;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return P;
|
||||
end Num_Overlaps;
|
||||
|
||||
------------
|
||||
-- Remove --
|
||||
------------
|
||||
|
||||
function Remove (C : Container; I : Index_Type) return Container is
|
||||
begin
|
||||
if To_Count (I) = C.Length then
|
||||
return Container'(Length => C.Length - 1,
|
||||
Controlled_Base => C.Controlled_Base);
|
||||
else
|
||||
declare
|
||||
A : constant Array_Base_Controlled_Access
|
||||
:= Content_Init (C.Length - 1);
|
||||
P : Count_Type := 0;
|
||||
begin
|
||||
A.Base.Max_Length := C.Length - 1;
|
||||
for J in 1 .. C.Length loop
|
||||
if J /= To_Count (I) then
|
||||
P := P + 1;
|
||||
A.Base.Elements (P) := Elements (C) (J);
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return Container'(Length => C.Length - 1, Controlled_Base => A);
|
||||
end;
|
||||
end if;
|
||||
end Remove;
|
||||
|
||||
------------
|
||||
-- Resize --
|
||||
------------
|
||||
|
||||
procedure Resize (Base : Array_Base_Access) is
|
||||
begin
|
||||
if Base.Max_Length < Base.Elements'Length then
|
||||
return;
|
||||
end if;
|
||||
|
||||
pragma Assert (Base.Max_Length = Base.Elements'Length);
|
||||
|
||||
if Base.Max_Length = Count_Type'Last then
|
||||
raise Constraint_Error;
|
||||
end if;
|
||||
|
||||
declare
|
||||
procedure Finalize is new Ada.Unchecked_Deallocation
|
||||
(Object => Element_Array,
|
||||
Name => Element_Array_Access_Base);
|
||||
|
||||
New_Length : constant Positive_Count_Type :=
|
||||
(if Base.Max_Length > Count_Type'Last / 2 then Count_Type'Last
|
||||
else 2 * Base.Max_Length);
|
||||
Elements : constant Element_Array_Access :=
|
||||
new Element_Array (1 .. New_Length);
|
||||
Old_Elmts : Element_Array_Access_Base := Base.Elements;
|
||||
begin
|
||||
Elements (1 .. Base.Max_Length) := Base.Elements.all;
|
||||
Base.Elements := Elements;
|
||||
Finalize (Old_Elmts);
|
||||
end;
|
||||
end Resize;
|
||||
|
||||
---------
|
||||
-- Set --
|
||||
---------
|
||||
|
||||
function Set
|
||||
(C : Container;
|
||||
I : Index_Type;
|
||||
E : Element_Type) return Container
|
||||
is
|
||||
Result : constant Container :=
|
||||
Container'(Length => C.Length,
|
||||
Controlled_Base => Content_Init (C.Length));
|
||||
R_Base : Array_Base_Access renames Result.Controlled_Base.Base;
|
||||
|
||||
begin
|
||||
R_Base.Max_Length := C.Length;
|
||||
R_Base.Elements (1 .. C.Length) := Elements (C) (1 .. C.Length);
|
||||
R_Base.Elements (To_Count (I)) := Element_Init (E);
|
||||
return Result;
|
||||
end Set;
|
||||
|
||||
-----------
|
||||
-- Union --
|
||||
-----------
|
||||
|
||||
function Union (C1 : Container; C2 : Container) return Container is
|
||||
N : constant Count_Type := Num_Overlaps (C1, C2);
|
||||
|
||||
begin
|
||||
-- if C2 is completely included in C1 then return C1
|
||||
|
||||
if N = Length (C2) then
|
||||
return C1;
|
||||
end if;
|
||||
|
||||
-- else loop through C2 to find the remaining elements
|
||||
|
||||
declare
|
||||
L : constant Count_Type := Length (C1) - N + Length (C2);
|
||||
A : constant Array_Base_Controlled_Access := Content_Init (L);
|
||||
P : Count_Type := Length (C1);
|
||||
begin
|
||||
A.Base.Max_Length := L;
|
||||
A.Base.Elements (1 .. C1.Length) := Elements (C1) (1 .. C1.Length);
|
||||
for I in 1 .. C2.Length loop
|
||||
if Find (C1, Get (Elements (C2), I)) = 0 then
|
||||
P := P + 1;
|
||||
A.Base.Elements (P) := Elements (C2) (I);
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return Container'(Length => L, Controlled_Base => A);
|
||||
end;
|
||||
end Union;
|
||||
|
||||
end Ada.Containers.Functional_Base;
|
@ -1,198 +0,0 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- --
|
||||
-- GNAT LIBRARY COMPONENTS --
|
||||
-- --
|
||||
-- ADA.CONTAINERS.FUNCTIONAL_BASE --
|
||||
-- --
|
||||
-- S p e c --
|
||||
-- --
|
||||
-- Copyright (C) 2016-2022, 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 --
|
||||
-- apply solely to the contents of the part following the private keyword. --
|
||||
-- --
|
||||
-- GNAT is free software; you can redistribute it and/or modify it under --
|
||||
-- terms of the GNU General Public License as published by the Free Soft- --
|
||||
-- ware Foundation; either version 3, or (at your option) any later ver- --
|
||||
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
||||
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
||||
-- or FITNESS FOR A PARTICULAR PURPOSE. --
|
||||
-- --
|
||||
-- As a special exception under Section 7 of GPL version 3, you are granted --
|
||||
-- additional permissions described in the GCC Runtime Library Exception, --
|
||||
-- version 3.1, as published by the Free Software Foundation. --
|
||||
-- --
|
||||
-- You should have received a copy of the GNU General Public License and --
|
||||
-- a copy of the GCC Runtime Library Exception along with this program; --
|
||||
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
-- Functional containers are neither controlled nor limited. This is safe, as
|
||||
-- no primitives are provided to modify them.
|
||||
-- Memory allocated inside functional containers is never reclaimed.
|
||||
|
||||
pragma Ada_2012;
|
||||
|
||||
-- To allow reference counting on the base container
|
||||
|
||||
private with Ada.Finalization;
|
||||
|
||||
private generic
|
||||
type Index_Type is (<>);
|
||||
-- To avoid Constraint_Error being raised at run time, Index_Type'Base
|
||||
-- should have at least one more element at the low end than Index_Type.
|
||||
|
||||
type Element_Type (<>) is private;
|
||||
with function "=" (Left, Right : Element_Type) return Boolean is <>;
|
||||
|
||||
package Ada.Containers.Functional_Base with SPARK_Mode => Off is
|
||||
|
||||
subtype Extended_Index is Index_Type'Base range
|
||||
Index_Type'Pred (Index_Type'First) .. Index_Type'Last;
|
||||
|
||||
type Container is private;
|
||||
|
||||
function "=" (C1 : Container; C2 : Container) return Boolean;
|
||||
-- Return True if C1 and C2 contain the same elements at the same position
|
||||
|
||||
function Length (C : Container) return Count_Type;
|
||||
-- Number of elements stored in C
|
||||
|
||||
function Get (C : Container; I : Index_Type) return Element_Type;
|
||||
-- Access to the element at index I in C
|
||||
|
||||
function Set
|
||||
(C : Container;
|
||||
I : Index_Type;
|
||||
E : Element_Type) return Container;
|
||||
-- Return a new container which is equal to C except for the element at
|
||||
-- index I, which is set to E.
|
||||
|
||||
function Add
|
||||
(C : Container;
|
||||
I : Index_Type;
|
||||
E : Element_Type) return Container;
|
||||
-- Return a new container that is C with E inserted at index I
|
||||
|
||||
function Remove (C : Container; I : Index_Type) return Container;
|
||||
-- Return a new container that is C without the element at index I
|
||||
|
||||
function Find (C : Container; E : Element_Type) return Extended_Index;
|
||||
-- Return the first index for which the element stored in C is I. If there
|
||||
-- are no such indexes, return Extended_Index'First.
|
||||
|
||||
--------------------
|
||||
-- Set Operations --
|
||||
--------------------
|
||||
|
||||
function "<=" (C1 : Container; C2 : Container) return Boolean;
|
||||
-- Return True if every element of C1 is in C2
|
||||
|
||||
function Num_Overlaps (C1 : Container; C2 : Container) return Count_Type;
|
||||
-- Return the number of elements that are in both C1 and C2
|
||||
|
||||
function Union (C1 : Container; C2 : Container) return Container;
|
||||
-- Return a container which is C1 plus all the elements of C2 that are not
|
||||
-- in C1.
|
||||
|
||||
function Intersection (C1 : Container; C2 : Container) return Container;
|
||||
-- Return a container which is C1 minus all the elements that are also in
|
||||
-- C2.
|
||||
|
||||
private
|
||||
|
||||
-- Theoretically, each operation on a functional container implies the
|
||||
-- creation of a new container i.e. the copy of the array itself and all
|
||||
-- the elements in it. In the implementation, most of these copies are
|
||||
-- avoided by sharing between the containers.
|
||||
--
|
||||
-- A container stores its last used index. So, when adding an
|
||||
-- element at the end of the container, the exact same array can be reused.
|
||||
-- As a functionnal container cannot be modifed once created, there is no
|
||||
-- risk of unwanted modifications.
|
||||
--
|
||||
-- _1_2_3_
|
||||
-- S : end => [1, 2, 3]
|
||||
-- |
|
||||
-- |1|2|3|4|.|.|
|
||||
-- |
|
||||
-- Add (S, 4, 4) : end => [1, 2, 3, 4]
|
||||
--
|
||||
-- The elements are also shared between containers as much as possible. For
|
||||
-- example, when something is added in the middle, the array is changed but
|
||||
-- the elementes are reused.
|
||||
--
|
||||
-- _1_2_3_4_
|
||||
-- S : |1|2|3|4| => [1, 2, 3, 4]
|
||||
-- | \ \ \
|
||||
-- Add (S, 2, 5) : |1|5|2|3|4| => [1, 5, 2, 3, 4]
|
||||
--
|
||||
-- To make this sharing possible, both the elements and the arrays are
|
||||
-- stored inside dynamically allocated access types which shall be
|
||||
-- deallocated when they are no longer used. The memory is managed using
|
||||
-- reference counting both at the array and at the element level.
|
||||
|
||||
subtype Positive_Count_Type is Count_Type range 1 .. Count_Type'Last;
|
||||
|
||||
type Reference_Count_Type is new Natural;
|
||||
|
||||
type Element_Access is access all Element_Type;
|
||||
|
||||
type Refcounted_Element is record
|
||||
Reference_Count : Reference_Count_Type;
|
||||
E_Access : Element_Access;
|
||||
end record;
|
||||
|
||||
type Refcounted_Element_Access is access Refcounted_Element;
|
||||
|
||||
type Controlled_Element_Access is new Ada.Finalization.Controlled
|
||||
with record
|
||||
Ref : Refcounted_Element_Access := null;
|
||||
end record;
|
||||
|
||||
function Element_Init (E : Element_Type) return Controlled_Element_Access;
|
||||
-- Use to initialize a refcounted element
|
||||
|
||||
type Element_Array is
|
||||
array (Positive_Count_Type range <>) of Controlled_Element_Access;
|
||||
|
||||
type Element_Array_Access_Base is access Element_Array;
|
||||
|
||||
subtype Element_Array_Access is Element_Array_Access_Base;
|
||||
|
||||
type Array_Base is record
|
||||
Reference_Count : Reference_Count_Type;
|
||||
Max_Length : Count_Type;
|
||||
Elements : Element_Array_Access;
|
||||
end record;
|
||||
|
||||
type Array_Base_Access is access Array_Base;
|
||||
|
||||
type Array_Base_Controlled_Access is new Ada.Finalization.Controlled
|
||||
with record
|
||||
Base : Array_Base_Access;
|
||||
end record;
|
||||
|
||||
overriding procedure Adjust
|
||||
(Controlled_Base : in out Array_Base_Controlled_Access);
|
||||
|
||||
overriding procedure Finalize
|
||||
(Controlled_Base : in out Array_Base_Controlled_Access);
|
||||
|
||||
overriding procedure Adjust
|
||||
(Ctrl_E : in out Controlled_Element_Access);
|
||||
|
||||
overriding procedure Finalize
|
||||
(Ctrl_E : in out Controlled_Element_Access);
|
||||
|
||||
function Content_Init (L : Count_Type := 0)
|
||||
return Array_Base_Controlled_Access;
|
||||
-- Used to initialize the content of an array base with length L
|
||||
|
||||
type Container is record
|
||||
Length : Count_Type := 0;
|
||||
Controlled_Base : Array_Base_Controlled_Access := Content_Init;
|
||||
end record;
|
||||
|
||||
end Ada.Containers.Functional_Base;
|
@ -1,306 +0,0 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- --
|
||||
-- GNAT LIBRARY COMPONENTS --
|
||||
-- --
|
||||
-- ADA.CONTAINERS.FUNCTIONAL_MAPS --
|
||||
-- --
|
||||
-- B o d y --
|
||||
-- --
|
||||
-- Copyright (C) 2016-2022, 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 --
|
||||
-- apply solely to the contents of the part following the private keyword. --
|
||||
-- --
|
||||
-- GNAT is free software; you can redistribute it and/or modify it under --
|
||||
-- terms of the GNU General Public License as published by the Free Soft- --
|
||||
-- ware Foundation; either version 3, or (at your option) any later ver- --
|
||||
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
||||
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
||||
-- or FITNESS FOR A PARTICULAR PURPOSE. --
|
||||
-- --
|
||||
-- As a special exception under Section 7 of GPL version 3, you are granted --
|
||||
-- additional permissions described in the GCC Runtime Library Exception, --
|
||||
-- version 3.1, as published by the Free Software Foundation. --
|
||||
-- --
|
||||
-- You should have received a copy of the GNU General Public License and --
|
||||
-- a copy of the GCC Runtime Library Exception along with this program; --
|
||||
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
pragma Ada_2012;
|
||||
package body Ada.Containers.Functional_Maps with SPARK_Mode => Off is
|
||||
use Key_Containers;
|
||||
use Element_Containers;
|
||||
|
||||
package Conversions is new Signed_Conversions (Int => Count_Type);
|
||||
use Conversions;
|
||||
|
||||
---------
|
||||
-- "=" --
|
||||
---------
|
||||
|
||||
function "=" (Left : Map; Right : Map) return Boolean is
|
||||
(Left.Keys <= Right.Keys and Right <= Left);
|
||||
|
||||
----------
|
||||
-- "<=" --
|
||||
----------
|
||||
|
||||
function "<=" (Left : Map; Right : Map) return Boolean is
|
||||
I2 : Count_Type;
|
||||
|
||||
begin
|
||||
for I1 in 1 .. Length (Left.Keys) loop
|
||||
I2 := Find (Right.Keys, Get (Left.Keys, I1));
|
||||
if I2 = 0
|
||||
or else Get (Right.Elements, I2) /= Get (Left.Elements, I1)
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
return True;
|
||||
end "<=";
|
||||
|
||||
---------
|
||||
-- Add --
|
||||
---------
|
||||
|
||||
function Add
|
||||
(Container : Map;
|
||||
New_Key : Key_Type;
|
||||
New_Item : Element_Type) return Map
|
||||
is
|
||||
begin
|
||||
return
|
||||
(Keys =>
|
||||
Add (Container.Keys, Length (Container.Keys) + 1, New_Key),
|
||||
Elements =>
|
||||
Add
|
||||
(Container.Elements, Length (Container.Elements) + 1, New_Item));
|
||||
end Add;
|
||||
|
||||
---------------------------
|
||||
-- Elements_Equal_Except --
|
||||
---------------------------
|
||||
|
||||
function Elements_Equal_Except
|
||||
(Left : Map;
|
||||
Right : Map;
|
||||
New_Key : Key_Type) return Boolean
|
||||
is
|
||||
begin
|
||||
for J in 1 .. Length (Left.Keys) loop
|
||||
declare
|
||||
K : constant Key_Type := Get (Left.Keys, J);
|
||||
begin
|
||||
if not Equivalent_Keys (K, New_Key)
|
||||
and then
|
||||
(Find (Right.Keys, K) = 0
|
||||
or else Get (Right.Elements, Find (Right.Keys, K)) /=
|
||||
Get (Left.Elements, J))
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end;
|
||||
end loop;
|
||||
return True;
|
||||
end Elements_Equal_Except;
|
||||
|
||||
function Elements_Equal_Except
|
||||
(Left : Map;
|
||||
Right : Map;
|
||||
X : Key_Type;
|
||||
Y : Key_Type) return Boolean
|
||||
is
|
||||
begin
|
||||
for J in 1 .. Length (Left.Keys) loop
|
||||
declare
|
||||
K : constant Key_Type := Get (Left.Keys, J);
|
||||
begin
|
||||
if not Equivalent_Keys (K, X)
|
||||
and then not Equivalent_Keys (K, Y)
|
||||
and then
|
||||
(Find (Right.Keys, K) = 0
|
||||
or else Get (Right.Elements, Find (Right.Keys, K)) /=
|
||||
Get (Left.Elements, J))
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end;
|
||||
end loop;
|
||||
return True;
|
||||
end Elements_Equal_Except;
|
||||
|
||||
---------------
|
||||
-- Empty_Map --
|
||||
---------------
|
||||
|
||||
function Empty_Map return Map is
|
||||
((others => <>));
|
||||
|
||||
---------
|
||||
-- Get --
|
||||
---------
|
||||
|
||||
function Get (Container : Map; Key : Key_Type) return Element_Type is
|
||||
begin
|
||||
return Get (Container.Elements, Find (Container.Keys, Key));
|
||||
end Get;
|
||||
|
||||
-------------
|
||||
-- Has_Key --
|
||||
-------------
|
||||
|
||||
function Has_Key (Container : Map; Key : Key_Type) return Boolean is
|
||||
begin
|
||||
return Find (Container.Keys, Key) > 0;
|
||||
end Has_Key;
|
||||
|
||||
-----------------
|
||||
-- Has_Witness --
|
||||
-----------------
|
||||
|
||||
function Has_Witness
|
||||
(Container : Map;
|
||||
Witness : Count_Type) return Boolean
|
||||
is
|
||||
(Witness in 1 .. Length (Container.Keys));
|
||||
|
||||
--------------
|
||||
-- Is_Empty --
|
||||
--------------
|
||||
|
||||
function Is_Empty (Container : Map) return Boolean is
|
||||
begin
|
||||
return Length (Container.Keys) = 0;
|
||||
end Is_Empty;
|
||||
|
||||
-------------------
|
||||
-- Keys_Included --
|
||||
-------------------
|
||||
|
||||
function Keys_Included (Left : Map; Right : Map) return Boolean is
|
||||
begin
|
||||
for J in 1 .. Length (Left.Keys) loop
|
||||
declare
|
||||
K : constant Key_Type := Get (Left.Keys, J);
|
||||
begin
|
||||
if Find (Right.Keys, K) = 0 then
|
||||
return False;
|
||||
end if;
|
||||
end;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Keys_Included;
|
||||
|
||||
--------------------------
|
||||
-- Keys_Included_Except --
|
||||
--------------------------
|
||||
|
||||
function Keys_Included_Except
|
||||
(Left : Map;
|
||||
Right : Map;
|
||||
New_Key : Key_Type) return Boolean
|
||||
is
|
||||
begin
|
||||
for J in 1 .. Length (Left.Keys) loop
|
||||
declare
|
||||
K : constant Key_Type := Get (Left.Keys, J);
|
||||
begin
|
||||
if not Equivalent_Keys (K, New_Key)
|
||||
and then Find (Right.Keys, K) = 0
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Keys_Included_Except;
|
||||
|
||||
function Keys_Included_Except
|
||||
(Left : Map;
|
||||
Right : Map;
|
||||
X : Key_Type;
|
||||
Y : Key_Type) return Boolean
|
||||
is
|
||||
begin
|
||||
for J in 1 .. Length (Left.Keys) loop
|
||||
declare
|
||||
K : constant Key_Type := Get (Left.Keys, J);
|
||||
begin
|
||||
if not Equivalent_Keys (K, X)
|
||||
and then not Equivalent_Keys (K, Y)
|
||||
and then Find (Right.Keys, K) = 0
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Keys_Included_Except;
|
||||
|
||||
------------
|
||||
-- Length --
|
||||
------------
|
||||
|
||||
function Length (Container : Map) return Big_Natural is
|
||||
begin
|
||||
return To_Big_Integer (Length (Container.Elements));
|
||||
end Length;
|
||||
|
||||
------------
|
||||
-- Remove --
|
||||
------------
|
||||
|
||||
function Remove (Container : Map; Key : Key_Type) return Map is
|
||||
J : constant Extended_Index := Find (Container.Keys, Key);
|
||||
begin
|
||||
return
|
||||
(Keys => Remove (Container.Keys, J),
|
||||
Elements => Remove (Container.Elements, J));
|
||||
end Remove;
|
||||
|
||||
---------------
|
||||
-- Same_Keys --
|
||||
---------------
|
||||
|
||||
function Same_Keys (Left : Map; Right : Map) return Boolean is
|
||||
(Keys_Included (Left, Right)
|
||||
and Keys_Included (Left => Right, Right => Left));
|
||||
|
||||
---------
|
||||
-- Set --
|
||||
---------
|
||||
|
||||
function Set
|
||||
(Container : Map;
|
||||
Key : Key_Type;
|
||||
New_Item : Element_Type) return Map
|
||||
is
|
||||
(Keys => Container.Keys,
|
||||
Elements =>
|
||||
Set (Container.Elements, Find (Container.Keys, Key), New_Item));
|
||||
|
||||
-----------
|
||||
-- W_Get --
|
||||
-----------
|
||||
|
||||
function W_Get
|
||||
(Container : Map;
|
||||
Witness : Count_Type) return Element_Type
|
||||
is
|
||||
(Get (Container.Elements, Witness));
|
||||
|
||||
-------------
|
||||
-- Witness --
|
||||
-------------
|
||||
|
||||
function Witness (Container : Map; Key : Key_Type) return Count_Type is
|
||||
(Find (Container.Keys, Key));
|
||||
|
||||
end Ada.Containers.Functional_Maps;
|
@ -29,368 +29,12 @@
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
pragma Ada_2012;
|
||||
private with Ada.Containers.Functional_Base;
|
||||
|
||||
with Ada.Numerics.Big_Numbers.Big_Integers;
|
||||
use Ada.Numerics.Big_Numbers.Big_Integers;
|
||||
|
||||
generic
|
||||
type Key_Type (<>) is private;
|
||||
type Element_Type (<>) is private;
|
||||
package Ada.Containers.Functional_Maps with SPARK_Mode is
|
||||
|
||||
with function Equivalent_Keys
|
||||
(Left : Key_Type;
|
||||
Right : Key_Type) return Boolean is "=";
|
||||
with function "=" (Left, Right : Element_Type) return Boolean is <>;
|
||||
|
||||
Enable_Handling_Of_Equivalence : Boolean := True;
|
||||
-- This constant should only be set to False when no particular handling
|
||||
-- of equivalence over keys is needed, that is, Equivalent_Keys defines a
|
||||
-- key uniquely.
|
||||
|
||||
package Ada.Containers.Functional_Maps with
|
||||
SPARK_Mode,
|
||||
Annotate => (GNATprove, Always_Return)
|
||||
is
|
||||
|
||||
type Map is private with
|
||||
Default_Initial_Condition => Is_Empty (Map) and Length (Map) = 0,
|
||||
Iterable => (First => Iter_First,
|
||||
Next => Iter_Next,
|
||||
Has_Element => Iter_Has_Element,
|
||||
Element => Iter_Element);
|
||||
-- Maps are empty when default initialized.
|
||||
-- "For in" quantification over maps should not be used.
|
||||
-- "For of" quantification over maps iterates over keys.
|
||||
-- Note that, for proof, "for of" quantification is understood modulo
|
||||
-- equivalence (the range of quantification comprises all the keys that are
|
||||
-- equivalent to any key of the map).
|
||||
|
||||
-----------------------
|
||||
-- Basic operations --
|
||||
-----------------------
|
||||
|
||||
-- Maps are axiomatized using Has_Key and Get, encoding respectively the
|
||||
-- presence of a key in a map and an accessor to elements associated with
|
||||
-- its keys. The length of a map is also added to protect Add against
|
||||
-- overflows but it is not actually modeled.
|
||||
|
||||
function Has_Key (Container : Map; Key : Key_Type) return Boolean with
|
||||
-- Return True if Key is present in Container
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
(if Enable_Handling_Of_Equivalence then
|
||||
|
||||
-- Has_Key returns the same result on all equivalent keys
|
||||
|
||||
(if (for some K of Container => Equivalent_Keys (K, Key)) then
|
||||
Has_Key'Result));
|
||||
|
||||
function Get (Container : Map; Key : Key_Type) return Element_Type with
|
||||
-- Return the element associated with Key in Container
|
||||
|
||||
Global => null,
|
||||
Pre => Has_Key (Container, Key),
|
||||
Post =>
|
||||
(if Enable_Handling_Of_Equivalence then
|
||||
|
||||
-- Get returns the same result on all equivalent keys
|
||||
|
||||
Get'Result = W_Get (Container, Witness (Container, Key))
|
||||
and (for all K of Container =>
|
||||
(Equivalent_Keys (K, Key) =
|
||||
(Witness (Container, Key) = Witness (Container, K)))));
|
||||
|
||||
function Length (Container : Map) return Big_Natural with
|
||||
Global => null;
|
||||
-- Return the number of mappings in Container
|
||||
|
||||
------------------------
|
||||
-- Property Functions --
|
||||
------------------------
|
||||
|
||||
function "<=" (Left : Map; Right : Map) return Boolean with
|
||||
-- Map inclusion
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
"<="'Result =
|
||||
(for all Key of Left =>
|
||||
Has_Key (Right, Key) and then Get (Right, Key) = Get (Left, Key));
|
||||
|
||||
function "=" (Left : Map; Right : Map) return Boolean with
|
||||
-- Extensional equality over maps
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
"="'Result =
|
||||
((for all Key of Left =>
|
||||
Has_Key (Right, Key)
|
||||
and then Get (Right, Key) = Get (Left, Key))
|
||||
and (for all Key of Right => Has_Key (Left, Key)));
|
||||
|
||||
pragma Warnings (Off, "unused variable ""Key""");
|
||||
function Is_Empty (Container : Map) return Boolean with
|
||||
-- A map is empty if it contains no key
|
||||
|
||||
Global => null,
|
||||
Post => Is_Empty'Result = (for all Key of Container => False);
|
||||
pragma Warnings (On, "unused variable ""Key""");
|
||||
|
||||
function Keys_Included (Left : Map; Right : Map) return Boolean
|
||||
-- Returns True if every Key of Left is in Right
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Keys_Included'Result = (for all Key of Left => Has_Key (Right, Key));
|
||||
|
||||
function Same_Keys (Left : Map; Right : Map) return Boolean
|
||||
-- Returns True if Left and Right have the same keys
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Same_Keys'Result =
|
||||
(Keys_Included (Left, Right)
|
||||
and Keys_Included (Left => Right, Right => Left));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Same_Keys);
|
||||
|
||||
function Keys_Included_Except
|
||||
(Left : Map;
|
||||
Right : Map;
|
||||
New_Key : Key_Type) return Boolean
|
||||
-- Returns True if Left contains only keys of Right and possibly New_Key
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Keys_Included_Except'Result =
|
||||
(for all Key of Left =>
|
||||
(if not Equivalent_Keys (Key, New_Key) then
|
||||
Has_Key (Right, Key)));
|
||||
|
||||
function Keys_Included_Except
|
||||
(Left : Map;
|
||||
Right : Map;
|
||||
X : Key_Type;
|
||||
Y : Key_Type) return Boolean
|
||||
-- Returns True if Left contains only keys of Right and possibly X and Y
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Keys_Included_Except'Result =
|
||||
(for all Key of Left =>
|
||||
(if not Equivalent_Keys (Key, X)
|
||||
and not Equivalent_Keys (Key, Y)
|
||||
then
|
||||
Has_Key (Right, Key)));
|
||||
|
||||
function Elements_Equal_Except
|
||||
(Left : Map;
|
||||
Right : Map;
|
||||
New_Key : Key_Type) return Boolean
|
||||
-- Returns True if all the keys of Left are mapped to the same elements in
|
||||
-- Left and Right except New_Key.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Elements_Equal_Except'Result =
|
||||
(for all Key of Left =>
|
||||
(if not Equivalent_Keys (Key, New_Key) then
|
||||
Has_Key (Right, Key)
|
||||
and then Get (Left, Key) = Get (Right, Key)));
|
||||
|
||||
function Elements_Equal_Except
|
||||
(Left : Map;
|
||||
Right : Map;
|
||||
X : Key_Type;
|
||||
Y : Key_Type) return Boolean
|
||||
-- Returns True if all the keys of Left are mapped to the same elements in
|
||||
-- Left and Right except X and Y.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Elements_Equal_Except'Result =
|
||||
(for all Key of Left =>
|
||||
(if not Equivalent_Keys (Key, X)
|
||||
and not Equivalent_Keys (Key, Y)
|
||||
then
|
||||
Has_Key (Right, Key)
|
||||
and then Get (Left, Key) = Get (Right, Key)));
|
||||
|
||||
----------------------------
|
||||
-- Construction Functions --
|
||||
----------------------------
|
||||
|
||||
-- For better efficiency of both proofs and execution, avoid using
|
||||
-- construction functions in annotations and rather use property functions.
|
||||
|
||||
function Add
|
||||
(Container : Map;
|
||||
New_Key : Key_Type;
|
||||
New_Item : Element_Type) return Map
|
||||
-- Returns Container augmented with the mapping Key -> New_Item
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => not Has_Key (Container, New_Key),
|
||||
Post =>
|
||||
Length (Container) + 1 = Length (Add'Result)
|
||||
and Has_Key (Add'Result, New_Key)
|
||||
and Get (Add'Result, New_Key) = New_Item
|
||||
and Container <= Add'Result
|
||||
and Keys_Included_Except (Add'Result, Container, New_Key);
|
||||
|
||||
function Empty_Map return Map with
|
||||
-- Return an empty Map
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
Length (Empty_Map'Result) = 0
|
||||
and Is_Empty (Empty_Map'Result);
|
||||
|
||||
function Remove
|
||||
(Container : Map;
|
||||
Key : Key_Type) return Map
|
||||
-- Returns Container without any mapping for Key
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Has_Key (Container, Key),
|
||||
Post =>
|
||||
Length (Container) = Length (Remove'Result) + 1
|
||||
and not Has_Key (Remove'Result, Key)
|
||||
and Remove'Result <= Container
|
||||
and Keys_Included_Except (Container, Remove'Result, Key);
|
||||
|
||||
function Set
|
||||
(Container : Map;
|
||||
Key : Key_Type;
|
||||
New_Item : Element_Type) return Map
|
||||
-- Returns Container, where the element associated with Key has been
|
||||
-- replaced by New_Item.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Has_Key (Container, Key),
|
||||
Post =>
|
||||
Length (Container) = Length (Set'Result)
|
||||
and Get (Set'Result, Key) = New_Item
|
||||
and Same_Keys (Container, Set'Result)
|
||||
and Elements_Equal_Except (Container, Set'Result, Key);
|
||||
|
||||
------------------------------
|
||||
-- Handling of Equivalence --
|
||||
------------------------------
|
||||
|
||||
-- These functions are used to specify that Get returns the same value on
|
||||
-- equivalent keys. They should not be used directly in user code.
|
||||
|
||||
function Has_Witness (Container : Map; Witness : Count_Type) return Boolean
|
||||
with
|
||||
Ghost,
|
||||
Global => null;
|
||||
-- Returns True if there is a key with witness Witness in Container
|
||||
|
||||
function Witness (Container : Map; Key : Key_Type) return Count_Type with
|
||||
-- Returns the witness of Key in Container
|
||||
|
||||
Ghost,
|
||||
Global => null,
|
||||
Pre => Has_Key (Container, Key),
|
||||
Post => Has_Witness (Container, Witness'Result);
|
||||
|
||||
function W_Get (Container : Map; Witness : Count_Type) return Element_Type
|
||||
with
|
||||
-- Returns the element associated with a witness in Container
|
||||
|
||||
Ghost,
|
||||
Global => null,
|
||||
Pre => Has_Witness (Container, Witness);
|
||||
|
||||
function Copy_Key (Key : Key_Type) return Key_Type is (Key);
|
||||
function Copy_Element (Item : Element_Type) return Element_Type is (Item);
|
||||
-- Elements and Keys of maps are copied by numerous primitives in this
|
||||
-- package. This function causes GNATprove to verify that such a copy is
|
||||
-- valid (in particular, it does not break the ownership policy of SPARK,
|
||||
-- i.e. it does not contain pointers that could be used to alias mutable
|
||||
-- data).
|
||||
|
||||
---------------------------
|
||||
-- Iteration Primitives --
|
||||
---------------------------
|
||||
|
||||
type Private_Key is private;
|
||||
|
||||
function Iter_First (Container : Map) return Private_Key with
|
||||
Global => null;
|
||||
|
||||
function Iter_Has_Element
|
||||
(Container : Map;
|
||||
Key : Private_Key) return Boolean
|
||||
with
|
||||
Global => null;
|
||||
|
||||
function Iter_Next (Container : Map; Key : Private_Key) return Private_Key
|
||||
with
|
||||
Global => null,
|
||||
Pre => Iter_Has_Element (Container, Key);
|
||||
|
||||
function Iter_Element (Container : Map; Key : Private_Key) return Key_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre => Iter_Has_Element (Container, Key);
|
||||
pragma Annotate (GNATprove, Iterable_For_Proof, "Contains", Has_Key);
|
||||
|
||||
private
|
||||
|
||||
pragma SPARK_Mode (Off);
|
||||
|
||||
function "="
|
||||
(Left : Key_Type;
|
||||
Right : Key_Type) return Boolean renames Equivalent_Keys;
|
||||
|
||||
subtype Positive_Count_Type is Count_Type range 1 .. Count_Type'Last;
|
||||
|
||||
package Element_Containers is new Ada.Containers.Functional_Base
|
||||
(Element_Type => Element_Type,
|
||||
Index_Type => Positive_Count_Type);
|
||||
|
||||
package Key_Containers is new Ada.Containers.Functional_Base
|
||||
(Element_Type => Key_Type,
|
||||
Index_Type => Positive_Count_Type);
|
||||
|
||||
type Map is record
|
||||
Keys : Key_Containers.Container;
|
||||
Elements : Element_Containers.Container;
|
||||
end record;
|
||||
|
||||
type Private_Key is new Count_Type;
|
||||
|
||||
function Iter_First (Container : Map) return Private_Key is (1);
|
||||
|
||||
function Iter_Has_Element
|
||||
(Container : Map;
|
||||
Key : Private_Key) return Boolean
|
||||
is
|
||||
(Count_Type (Key) in 1 .. Key_Containers.Length (Container.Keys));
|
||||
|
||||
function Iter_Next
|
||||
(Container : Map;
|
||||
Key : Private_Key) return Private_Key
|
||||
is
|
||||
(if Key = Private_Key'Last then 0 else Key + 1);
|
||||
|
||||
function Iter_Element
|
||||
(Container : Map;
|
||||
Key : Private_Key) return Key_Type
|
||||
is
|
||||
(Key_Containers.Get (Container.Keys, Count_Type (Key)));
|
||||
pragma Compile_Time_Error
|
||||
(True,
|
||||
"This package has been moved to the SPARK library shipped with any"
|
||||
& " SPARK release starting with version 23.");
|
||||
|
||||
end Ada.Containers.Functional_Maps;
|
||||
|
@ -1,184 +0,0 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- --
|
||||
-- GNAT LIBRARY COMPONENTS --
|
||||
-- --
|
||||
-- ADA.CONTAINERS.FUNCTIONAL_SETS --
|
||||
-- --
|
||||
-- B o d y --
|
||||
-- --
|
||||
-- Copyright (C) 2016-2022, 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 --
|
||||
-- apply solely to the contents of the part following the private keyword. --
|
||||
-- --
|
||||
-- GNAT is free software; you can redistribute it and/or modify it under --
|
||||
-- terms of the GNU General Public License as published by the Free Soft- --
|
||||
-- ware Foundation; either version 3, or (at your option) any later ver- --
|
||||
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
||||
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
||||
-- or FITNESS FOR A PARTICULAR PURPOSE. --
|
||||
-- --
|
||||
-- As a special exception under Section 7 of GPL version 3, you are granted --
|
||||
-- additional permissions described in the GCC Runtime Library Exception, --
|
||||
-- version 3.1, as published by the Free Software Foundation. --
|
||||
-- --
|
||||
-- You should have received a copy of the GNU General Public License and --
|
||||
-- a copy of the GCC Runtime Library Exception along with this program; --
|
||||
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
pragma Ada_2012;
|
||||
|
||||
package body Ada.Containers.Functional_Sets with SPARK_Mode => Off is
|
||||
use Containers;
|
||||
|
||||
package Conversions is new Signed_Conversions (Int => Count_Type);
|
||||
use Conversions;
|
||||
|
||||
---------
|
||||
-- "=" --
|
||||
---------
|
||||
|
||||
function "=" (Left : Set; Right : Set) return Boolean is
|
||||
(Left.Content <= Right.Content and Right.Content <= Left.Content);
|
||||
|
||||
----------
|
||||
-- "<=" --
|
||||
----------
|
||||
|
||||
function "<=" (Left : Set; Right : Set) return Boolean is
|
||||
(Left.Content <= Right.Content);
|
||||
|
||||
---------
|
||||
-- Add --
|
||||
---------
|
||||
|
||||
function Add (Container : Set; Item : Element_Type) return Set is
|
||||
(Content =>
|
||||
Add (Container.Content, Length (Container.Content) + 1, Item));
|
||||
|
||||
--------------
|
||||
-- Contains --
|
||||
--------------
|
||||
|
||||
function Contains (Container : Set; Item : Element_Type) return Boolean is
|
||||
(Find (Container.Content, Item) > 0);
|
||||
|
||||
---------------
|
||||
-- Empty_Set --
|
||||
---------------
|
||||
|
||||
function Empty_Set return Set is
|
||||
((others => <>));
|
||||
|
||||
---------------------
|
||||
-- Included_Except --
|
||||
---------------------
|
||||
|
||||
function Included_Except
|
||||
(Left : Set;
|
||||
Right : Set;
|
||||
Item : Element_Type) return Boolean
|
||||
is
|
||||
(for all E of Left =>
|
||||
Equivalent_Elements (E, Item) or Contains (Right, E));
|
||||
|
||||
-----------------------
|
||||
-- Included_In_Union --
|
||||
-----------------------
|
||||
|
||||
function Included_In_Union
|
||||
(Container : Set;
|
||||
Left : Set;
|
||||
Right : Set) return Boolean
|
||||
is
|
||||
(for all Item of Container =>
|
||||
Contains (Left, Item) or Contains (Right, Item));
|
||||
|
||||
---------------------------
|
||||
-- Includes_Intersection --
|
||||
---------------------------
|
||||
|
||||
function Includes_Intersection
|
||||
(Container : Set;
|
||||
Left : Set;
|
||||
Right : Set) return Boolean
|
||||
is
|
||||
(for all Item of Left =>
|
||||
(if Contains (Right, Item) then Contains (Container, Item)));
|
||||
|
||||
------------------
|
||||
-- Intersection --
|
||||
------------------
|
||||
|
||||
function Intersection (Left : Set; Right : Set) return Set is
|
||||
(Content => Intersection (Left.Content, Right.Content));
|
||||
|
||||
--------------
|
||||
-- Is_Empty --
|
||||
--------------
|
||||
|
||||
function Is_Empty (Container : Set) return Boolean is
|
||||
(Length (Container.Content) = 0);
|
||||
|
||||
------------------
|
||||
-- Is_Singleton --
|
||||
------------------
|
||||
|
||||
function Is_Singleton
|
||||
(Container : Set;
|
||||
New_Item : Element_Type) return Boolean
|
||||
is
|
||||
(Length (Container.Content) = 1
|
||||
and New_Item = Get (Container.Content, 1));
|
||||
|
||||
------------
|
||||
-- Length --
|
||||
------------
|
||||
|
||||
function Length (Container : Set) return Big_Natural is
|
||||
(To_Big_Integer (Length (Container.Content)));
|
||||
|
||||
-----------------
|
||||
-- Not_In_Both --
|
||||
-----------------
|
||||
|
||||
function Not_In_Both
|
||||
(Container : Set;
|
||||
Left : Set;
|
||||
Right : Set) return Boolean
|
||||
is
|
||||
(for all Item of Container =>
|
||||
not Contains (Right, Item) or not Contains (Left, Item));
|
||||
|
||||
----------------
|
||||
-- No_Overlap --
|
||||
----------------
|
||||
|
||||
function No_Overlap (Left : Set; Right : Set) return Boolean is
|
||||
(Num_Overlaps (Left.Content, Right.Content) = 0);
|
||||
|
||||
------------------
|
||||
-- Num_Overlaps --
|
||||
------------------
|
||||
|
||||
function Num_Overlaps (Left : Set; Right : Set) return Big_Natural is
|
||||
(To_Big_Integer (Num_Overlaps (Left.Content, Right.Content)));
|
||||
|
||||
------------
|
||||
-- Remove --
|
||||
------------
|
||||
|
||||
function Remove (Container : Set; Item : Element_Type) return Set is
|
||||
(Content => Remove (Container.Content, Find (Container.Content, Item)));
|
||||
|
||||
-----------
|
||||
-- Union --
|
||||
-----------
|
||||
|
||||
function Union (Left : Set; Right : Set) return Set is
|
||||
(Content => Union (Left.Content, Right.Content));
|
||||
|
||||
end Ada.Containers.Functional_Sets;
|
@ -29,308 +29,12 @@
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
pragma Ada_2012;
|
||||
private with Ada.Containers.Functional_Base;
|
||||
|
||||
with Ada.Numerics.Big_Numbers.Big_Integers;
|
||||
use Ada.Numerics.Big_Numbers.Big_Integers;
|
||||
|
||||
generic
|
||||
type Element_Type (<>) is private;
|
||||
package Ada.Containers.Functional_Sets with SPARK_Mode is
|
||||
|
||||
with function Equivalent_Elements
|
||||
(Left : Element_Type;
|
||||
Right : Element_Type) return Boolean is "=";
|
||||
|
||||
Enable_Handling_Of_Equivalence : Boolean := True;
|
||||
-- This constant should only be set to False when no particular handling
|
||||
-- of equivalence over elements is needed, that is, Equivalent_Elements
|
||||
-- defines an element uniquely.
|
||||
|
||||
package Ada.Containers.Functional_Sets with
|
||||
SPARK_Mode,
|
||||
Annotate => (GNATprove, Always_Return)
|
||||
is
|
||||
|
||||
type Set is private with
|
||||
Default_Initial_Condition => Is_Empty (Set),
|
||||
Iterable => (First => Iter_First,
|
||||
Next => Iter_Next,
|
||||
Has_Element => Iter_Has_Element,
|
||||
Element => Iter_Element);
|
||||
-- Sets are empty when default initialized.
|
||||
-- "For in" quantification over sets should not be used.
|
||||
-- "For of" quantification over sets iterates over elements.
|
||||
-- Note that, for proof, "for of" quantification is understood modulo
|
||||
-- equivalence (the range of quantification comprises all the elements that
|
||||
-- are equivalent to any element of the set).
|
||||
|
||||
-----------------------
|
||||
-- Basic operations --
|
||||
-----------------------
|
||||
|
||||
-- Sets are axiomatized using Contains, which encodes whether an element is
|
||||
-- contained in a set. The length of a set is also added to protect Add
|
||||
-- against overflows but it is not actually modeled.
|
||||
|
||||
function Contains (Container : Set; Item : Element_Type) return Boolean with
|
||||
-- Return True if Item is contained in Container
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
(if Enable_Handling_Of_Equivalence then
|
||||
|
||||
-- Contains returns the same result on all equivalent elements
|
||||
|
||||
(if (for some E of Container => Equivalent_Elements (E, Item)) then
|
||||
Contains'Result));
|
||||
|
||||
function Length (Container : Set) return Big_Natural with
|
||||
Global => null;
|
||||
-- Return the number of elements in Container
|
||||
|
||||
------------------------
|
||||
-- Property Functions --
|
||||
------------------------
|
||||
|
||||
function "<=" (Left : Set; Right : Set) return Boolean with
|
||||
-- Set inclusion
|
||||
|
||||
Global => null,
|
||||
Post => "<="'Result = (for all Item of Left => Contains (Right, Item));
|
||||
|
||||
function "=" (Left : Set; Right : Set) return Boolean with
|
||||
-- Extensional equality over sets
|
||||
|
||||
Global => null,
|
||||
Post => "="'Result = (Left <= Right and Right <= Left);
|
||||
|
||||
pragma Warnings (Off, "unused variable ""Item""");
|
||||
function Is_Empty (Container : Set) return Boolean with
|
||||
-- A set is empty if it contains no element
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
Is_Empty'Result = (for all Item of Container => False)
|
||||
and Is_Empty'Result = (Length (Container) = 0);
|
||||
pragma Warnings (On, "unused variable ""Item""");
|
||||
|
||||
function Included_Except
|
||||
(Left : Set;
|
||||
Right : Set;
|
||||
Item : Element_Type) return Boolean
|
||||
-- Return True if Left contains only elements of Right except possibly
|
||||
-- Item.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Included_Except'Result =
|
||||
(for all E of Left =>
|
||||
Contains (Right, E) or Equivalent_Elements (E, Item));
|
||||
|
||||
function Includes_Intersection
|
||||
(Container : Set;
|
||||
Left : Set;
|
||||
Right : Set) return Boolean
|
||||
with
|
||||
-- Return True if every element of the intersection of Left and Right is
|
||||
-- in Container.
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
Includes_Intersection'Result =
|
||||
(for all Item of Left =>
|
||||
(if Contains (Right, Item) then Contains (Container, Item)));
|
||||
|
||||
function Included_In_Union
|
||||
(Container : Set;
|
||||
Left : Set;
|
||||
Right : Set) return Boolean
|
||||
with
|
||||
-- Return True if every element of Container is the union of Left and Right
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
Included_In_Union'Result =
|
||||
(for all Item of Container =>
|
||||
Contains (Left, Item) or Contains (Right, Item));
|
||||
|
||||
function Is_Singleton
|
||||
(Container : Set;
|
||||
New_Item : Element_Type) return Boolean
|
||||
with
|
||||
-- Return True Container only contains New_Item
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
Is_Singleton'Result =
|
||||
(for all Item of Container => Equivalent_Elements (Item, New_Item));
|
||||
|
||||
function Not_In_Both
|
||||
(Container : Set;
|
||||
Left : Set;
|
||||
Right : Set) return Boolean
|
||||
-- Return True if there are no elements in Container that are in Left and
|
||||
-- Right.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Not_In_Both'Result =
|
||||
(for all Item of Container =>
|
||||
not Contains (Left, Item) or not Contains (Right, Item));
|
||||
|
||||
function No_Overlap (Left : Set; Right : Set) return Boolean with
|
||||
-- Return True if there are no equivalent elements in Left and Right
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
No_Overlap'Result =
|
||||
(for all Item of Left => not Contains (Right, Item));
|
||||
|
||||
function Num_Overlaps (Left : Set; Right : Set) return Big_Natural with
|
||||
-- Number of elements that are both in Left and Right
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
Num_Overlaps'Result = Length (Intersection (Left, Right))
|
||||
and (if Left <= Right then Num_Overlaps'Result = Length (Left)
|
||||
else Num_Overlaps'Result < Length (Left))
|
||||
and (if Right <= Left then Num_Overlaps'Result = Length (Right)
|
||||
else Num_Overlaps'Result < Length (Right))
|
||||
and (Num_Overlaps'Result = 0) = No_Overlap (Left, Right);
|
||||
|
||||
----------------------------
|
||||
-- Construction Functions --
|
||||
----------------------------
|
||||
|
||||
-- For better efficiency of both proofs and execution, avoid using
|
||||
-- construction functions in annotations and rather use property functions.
|
||||
|
||||
function Add (Container : Set; Item : Element_Type) return Set with
|
||||
-- Return a new set containing all the elements of Container plus E
|
||||
|
||||
Global => null,
|
||||
Pre => not Contains (Container, Item),
|
||||
Post =>
|
||||
Length (Add'Result) = Length (Container) + 1
|
||||
and Contains (Add'Result, Item)
|
||||
and Container <= Add'Result
|
||||
and Included_Except (Add'Result, Container, Item);
|
||||
|
||||
function Empty_Set return Set with
|
||||
-- Return a new empty set
|
||||
|
||||
Global => null,
|
||||
Post => Is_Empty (Empty_Set'Result);
|
||||
|
||||
function Remove (Container : Set; Item : Element_Type) return Set with
|
||||
-- Return a new set containing all the elements of Container except E
|
||||
|
||||
Global => null,
|
||||
Pre => Contains (Container, Item),
|
||||
Post =>
|
||||
Length (Remove'Result) = Length (Container) - 1
|
||||
and not Contains (Remove'Result, Item)
|
||||
and Remove'Result <= Container
|
||||
and Included_Except (Container, Remove'Result, Item);
|
||||
|
||||
function Intersection (Left : Set; Right : Set) return Set with
|
||||
-- Returns the intersection of Left and Right
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
Intersection'Result <= Left
|
||||
and Intersection'Result <= Right
|
||||
and Includes_Intersection (Intersection'Result, Left, Right);
|
||||
|
||||
function Union (Left : Set; Right : Set) return Set with
|
||||
-- Returns the union of Left and Right
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
Length (Union'Result) =
|
||||
Length (Left) - Num_Overlaps (Left, Right) + Length (Right)
|
||||
and Left <= Union'Result
|
||||
and Right <= Union'Result
|
||||
and Included_In_Union (Union'Result, Left, Right);
|
||||
|
||||
function Copy_Element (Item : Element_Type) return Element_Type is (Item);
|
||||
-- Elements of containers are copied by numerous primitives in this
|
||||
-- package. This function causes GNATprove to verify that such a copy is
|
||||
-- valid (in particular, it does not break the ownership policy of SPARK,
|
||||
-- i.e. it does not contain pointers that could be used to alias mutable
|
||||
-- data).
|
||||
|
||||
---------------------------
|
||||
-- Iteration Primitives --
|
||||
---------------------------
|
||||
|
||||
type Private_Key is private;
|
||||
|
||||
function Iter_First (Container : Set) return Private_Key with
|
||||
Global => null;
|
||||
|
||||
function Iter_Has_Element
|
||||
(Container : Set;
|
||||
Key : Private_Key) return Boolean
|
||||
with
|
||||
Global => null;
|
||||
|
||||
function Iter_Next
|
||||
(Container : Set;
|
||||
Key : Private_Key) return Private_Key
|
||||
with
|
||||
Global => null,
|
||||
Pre => Iter_Has_Element (Container, Key);
|
||||
|
||||
function Iter_Element
|
||||
(Container : Set;
|
||||
Key : Private_Key) return Element_Type
|
||||
with
|
||||
Global => null,
|
||||
Pre => Iter_Has_Element (Container, Key);
|
||||
pragma Annotate (GNATprove, Iterable_For_Proof, "Contains", Contains);
|
||||
|
||||
private
|
||||
|
||||
pragma SPARK_Mode (Off);
|
||||
|
||||
subtype Positive_Count_Type is Count_Type range 1 .. Count_Type'Last;
|
||||
|
||||
function "="
|
||||
(Left : Element_Type;
|
||||
Right : Element_Type) return Boolean renames Equivalent_Elements;
|
||||
|
||||
package Containers is new Ada.Containers.Functional_Base
|
||||
(Element_Type => Element_Type,
|
||||
Index_Type => Positive_Count_Type);
|
||||
|
||||
type Set is record
|
||||
Content : Containers.Container;
|
||||
end record;
|
||||
|
||||
type Private_Key is new Count_Type;
|
||||
|
||||
function Iter_First (Container : Set) return Private_Key is (1);
|
||||
|
||||
function Iter_Has_Element
|
||||
(Container : Set;
|
||||
Key : Private_Key) return Boolean
|
||||
is
|
||||
(Count_Type (Key) in 1 .. Containers.Length (Container.Content));
|
||||
|
||||
function Iter_Next
|
||||
(Container : Set;
|
||||
Key : Private_Key) return Private_Key
|
||||
is
|
||||
(if Key = Private_Key'Last then 0 else Key + 1);
|
||||
|
||||
function Iter_Element
|
||||
(Container : Set;
|
||||
Key : Private_Key) return Element_Type
|
||||
is
|
||||
(Containers.Get (Container.Content, Count_Type (Key)));
|
||||
pragma Compile_Time_Error
|
||||
(True,
|
||||
"This package has been moved to the SPARK library shipped with any"
|
||||
& " SPARK release starting with version 23.");
|
||||
|
||||
end Ada.Containers.Functional_Sets;
|
||||
|
@ -1,262 +0,0 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- --
|
||||
-- GNAT LIBRARY COMPONENTS --
|
||||
-- --
|
||||
-- ADA.CONTAINERS.FUNCTIONAL_VECTORS --
|
||||
-- --
|
||||
-- B o d y --
|
||||
-- --
|
||||
-- Copyright (C) 2016-2022, 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 --
|
||||
-- apply solely to the contents of the part following the private keyword. --
|
||||
-- --
|
||||
-- GNAT is free software; you can redistribute it and/or modify it under --
|
||||
-- terms of the GNU General Public License as published by the Free Soft- --
|
||||
-- ware Foundation; either version 3, or (at your option) any later ver- --
|
||||
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
||||
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
||||
-- or FITNESS FOR A PARTICULAR PURPOSE. --
|
||||
-- --
|
||||
-- As a special exception under Section 7 of GPL version 3, you are granted --
|
||||
-- additional permissions described in the GCC Runtime Library Exception, --
|
||||
-- version 3.1, as published by the Free Software Foundation. --
|
||||
-- --
|
||||
-- You should have received a copy of the GNU General Public License and --
|
||||
-- a copy of the GCC Runtime Library Exception along with this program; --
|
||||
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
pragma Ada_2012;
|
||||
package body Ada.Containers.Functional_Vectors with SPARK_Mode => Off is
|
||||
use Containers;
|
||||
|
||||
---------
|
||||
-- "<" --
|
||||
---------
|
||||
|
||||
function "<" (Left : Sequence; Right : Sequence) return Boolean is
|
||||
(Length (Left.Content) < Length (Right.Content)
|
||||
and then (for all I in Index_Type'First .. Last (Left) =>
|
||||
Get (Left.Content, I) = Get (Right.Content, I)));
|
||||
|
||||
----------
|
||||
-- "<=" --
|
||||
----------
|
||||
|
||||
function "<=" (Left : Sequence; Right : Sequence) return Boolean is
|
||||
(Length (Left.Content) <= Length (Right.Content)
|
||||
and then (for all I in Index_Type'First .. Last (Left) =>
|
||||
Get (Left.Content, I) = Get (Right.Content, I)));
|
||||
|
||||
---------
|
||||
-- "=" --
|
||||
---------
|
||||
|
||||
function "=" (Left : Sequence; Right : Sequence) return Boolean is
|
||||
(Left.Content = Right.Content);
|
||||
|
||||
---------
|
||||
-- Add --
|
||||
---------
|
||||
|
||||
function Add
|
||||
(Container : Sequence;
|
||||
New_Item : Element_Type) return Sequence
|
||||
is
|
||||
(Content =>
|
||||
Add (Container.Content,
|
||||
Index_Type'Val (Index_Type'Pos (Index_Type'First) +
|
||||
Length (Container.Content)),
|
||||
New_Item));
|
||||
|
||||
function Add
|
||||
(Container : Sequence;
|
||||
Position : Index_Type;
|
||||
New_Item : Element_Type) return Sequence
|
||||
is
|
||||
(Content => Add (Container.Content, Position, New_Item));
|
||||
|
||||
--------------------
|
||||
-- Constant_Range --
|
||||
--------------------
|
||||
|
||||
function Constant_Range
|
||||
(Container : Sequence;
|
||||
Fst : Index_Type;
|
||||
Lst : Extended_Index;
|
||||
Item : Element_Type) return Boolean is
|
||||
begin
|
||||
for I in Fst .. Lst loop
|
||||
if Get (Container.Content, I) /= Item then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Constant_Range;
|
||||
|
||||
--------------
|
||||
-- Contains --
|
||||
--------------
|
||||
|
||||
function Contains
|
||||
(Container : Sequence;
|
||||
Fst : Index_Type;
|
||||
Lst : Extended_Index;
|
||||
Item : Element_Type) return Boolean
|
||||
is
|
||||
begin
|
||||
for I in Fst .. Lst loop
|
||||
if Get (Container.Content, I) = Item then
|
||||
return True;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return False;
|
||||
end Contains;
|
||||
|
||||
--------------------
|
||||
-- Empty_Sequence --
|
||||
--------------------
|
||||
|
||||
function Empty_Sequence return Sequence is
|
||||
((others => <>));
|
||||
|
||||
------------------
|
||||
-- Equal_Except --
|
||||
------------------
|
||||
|
||||
function Equal_Except
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Position : Index_Type) return Boolean
|
||||
is
|
||||
begin
|
||||
if Length (Left.Content) /= Length (Right.Content) then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
for I in Index_Type'First .. Last (Left) loop
|
||||
if I /= Position
|
||||
and then Get (Left.Content, I) /= Get (Right.Content, I)
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Equal_Except;
|
||||
|
||||
function Equal_Except
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
X : Index_Type;
|
||||
Y : Index_Type) return Boolean
|
||||
is
|
||||
begin
|
||||
if Length (Left.Content) /= Length (Right.Content) then
|
||||
return False;
|
||||
end if;
|
||||
|
||||
for I in Index_Type'First .. Last (Left) loop
|
||||
if I /= X and then I /= Y
|
||||
and then Get (Left.Content, I) /= Get (Right.Content, I)
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Equal_Except;
|
||||
|
||||
---------
|
||||
-- Get --
|
||||
---------
|
||||
|
||||
function Get (Container : Sequence;
|
||||
Position : Extended_Index) return Element_Type
|
||||
is
|
||||
(Get (Container.Content, Position));
|
||||
|
||||
----------
|
||||
-- Last --
|
||||
----------
|
||||
|
||||
function Last (Container : Sequence) return Extended_Index is
|
||||
(Index_Type'Val
|
||||
((Index_Type'Pos (Index_Type'First) - 1) + Length (Container)));
|
||||
|
||||
------------
|
||||
-- Length --
|
||||
------------
|
||||
|
||||
function Length (Container : Sequence) return Count_Type is
|
||||
(Length (Container.Content));
|
||||
|
||||
-----------------
|
||||
-- Range_Equal --
|
||||
-----------------
|
||||
|
||||
function Range_Equal
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Fst : Index_Type;
|
||||
Lst : Extended_Index) return Boolean
|
||||
is
|
||||
begin
|
||||
for I in Fst .. Lst loop
|
||||
if Get (Left, I) /= Get (Right, I) then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return True;
|
||||
end Range_Equal;
|
||||
|
||||
-------------------
|
||||
-- Range_Shifted --
|
||||
-------------------
|
||||
|
||||
function Range_Shifted
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Fst : Index_Type;
|
||||
Lst : Extended_Index;
|
||||
Offset : Count_Type'Base) return Boolean
|
||||
is
|
||||
begin
|
||||
for I in Fst .. Lst loop
|
||||
if Get (Left, I) /=
|
||||
Get (Right, Index_Type'Val (Index_Type'Pos (I) + Offset))
|
||||
then
|
||||
return False;
|
||||
end if;
|
||||
end loop;
|
||||
return True;
|
||||
end Range_Shifted;
|
||||
|
||||
------------
|
||||
-- Remove --
|
||||
------------
|
||||
|
||||
function Remove
|
||||
(Container : Sequence;
|
||||
Position : Index_Type) return Sequence
|
||||
is
|
||||
(Content => Remove (Container.Content, Position));
|
||||
|
||||
---------
|
||||
-- Set --
|
||||
---------
|
||||
|
||||
function Set
|
||||
(Container : Sequence;
|
||||
Position : Index_Type;
|
||||
New_Item : Element_Type) return Sequence
|
||||
is
|
||||
(Content => Set (Container.Content, Position, New_Item));
|
||||
|
||||
end Ada.Containers.Functional_Vectors;
|
@ -29,383 +29,12 @@
|
||||
-- <http://www.gnu.org/licenses/>. --
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
pragma Ada_2012;
|
||||
private with Ada.Containers.Functional_Base;
|
||||
|
||||
generic
|
||||
type Index_Type is (<>);
|
||||
-- To avoid Constraint_Error being raised at run time, Index_Type'Base
|
||||
-- should have at least one more element at the low end than Index_Type.
|
||||
package Ada.Containers.Functional_Vectors with SPARK_Mode is
|
||||
|
||||
type Element_Type (<>) is private;
|
||||
with function "=" (Left, Right : Element_Type) return Boolean is <>;
|
||||
|
||||
package Ada.Containers.Functional_Vectors with
|
||||
SPARK_Mode,
|
||||
Annotate => (GNATprove, Always_Return)
|
||||
is
|
||||
|
||||
subtype Extended_Index is Index_Type'Base range
|
||||
Index_Type'Pred (Index_Type'First) .. Index_Type'Last;
|
||||
-- Index_Type with one more element at the low end of the range.
|
||||
-- This type is never used but it forces GNATprove to check that there is
|
||||
-- room for one more element at the low end of Index_Type.
|
||||
|
||||
type Sequence is private
|
||||
with Default_Initial_Condition => Length (Sequence) = 0,
|
||||
Iterable => (First => Iter_First,
|
||||
Has_Element => Iter_Has_Element,
|
||||
Next => Iter_Next,
|
||||
Element => Get);
|
||||
-- Sequences are empty when default initialized.
|
||||
-- Quantification over sequences can be done using the regular
|
||||
-- quantification over its range or directly on its elements with "for of".
|
||||
|
||||
-----------------------
|
||||
-- Basic operations --
|
||||
-----------------------
|
||||
|
||||
-- Sequences are axiomatized using Length and Get, providing respectively
|
||||
-- the length of a sequence and an accessor to its Nth element:
|
||||
|
||||
function Length (Container : Sequence) return Count_Type with
|
||||
-- Length of a sequence
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
(Index_Type'Pos (Index_Type'First) - 1) + Length'Result <=
|
||||
Index_Type'Pos (Index_Type'Last);
|
||||
|
||||
function Get
|
||||
(Container : Sequence;
|
||||
Position : Extended_Index) return Element_Type
|
||||
-- Access the Element at position Position in Container
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Position in Index_Type'First .. Last (Container);
|
||||
|
||||
function Last (Container : Sequence) return Extended_Index with
|
||||
-- Last index of a sequence
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
Last'Result =
|
||||
Index_Type'Val ((Index_Type'Pos (Index_Type'First) - 1) +
|
||||
Length (Container));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Last);
|
||||
|
||||
function First return Extended_Index is (Index_Type'First) with
|
||||
Global => null;
|
||||
-- First index of a sequence
|
||||
|
||||
------------------------
|
||||
-- Property Functions --
|
||||
------------------------
|
||||
|
||||
function "=" (Left : Sequence; Right : Sequence) return Boolean with
|
||||
-- Extensional equality over sequences
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
"="'Result =
|
||||
(Length (Left) = Length (Right)
|
||||
and then (for all N in Index_Type'First .. Last (Left) =>
|
||||
Get (Left, N) = Get (Right, N)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, "=");
|
||||
|
||||
function "<" (Left : Sequence; Right : Sequence) return Boolean with
|
||||
-- Left is a strict subsequence of Right
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
"<"'Result =
|
||||
(Length (Left) < Length (Right)
|
||||
and then (for all N in Index_Type'First .. Last (Left) =>
|
||||
Get (Left, N) = Get (Right, N)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, "<");
|
||||
|
||||
function "<=" (Left : Sequence; Right : Sequence) return Boolean with
|
||||
-- Left is a subsequence of Right
|
||||
|
||||
Global => null,
|
||||
Post =>
|
||||
"<="'Result =
|
||||
(Length (Left) <= Length (Right)
|
||||
and then (for all N in Index_Type'First .. Last (Left) =>
|
||||
Get (Left, N) = Get (Right, N)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, "<=");
|
||||
|
||||
function Contains
|
||||
(Container : Sequence;
|
||||
Fst : Index_Type;
|
||||
Lst : Extended_Index;
|
||||
Item : Element_Type) return Boolean
|
||||
-- Returns True if Item occurs in the range from Fst to Lst of Container
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Lst <= Last (Container),
|
||||
Post =>
|
||||
Contains'Result =
|
||||
(for some I in Fst .. Lst => Get (Container, I) = Item);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Contains);
|
||||
|
||||
function Constant_Range
|
||||
(Container : Sequence;
|
||||
Fst : Index_Type;
|
||||
Lst : Extended_Index;
|
||||
Item : Element_Type) return Boolean
|
||||
-- Returns True if every element of the range from Fst to Lst of Container
|
||||
-- is equal to Item.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Lst <= Last (Container),
|
||||
Post =>
|
||||
Constant_Range'Result =
|
||||
(for all I in Fst .. Lst => Get (Container, I) = Item);
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Constant_Range);
|
||||
|
||||
function Equal_Except
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Position : Index_Type) return Boolean
|
||||
-- Returns True is Left and Right are the same except at position Position
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Position <= Last (Left),
|
||||
Post =>
|
||||
Equal_Except'Result =
|
||||
(Length (Left) = Length (Right)
|
||||
and then (for all I in Index_Type'First .. Last (Left) =>
|
||||
(if I /= Position then Get (Left, I) = Get (Right, I))));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Equal_Except);
|
||||
|
||||
function Equal_Except
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
X : Index_Type;
|
||||
Y : Index_Type) return Boolean
|
||||
-- Returns True is Left and Right are the same except at positions X and Y
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => X <= Last (Left) and Y <= Last (Left),
|
||||
Post =>
|
||||
Equal_Except'Result =
|
||||
(Length (Left) = Length (Right)
|
||||
and then (for all I in Index_Type'First .. Last (Left) =>
|
||||
(if I /= X and I /= Y then
|
||||
Get (Left, I) = Get (Right, I))));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Equal_Except);
|
||||
|
||||
function Range_Equal
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Fst : Index_Type;
|
||||
Lst : Extended_Index) return Boolean
|
||||
-- Returns True if the ranges from Fst to Lst contain the same elements in
|
||||
-- Left and Right.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Lst <= Last (Left) and Lst <= Last (Right),
|
||||
Post =>
|
||||
Range_Equal'Result =
|
||||
(for all I in Fst .. Lst => Get (Left, I) = Get (Right, I));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Range_Equal);
|
||||
|
||||
function Range_Shifted
|
||||
(Left : Sequence;
|
||||
Right : Sequence;
|
||||
Fst : Index_Type;
|
||||
Lst : Extended_Index;
|
||||
Offset : Count_Type'Base) return Boolean
|
||||
-- Returns True if the range from Fst to Lst in Left contains the same
|
||||
-- elements as the range from Fst + Offset to Lst + Offset in Right.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Lst <= Last (Left)
|
||||
and then
|
||||
(if Offset < 0 then
|
||||
Index_Type'Pos (Index_Type'Base'First) - Offset <=
|
||||
Index_Type'Pos (Index_Type'First))
|
||||
and then
|
||||
(if Fst <= Lst then
|
||||
Offset in
|
||||
Index_Type'Pos (Index_Type'First) - Index_Type'Pos (Fst) ..
|
||||
(Index_Type'Pos (Index_Type'First) - 1) + Length (Right) -
|
||||
Index_Type'Pos (Lst)),
|
||||
Post =>
|
||||
Range_Shifted'Result =
|
||||
((for all I in Fst .. Lst =>
|
||||
Get (Left, I) =
|
||||
Get (Right, Index_Type'Val (Index_Type'Pos (I) + Offset)))
|
||||
and
|
||||
(for all I in Index_Type'Val (Index_Type'Pos (Fst) + Offset) ..
|
||||
Index_Type'Val (Index_Type'Pos (Lst) + Offset)
|
||||
=>
|
||||
Get (Left, Index_Type'Val (Index_Type'Pos (I) - Offset)) =
|
||||
Get (Right, I)));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Range_Shifted);
|
||||
|
||||
----------------------------
|
||||
-- Construction Functions --
|
||||
----------------------------
|
||||
|
||||
-- For better efficiency of both proofs and execution, avoid using
|
||||
-- construction functions in annotations and rather use property functions.
|
||||
|
||||
function Set
|
||||
(Container : Sequence;
|
||||
Position : Index_Type;
|
||||
New_Item : Element_Type) return Sequence
|
||||
-- Returns a new sequence which contains the same elements as Container
|
||||
-- except for the one at position Position which is replaced by New_Item.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Position in Index_Type'First .. Last (Container),
|
||||
Post =>
|
||||
Get (Set'Result, Position) = New_Item
|
||||
and then Equal_Except (Container, Set'Result, Position);
|
||||
|
||||
function Add (Container : Sequence; New_Item : Element_Type) return Sequence
|
||||
-- Returns a new sequence which contains the same elements as Container
|
||||
-- plus New_Item at the end.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) < Count_Type'Last
|
||||
and then Last (Container) < Index_Type'Last,
|
||||
Post =>
|
||||
Length (Add'Result) = Length (Container) + 1
|
||||
and then Get (Add'Result, Last (Add'Result)) = New_Item
|
||||
and then Container <= Add'Result;
|
||||
|
||||
function Add
|
||||
(Container : Sequence;
|
||||
Position : Index_Type;
|
||||
New_Item : Element_Type) return Sequence
|
||||
with
|
||||
-- Returns a new sequence which contains the same elements as Container
|
||||
-- except that New_Item has been inserted at position Position.
|
||||
|
||||
Global => null,
|
||||
Pre =>
|
||||
Length (Container) < Count_Type'Last
|
||||
and then Last (Container) < Index_Type'Last
|
||||
and then Position <= Extended_Index'Succ (Last (Container)),
|
||||
Post =>
|
||||
Length (Add'Result) = Length (Container) + 1
|
||||
and then Get (Add'Result, Position) = New_Item
|
||||
and then Range_Equal
|
||||
(Left => Container,
|
||||
Right => Add'Result,
|
||||
Fst => Index_Type'First,
|
||||
Lst => Index_Type'Pred (Position))
|
||||
and then Range_Shifted
|
||||
(Left => Container,
|
||||
Right => Add'Result,
|
||||
Fst => Position,
|
||||
Lst => Last (Container),
|
||||
Offset => 1);
|
||||
|
||||
function Remove
|
||||
(Container : Sequence;
|
||||
Position : Index_Type) return Sequence
|
||||
-- Returns a new sequence which contains the same elements as Container
|
||||
-- except that the element at position Position has been removed.
|
||||
|
||||
with
|
||||
Global => null,
|
||||
Pre => Position in Index_Type'First .. Last (Container),
|
||||
Post =>
|
||||
Length (Remove'Result) = Length (Container) - 1
|
||||
and then Range_Equal
|
||||
(Left => Container,
|
||||
Right => Remove'Result,
|
||||
Fst => Index_Type'First,
|
||||
Lst => Index_Type'Pred (Position))
|
||||
and then Range_Shifted
|
||||
(Left => Remove'Result,
|
||||
Right => Container,
|
||||
Fst => Position,
|
||||
Lst => Last (Remove'Result),
|
||||
Offset => 1);
|
||||
|
||||
function Copy_Element (Item : Element_Type) return Element_Type is (Item);
|
||||
-- Elements of containers are copied by numerous primitives in this
|
||||
-- package. This function causes GNATprove to verify that such a copy is
|
||||
-- valid (in particular, it does not break the ownership policy of SPARK,
|
||||
-- i.e. it does not contain pointers that could be used to alias mutable
|
||||
-- data).
|
||||
|
||||
function Empty_Sequence return Sequence with
|
||||
-- Return an empty Sequence
|
||||
|
||||
Global => null,
|
||||
Post => Length (Empty_Sequence'Result) = 0;
|
||||
|
||||
---------------------------
|
||||
-- Iteration Primitives --
|
||||
---------------------------
|
||||
|
||||
function Iter_First (Container : Sequence) return Extended_Index with
|
||||
Global => null;
|
||||
|
||||
function Iter_Has_Element
|
||||
(Container : Sequence;
|
||||
Position : Extended_Index) return Boolean
|
||||
with
|
||||
Global => null,
|
||||
Post =>
|
||||
Iter_Has_Element'Result =
|
||||
(Position in Index_Type'First .. Last (Container));
|
||||
pragma Annotate (GNATprove, Inline_For_Proof, Iter_Has_Element);
|
||||
|
||||
function Iter_Next
|
||||
(Container : Sequence;
|
||||
Position : Extended_Index) return Extended_Index
|
||||
with
|
||||
Global => null,
|
||||
Pre => Iter_Has_Element (Container, Position);
|
||||
|
||||
private
|
||||
|
||||
pragma SPARK_Mode (Off);
|
||||
|
||||
package Containers is new Ada.Containers.Functional_Base
|
||||
(Index_Type => Index_Type,
|
||||
Element_Type => Element_Type);
|
||||
|
||||
type Sequence is record
|
||||
Content : Containers.Container;
|
||||
end record;
|
||||
|
||||
function Iter_First (Container : Sequence) return Extended_Index is
|
||||
(Index_Type'First);
|
||||
|
||||
function Iter_Next
|
||||
(Container : Sequence;
|
||||
Position : Extended_Index) return Extended_Index
|
||||
is
|
||||
(if Position = Extended_Index'Last then
|
||||
Extended_Index'First
|
||||
else
|
||||
Extended_Index'Succ (Position));
|
||||
|
||||
function Iter_Has_Element
|
||||
(Container : Sequence;
|
||||
Position : Extended_Index) return Boolean
|
||||
is
|
||||
(Position in Index_Type'First ..
|
||||
(Index_Type'Val
|
||||
((Index_Type'Pos (Index_Type'First) - 1) + Length (Container))));
|
||||
pragma Compile_Time_Error
|
||||
(True,
|
||||
"This package has been moved to the SPARK library shipped with any"
|
||||
& " SPARK release starting with version 23.");
|
||||
|
||||
end Ada.Containers.Functional_Vectors;
|
||||
|
@ -1,5 +0,0 @@
|
||||
-- { dg-do compile }
|
||||
|
||||
package body Aspect2 is
|
||||
procedure Foo is null;
|
||||
end Aspect2;
|
@ -1,30 +0,0 @@
|
||||
with Ada.Containers.Functional_Vectors;
|
||||
with Ada.Containers; use Ada.Containers;
|
||||
|
||||
generic
|
||||
type Element_Type (<>) is private;
|
||||
type Element_Model (<>) is private;
|
||||
with function Model (X : Element_Type) return Element_Model is <>;
|
||||
with function Copy (X : Element_Type) return Element_Type is <>;
|
||||
package Aspect2 with SPARK_Mode is
|
||||
pragma Unevaluated_Use_Of_Old (Allow);
|
||||
|
||||
type Vector is private;
|
||||
|
||||
function Length (V : Vector) return Natural;
|
||||
|
||||
procedure Foo;
|
||||
|
||||
private
|
||||
type Element_Access is access Element_Type;
|
||||
type Element_Array is array (Positive range <>) of Element_Access with
|
||||
Dynamic_Predicate => Element_Array'First = 1;
|
||||
type Element_Array_Access is access Element_Array;
|
||||
type Vector is record
|
||||
Top : Natural := 0;
|
||||
Content : Element_Array_Access;
|
||||
end record;
|
||||
|
||||
function Length (V : Vector) return Natural is
|
||||
(V.Top);
|
||||
end Aspect2;
|
@ -1,21 +0,0 @@
|
||||
-- { dg-do run }
|
||||
-- { dg-options "-gnata" }
|
||||
|
||||
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
|
||||
with Config_Pragma1_Pkg; use Config_Pragma1_Pkg;
|
||||
|
||||
procedure Config_Pragma1 is
|
||||
Target : String10;
|
||||
|
||||
begin
|
||||
for I in Positive10 loop
|
||||
Move
|
||||
(Source => Positive10'Image(I),
|
||||
Target => Target);
|
||||
|
||||
FHM.Include
|
||||
(Container => FHMM,
|
||||
Key => Target,
|
||||
New_Item => I);
|
||||
end loop;
|
||||
end Config_Pragma1;
|
@ -1,21 +0,0 @@
|
||||
pragma Assertion_Policy (Ignore);
|
||||
|
||||
with Ada.Containers; use Ada.Containers;
|
||||
with Ada.Containers.Formal_Hashed_Maps;
|
||||
with Ada.Strings; use Ada.Strings;
|
||||
with Ada.Strings.Hash;
|
||||
|
||||
package Config_Pragma1_Pkg is
|
||||
subtype Positive10 is Positive range 1 .. 1000;
|
||||
subtype String10 is String (Positive10);
|
||||
|
||||
package FHM is new Formal_Hashed_Maps
|
||||
(Key_Type => String10,
|
||||
Element_Type => Positive10,
|
||||
Hash => Hash,
|
||||
Equivalent_Keys => "=");
|
||||
|
||||
FHMM : FHM.Map
|
||||
(Capacity => 1_000_000,
|
||||
Modulus => FHM.Default_Modulus (Count_Type (1_000_000)));
|
||||
end Config_Pragma1_Pkg;
|
@ -1,6 +0,0 @@
|
||||
-- { dg-do compile }
|
||||
-- { dg-options "-gnata" }
|
||||
|
||||
package body Equal8 is
|
||||
procedure Foo is null;
|
||||
end Equal8;
|
@ -1,36 +0,0 @@
|
||||
with Ada.Containers.Formal_Hashed_Sets;
|
||||
with Ada.Strings.Hash;
|
||||
|
||||
-- with Dynamic_Strings; use Dynamic_Strings;
|
||||
-- with Bounded_Dynamic_Strings;
|
||||
|
||||
with Equal8_Pkg;
|
||||
|
||||
package Equal8 is
|
||||
|
||||
package Dynamic_Strings is
|
||||
-- pragma SPARK_Mode (On);
|
||||
|
||||
package Bounded_Dynamic_Strings is new Equal8_Pkg
|
||||
(Component => Character,
|
||||
List_Index => Positive,
|
||||
List => String,
|
||||
Default_Value => ' ');
|
||||
type Dynamic_String is new Bounded_Dynamic_Strings.Sequence;
|
||||
|
||||
end Dynamic_Strings;
|
||||
use Dynamic_Strings;
|
||||
|
||||
subtype Subscription_Address is Dynamic_String (Capacity => 255);
|
||||
|
||||
function Hashed_Subscription_Address (Element : Subscription_Address)
|
||||
return Ada.Containers.Hash_Type is
|
||||
(Ada.Strings.Hash (Value (Element)));
|
||||
|
||||
package Subscription_Addresses is new Ada.Containers.Formal_Hashed_Sets
|
||||
(Element_Type => Subscription_Address,
|
||||
Hash => Hashed_Subscription_Address,
|
||||
Equivalent_Elements => "=");
|
||||
|
||||
procedure Foo;
|
||||
end Equal8;
|
@ -1,58 +0,0 @@
|
||||
generic
|
||||
type Component is private;
|
||||
type List_Index is range <>;
|
||||
type List is array (List_Index range <>) of Component;
|
||||
Default_Value : Component;
|
||||
-- with function "=" (Left, Right : List) return Boolean is <>;
|
||||
|
||||
package Equal8_Pkg is
|
||||
|
||||
pragma Pure;
|
||||
|
||||
Maximum_Length : constant List_Index := List_Index'Last;
|
||||
|
||||
subtype Natural_Index is List_Index'Base range 0 .. Maximum_Length;
|
||||
type Sequence (Capacity : Natural_Index) is private;
|
||||
-- from zero to Capacity.
|
||||
|
||||
function Value (This : Sequence) return List;
|
||||
-- Returns the content of this sequence. The value returned is the
|
||||
-- "logical" value in that only that slice which is currently assigned
|
||||
-- is returned, as opposed to the entire physical representation.
|
||||
|
||||
overriding
|
||||
function "=" (Left, Right : Sequence) return Boolean with
|
||||
Inline;
|
||||
|
||||
function "=" (Left : Sequence; Right : List) return Boolean with
|
||||
Inline;
|
||||
|
||||
private
|
||||
type Sequence (Capacity : Natural_Index) is record
|
||||
Current_Length : Natural_Index := 0;
|
||||
Content : List (1 .. Capacity) := (others => Default_Value);
|
||||
end record;
|
||||
|
||||
-----------
|
||||
-- Value --
|
||||
-----------
|
||||
|
||||
function Value (This : Sequence) return List is
|
||||
(This.Content (1 .. This.Current_Length));
|
||||
|
||||
---------
|
||||
-- "=" --
|
||||
---------
|
||||
|
||||
overriding
|
||||
function "=" (Left, Right : Sequence) return Boolean is
|
||||
(Value (Left) = Value (Right));
|
||||
|
||||
---------
|
||||
-- "=" --
|
||||
---------
|
||||
|
||||
function "=" (Left : Sequence; Right : List) return Boolean is
|
||||
(Value (Left) = Right);
|
||||
end Equal8_Pkg;
|
||||
|
@ -1,23 +0,0 @@
|
||||
-- { dg-do compile }
|
||||
|
||||
with Ada.Containers.Formal_Hashed_Sets;
|
||||
|
||||
procedure Formal_Containers is
|
||||
type T is new Integer;
|
||||
|
||||
function Eq (X : T; Y : T) return Boolean;
|
||||
|
||||
function Hash (X : T) return Ada.Containers.Hash_Type is (0);
|
||||
|
||||
package TSet is new Ada.Containers.Formal_Hashed_Sets
|
||||
(Element_Type => T,
|
||||
Hash => Hash,
|
||||
Equivalent_Elements => Eq);
|
||||
|
||||
S : Tset.Set := TSet.Empty_Set;
|
||||
|
||||
function Eq (X : T; Y : T) return Boolean is
|
||||
begin
|
||||
return TSet.Contains (S, X) or TSet.Contains (S, Y);
|
||||
end Eq;
|
||||
begin null; end Formal_Containers;
|
@ -1,20 +0,0 @@
|
||||
-- { dg-do compile }
|
||||
|
||||
with Ada.Text_IO;
|
||||
|
||||
package body Iter1 is
|
||||
|
||||
type Table is array (Integer range <>) of Float;
|
||||
My_Table : Table := (1.0, 2.0, 3.0);
|
||||
|
||||
procedure Dummy (L : My_Lists.List) is
|
||||
begin
|
||||
for Item : Boolean of L loop -- { dg-error "subtype indication does not match element type" }
|
||||
Ada.Text_IO.Put_Line (Integer'Image (Item));
|
||||
end loop;
|
||||
|
||||
for Item : Boolean of My_Table loop -- { dg-error "subtype indication does not match component type" }
|
||||
null;
|
||||
end loop;
|
||||
end;
|
||||
end Iter1;
|
@ -1,8 +0,0 @@
|
||||
with Ada.Containers.Formal_Doubly_Linked_Lists;
|
||||
|
||||
package Iter1 is
|
||||
package My_Lists is new Ada.Containers.Formal_Doubly_Linked_Lists
|
||||
(Element_Type => Integer);
|
||||
|
||||
procedure Dummy (L : My_Lists.List);
|
||||
end Iter1;
|
Loading…
x
Reference in New Issue
Block a user