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 a constant of
the container type, or 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 of some
nonlimited type, 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 discrete type, with that type being 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 of a nonlimited type (the
key type of the container
type), and the third, an
in parameter of a nonlimited type that
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. If the container type is limited, the name specified for Empty
shall denote a function rather than a constant object.
For an Aggregate aspect, the key type of Assign_Indexed
shall be the same type as that of the parameters of New_Indexed. Additionally,
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.
Static Semantics
The Aggregate aspect is nonoverridable (see
13.1.1).
Syntax
null_container_aggregate ::= '[' ']'
Name Resolution Rules
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 Add_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, by assignment from the Empty constant, or
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:
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 in sequence 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,
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.
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);
Empty_Map : constant 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 : Integer := 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