5.5 Loop Statements
Syntax
Name Resolution Rules
Static Semantics
Dynamic Semantics
Term entry: iterator filter —
construct that is used to restrict the elements produced by an iteration
to those for which a boolean condition evaluates to True
{
AI12-0251-1}
{
AI12-0294-1}
If the reserved word
parallel is present in the
iteration_scheme
of a
loop_statement
(a
parallel loop),
the
iterations are partitioned into one or more
chunks,
each with its own separate logical thread of control (see Clause
9).
If a
chunk_specification
is present in a parallel loop, it is elaborated first, and the result
of the elaboration determines the maximum number of chunks used for the
parallel loop.
If the
chunk_specification
is an
integer_simple_expression,
the elaboration evaluates the expression, and the value of the expression
determines the maximum number of chunks. If a
discrete_subtype_definition
is present, the elaboration elaborates the
discrete_subtype_definition,
which defines the subtype of the chunk parameter, and the number of values
in this subtype determines the maximum number of chunks. After elaborating
the
chunk_specification,
a check is made that the determined maximum number of chunks is greater
than zero. If this check fails, Program_Error is raised.
{
AI05-0139-2}
{
AI05-0262-1}
{
AI12-0071-1}
{
AI12-0119-1}
{
AI12-0250-1}
{
AI12-0251-1}
{
AI12-0294-1}
{
AI12-0355-2}
{
AI12-0416-1}
For the execution of a
loop_statement
that has an
iteration_scheme
including a
loop_parameter_specification,
after elaborating the
chunk_specification
and
aspect_specification,
if any, the
loop_parameter_specification
is elaborated. This elaborates the
discrete_subtype_definition,
which defines the subtype of the loop parameter. If the
discrete_subtype_definition
defines a subtype with a null range, the execution of the
loop_statement
is complete. Otherwise, the
sequence_of_statements
is conditionally executed once for each value of the discrete subtype
defined by the
discrete_subtype_definition
that satisfies the predicates of the subtype (or until the loop is left
as a consequence of a transfer of control).
Prior
to each such iteration, the corresponding value of the discrete subtype
is assigned to the loop parameter associated with the given iteration.
If the loop is a parallel loop, each chunk has its own logical thread
of control with its own copy of the loop parameter; otherwise (a
sequential
loop)
, a single logical thread
of control performs the loop, and there is a single copy of the loop
parameter. Each logical thread of control handles a distinct subrange
of the values of the subtype of the loop parameter such that all values
are covered with no overlaps. Within each logical thread of control,
the values are assigned to the loop parameter in increasing order unless
the reserved word
reverse is present, in which case the values
are assigned in decreasing order. In the absence of a transfer of control,
the associated parallel construct of a
loop_parameter_specification
is complete when all of its logical threads of control are complete.
To be honest: {
AI12-0294-1}
This wording does not describe when the loop parameter object(s) are
created. That creation has no side-effects (other than possibly raising
Storage_Error, but anything can do that), so we simplified the wording
by leaving it out. Each object has to be created before any iteration
that depends on it starts, but we do not (for instance) require that
the objects are all created at once at the start of the loop, nor that
the objects are created after the elaboration of the
discrete_subtype_definition.
Ramification: {
AI05-0262-1}
The predicate (if any) necessarily has to be a static predicate as a
dynamic predicate is explicitly disallowed — see
3.2.4.
Reason: {
AI05-0262-1}
If there is a predicate, the loop still visits the values in the order
of the underlying base type; the order of the values in the predicate
is irrelevant. This is the case so that the following loops have the
same sequence of calls and parameters on procedure Call for any subtype
S:
for I in S loop
Call (I);
end loop;
for I in S'Base loop
if I in S then
Call (I);
end if;
end loop;
Discussion: {
AI12-0416-1}
The rules for completing a parallel construct when there is a transfer
of control are given in
5.1.
{
AI12-0251-1}
Whether or not a
chunk_specification
is present in a parallel loop, the total number of iterations of the
loop represents an upper bound on the number of logical threads of control
devoted to the loop.
NOTE 3 The
discrete_subtype_definition
of a for loop is elaborated just once. Use of the reserved word
reverse
does not alter the discrete subtype defined, so that the following
iteration_schemes
are not equivalent; the first has a null range.
for J in reverse 1 .. 0
for J in 0 .. 1
Examples
Example of a loop
statement without an iteration scheme:
loop
Get(Current_Character);
exit when Current_Character = '*';
end loop;
Example of a loop
statement with a while iteration scheme:
while Bid(N).Price < Cut_Off.Price loop
Record_Bid(Bid(N).Price);
N := N + 1;
end loop;
Example of a loop
statement with a for iteration scheme:
for J in Buffer'Range loop -- works even with a null range
if Buffer(J) /= Space then
Put(Buffer(J));
end if;
end loop;
Example of a loop
statement with a name:
Summation:
while Next /= Head
loop --
see 3.10.1
Sum := Sum + Next.Value;
Next := Next.Succ;
end loop Summation;
--
see 3.6
parallel
for I
in Grid'Range(1)
loop
Grid(I, 1) := (
for all J
in Grid'Range(2) => Grid(I,J) = True);
end loop;
{
AI12-0312-1}
Example of a parallel loop with a chunk specification:
declare
subtype Chunk_Number is Natural range 1 .. 8;
Partial_Sum,
Partial_Max : array (Chunk_Number) of Natural := (others => 0);
Partial_Min : array (Chunk_Number) of Natural :=
(others => Natural'Last);
begin
parallel (Chunk in Chunk_Number)
for I in Grid'Range(1) loop
declare
True_Count : constant Natural :=
[for J in Grid'Range(2) =>
(if Grid (I, J) then 1 else 0)]'Reduce("+",0);
begin
Partial_Sum (Chunk) := @ + True_Count;
Partial_Min (Chunk) := Natural'Min(@, True_Count);
Partial_Max (Chunk) := Natural'Max(@, True_Count);
end;
end loop;
{
AI12-0386-1}
Put_Line
("Total=" & Partial_Sum'Reduce("+", 0)'Image &
", Min=" & Partial_Min'Reduce(Natural'Min, Natural'Last)'Image &
", Max=" & Partial_Max'Reduce(Natural'Max, 0)'Image);
end;
Wording Changes from Ada 83
Wording Changes from Ada 2005
Extensions to Ada 2012
Wording Changes from Ada 2012
{
AI12-0071-1}
Corrigendum: Updated wording of loop execution to use the new
term "satisfies the predicates" (see
3.2.4).
{
AI12-0061-1}
Added text so that the nominal subtype of a loop parameter is clearly
defined.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe