Search code examples
arraysdelphienumsdynamic-arrays

Access dynamic array with enumeration type


I work on the standard data class of our software. Here a minimal example of the current state:

  TDataOne = (Width, Length, Height);
  TDataTwo = (Diameter, Weight);

  TDatStruct = class;

  TDatSubStructOne = class(TDatStruct)
    public
      myData : array[TDataOne] of double;
      procedure writeToFile(AFileName : string);
  end;
  TDatSubStructTwo = class(TDatStruct)
    public
      myData : array[TDataTwo] of double;
      procedure writeToFile(AFileName : string);
  end;

In order to reduce code redundancy I would like to conceive a data structure with a common writing function in TDatStruct. The challenges (at least for me as amateur) are:

  1. mydata is of variable size depending on the substruct and bases on different enum types
  2. I still want to access mydata with an enumerated type in the sub structs
  3. I do not want to pass the sub structure data as parameter to the common write function because of the number of different arrays in the real code

The only idea (neglecting point 3) I have is to pass the array data of the sub structure to the common write procedure as open array parameter like:

writeToFile(AFileName : string; writeData : array of double);

Is there any way to combine a dynamic array with an enumerated type or a virtual enumerated array? Or am I completely on the wrong path?


Solution

  • mydata is of variable size depending on the substruct and bases on different enum types

    Delphi has the intrinsic functions Low and High
    You don't need to know the size of the array.

    I still want to access mydata with an enumerated type in the sub structs

    Use the succ and pred intrinsic methods to walk through the enumeration.

    I do not want to pass the sub structure data as parameter to the common write function because of the number of different arrays in the real code

    All of your arrays look the same to me... They are simply array of double, albeit with a different number of elements.

    You can implement writeToFile like so:

    procedure writeArrayToFile(const AFileName : string; const writeData : array of double);
    var
      i: integer;
    begin
      for i:= low(writeData) to High(writeData) do begin
        WriteADoubleToFile(AFilename, writeData[i]);
      end; {for i}
    end;
    

    Note the use of const if you don't use this the array will be copied to the stack, causing huge delays with big arrays.

    If the array is a data member of your class, then you can simply write the code like so:

    procedure TDatStruct.writeToFile(const AFileName : string);
    begin
      WriteArrayToFile(FileName, GetMyData^);
    end;
    

    Note that because the parent class TDatStruct does not actually have any data inside, you'll need to write a virtual function that will get that data.

    type 
      TMyArray = array[0..0] of double;
      PMyArray = ^TMyArray; 
    
    .....
     TDatStruct = class
     protected 
       function GetMyData: PMyArray; virtual; abstract;  
     public
       procedure WriteToFile(const Filename: string); //no need for virtual  
     end;
    

    The open array parameter of the WriteArrayToFile will fix the issue for you.

    Note that the array parameters in writeToFile is an "open array parameter", this is will accept both static and dynamic arrays.

    If you use different kinds of arrays (double/string etc).
    Then use a generic method.

    Is there any way to combine a dynamic array with an enumerated type or a virtual enumerated array? Or am I completely on the wrong path?

    A dynamic array has a variable number of elements.
    You cannot index it using a enumeration directly.
    However you can translate the enumerated value into an integer using the Ord intrinsic function.
    It also works for enumerations with more than 256 values. The documentation is incorrect, it will return bytes, words or cardinals as needed.

    function FixedArrayToDynamicArray(const input: array of double): TArray<double>;  
    begin
      //translate a fixed array to a dynamic array.  
      SetLength(Result, High(input)); 
      Move(input[0], Result[0], SizeOf(Double) * High(input));
    end;
    

    pre-generics the code becomes:

    type 
      TDoubleArray = array of double; 
    
    function FixedArrayToDynamicArray(const input: array of double): TDoubleArray;  
    ... same from here on.