645 lines
18 KiB
Ada
645 lines
18 KiB
Ada
|
------------------------------------------------------------------------------
|
||
|
-- --
|
||
|
-- GNAT LIBRARY COMPONENTS --
|
||
|
-- --
|
||
|
-- A D A . C O N T A I N E R S . F O R M A L _ V E C T O R S --
|
||
|
-- --
|
||
|
-- B o d y --
|
||
|
-- --
|
||
|
-- Copyright (C) 2010-2015, 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.Generic_Array_Sort;
|
||
|
with Ada.Unchecked_Deallocation;
|
||
|
|
||
|
with System; use type System.Address;
|
||
|
|
||
|
package body Ada.Containers.Formal_Vectors with
|
||
|
SPARK_Mode => Off
|
||
|
is
|
||
|
|
||
|
Growth_Factor : constant := 2;
|
||
|
-- When growing a container, multiply current capacity by this. Doubling
|
||
|
-- leads to amortized linear-time copying.
|
||
|
|
||
|
type Int is range System.Min_Int .. System.Max_Int;
|
||
|
type UInt is mod System.Max_Binary_Modulus;
|
||
|
|
||
|
procedure Free is
|
||
|
new Ada.Unchecked_Deallocation (Elements_Array, Elements_Array_Ptr);
|
||
|
|
||
|
type Maximal_Array_Ptr is access all Elements_Array (Array_Index)
|
||
|
with Storage_Size => 0;
|
||
|
type Maximal_Array_Ptr_Const is access constant Elements_Array (Array_Index)
|
||
|
with Storage_Size => 0;
|
||
|
|
||
|
function Elems (Container : in out Vector) return Maximal_Array_Ptr;
|
||
|
function Elemsc
|
||
|
(Container : Vector) return Maximal_Array_Ptr_Const;
|
||
|
-- Returns a pointer to the Elements array currently in use -- either
|
||
|
-- Container.Elements_Ptr or a pointer to Container.Elements. We work with
|
||
|
-- pointers to a bogus array subtype that is constrained with the maximum
|
||
|
-- possible bounds. This means that the pointer is a thin pointer. This is
|
||
|
-- necessary because 'Unrestricted_Access doesn't work when it produces
|
||
|
-- access-to-unconstrained and is returned from a function.
|
||
|
--
|
||
|
-- Note that this is dangerous: make sure calls to this use an indexed
|
||
|
-- component or slice that is within the bounds 1 .. Length (Container).
|
||
|
|
||
|
function Get_Element
|
||
|
(Container : Vector;
|
||
|
Position : Capacity_Range) return Element_Type;
|
||
|
|
||
|
---------
|
||
|
-- "=" --
|
||
|
---------
|
||
|
|
||
|
function "=" (Left, Right : Vector) return Boolean is
|
||
|
begin
|
||
|
if Left'Address = Right'Address then
|
||
|
return True;
|
||
|
end if;
|
||
|
|
||
|
if Length (Left) /= Length (Right) then
|
||
|
return False;
|
||
|
end if;
|
||
|
|
||
|
for J in 1 .. Length (Left) loop
|
||
|
if Get_Element (Left, J) /= Get_Element (Right, J) then
|
||
|
return False;
|
||
|
end if;
|
||
|
end loop;
|
||
|
|
||
|
return True;
|
||
|
end "=";
|
||
|
|
||
|
------------
|
||
|
-- Append --
|
||
|
------------
|
||
|
|
||
|
procedure Append (Container : in out Vector; New_Item : Vector) is
|
||
|
begin
|
||
|
for X in First_Index (New_Item) .. Last_Index (New_Item) loop
|
||
|
Append (Container, Element (New_Item, X));
|
||
|
end loop;
|
||
|
end Append;
|
||
|
|
||
|
procedure Append
|
||
|
(Container : in out Vector;
|
||
|
New_Item : Element_Type)
|
||
|
is
|
||
|
New_Length : constant UInt := UInt (Length (Container) + 1);
|
||
|
begin
|
||
|
if not Bounded and then
|
||
|
Capacity (Container) < Capacity_Range (New_Length)
|
||
|
then
|
||
|
Reserve_Capacity
|
||
|
(Container,
|
||
|
Capacity_Range'Max (Capacity (Container) * Growth_Factor,
|
||
|
Capacity_Range (New_Length)));
|
||
|
end if;
|
||
|
|
||
|
if Container.Last = Index_Type'Last then
|
||
|
raise Constraint_Error with "vector is already at its maximum length";
|
||
|
end if;
|
||
|
|
||
|
-- TODO: should check whether length > max capacity (cnt_t'last) ???
|
||
|
|
||
|
Container.Last := Container.Last + 1;
|
||
|
Elems (Container) (Length (Container)) := New_Item;
|
||
|
end Append;
|
||
|
|
||
|
------------
|
||
|
-- Assign --
|
||
|
------------
|
||
|
|
||
|
procedure Assign (Target : in out Vector; Source : Vector) is
|
||
|
LS : constant Capacity_Range := Length (Source);
|
||
|
|
||
|
begin
|
||
|
if Target'Address = Source'Address then
|
||
|
return;
|
||
|
end if;
|
||
|
|
||
|
if Bounded and then Target.Capacity < LS then
|
||
|
raise Constraint_Error;
|
||
|
end if;
|
||
|
|
||
|
Clear (Target);
|
||
|
Append (Target, Source);
|
||
|
end Assign;
|
||
|
|
||
|
--------------
|
||
|
-- Capacity --
|
||
|
--------------
|
||
|
|
||
|
function Capacity (Container : Vector) return Capacity_Range is
|
||
|
begin
|
||
|
return (if Container.Elements_Ptr = null
|
||
|
then Container.Elements'Length
|
||
|
else Container.Elements_Ptr.all'Length);
|
||
|
end Capacity;
|
||
|
|
||
|
-----------
|
||
|
-- Clear --
|
||
|
-----------
|
||
|
|
||
|
procedure Clear (Container : in out Vector) is
|
||
|
begin
|
||
|
Container.Last := No_Index;
|
||
|
|
||
|
-- Free element, note that this is OK if Elements_Ptr is null
|
||
|
|
||
|
Free (Container.Elements_Ptr);
|
||
|
end Clear;
|
||
|
|
||
|
--------------
|
||
|
-- Contains --
|
||
|
--------------
|
||
|
|
||
|
function Contains
|
||
|
(Container : Vector;
|
||
|
Item : Element_Type) return Boolean
|
||
|
is
|
||
|
begin
|
||
|
return Find_Index (Container, Item) /= No_Index;
|
||
|
end Contains;
|
||
|
|
||
|
----------
|
||
|
-- Copy --
|
||
|
----------
|
||
|
|
||
|
function Copy
|
||
|
(Source : Vector;
|
||
|
Capacity : Capacity_Range := 0) return Vector
|
||
|
is
|
||
|
LS : constant Capacity_Range := Length (Source);
|
||
|
C : Capacity_Range;
|
||
|
|
||
|
begin
|
||
|
if Capacity = 0 then
|
||
|
C := LS;
|
||
|
elsif Capacity >= LS then
|
||
|
C := Capacity;
|
||
|
else
|
||
|
raise Capacity_Error;
|
||
|
end if;
|
||
|
|
||
|
return Target : Vector (C) do
|
||
|
Elems (Target) (1 .. LS) := Elemsc (Source) (1 .. LS);
|
||
|
Target.Last := Source.Last;
|
||
|
end return;
|
||
|
end Copy;
|
||
|
|
||
|
---------------------
|
||
|
-- Current_To_Last --
|
||
|
---------------------
|
||
|
|
||
|
function Current_To_Last
|
||
|
(Container : Vector;
|
||
|
Current : Index_Type) return Vector
|
||
|
is
|
||
|
begin
|
||
|
return Result : Vector (Count_Type (Container.Last - Current + 1))
|
||
|
do
|
||
|
for X in Current .. Container.Last loop
|
||
|
Append (Result, Element (Container, X));
|
||
|
end loop;
|
||
|
end return;
|
||
|
end Current_To_Last;
|
||
|
|
||
|
-----------------
|
||
|
-- Delete_Last --
|
||
|
-----------------
|
||
|
|
||
|
procedure Delete_Last
|
||
|
(Container : in out Vector)
|
||
|
is
|
||
|
Count : constant Capacity_Range := 1;
|
||
|
Index : Int'Base;
|
||
|
|
||
|
begin
|
||
|
Index := Int'Base (Container.Last) - Int'Base (Count);
|
||
|
|
||
|
if Index < Index_Type'Pos (Index_Type'First) then
|
||
|
Container.Last := No_Index;
|
||
|
else
|
||
|
Container.Last := Index_Type (Index);
|
||
|
end if;
|
||
|
end Delete_Last;
|
||
|
|
||
|
-------------
|
||
|
-- Element --
|
||
|
-------------
|
||
|
|
||
|
function Element
|
||
|
(Container : Vector;
|
||
|
Index : Index_Type) return Element_Type
|
||
|
is
|
||
|
begin
|
||
|
if Index > Container.Last then
|
||
|
raise Constraint_Error with "Index is out of range";
|
||
|
end if;
|
||
|
|
||
|
declare
|
||
|
II : constant Int'Base := Int (Index) - Int (No_Index);
|
||
|
I : constant Capacity_Range := Capacity_Range (II);
|
||
|
begin
|
||
|
return Get_Element (Container, I);
|
||
|
end;
|
||
|
end Element;
|
||
|
|
||
|
--------------
|
||
|
-- Elements --
|
||
|
--------------
|
||
|
|
||
|
function Elems (Container : in out Vector) return Maximal_Array_Ptr is
|
||
|
begin
|
||
|
return (if Container.Elements_Ptr = null
|
||
|
then Container.Elements'Unrestricted_Access
|
||
|
else Container.Elements_Ptr.all'Unrestricted_Access);
|
||
|
end Elems;
|
||
|
|
||
|
function Elemsc
|
||
|
(Container : Vector) return Maximal_Array_Ptr_Const is
|
||
|
begin
|
||
|
return (if Container.Elements_Ptr = null
|
||
|
then Container.Elements'Unrestricted_Access
|
||
|
else Container.Elements_Ptr.all'Unrestricted_Access);
|
||
|
end Elemsc;
|
||
|
|
||
|
----------------
|
||
|
-- Find_Index --
|
||
|
----------------
|
||
|
|
||
|
function Find_Index
|
||
|
(Container : Vector;
|
||
|
Item : Element_Type;
|
||
|
Index : Index_Type := Index_Type'First) return Extended_Index
|
||
|
is
|
||
|
K : Capacity_Range;
|
||
|
Last : constant Index_Type := Last_Index (Container);
|
||
|
|
||
|
begin
|
||
|
K := Capacity_Range (Int (Index) - Int (No_Index));
|
||
|
for Indx in Index .. Last loop
|
||
|
if Get_Element (Container, K) = Item then
|
||
|
return Indx;
|
||
|
end if;
|
||
|
|
||
|
K := K + 1;
|
||
|
end loop;
|
||
|
|
||
|
return No_Index;
|
||
|
end Find_Index;
|
||
|
|
||
|
-------------------
|
||
|
-- First_Element --
|
||
|
-------------------
|
||
|
|
||
|
function First_Element (Container : Vector) return Element_Type is
|
||
|
begin
|
||
|
if Is_Empty (Container) then
|
||
|
raise Constraint_Error with "Container is empty";
|
||
|
else
|
||
|
return Get_Element (Container, 1);
|
||
|
end if;
|
||
|
end First_Element;
|
||
|
|
||
|
-----------------
|
||
|
-- First_Index --
|
||
|
-----------------
|
||
|
|
||
|
function First_Index (Container : Vector) return Index_Type is
|
||
|
pragma Unreferenced (Container);
|
||
|
begin
|
||
|
return Index_Type'First;
|
||
|
end First_Index;
|
||
|
|
||
|
-----------------------
|
||
|
-- First_To_Previous --
|
||
|
-----------------------
|
||
|
|
||
|
function First_To_Previous
|
||
|
(Container : Vector;
|
||
|
Current : Index_Type) return Vector
|
||
|
is
|
||
|
begin
|
||
|
return Result : Vector
|
||
|
(Count_Type (Current - First_Index (Container)))
|
||
|
do
|
||
|
for X in First_Index (Container) .. Current - 1 loop
|
||
|
Append (Result, Element (Container, X));
|
||
|
end loop;
|
||
|
end return;
|
||
|
end First_To_Previous;
|
||
|
|
||
|
---------------------
|
||
|
-- Generic_Sorting --
|
||
|
---------------------
|
||
|
|
||
|
package body Generic_Sorting with SPARK_Mode => Off is
|
||
|
|
||
|
---------------
|
||
|
-- Is_Sorted --
|
||
|
---------------
|
||
|
|
||
|
function Is_Sorted (Container : Vector) return Boolean is
|
||
|
L : constant Capacity_Range := Length (Container);
|
||
|
begin
|
||
|
for J in 1 .. L - 1 loop
|
||
|
if Get_Element (Container, J + 1) <
|
||
|
Get_Element (Container, J)
|
||
|
then
|
||
|
return False;
|
||
|
end if;
|
||
|
end loop;
|
||
|
|
||
|
return True;
|
||
|
end Is_Sorted;
|
||
|
|
||
|
----------
|
||
|
-- Sort --
|
||
|
----------
|
||
|
|
||
|
procedure Sort (Container : in out Vector)
|
||
|
is
|
||
|
procedure Sort is
|
||
|
new Generic_Array_Sort
|
||
|
(Index_Type => Array_Index,
|
||
|
Element_Type => Element_Type,
|
||
|
Array_Type => Elements_Array,
|
||
|
"<" => "<");
|
||
|
|
||
|
Len : constant Capacity_Range := Length (Container);
|
||
|
begin
|
||
|
if Container.Last <= Index_Type'First then
|
||
|
return;
|
||
|
else
|
||
|
Sort (Elems (Container) (1 .. Len));
|
||
|
end if;
|
||
|
end Sort;
|
||
|
|
||
|
end Generic_Sorting;
|
||
|
|
||
|
-----------------
|
||
|
-- Get_Element --
|
||
|
-----------------
|
||
|
|
||
|
function Get_Element
|
||
|
(Container : Vector;
|
||
|
Position : Capacity_Range) return Element_Type
|
||
|
is
|
||
|
begin
|
||
|
return Elemsc (Container) (Position);
|
||
|
end Get_Element;
|
||
|
|
||
|
-----------------
|
||
|
-- Has_Element --
|
||
|
-----------------
|
||
|
|
||
|
function Has_Element
|
||
|
(Container : Vector; Position : Extended_Index) return Boolean is
|
||
|
begin
|
||
|
return Position in First_Index (Container) .. Last_Index (Container);
|
||
|
end Has_Element;
|
||
|
|
||
|
--------------
|
||
|
-- Is_Empty --
|
||
|
--------------
|
||
|
|
||
|
function Is_Empty (Container : Vector) return Boolean is
|
||
|
begin
|
||
|
return Last_Index (Container) < Index_Type'First;
|
||
|
end Is_Empty;
|
||
|
|
||
|
------------------
|
||
|
-- Last_Element --
|
||
|
------------------
|
||
|
|
||
|
function Last_Element (Container : Vector) return Element_Type is
|
||
|
begin
|
||
|
if Is_Empty (Container) then
|
||
|
raise Constraint_Error with "Container is empty";
|
||
|
else
|
||
|
return Get_Element (Container, Length (Container));
|
||
|
end if;
|
||
|
end Last_Element;
|
||
|
|
||
|
----------------
|
||
|
-- Last_Index --
|
||
|
----------------
|
||
|
|
||
|
function Last_Index (Container : Vector) return Extended_Index is
|
||
|
begin
|
||
|
return Container.Last;
|
||
|
end Last_Index;
|
||
|
|
||
|
------------
|
||
|
-- Length --
|
||
|
------------
|
||
|
|
||
|
function Length (Container : Vector) return Capacity_Range is
|
||
|
L : constant Int := Int (Last_Index (Container));
|
||
|
F : constant Int := Int (Index_Type'First);
|
||
|
N : constant Int'Base := L - F + 1;
|
||
|
begin
|
||
|
return Capacity_Range (N);
|
||
|
end Length;
|
||
|
|
||
|
---------------------
|
||
|
-- Replace_Element --
|
||
|
---------------------
|
||
|
|
||
|
procedure Replace_Element
|
||
|
(Container : in out Vector;
|
||
|
Index : Index_Type;
|
||
|
New_Item : Element_Type)
|
||
|
is
|
||
|
begin
|
||
|
if Index > Container.Last then
|
||
|
raise Constraint_Error with "Index is out of range";
|
||
|
end if;
|
||
|
|
||
|
declare
|
||
|
II : constant Int'Base := Int (Index) - Int (No_Index);
|
||
|
I : constant Capacity_Range := Capacity_Range (II);
|
||
|
begin
|
||
|
Elems (Container) (I) := New_Item;
|
||
|
end;
|
||
|
end Replace_Element;
|
||
|
|
||
|
----------------------
|
||
|
-- Reserve_Capacity --
|
||
|
----------------------
|
||
|
|
||
|
procedure Reserve_Capacity
|
||
|
(Container : in out Vector;
|
||
|
Capacity : Capacity_Range)
|
||
|
is
|
||
|
begin
|
||
|
if Bounded then
|
||
|
if Capacity > Container.Capacity then
|
||
|
raise Constraint_Error with "Capacity is out of range";
|
||
|
end if;
|
||
|
else
|
||
|
if Capacity > Formal_Vectors.Capacity (Container) then
|
||
|
declare
|
||
|
New_Elements : constant Elements_Array_Ptr :=
|
||
|
new Elements_Array (1 .. Capacity);
|
||
|
L : constant Capacity_Range := Length (Container);
|
||
|
begin
|
||
|
New_Elements (1 .. L) := Elemsc (Container) (1 .. L);
|
||
|
Free (Container.Elements_Ptr);
|
||
|
Container.Elements_Ptr := New_Elements;
|
||
|
end;
|
||
|
end if;
|
||
|
end if;
|
||
|
end Reserve_Capacity;
|
||
|
|
||
|
----------------------
|
||
|
-- Reverse_Elements --
|
||
|
----------------------
|
||
|
|
||
|
procedure Reverse_Elements (Container : in out Vector) is
|
||
|
begin
|
||
|
if Length (Container) <= 1 then
|
||
|
return;
|
||
|
end if;
|
||
|
|
||
|
declare
|
||
|
I, J : Capacity_Range;
|
||
|
E : Elements_Array renames
|
||
|
Elems (Container) (1 .. Length (Container));
|
||
|
|
||
|
begin
|
||
|
I := 1;
|
||
|
J := Length (Container);
|
||
|
while I < J loop
|
||
|
declare
|
||
|
EI : constant Element_Type := E (I);
|
||
|
begin
|
||
|
E (I) := E (J);
|
||
|
E (J) := EI;
|
||
|
end;
|
||
|
|
||
|
I := I + 1;
|
||
|
J := J - 1;
|
||
|
end loop;
|
||
|
end;
|
||
|
end Reverse_Elements;
|
||
|
|
||
|
------------------------
|
||
|
-- Reverse_Find_Index --
|
||
|
------------------------
|
||
|
|
||
|
function Reverse_Find_Index
|
||
|
(Container : Vector;
|
||
|
Item : Element_Type;
|
||
|
Index : Index_Type := Index_Type'Last) return Extended_Index
|
||
|
is
|
||
|
Last : Index_Type'Base;
|
||
|
K : Capacity_Range;
|
||
|
|
||
|
begin
|
||
|
if Index > Last_Index (Container) then
|
||
|
Last := Last_Index (Container);
|
||
|
else
|
||
|
Last := Index;
|
||
|
end if;
|
||
|
|
||
|
K := Capacity_Range (Int (Last) - Int (No_Index));
|
||
|
for Indx in reverse Index_Type'First .. Last loop
|
||
|
if Get_Element (Container, K) = Item then
|
||
|
return Indx;
|
||
|
end if;
|
||
|
|
||
|
K := K - 1;
|
||
|
end loop;
|
||
|
|
||
|
return No_Index;
|
||
|
end Reverse_Find_Index;
|
||
|
|
||
|
----------
|
||
|
-- Swap --
|
||
|
----------
|
||
|
|
||
|
procedure Swap (Container : in out Vector; I, J : Index_Type) is
|
||
|
begin
|
||
|
if I > Container.Last then
|
||
|
raise Constraint_Error with "I index is out of range";
|
||
|
end if;
|
||
|
|
||
|
if J > Container.Last then
|
||
|
raise Constraint_Error with "J index is out of range";
|
||
|
end if;
|
||
|
|
||
|
if I = J then
|
||
|
return;
|
||
|
end if;
|
||
|
|
||
|
declare
|
||
|
II : constant Int'Base := Int (I) - Int (No_Index);
|
||
|
JJ : constant Int'Base := Int (J) - Int (No_Index);
|
||
|
|
||
|
EI : Element_Type renames Elems (Container) (Capacity_Range (II));
|
||
|
EJ : Element_Type renames Elems (Container) (Capacity_Range (JJ));
|
||
|
|
||
|
EI_Copy : constant Element_Type := EI;
|
||
|
|
||
|
begin
|
||
|
EI := EJ;
|
||
|
EJ := EI_Copy;
|
||
|
end;
|
||
|
end Swap;
|
||
|
|
||
|
---------------
|
||
|
-- To_Vector --
|
||
|
---------------
|
||
|
|
||
|
function To_Vector
|
||
|
(New_Item : Element_Type;
|
||
|
Length : Capacity_Range) return Vector
|
||
|
is
|
||
|
begin
|
||
|
if Length = 0 then
|
||
|
return Empty_Vector;
|
||
|
end if;
|
||
|
|
||
|
declare
|
||
|
First : constant Int := Int (Index_Type'First);
|
||
|
Last_As_Int : constant Int'Base := First + Int (Length) - 1;
|
||
|
Last : Index_Type;
|
||
|
|
||
|
begin
|
||
|
if Last_As_Int > Index_Type'Pos (Index_Type'Last) then
|
||
|
raise Constraint_Error with "Length is out of range"; -- ???
|
||
|
end if;
|
||
|
|
||
|
Last := Index_Type (Last_As_Int);
|
||
|
|
||
|
return (Capacity => Length,
|
||
|
Last => Last,
|
||
|
Elements_Ptr => <>,
|
||
|
Elements => (others => New_Item));
|
||
|
end;
|
||
|
end To_Vector;
|
||
|
|
||
|
end Ada.Containers.Formal_Vectors;
|