Home > other >  Wrap-around Semantics for accessing Array Slices indexed by a Modular Type
Wrap-around Semantics for accessing Array Slices indexed by a Modular Type

Time:10-29

I would like to create an array and access it in the following way for read and write slice operations (i.e. more than one element at once):

  • If the indices are within range access them as usual
  • If the second index is smaller than the first index, access the data as follows: First .. A'Last & A'First .. (First 5) (turns out this doesn't work as-is due to concatenation result upper bound out of range)

I have come up with the following example to demonstrate the issue:

with Ada.Text_IO;
use  Ada.Text_IO;

procedure Test_Modular is
    type Idx is mod 10;
    type My_Array is array (Idx range <>) of Integer;

    A: My_Array(Idx) := (
        0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5,
        6 => 6, 7 => 7, 8 => 8, 9 => 9
    );

    First: constant Idx := 7;

    S: constant My_Array := A(First .. First   5);
begin

    for I in S'range loop
        Put_Line(Idx'Image(I) & " --> " & Integer'Image(S(I)));
    end loop;

end Test_Modular;

As in the example, the 5 is static, the compiler warns me as follows:

$ gnatmake -o test_modular test_modular.adb
x86_64-linux-gnu-gcc-10 -c test_modular.adb
test_modular.adb:18:19: warning: loop range is null, loop will not execute
x86_64-linux-gnu-gnatbind-10 -x test_modular.ali
x86_64-linux-gnu-gnatlink-10 test_modular.ali -o test_modular

When running the program, I observe the following:

$ ./test_modular

i.e. no output as predicted by the compiler warning.

Now I wonder: Is there a way to write the slice like A(First .. First 5) and make it “wrap around” such that the data accessed will be the same as in this modified example program except without having to distinguish the two cases in the code explicitly?

with Ada.Text_IO;
use  Ada.Text_IO;

procedure Test_Modular_2 is
    type Idx is mod 10;
    type My_Array is array (Idx range <>) of Integer;

    A: My_Array(Idx) := (
        0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5,
        6 => 6, 7 => 7, 8 => 8, 9 => 9
    );

    First: constant Idx := 7;

    S1: constant My_Array := A(First .. A'Last);
    S2: constant My_Array := A(A'First .. (First   5));
begin

    for I in S1'range loop
        Put_Line(Idx'Image(I) & " --> " & Integer'Image(S1(I)));
    end loop;
    for I in S2'range loop
        Put_Line(Idx'Image(I) & " --> " & Integer'Image(S2(I)));
    end loop;

end Test_Modular_2;

CodePudding user response:

Try the following approach:

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
   type Idx is mod 10;
   type My_Array is array (Idx range <>) of Integer;

   function rotate (arr : My_Array; head : Idx; tail : Idx) return My_Array is
      P1_Len : Natural;
      P2_Len : Natural;
   begin
      P1_Len :=
        (if head <= tail then Natural (tail) - Natural (head)   1
         else Natural (arr'Last) - Natural (head)   1);
      P2_Len := (if head <= tail then 0 else Natural (tail)   1);
      declare
         Result : My_Array (0 .. Idx (P1_Len   P2_Len - 1));
      begin
         if head <= tail then
            Result := arr (head .. tail);
         else
            Result (0 .. Idx (P1_Len - 1))       := arr (head .. arr'Last);
            Result (Idx (P1_Len) .. Result'Last) := arr (0 .. tail);
         end if;
         return Result;
      end;
   end rotate;

   procedure print (A : My_Array) is
   begin
      for V of A loop
         Put (V'Image);
      end loop;
      New_Line;
   end print;

   A : My_Array :=
     (0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, 8 => 8,
      9 => 9);
   head : Idx := 7;
   tail : Idx := head   5;

begin
   Put_Line ("Head: " & head'Image & " Tail:" & tail'Image);
   Put_Line ("Initial value order:");
   print (A);
   declare
      S1 : My_Array := rotate (A, head, tail);
   begin

      Put_Line ("Rotated value order:");
      print (S1);
   end;

end Main;

The rotate function above rotates the set of values indicated by the head and tail index values, placing the head value at the start of the array returned by rotate. This example shows that the resulting array may contain fewer elements than the array passed as a parameter to the function.

  • Related