1

I am working on a program that needs to write a gigantic, multilayer array to several smaller buffers. I am looking to do this by using unchecked_conversion to flatten the multilayer array into a single layer array, then slice up the array. To recover it from memory, I want to append the parts back into order and Unchecked_Conversion them back to tohe original state.

The original implementation looks something like this:

-- array of up to 500 (most likely 100 - 200 though)
type Bottom_Level is array(1 .. 500) of Integer;

-- colors type
type Colors is (red, blue, green, purple);
for Colors use (red => 1, blue => 2, green => 3, purple => 4);

-- Middle Level Array
type Middle_Level is array(Colors) of Bottom_Level;

-- shapes type
type Shapes is (square, triangle, circle);
for Shapes use (square => 1, triangle => 2, circle => 3);

-- Top Level Array
type Top_Level is array(Shapes) of Middle_Level;

I would like to flatten it into an array like:

type Monolithic_Array is Array (1 .. 6000) of Integer;

Would Unchecked_Conversion do something of this sort, or would it mangle the original array so that it is unrecoverable? Thanks!

SquidsEnMasse
  • 716
  • 2
  • 7
  • 17
  • Your question refers to "records", yet we see only arrays. Is there something amiss? – Marc C Oct 01 '13 at 17:50
  • typo. Fixed with edit – SquidsEnMasse Oct 01 '13 at 18:10
  • Unless the platform is an AVR or MSP430 or something, 15MB isn't exactly huge. I would suggest not worrying about it: that's just unnecessary work. As for "sending across an interface" in smaller chunks, I would look at Stream_IO - you can implement your own I/O Read and Write facilities for low level blocks, and the higher level facilities (inbuilt TopLevelArray'write ) will despatch to them automatically. Very nice... –  Oct 01 '13 at 19:00
  • Does the receiving side know how big the Bottom_Level components are going to be before it starts receiving? And are the sender and receiver the same machine architecture (ie both big-endian, or both little-endian)? – Simon Wright Oct 01 '13 at 20:10

2 Answers2

2

Yeah, since these are statically sized arrays, Unchecked_Conversion would work.

(But it's a rather unusual way to go about this. Had we some idea of what you're actually trying to do, a more apt data structure could perhaps be suggested.)

Another approach is aliasing (warning, not compiled):

TL     : Top_Level;

Buffer : Monolithic_Array;
for Buffer'Address use TL'Address;

So long as you populate your receiving buffer in the same sequence as you transmit the source buffer segments, it should reassemble just fine.

Marc C
  • 8,664
  • 1
  • 24
  • 29
  • I have a huge array list structure, nearly 10,000 elements (15 ish MB), and need to break it down into ~1 kb chunks to send across an interface, then re-assemble it on the other side. Thanks! – SquidsEnMasse Oct 01 '13 at 18:24
1

Here's some examples of how to do such conversions; it also iterates through the set of conversion-functions and tests them for correctness. Implementing a Stream_Convert is left as an exercise for the reader. (Translation from programmerese: "I'm too lazy to do it.")

Pragma Ada_2012;

With
Ada.Streams.Stream_IO,
Ada.Text_IO,
Interfaces;

Procedure Test_Arrays is

    Type Byte is new Interfaces.Unsigned_8;

    Type MD is Array (1..3, 1..3) of Byte;
    Type SD is Array (1..MD'Size/MD'Component_Size) of Byte;


    -- INDEX-CALCULATION METHOD
    Function Mod_Convert( Input : SD ) return MD is
        subtype Primary   is Integer range MD'Range(1); --'
        subtype Secondary is Integer range MD'Range(2); --'
    begin
        return Result : MD do
            for Index_1 in Primary loop
                for Index_2 in Secondary loop
                    Result(Index_1, Index_2):= 
                      Input( Integer'Pred(Index_1)*Primary'Last + Index_2 );
                end loop;
            end loop;
        end return;
    end Mod_Convert;

    Function Mod_Convert( Input : MD ) return SD is
        subtype Primary   is Integer range MD'Range(1); --'
        subtype Secondary is Integer range MD'Range(2); --'
    begin
        return Result : SD do
            for Index in Result'Range loop --'
                declare
                    Index_2 : Integer renames Integer'Succ( Integer'Pred(Index) mod Secondary'Last); --'
                    Index_1 : Integer renames Integer'Succ((Index-Index_2) / Primary'Last);
                begin
                   Result(Index) := Input( Index_1, Index_2 );
                end;
            end loop;
        end return;
    end Mod_Convert;


    -- OVERLAY METHOD
    Function Overlay_Convert( Input : MD ) return SD is
        Result : SD with Import, Convention => Ada, Address => Input'Address; --'
    begin
        Return Result;
    end Overlay_Convert;

    Function Overlay_Convert( Input : SD ) return MD is
        Result : MD with Import, Convention => Ada, Address => Input'Address; --'
    begin
        Return Result;
    end Overlay_Convert;


    -- Print out MD-array.
    Procedure Print( Input : MD ) is
        Use Ada.Text_IO;
    begin
        for Index_1 in MD'Range(1) loop --'
            for Index_2 in MD'Range(2) loop --'
                Put( Byte'Image(Input(Index_1, Index_2)) ); --'
            end loop;
            New_Line;
        end loop;
    end Print;


    -- Print out SD-array.
    Procedure Print( Input : SD ) is
        Use Ada.Text_IO;
    begin
        for Item of Input loop
            Put( Byte'Image(Item) ); --'
        end loop;
        New_Line;
    end Print;


    Type Conversins is ( mod_type, overlay );

    type SD_to_MD_Conversion is not null access function(Input : SD) return MD;
    type MD_to_SD_Conversion is not null access function(Input : MD) return SD;

    type Conversion_Record is record
        SD_to_MD : SD_to_MD_Conversion;
        MD_to_SD : MD_to_SD_Conversion;
    end record;

    Conversions_Var : constant Array( Conversins ) of Conversion_Record:=
      ( mod_type => (Mod_Convert'Access, Mod_Convert'Access),
        overlay  => (Overlay_Convert'Access, Overlay_Convert'Access)
      );

    J : Constant SD := ( 9,8,7,6,5,4,3,2,1 );
Begin

    for Conversion : Conversion_Record of Conversions_Var loop
        declare
            J_prime : MD renames Conversion.SD_to_MD( J );
            J_doubleprime : SD renames Conversion.Md_to_SD( J_prime );
        begin
            Print( J );
            Print( J_prime );
            Print( J_doubleprime );
            Ada.Text_IO.New_Line;
            if J_doubleprime = J then
                Ada.Text_IO.put_line( "Conversion is good." );
            else
                Ada.Text_IO.put_line( "WARNING: BAD CONVERSION!" );
            end if;
        end;
    end loop;    

End Test_Arrays;
Shark8
  • 4,095
  • 1
  • 17
  • 31