4.3.5 Container Aggregates
For a type other than
an array type, the following type-related operational aspect may be specified:
Aggregate
This aspect is an
aggregate
of the form:
(Empty =>
name[,
Add_Named =>
procedure_name][,
Add_Unnamed =>
procedure_name][,
New_Indexed =>
function_name,
Assign_Indexed =>
procedure_name])
The type for which this aspect is specified
is known as the
container type of the Aggregate aspect.
A
procedure_name
shall be specified for at least one of Add_Named, Add_Unnamed, or Assign_Indexed.
If Add_Named is specified, neither Add_Unnamed nor Assign_Indexed shall
be specified. Either both or neither of New_Indexed and Assign_Indexed
shall be specified.
Name Resolution Rules
The
name
specified for Empty for an Aggregate aspect shall denote exactly one
function with a result type of the container type that has no parameters,
or that has one
in parameter of a signed integer type.
The
procedure_name
specified for Add_Unnamed for an Aggregate aspect shall denote exactly
one procedure that has two parameters, the first an
in out parameter
of the container type, and the second an
in parameter whose type
is called the
element type of the container type.
The
function_name
specified for New_Indexed for an Aggregate aspect shall denote exactly
one function with a result type of the container type, and two parameters
of the same type, called the
key type of the container type.
The
procedure_name
specified for Add_Named or Assign_Indexed for an Aggregate aspect shall
denote exactly one procedure that has three parameters, the first an
in out parameter of the container type, the second an
in
parameter whose type is called the
key type of the container type,
and the third, an
in parameter whose type is called the
element
type of the container type.
Legality Rules
If the container type of an Aggregate aspect is a
private type, the full type of the container type shall not be an array
type.
For an Aggregate aspect, neither the element type
nor the key type (if any) of the container type shall be a limited type.
Additionally, the key type of Assign_Indexed shall be the same type as
that of the parameters of New_Indexed, and that type shall be a discrete
type. If both Add_Unnamed and Assign_Indexed are specified, the final
parameters shall be of the same type — the element type of the
container type.
None of the subprograms specified for an Aggregate
aspect shall have a formal access parameter, nor an explicitly aliased
formal parameter.
If the container type T is not abstract,
then none of the subprograms specified in the Aggregate aspect for T
shall be abstract.
In addition to the places where
Legality Rules normally apply (see
12.3),
these rules apply also in the private part of an instance of a generic
unit.
Static Semantics
The Aggregate aspect is nonoverridable (see
13.1.1).
Syntax
null_container_aggregate ::= '[' ']'
Name Resolution Rules
The expected type for a
container_aggregate
shall be a single type for which the Aggregate aspect has been specified,
or a class-wide type rooted at such a type. The expected type for each
expression
of a
container_aggregate
is the element type of the expected type. For the purposes of this subclause,
the expected type
has an Aggregate aspect
if it is class-wide and the aspect has been specified for its root type.
Legality Rules
Dynamic Semantics
The evaluation of a
container_aggregate
starts by creating an anonymous object
A of the expected type
T, initialized as follows:
if the
aggregate
is an indexed aggregate, from the result of a call on the New_Indexed
function; the actual parameters in this call represent the lower and
upper bound of the
aggregate,
and are determined as follows:
if the
aggregate
is a
positional_container_aggregate,
the lower bound is the low bound of the subtype of the key parameter
of the Assign_Indexed procedure, and the upper bound has a position number
that is the sum of the position number of the lower bound and one less
than the number of
expressions
in the
aggregate;
if the
aggregate
is not an indexed aggregate, from a call on the Empty function specified
in the Aggregate aspect. In the case of an Empty function with a formal
parameter, the actual parameter has the following value:
This paragraph
was deleted.
otherwise, to an implementation-defined
value.
The evaluation then
proceeds as follows:
for a
positional_container_aggregate
of a type with a specified Add_Unnamed procedure, each
expression
is evaluated in an arbitrary order,
and the Add_Unnamed
procedure is invoked in sequence with the anonymous object
A as
the first parameter and the result of evaluating each
expression
as the second parameter, in the order of the
expressions;
for a
positional_container_aggregate
that is an indexed aggregate, each
expression
is evaluated in an arbitrary order,
and the Assign_Indexed
procedure is invoked once for each
expression
of the
aggregate
with the anonymous object
A as the first parameter, the key value
as the second parameter, computed by starting with the low bound of the
subtype of the key formal parameter of the Assign_Indexed procedure and
taking the successor of this value for each successive
expression
of the
aggregate,
and the result of evaluating each
expression
as the third parameter;
otherwise, with the loop parameter as
the second parameter;
for a
named_container_aggregate
that is an indexed aggregate, the evaluation proceeds as above for the
case of Add_Named, but with the Assign_Indexed procedure being invoked
instead of Add_Named; in the case of a
container_element_association
with a <> rather than an
expression,
the corresponding call on Assign_Indexed is not performed, leaving the
component as it was upon return from the New_Indexed function;
1.
2.
an iteration is performed, and for each value conditionally produced
by the iteration (see
5.5 and
5.5.2)
the Add_Unnamed procedure is invoked, with the anonymous object
A
as the first parameter and the result of evaluating the
expression
as the second parameter.
When the above wording says that a subprogram is
invoked or called, this is a subprogram call as defined in
6.4,
with parameter associations as specified in the wording evaluated as
defined
6.4.1. In particular, this means
that the parameters are converted to the subtype of the formal parameter
(which can raise an exception — see
4.6).
Furthermore, if the expected type is class-wide, the semantics defined
in
3.9.2 for tag-indeterminate expressions
apply to the call on Empty or New_Indexed, and those for controlling
tags apply to the (dispatching) calls on Add_Named, Add_Unnamed, and
Assign_Indexed.
The nominal subtype for an indexed aggregate is the
return subtype of the New_Indexed function. The nominal subtype for any
other container aggregate is the return subtype of the Empty function.
Examples
Examples of specifying
the Aggregate aspect for a Set_Type, a Map_Type, and a Vector_Type:
-- Set_Type is a set-like container type.
type Set_Type is private
with Aggregate => (Empty => Empty_Set,
Add_Unnamed => Include);
function Empty_Set return Set_Type;
subtype Small_Int is Integer range -1000..1000;
procedure Include (S : in out Set_Type; N : in Small_Int);
-- Map_Type is a map-like container type.
type Map_Type is private
with Aggregate => (Empty => Empty_Map,
Add_Named => Add_To_Map);
procedure Add_To_Map (M : in out Map_Type;
Key : in Integer;
Value : in String);
function Empty_Map return Map_Type;
-- Vector_Type is an extensible array-like container type.
type Vector_Type is private
with Aggregate => (Empty => Empty_Vector,
Add_Unnamed => Append_One,
New_Indexed => New_Vector,
Assign_Indexed => Assign_Element);
function Empty_Vector (Capacity : Natural := 0) return Vector_Type;
procedure Append_One (V : in out Vector_Type; New_Item : in String);
procedure Assign_Element (V : in out Vector_Type;
Index : in Positive;
Item : in String);
function New_Vector (First, Last : Positive) return Vector_Type
with Pre => First = Positive'First;
-- Vectors are always indexed starting at the
-- lower bound of their index subtype.
-- Private part not shown.
Examples of container
aggregates for Set_Type, Map_Type, and Vector_Type:
-- Example aggregates using Set_Type.
S : Set_Type;
-- Assign the empty set to S:
S := [];
-- Is equivalent to:
S := Empty_Set;
-- A positional set aggregate:
S := [1, 2];
-- Is equivalent to:
S := Empty_Set;
Include (S, 1);
Include (S, 2);
-- Is equivalent to:
S := Empty_Set;
for Item in 1 .. 5 loop
Include (S, Item * 2);
end loop;
-- Is equivalent (assuming set semantics) to:
S := Empty_Set;
for Item in 1 .. 5 loop
Include (S, Item);
end loop;
for Item in -5 .. -1 loop
Include (S, Item);
end loop;
-- Example aggregates using Map_Type.
M : Map_Type;
-- A simple named map aggregate:
M := [12 => "house", 14 => "beige"];
-- Is equivalent to:
M := Empty_Map;
Add_To_Map (M, 12, "house");
Add_To_Map (M, 14, "beige");
-- Define a table of pairs:
type Pair is record
Key : Integer;
Value : access constant String;
end record;
Table : constant array(Positive range <>) of Pair :=
[(Key => 33, Value => new String'("a nice string")),
(Key => 44, Value => new String'("an even better string"))];
-- Is equivalent to:
M := Empty_Map;
for P of Table loop
Add_To_Map (M, P.Key, P.Value.all);
end loop;
-- Create an image table for an array of integers:
Keys : constant array(Positive range <>) of Integer := [2, 3, 5, 7, 11];
--
A map aggregate where the values produced by the
--
iterated_element_association are of the same type as the key
--
(hence a separate key_expression is unnecessary):
M := [
for Key
of Keys => Integer'Image (Key)];
-- Is equivalent to:
M := Empty_Map;
for Key of Keys loop
Add_To_Map (M, Key, Integer'Image (Key));
end loop;
-- Example aggregates using Vector_Type.
V : Vector_Type;
-- A positional vector aggregate:
V := ["abc", "def"];
-- Is equivalent to:
V := Empty_Vector (2);
Append_One (V, "abc");
Append_One (V, "def");
-- An indexed vector aggregate:
V := [1 => "this", 2 => "is", 3 => "a", 4 => "test"];
-- Is equivalent to:
V := New_Vector (1, 4);
Assign_Element (V, 1, "this");
Assign_Element (V, 2, "is");
Assign_Element (V, 3, "a");
Assign_Element (V, 4, "test");
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe