5.5.2 Generalized Loop Iteration
Syntax
Name Resolution Rules
For the first form of
iterator_specification,
called a
generalized iterator,
the expected type for the
iterator_name
is any iterator type.
For the second form of
iterator_specification,
the expected type for the
iterable_name
is any array or iterable container type.
If the
iterable_name
denotes an array object, the
iterator_specification
is called an
array component iterator;
otherwise it is called a
container element iterator.
Legality Rules
If the reserved word
reverse appears, the
iterator_specification
is a
reverse iterator.
If the
iterator_specification
is for a parallel construct, the
iterator_specification
is a
parallel iterator.
Otherwise, it is a
forward iterator.
Forward and reverse iterators are collectively called
sequential
iterators.
In a reverse generalized
iterator, the
iterator_name
shall be of a reversible iterator type. In a parallel generalized iterator,
the
iterator_name
shall be of a parallel iterator type. In a reverse container element
iterator, the default iterator type for the type of the
iterable_name
shall be a reversible iterator type. In a parallel container element
iterator, the default iterator type for the type of the
iterable_name
shall be of a parallel iterator type.
In a container element iterator whose
iterable_name
has type
T, if the
iterable_name
denotes a constant or the Variable_Indexing aspect is not specified for
T, then the Constant_Indexing aspect shall be specified for
T.
The
iterator_name
or
iterable_name
of an
iterator_specification
shall not denote a subcomponent that depends on discriminants of an object
whose nominal subtype is unconstrained, unless the object is known to
be constrained.
A container element iterator is illegal if the call
of the default iterator function that creates the loop iterator (see
below) is illegal.
A generalized iterator is illegal if the iteration
cursor subtype of the
iterator_name
is a limited type at the point of the generalized iterator. A container
element iterator is illegal if the default cursor subtype of the type
of the
iterable_name
is a limited type at the point of the container element iterator.
Static Semantics
An
iterator_specification
declares a
loop parameter.
In a generalized
iterator, an array component iterator, or a container element iterator,
if a
loop_parameter_subtype_indication
is present, it determines the nominal subtype of the loop parameter.
In a generalized iterator, if a
loop_parameter_subtype_indication
is not present, the nominal subtype of the loop parameter is the iteration
cursor subtype. In an array component iterator, if a
loop_parameter_subtype_indication
is not present, the nominal subtype of the loop parameter is the component
subtype of the type of the
iterable_name.
In a container element iterator, if a
loop_parameter_subtype_indication
is not present, the nominal subtype of the loop parameter is the default
element subtype for the type of the
iterable_name.
In a generalized iterator, the loop parameter is
a constant. In an array component iterator, the loop parameter is a constant
if the
iterable_name
denotes a constant; otherwise it denotes a variable. In a container element
iterator, the loop parameter is a constant if the
iterable_name
denotes a constant, or if the Variable_Indexing aspect is not specified
for the type of the
iterable_name;
otherwise it is a variable.
Dynamic Semantics
For a sequential generalized iterator, the loop parameter
is created, the
iterator_name
is evaluated, and the denoted iterator object becomes the
loop iterator.
In a forward generalized iterator, the operation First of the iterator
type is called on the loop iterator, to produce the initial value for
the loop parameter. If the result of calling Has_Element on the initial
value is False, then the execution of the
loop_statement
is complete. Otherwise, the
sequence_of_statements
is conditionally executed and then the Next operation of the iterator
type is called with the loop iterator and the current value of the loop
parameter to produce the next value to be assigned to the loop parameter.
This repeats until the result of calling Has_Element on the loop parameter
is False, or the loop is left as a consequence of a transfer of control.
For a reverse generalized iterator, the operations Last and Previous
are called rather than First and Next.
For a parallel generalized iterator, the
chunk_specification,
if any, of the associated parallel construct, is first elaborated, to
determine the maximum number of chunks (see
5.5),
and then the operation Split_Into_Chunks of the iterator type is called,
with the determined maximum passed as the Max_Chunks parameter, specifying
the upper bound for the number of loop parameter objects (and the number
of logical threads of control) to be associated with the iterator. In
the absence of a
chunk_specification,
the maximum number of chunks is determined in an implementation-defined
manner.
Upon return from Split_Into_Chunks, the actual
number of chunks for the loop is determined by calling the Chunk_Count
operation of the iterator, at which point one logical thread of control
is initiated for each chunk, with an associated chunk index in the range
from one to the actual number of chunks.
Within each logical thread of control, a loop parameter
is created. If a
chunk_specification
with a
discrete_subtype_definition
is present in the associated parallel construct, then a chunk parameter
is created and initialized with a value from the discrete subtype defined
by the
discrete_subtype_definition,
so that the order of the chosen chunk parameter values correspond to
the order of the chunk indices associated with the logical threads of
control. The operation First of the iterator type that has a Chunk parameter
is called on the loop iterator, with Chunk initialized from the corresponding
chunk index, to produce the initial value for the loop parameter. If
the result of calling Has_Element on this initial value is False, then
the execution of the logical thread of control is complete. Otherwise,
the
sequence_of_statements
is conditionally executed, and then the Next operation of the iterator
type that has a Chunk parameter is called with the loop iterator, the
current value of the loop parameter, and the corresponding chunk index,
to produce the next value to be assigned to the loop parameter. This
repeats until the result of calling Has_Element on the loop parameter
is False, or the associated parallel construct is left as a consequence
of a transfer of control.
In the absence of a transfer of control, the associated
parallel construct of a parallel generalized iterator is complete when
all of its logical threads of control are complete.
For an array component iterator, the
chunk_specification
of the associated parallel construct, if any, is first elaborated to
determine the maximum number of chunks (see
5.5),
and then the
iterable_name
is evaluated and the denoted array object becomes the
array for the
loop.
If the array for the loop is a null array,
then the execution of the
loop_statement
is complete. Otherwise, the
sequence_of_statements
is conditionally executed with the loop parameter denoting each component
of the array for the loop, using a
canonical order of components,
which is last dimension varying fastest (unless the array has convention
Fortran, in which case it is first dimension varying fastest). For a
forward array component iterator, the iteration starts with the component
whose index values are each the first in their index range, and continues
in the canonical order. For a reverse array component iterator, the iteration
starts with the component whose index values are each the last in their
index range, and continues in the reverse of the canonical order. For
a parallel array component iterator, the iteration is broken up into
contiguous chunks of the canonical order, such that all components are
covered with no overlaps; each chunk has its own logical thread of control
with its own loop parameter and iteration within each chunk is in the
canonical order. The number of chunks is implementation defined, but
is limited in the presence of a
chunk_specification
to the determined maximum. The loop iteration proceeds until the
sequence_of_statements
has been conditionally executed for each component of the array for the
loop, or until the loop is left as a consequence of a transfer of control.
If a
chunk_specification
with a
discrete_subtype_definition
is present in the associated parallel construct, then the logical thread
of control associated with a given chunk has a chunk parameter initialized
with a distinct value from the discrete subtype defined by the
discrete_subtype_definition.
The values of the chunk parameters are assigned such that they increase
in the canonical order of the starting array components for the chunks.
For a container element iterator, the
chunk_specification
of the associated parallel construct, if any, is first elaborated to
determine the maximum number of chunks (see
5.5),
and then the
iterable_name
is evaluated. If the container type has Iterator_View specified, an object
of the Iterator_View type is created with the discriminant referencing
the iterable container object denoted by the
iterable_name.
This is the
iterable container object for the loop. Otherwise,
the iterable container object denoted by the
iterable_name
becomes the iterable container object for the loop.
The default iterator function for the type of the iterable container
object for the loop is called on the iterable container object and the
result is the
loop iterator.
For a sequential
container element iterator, an object of the default cursor subtype is
created (the
loop cursor).
For a parallel
container element iterator, each chunk of iterations will have its own
loop cursor, again of the default cursor subtype.
A container element iterator then proceeds as described
above for a generalized iterator, except that each reference to a loop
parameter is replaced by a reference to the corresponding loop cursor.
For a container element iterator, the loop parameter for each iteration
instead denotes an indexing (see
4.1.6) into
the iterable container object for the loop, with the only parameter to
the indexing being the value of the loop cursor for the given iteration.
If the loop parameter is a constant (see above), then the indexing uses
the default constant indexing function for the type of the iterable container
object for the loop; otherwise it uses the default variable indexing
function.
Any exception propagated by the execution of a generalized
iterator or container element iterator is propagated by the immediately
enclosing loop statement.
Examples
Example of a parallel
generalized loop over an array:
parallel
for Element
of Board
loop --
See 3.6.1.
Element := Element * 2.0; --
Double each element of Board, a two-dimensional array.
end loop;
For examples of use of generalized iterators,
see A.18.33 and the corresponding container
packages in A.18.2 and A.18.3.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe