!standard A.18.2(8/5) 19-06-16 AI12-0339-1/01
!class Amendment 19-06-16
!status work item 19-06-16
!status received 19-06-12
!priority Low
!difficulty Easy
!subject Empty function for Container aggregates
!summary
Define appropriate Empty functions for all the containers. For containers
types that have an associated Capacity, the corresponding Empty function accepts a
Capacity parameter to specify this value. The Capacity parameter will have a
system defined default value. For other container types that do not have the
notion of capacity, the Empty function will be parameterless.
!problem
AI12-0212-1 defines the aggregate aspect, which adds the capability of specifying
container aggregates. One part of the aggregate aspect specification, Empty,
identifies the name that denotes a constant of the container type, or a function with a
result of the container type that is used to produce an empty container object.
Currently, the containers name the preexisting constant object defined in Ada 2012,
for Empty. However, these constant objects, for container types that
have the notion of capacity, have a capacity of 0 elements, but container
aggregates often are used to create container aggregates that have 1 or more
elements. It would be more efficient, for cases where multiple elements are
needed, if the constructed container object was initially sized to have a
capacity that could accommodate all the elements
associated with the aggregate. It can be very inefficient for a container such as
a vector container to start with 0 capacity, and increase the capacity as each
element of the aggregate is inserted into the container. Should a mechanism
be provided to allow container objects to be initially sized to a given
capacity, allowing for more efficient construction of container objects? (Yes.)
!proposal
We propose to add an Empty function to all the containers that have the Aggregate
aspect, and modify the Aggregate aspect such that the Empty field denotes the new
function instead of the original constant object. For those containers that
have the notion of capacity, the Empty function will accept a Capacity parameter to
indicate the initial capacity of the container object of the result of the Empty
function. The Capacity parameter will have a system defined default value.
Otherwise, for containers that do not have the notion of capacity, the Empty
function will be a parameter-less function, that returns a container object with
zero elements.
!wording
Modify A.18.2 (8/5)
type Vector is tagged private
with Constant_Indexing => Constant_Reference,
Variable_Indexing => Reference,
Default_Iterator => Iterate,
Iterator_Element => Element_Type,
Iterator_View => Stable.Vector,
Aggregate => (Empty => Empty[_Vector],
Add_Unnamed => Append_One,
New_Indexed => New_Vector,
Assign_Indexed => Replace_Element),
Stable_Properties => (Length, Capacity,
Tampering_With_Cursors_Prohibited,
Tampering_With_Elements_Prohibited),
Default_Initial_Condition =>
Length (Vector) = 0 and then
(not Tampering_With_Cursors_Prohibited (Vector)) and then
(not Tampering_With_Elements_Prohibited (Vector));
Insert before A.18.2 (13/5)
function Empty
(Capacity : Count_Type := Implementation Defined) return Vector
with Pre => (if Capacity > Maximum_Length then raise Constraint_Error),
Post =>
Empty'Result.Capacity = Capacity and then
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0;
Modify A.18.2 (78.2/5)
type Vector (Base : not null access Vectors.Vector) is
tagged limited private
with Constant_Indexing => Constant_Reference,
Variable_Indexing => Reference,
Default_Iterator => Iterate,
Iterator_Element => Element_Type,
Aggregate => (Empty => Empty[_Vector],
Add_Unnamed => Append_One,
New_Indexed => New_Vector,
Assign_Indexed => Replace_Element),
Stable_Properties => (Length, Capacity),
Global => (in Vector.Base.all, synchronized out Vector.Base.all),
Default_Initial_Condition => Length (Vector) = 0;
pragma Preelaborable_Initialization(Vector);
Insert before A.18.2 (99/5)
function Empty (Capacity : Count_Type := Implementation Defined) return Vector
with Pre => (if Capacity > Maximum_Length then raise Constraint_Error),
Post =>
Empty'Result.Capacity = Capacity and then
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0;
Returns a vector with a length of 0 that has additional storage allocated to
ensure that the length of the resulting vector can become at least the value
Capacity without requiring an additional call to Reserve_Capacity.
Insert before A.18.3 (9.1/5)
function Empty return List
with Post =>
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0 is (Empty_List);
Modify A.18.5 (3/5)
type Map is tagged private
with Constant_Indexing => Constant_Reference,
Variable_Indexing => Reference,
Default_Iterator => Iterate,
Iterator_Element => Element_Type,
Iterator_View => Stable.Map,
Aggregate => (Empty => Empty[_Map],
Add_Named => Insert),
Stable_Properties => (Length,
Tampering_With_Cursors_Prohibited,
Tampering_With_Elements_Prohibited),
Default_Initial_Condition =>
Length (Map) = 0 and then
(not Tampering_With_Cursors_Prohibited (Map)) and then
(not Tampering_With_Elements_Prohibited (Map));
pragma Preelaborable_Initialization(Map);
Insert before A.18.5 (6.1/5)
function Empty
(Capacity : Count_Type := Implementation Defined) return Map
with Post =>
Empty'Result.Capacity = Capacity and then
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0;
Modify A.18.5 (37.3/5)
type Map (Base : not null access Hashed_Maps.Map) is
tagged limited private
with Constant_Indexing => Constant_Reference,
Variable_Indexing => Reference,
Default_Iterator => Iterate,
Iterator_Element => Element_Type,
Aggregate => (Empty => Empty[_Map],
Add_Named => Insert),
Stable_Properties => (Length),
Global => (in Map.Base.all, synchronized out Map.Base.all),
Default_Initial_Condition => Length (Map) = 0;
pragma Preelaborable_Initialization(Map);
Insert before A.18.5 (47/5)
function Empty (Capacity : Count_Type := Implementation Defined) return Map
with Post =>
Empty'Result.Capacity = Capacity and then
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0;
Returns a map with a length of 0 that has additional storage allocated to ensure
that the length of the resulting map can become at least the value Capacity
without requiring an additional call to Reserve_Capacity.
Insert before A.18.6 (7.1/5)
function Empty return Map
with Post =>
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0 is (Empty_Map);
Modify A.18.8 (3/5)
type Set is tagged private
with Constant_Indexing => Constant_Reference,
Default_Iterator => Iterate,
Iterator_Element => Element_Type,
Iterator_View => Stable.Set,
Aggregate => (Empty => Empty[_Set],
Add_Unnamed => Include),
Stable_Properties => (Length,
Tampering_With_Cursors_Prohibited),
Default_Initial_Condition =>
Length (Set) = 0 and then
(not Tampering_With_Cursors_Prohibited (Set));
pragma Preelaborable_Initialization(Set);
Insert before A.18.8 (6.1/5)
function Empty
(Capacity : Count_Type := Implementation Defined) return Map
with Post =>
Empty'Result.Capacity = Capacity and then
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0;
Modify A.18.8 (59.2/5)
type Set (Base : not null access Hashed_Sets.Set) is
tagged limited private
with Constant_Indexing => Constant_Reference,
Default_Iterator => Iterate,
Iterator_Element => Element_Type,
Aggregate => (Empty => Empty[_Set],
Add_Unnamed => Include),
Stable_Properties => (Length),
Global => (in Set.Base.all, synchronized out Set.Base.all),
Default_Initial_Condition => Length (Set) = 0;
pragma Preelaborable_Initialization(Set);
Insert before A.18.8 (69/5)
function Empty (Capacity : Count_Type := Implementation Defined) return Set
with Post =>
Empty'Result.Capacity = Capacity and then
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0;
Returns a set with a length of 0 that has additional storage allocated to ensure
that the length of the resulting set can become at least the value Capacity
without requiring an additional call to Reserve_Capacity.
Insert before A.18.9 (7.1/5)
function Empty return Set
with Post =>
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0 is (Empty_Set);
Insert before A.18.10 (11.1/5)
function Empty return Tree
with Post =>
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty.Result.Is_Empty is (Empty_Tree);
Insert before A.18.18 (7.1/5)
function Empty return Holder
with Post =>
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Is_Empty is (Empty_Holder);
Insert before A.18.20 (7/5)
The function Empty is replaced by:
function Empty
(Capacity : Count_Type := Implementation Defined) return List
with Post =>
Empty'Result.Capacity = Capacity and then
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0;
Returns a List with a length of 0 and a capacity of Capacity.
Insert before A.18.22 (7/5)
The function Empty is replaced by:
function Empty
(Capacity : Count_Type := Implementation Defined) return Map
with Post =>
Empty'Result.Capacity = Capacity and then
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0;
Returns a Map with a length of 0 and a capacity of Capacity.
Insert before A.18.24 (7/5)
The function Empty is replaced by:
function Empty
(Capacity : Count_Type := Implementation Defined) return Set
with Post =>
Empty'Result.Capacity = Capacity and then
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Length = 0;
Returns a Set with a length of 0 and a capacity of Capacity.
Insert before A.18.25 (8/3)
The function Empty is replaced by:
function Empty
(Capacity : Count_Type := Implementation Defined) return Tree
with Post =>
Empty'Result.Capacity = Capacity and then
not Tampering_With_Elements_Prohibited (Empty'Result) and then
not Tampering_With_Cursors_Prohibited (Empty'Result) and then
Empty'Result.Is_Empty;
Returns an Tree with a capacity of Capacity and for which Is_Empty returns True.
!discussion
We considered whether the Empty function should be added to the various
synchronized queue containers. Those containers do not define stable views,
do not have the Aggregate aspect, nor do they define an Empty_Queue object,
so it seemed best to not attempt to define an empty function for these
containers.
!ASIS
!ACATS test
ACATS B and C-Tests are needed to check that the new capabilities are supported.
!appendix
From: Tucker Taft
Sent: Wednesday, June 12, 2019 12:23 AM
A comment from an GNAT user mentioned that we have not provided in Ada 202X
"Empty" functions that take a capacity, to support the capability available to
container aggregates. Perhaps we should do so to make the container aggregate
construction process more efficient! Seems particularly important for
vectors, but could be useful for any case where the compiler can predict the
size of the aggregate being created.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, June 12, 2019 7:59 AM
Seems like it would be necessary for bounded containers, esp. if someone
wanted to use :=.
****************************************************************
From: Tucker Taft
Sent: Wednesday, June 12, 2019 9:47 AM
It seems important for dynamic containers as well, from an efficiency point of
view. Otherwise the container might be expanded for each element, or
over-expanded well beyond the size needed.
****************************************************************
From: Brad Moore
Sent: Sunday, June 16, 2019 1:29 AM
Here is a new AI that we talked about yesterday (AI12-0338?) that defines an
Empty function for most of the Ada containers. [This is version /01 of the AI -
Editor.]
****************************************************************