Reputation: 1289
So I have the following Ada array declaration buried inside a package body, that eventually gets passed to a C function
declare
type t_buffer is array (0 .. ARR_SIZE) of Unsigned_32;
buffer : constant access t_buffer := new t_buffer;
begin
c_obj.buffer_p := buffer (1)'Address;
c_obj.buffer_length := Unsigned_64 (buffer'Last);
for idx in Integer range buffer'Range loop
buffer (idx) := Unsigned_32 (idx * 4);
end loop;
end
However, the elements of the array aren't actually always Unsigned_32
/uint32_t
- it varies between uint8_t
, uint16_t
, uint32_t
& uint64_t
, depending on a (runtime) parameter. This means that when it gets read as a (for example) uint16_t array in the C code, the numbers are coming out as a sequence of 0,0,4,0,8,0,... instead of the intended 0,4,8,... when the uint32_t
is "split" into 2 different numbers.
Ada doesn't have something approximating dependent types so I can't dynamically create the array type. I'm not sure how I can solve this at all nicely, possibly something to do with making an array of Unsigned_8 and bitshifting as appropriate?
Upvotes: 0
Views: 645
Reputation: 6611
The way Ada works, you have to have four different array types.
But you can encapsulate the selection of the array types in a variant record:
package Variant_Records is
type Word_Sizes is range 8 .. 64
with Static_Predicate => Word_Sizes in 8 | 16 | 32 | 64;
type Data_8_Bit is mod 2 ** 8 with Size => 8;
type Data_16_Bit is mod 2 ** 16 with Size => 16;
type Data_32_Bit is mod 2 ** 32 with Size => 32;
type Data_64_Bit is mod 2 ** 64 with Size => 64;
type Array_8_Bit is array (Positive range <>) of Data_8_Bit;
type Array_16_Bit is array (Positive range <>) of Data_16_Bit;
type Array_32_Bit is array (Positive range <>) of Data_32_Bit;
type Array_64_Bit is array (Positive range <>) of Data_64_Bit;
type Data_Array (Word_Size : Word_Sizes;
Length : Natural) is
record
case Word_Size is
when 8 => Data_8 : Array_8_Bit (1 .. Length);
when 16 => Data_16 : Array_16_Bit (1 .. Length);
when 32 => Data_32 : Array_32_Bit (1 .. Length);
when 64 => Data_64 : Array_64_Bit (1 .. Length);
end case;
end record;
end Variant_Records;
And then an example of some usage:
with Variant_Records;
procedure Using_Variant_Records is
use Variant_Records;
A : Data_Array (Word_Size => 8, Length => 16);
B : Data_Array (Word_Size => 64, Length => 2);
begin
for I in A.Data_8'Range loop
A.Data_8 (I) := 2 * Data_8_Bit (I) + 4;
end loop;
for I in B.Data_64'Range loop
B.Data_64 (I) := Data_64_Bit (8 ** I) + 4;
end loop;
declare
D : Data_Array := B;
begin
for E of D.Data_64 loop
E := E * 8;
end loop;
end;
end Using_Variant_Records;
Upvotes: 3