Morgan Thrapp
Morgan Thrapp

Reputation: 9986

array append in delphi

I'm trying to implement array append in Delphi 7, because the standard library does not have it. This is what I have so far, but it complains about incompatible types when I try to get the length of the array.

procedure ArrayAppend(var GenericArray; const Element);
var
  len: Integer;
begin
  len := Length(GenericArray);
  SetLength(GenericArray, len+1);
  GenericArray[len] := Element;
end;

I'm trying to find what the most generic type of array is in Delphi 7.

I also have no issue returning the modified array if that's the only way to do it.

Upvotes: 1

Views: 2128

Answers (1)

David Heffernan
David Heffernan

Reputation: 613491

To illustrate what Rob Kennedy said in comments, here is a function that will append a value to a dynamic array. However, this is a rather crippled function in that it does not support managed types. So you cannot have strings, interfaces, variants or dynamic arrays. Or indeed compound structures that contain any managed types.

{$APPTYPE CONSOLE}

uses
  SysUtils,
  TypInfo;

type
  PDynArrayTypeInfo = ^TDynArrayTypeInfo;
  TDynArrayTypeInfo = packed record
    kind: Byte;
    name: Byte;
    elSize: Longint;
    elType: ^PDynArrayTypeInfo;
    varType: Integer;
  end;

function DynArraySize(a: Pointer): Integer;
asm
        TEST EAX, EAX
        JZ   @@exit
        MOV  EAX, [EAX-4]
@@exit:
end;

type
  TIntegerArray = array of Integer;

procedure AppendUnmanaged(var arr{: TArray<T>}; const Value{: T}; TypeInfo: PTypeInfo);
var
  len, elSize: Integer;
begin
  len := DynArraySize(Pointer(arr)) + 1;
  DynArraySetLength(Pointer(arr), TypeInfo, 1, @len);
  inc(PAnsiChar(TypeInfo), PDynArrayTypeInfo(TypeInfo).name);
  elSize := PDynArrayTypeInfo(TypeInfo).elSize;
  Move(Value, (PAnsiChar(Pointer(arr)) + (len-1)*elSize)^, elSize);
end;

procedure Main;
var
  arr: TIntegerArray;
  i, Value: Integer;
begin
  Value := -1;
  AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));

  Value := 666;
  AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));

  Value := 42;
  AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));

  for i := low(arr) to high(arr) do
    Writeln(arr[i]);
end;

begin
  try
    Main;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

You can see some obvious problems with this when compared with modern day Delphi which has generic types and array concatenation baked into the language. Specifically I'm thinking of these issues:

  1. You have to provide a type info to the function.
  2. You cannot pass literals because they are not valid as untyped parameters.

Now, it is certainly possible to replicate what the compiler does when assigning a managed type. But is it really worthwhile? Is the code above, especially the calling code, really an improvement over the type safe alternatives? Personally I don't think so.

Upvotes: 2

Related Questions