ada

Byte-wise iteration through an array in generic function in Ada


I have an array in a generic function where I want to iterate through it byte by byte. In the following example I am using Wide_Wide_Character's, so a character is 4 bytes long. With 3 given input characters, I would have 12 bytes to iterate through. How can I achieve this? Thanks for your time.

with Ada.Text_IO;

procedure Test is

   generic
      type T is (<>);
      type T_Index is range <>;
      type T_Array is array (T_Index range <>) of T;
   function A (b : T_Array) return Integer;

   function A (b : T_Array) return Integer is
   begin

      --  how can I iterate here through each byte instead of "byte blocks"?
      --  should be 12 bytes in this example (3 characters * 4 bytes)
      --  can I map b to System.Storage_Elements.Storage_Array (without copying it)?
      for I in 1 .. b'Length loop
         Ada.Text_IO.Put_Line (b (T_Index (I))'Image);
      end loop;

      return 1;
   end A;

   function A1 is new A (Wide_Wide_Character, Positive, Wide_Wide_String);

   unused : Integer := A1 ("abc");

begin

   null;

end Test;

Solution

  • This can be done. The recommended way is to introduce a nested loop as shown in the example below and convert each array element to a storage array.

    Converting the array b to a storage array as a whole in one go is discouraged as an array may not be contiguously stored in memory if the index type is an enumeration type represented by non-contiguous values. In such case, the array may be stored in memory with "holes" depending on the compiler implementation.

    test.adb

    with Ada.Text_IO;
    with Ada.Unchecked_Conversion;
    with System.Storage_Elements;
    
    procedure Test with SPARK_Mode is
    
       generic
          type T is (<>);
          type T_Index is range <>;
          type T_Array is array (T_Index range <>) of T;
       procedure A (b : T_Array);
    
       procedure A (b : T_Array) is
    
          package SSE renames System.Storage_Elements;
          use type SSE.Storage_Count;
    
          Num_Storage_Elems : constant SSE.Storage_Count :=
            T'Size / SSE.Storage_Element'Size;
    
          subtype T_As_Storage_Array is SSE.Storage_Array (1 .. Num_Storage_Elems);
    
          --  Conversion per array element.
          function To_Storage_Array is new Ada.Unchecked_Conversion
            (Source => T, Target => T_As_Storage_Array);
    
       begin
          for Elem of b loop
             for Storage_Elem of To_Storage_Array (Elem) loop
                Ada.Text_IO.Put_Line (Storage_Elem'Image);
             end loop;
          end loop;
    
       end A;
    
       procedure A1 is new A (Wide_Wide_Character, Positive, Wide_Wide_String);
    
    begin
       A1 ("abc");
    end Test;
    

    output

    $ test
    97
     0
     0
     0
     98
     0
     0
     0
     99
     0
     0
     0