The Find_First_Of
algorithm is related to Find
: given an array
A
and an array B
, it will return the smallest valid index of
A
such that the element at this position also occurs in B
. The
Option
type is again used to encapsulate the result.
The signature of Find_First_Of
is the following:
function Find_First_Of (A : T_Arr; B : T_Arr) return Option;
In order to specify Find_First_Of
, we first define the
Has_Value_Of
predicate using the previously defined Has_Value
predicate:
function Has_Value_Of
(A : T_Arr;
B : T_Arr)
return Boolean is (for some I in A'Range => Has_Value (B, A (I)));
Again, Has_Value_Of
is defined in a package with the Ghost
aspect, so Has_Value_Of
can only be used in
specifications. Notice that defining Has_Value_Of
with
Has_Value
is easy: Has_Value_Of(A, B)
is true if some value in
A
occurs in B
.
Using Has_Value
and Has_Value_Of
, the specification of
Find_First_Of
can be written as
function Find_First_Of
(A : T_Arr;
B : T_Arr)
return Option with
Contract_Cases =>
(Has_Value_Of (A, B) =>
(Find_First_Of'Result.Exists = True)
and then (Has_Value (B, A (Find_First_Of'Result.Value)))
and then
(not Has_Value_Of (A (A'First .. Find_First_Of'Result.Value - 1), B)),
others => Find_First_Of'Result.Exists = False);
There are two behaviors for Find_First_Of
(defined here by two
contract cases):
- if there is a value of
A
occurring inB
, then the returnedOption
contains a valid index ofA
and this index is such that the element ofA
at this position occurs inB
and all the elements ofA
up to the index do not occur inB
- otherwise the returned
Option
does not contain a valid index ofA
The implementation of Find_First_Of is the following:
function Find_First_Of
(A : T_Arr;
B : T_Arr)
return Option
is
Result : Option := (Exists => False);
begin
for I in A'Range loop
if Find (B, A (I)).Exists then
Result := (Exists => True, Value => I);
return Result;
end if;
pragma Loop_Invariant (not Has_Value_Of (A (A'First .. I), B));
pragma Loop_Invariant (not Result.Exists);
end loop;
return Result;
end Find_First_Of;
We use the Find
algorithm on each element of A
to check if it
is present in B
. The invariants are rather
straightforward. Notice that we could have “inlined” Find
inside
Find_First_Of
, but this would lead to more invariants. Like ACSL
by Example, we emphasize here reuse over efficiency.