Delphi - How to pass "Type" as parameter

I would like to know if the declared type (in this case the record) can be passed to my function. I wouldn't even ask if it wasn't for a function SizeOf()

, because it can take a type as a parameter.

I am translating the code from C and I would like to keep it as close to the original as possible. Program C declares the PushArray and PushStruct macros. Since Delphi does not have macro support, I am trying to turn them into functions.

I searched for this version a bit and it seems to me that I can use generic types. Like function PushStruct<T>(Arena : Pmemory_arena; dtype : <T>)

, but you can only use it in an OOP type application.

function PushSize_(Arena : Pmemory_arena; Size : memory_index) : pointer;
begin
    Assert((Arena^.Used + Size) <= Arena^.Size);
    Result := Arena^.Base + Arena^.Used;
    Arena^.Used := Arena^.Used + Size;
end;

function PushStruct(Arena : Pmemory_arena; dtype : ?) : pointer;
begin 
    result := PushSize_(Arena, sizeof(dtype));
end;

function PushArray(Arena : Pmemory_arena; Count: uint32; dtype : ?) : pointer;
begin
    result := PushSize_(Arena, (Count)*sizeof(dtype))
end;

      

Here is the C source code:

#define PushStruct(Arena, type) (type *)PushSize_(Arena, sizeof(type))
#define PushArray(Arena, Count, type) (type *)PushSize_(Arena, (Count)*sizeof(type))
void *
PushSize_(memory_arena *Arena, memory_index Size)
{
    Assert((Arena->Used + Size) <= Arena->Size);
    void *Result = Arena->Base + Arena->Used;
    Arena->Used += Size;

    return(Result);
}

      

+3


source to share


3 answers


The C code does not pass the type to the function. The preprocessor expands the macro and calculates the size. You can see this from the function prototype:

void *PushSize_(memory_arena *Arena, memory_index Size)

      

Since you don't have macros in Delphi, you cannot arrange for direct translation. Personally, if it was me, I would not try to match the C code exactly. I would pass the size and leave it to the caller to use SizeOf

. I don't think this is a terrible burden. That still leaves you with something very close to literal translation - all you're missing are convenience macros.

If you want to use generics, you can do so, but you need to use a static method to do this. For example:

type
  TMyClass = class
    class function PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer; static;
    class function PushStruct<T>(Arena: Pmemory_arena): Pointer; static;
  end;
....
class function TMyClass.PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer;
begin
  Result := ....;
end;

class function TMyClass.PushStruct<T>(Arena: Pmemory_arena): Pointer;
begin
  Result := PushSize(Arena, SizeOf(T));
end;

      



If you want to return a typed pointer that looks like this:

type
  TMyClass<T> = class
    type P = ^ T;
    class function PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer; static;
    class function PushStruct(Arena: Pmemory_arena): P; static;
  end;
....
class function TMyClass<T>.PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer;
begin
  Result := ....;
end;

class function TMyClass<T>.PushStruct(Arena: Pmemory_arena): P;
begin
  Result := PushSize(Arena, SizeOf(T));
end;

      

Obviously, you know which name to use instead TMyClass

!

I'm not sure if generics are good here because I am assuming you want a literal translation as possible. I would not choose to use generics in this scenario.

+5


source


You can "expand macros" by simply declaring your own Push * functions for each post type as needed:



type
  // just guessing here...
  PMemoryArena = ^TMemoryArena;
  TMemoryArena = record
    Base: Pointer;
    Used: Cardinal;
    Size: Cardinal;
  end;
  TMemoryIndex = Cardinal;
  // 1st example record type
  PMyRecord1 = ^TMyRecord1;
  TMyRecord1 = record
    I1: Integer;
    I2: Integer;
  end;
  // 2nd example record type
  PMyRecord2 = ^TMyRecord2;
  TMyRecord2 = record
    D1: Double;
    D2: Double;
  end;

function PushSize_(Arena: PMemoryArena; Size: TMemoryIndex): Pointer; inline;
begin
  Assert(Arena^.Used + Size <= Arena^.Size);
  Result := Pointer(NativeUInt(Arena^.Base) + Arena^.Used);
  Inc(Arena^.Used, Size);
end;

function PushMyRecord1(Arena: PMemoryArena): PMyRecord1;
begin
  Result := PMyRecord1(PushSize_(Arena, SizeOf(TMyRecord1)));
end;

function PushMyRecord2(Arena: PMemoryArena): PMyRecord2;
begin
  Result := PMyRecord2(PushSize_(Arena, SizeOf(TMyRecord2)));
end;

      

+2


source


It seems unnecessary.

why not, for example

function PushStruct(Arena : Pmemory_arena) : pointer;
begin 
    result := PushSize_(Arena, sizeof( Arena ));
end;

      

0


source







All Articles