2

I am looking to create a packed record that can hold an array the varies in length from 5 - 50 elements. Is it possible to do this in such a way that the record can be packed with no wasted space? I will know how many elements will be in the array when I go to create the record.

-- the range of the array
type Array_Range_T is Integer range 5 .. 50;

-- the array type
type Array_Type_T is array range (Array_Range_T) of Integer;

-- the record
type My_Record_T (Array_Length : Integer := 5) is
  record
    -- OTHER DATA HERE
    The_Array : Array_Type_T(Array_Length);
  end record;
-- Pack the record
for My_Record_T use
  record
    -- OTHER DATA
    The_Array at 10 range 0 .. Array_Length * 16;
  end record;

for My_Record_T'Size use 80 + (Array_Length * 16);

This obviously won't compile, but shows the spirit of what I am trying to do. If possible I would like to keep the length of the array out of the record.

Thank you!

SquidsEnMasse
  • 716
  • 2
  • 7
  • 17
  • Why do you want to keep the length out of the record? Is this going to be used for something that will be read or written to a file or socket or something? Or are you just very concerned with memory usage? I don't think there's a direct solution in Ada, but knowing what you're trying to accomplish would help us figure out a workaround. – ajb Mar 31 '14 at 19:32
  • This is being used in a socket packet that is hard defined on the receiving end. It does not contain the number of elements but rather handles it based on the total number of bytes sent. – SquidsEnMasse Mar 31 '14 at 19:40
  • I had been going to suggest [pragma Unchecked_Union](http://www.ada-auth.org/standards/12rm/html/RM-B-3-3.html), but it’s for records with variant parts, and [all variants have to have the same size](http://www.ada-auth.org/standards/12rm/html/RM-B-3-3.html#p14)! – Simon Wright Apr 01 '14 at 07:55
  • @SimonWright I wonder if you're reading this wrong. The phrase "All objects of an unchecked union type have the same size" does *not* mean that you have to add filler components or anything to ensure the variants are the same size. It means the compiler has to add the needed padding. This clause is there because for normal *constrained* variant records, the compiler has the option to allocate only as much as needed if the variant for the known discriminant is smaller than the others. This option is taken away for Unchecked_Union. My apologizes if I'm misunderstood you. – ajb Apr 01 '14 at 15:43
  • @ajb I see that I changed “have the same size” to “have to have the same size”. But in any case that’s not what the OP wanted. Your answer covers that. – Simon Wright Apr 01 '14 at 17:35

2 Answers2

6

There really isn't a way in Ada to represent the record the way you're asking for. However, since your concern really isn't with how the record is represented in memory, but rather with how it's transmitted to a socket, you probably don't need to worry about record representation clauses.

Instead, you can define your own Write routine:

procedure Write (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
                 Item   : in My_Record_T);
for My_Record_T'Write use Write;

or, I believe this will work in Ada 2012:

type My_Record_T is record
    ...
end record
with Write => Write;

procedure Write (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
                 Item   : in My_Record_T);

and then the body will look like

procedure Write (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
                 Item   : in My_Record_T) is
begin
    -- Write out the record components, EXCEPT Array_Length and The_Array.
    T1'Write (Stream, Item.F1);  -- F1 is a record field, T1 is its type
    T2'Write (Stream, Item.F2);  -- F2 is a record field, T2 is its type
    ...

    -- Now write the desired data 
    declare
        Data_To_Write : Array_Type_T (1 .. Item.Array_Length)
            renames Item.The_Array (1 .. Item.Array_Length);
                -- I'm assuming the lower bound is 1, but if not, adjust your code
                -- accordingly
    begin
        Array_Type_T'Write (Stream, Data_To_Write);
            -- Note: using 'Write will write just the data, without any bound 
            -- information, which is what you want.
    end;
end Write;

This won't work if the other components need to be packed, though, e.g. if you want to write a byte to the socket that contains one 3-bit record component and one 5-bit record component. If that's necessary, I don't think the built-in 'Write attributes will do that for you; you may need to do your own bit-twiddling, or you could get tricky and define an array of Stream_Elements and use an Address clause or aspect to define an array that overlays the rest of the record. But I wouldn't use the overlay method unless I were 100% certain that the reader at the other end of the socket were an Ada program that uses the exact same type definition.

Note: I haven't tested this.

ajb
  • 31,309
  • 3
  • 58
  • 84
-1

Not sure I completely understand what you're trying to achieve but can't you do something like this

-- the range of the array
type Array_Range_T is range 1 .. 50;

-- the array type
type Array_Type_T is array (Array_Range_T range <>) of Integer;

Array_Length : constant := 5; --5 elements in the array

-- the record
type My_Record_T is
 record
    -- OTHER DATA HERE
    The_Array : Array_Type_T (1 .. Array_Length);
  end record;

-- Pack the record
for My_Record_T use
 record
-- OTHER DATA
The_Array at 0 range 0 .. (Array_Length * Integer'Size) - 1 ;
end record;

for My_Record_T'Size use (Array_Length * Integer'Size);
jdex
  • 1,279
  • 1
  • 13
  • 20
  • No. Making the array length a constant defeats the purpose. The `:= 5` in the discriminant record declaration (in the original code) is the _default_ value, but it can be changed. In your suggested code, it can't. – ajb Apr 01 '14 at 15:44
  • he stated in his original post that he knows how many elements in the array when declaring the record, that suggested to me the number of elements is static. – jdex Apr 01 '14 at 22:17
  • "I will know how many elements will be in the array when I go to create the record." No, that doesn't suggest "static", that suggests that the program knows, _at the point it starts creating the record_, how many elements it will be. The original post also says "varies in length from 5 - 50 elements", which doesn't really suggest that it's static. – ajb Apr 01 '14 at 22:22