Recent

Author Topic: Array of structure -> structure of arrays  (Read 1176 times)

BildatBoffin

  • Jr. Member
  • **
  • Posts: 51
Re: Array of structure -> structure of arrays
« Reply #15 on: June 05, 2026, 08:02:08 pm »
Is there a code that allow to do pointed transformation automatically? I mean some tricky generic code.

FPC generics are not powerfull enough for that. You'll need to write lot of code each time,. Even with a language that has template metaprog it's heavy, for example in D , and I have only overloaded appending a record...  :'(

Code: D  [Select][+][-]
  1. struct Model
  2. {
  3.     int a;
  4.     float b;
  5. }
  6.  
  7. struct SOA(T)
  8. {
  9.     static foreach(i,m; __traits(allMembers,T))
  10.         mixin (typeof(mixin(T.stringof,".",m)).stringof, "[] ", m, ";");
  11.  
  12.     void opOpAssign(string op)(T t)
  13.     if (op == "~")
  14.     {
  15.         static foreach(i,m; __traits(allMembers,T))
  16.             mixin(m) ~= __traits(getMember,t,m);
  17.     }
  18. }
  19.  
  20. void main()
  21. {
  22.     SOA!(Model) som;
  23.     som ~= Model(1,0.1);
  24.     som ~= Model(2,0.5);
  25.  
  26.     assert(som.a[1] == 2);
  27.     assert(som.b[1] == 0.5);
  28. }

I've read that you could use RTTI but I fear that you would loose the main point, i.e speed, better cache lines.

jamie

  • Hero Member
  • *****
  • Posts: 7829
Re: Array of structure -> structure of arrays
« Reply #16 on: June 05, 2026, 11:52:24 pm »
You can turn this into an array of assignments.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$modeSwitch AdvancedRecords}
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  9. type
  10.   TRec = record
  11.     D: DWord;
  12.     B: Byte;
  13.   end;
  14.  
  15.   { TRecArrays }
  16.  
  17.   TRecArrays = record
  18.     PD: PDWord;
  19.     PB: PByte;
  20.   Class operator := (ConstRef A:TRec):TRecArrays;
  21.   Class operator := (ConstRef B:TRecArrays):TRec;
  22.   end;
  23.  
  24.   { TForm1 }
  25.  
  26.   TForm1 = class(TForm)
  27.     Button1: TButton;
  28.     procedure Button1Click(Sender: TObject);
  29.   private
  30.  
  31.   public
  32.  
  33.   end;
  34.  
  35. var
  36.   Form1: TForm1;
  37.  
  38. implementation
  39.  
  40. {$R *.lfm}
  41.  
  42. { TRecArrays }
  43.  
  44. class operator TRecArrays.:=(ConstRef A: TRec): TRecArrays;
  45. begin
  46.  Result.PB := @A.B;
  47.  Result.PD := @A.D;
  48. end;
  49.  
  50. class operator TRecArrays.:=(ConstRef B: TRecArrays): TRec;
  51. begin
  52.  Result.B := B.PB^;
  53.  Result.D := B.PD^;
  54. end;
  55.  
  56. { TForm1 }
  57.  
  58. procedure TForm1.Button1Click(Sender: TObject);
  59. Var
  60.   A:TRecArrays;
  61.   R:TRec;
  62. begin
  63.  A := R;
  64.  R := A;
  65. end;
  66.  
  67. end.
  68.  
  69.  

As you can see, you got that.  With that you can have all the conversion coding you need without putting it in your main code.

if you wish, you can encapsulate that in a main record where you can have a Enumerator for the For loop, While, and Repeat.

 Normally enumerator's are automatic with FOR LOOPS, but you can create an iterator much like you see in C/C++ etc just by simply having a "GetEnumerator" function in the Record where it starts at -1 etc. so you can use them for other types of loop controls, not just FOR LOOP
The only true wisdom is knowing you know nothing

LemonParty

  • Hero Member
  • *****
  • Posts: 557
Re: Array of structure -> structure of arrays
« Reply #17 on: June 06, 2026, 11:34:18 am »
Quote
if you wish, you can encapsulate that in a main record where you can have a Enumerator for the For loop, While, and Repeat.
I never used enumerators before. Can you give an example?

The zip and unzip procedures that mention above is a great idea. But seems FPC generics are not enough powerful for this.
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

jamie

  • Hero Member
  • *****
  • Posts: 7829
Re: Array of structure -> structure of arrays
« Reply #18 on: June 06, 2026, 06:04:16 pm »
This is just an example of creating an Enumerator using some parts of  your own code.


The Copy operators I didn't implement but you can, this only shows a simple approach not only to the Enumerator but also to auto intializing the records and cleaning up background objects without your code doing this.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$modeSwitch AdvancedRecords}
  5.  
  6. interface
  7.  
  8. uses
  9.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,fgl;
  10.  
  11. type
  12.     { TRecArrays }
  13.   PRecArrays = ^TRecArrays;
  14.   TRecArrays = record
  15.     PD: PDWord;
  16.     PB: PByte;
  17.   //Class operator := (ConstRef A:TRec):TRecArrays;
  18.   //Class operator := (ConstRef B:TRecArrays):TRec;
  19.   end;
  20.  { TRecEnumberator }
  21.  
  22.  TRecEnumerator = class
  23.    Protected
  24.     TheList:TList;
  25.     ItemIndex:Integer;
  26.    Public
  27.    Constructor Create(AList:TList);
  28.    Function MoveNext:Boolean;
  29.    Function GetCurrent:PRecArrays;
  30.    Property Current:PRecArrays Read GetCurrent;
  31.    Procedure Reset;
  32.  end;
  33.  
  34.  { TBaseAr }
  35.  
  36.  TBaseAr = Record
  37.    F:TList;
  38.    Function GetEnumerator:TRecEnumerator;
  39.    class operator initialize(var a:TBaseAr);
  40.    Class operator Finalize(var a:TBasear);
  41.  end;
  42.  
  43.   { TForm1 }
  44.  
  45.   TForm1 = class(TForm)
  46.     Button1: TButton;
  47.     procedure Button1Click(Sender: TObject);
  48.   private
  49.  
  50.   public
  51.  
  52.   end;
  53.  
  54. var
  55.   Form1: TForm1;
  56.  
  57. implementation
  58.  
  59. {$R *.lfm}
  60.  
  61. { TRecArrays }
  62.  
  63. class operator TbaseAr.initialize(var A:TBaseAr);
  64. begin
  65.   A.F := TList.Create;
  66. end;
  67.  
  68. class operator TBaseAr.Finalize(Var A:TbaseAr);
  69. begin
  70.   While A.F.Count > 0 do
  71.   Begin
  72.     FreeMem(A.F.Items[A.F.Count-1]);
  73.     A.F.Delete(A.F.Count-1);
  74.   end;
  75.   A.F.Free;
  76. end;
  77.  
  78. { TRecEnumberator }
  79.  
  80. constructor TRecEnumerator.Create(AList:TList);
  81. begin
  82.   TheList := AList;
  83.   Reset;
  84. end;
  85.  
  86. function TRecEnumerator.MoveNext: Boolean;
  87. begin
  88.  Result:=False;
  89.  iF (ItemIndex+1) < TheList.Count Then
  90.   Begin
  91.    Result := True;
  92.    Inc(ItemIndex);
  93.   end;
  94. end;
  95.  
  96. function TRecEnumerator.GetCurrent:PrecArrays;
  97. begin
  98.   Result := TheList.Items[ItemIndex];
  99. end;
  100.  
  101.  
  102. procedure TRecEnumerator.Reset;
  103. begin
  104.  ItemIndex := -1;
  105. end;
  106.  
  107. { TBaseAr }
  108.  
  109. function TBaseAr.GetEnumerator: TRecEnumerator;
  110. begin
  111.   Result := TRecEnumerator.Create(F);
  112. end;
  113.  
  114. { TForm1 }
  115.  
  116. procedure TForm1.Button1Click(Sender: TObject);
  117. Const AByte:Byte = 127;
  118. Var
  119.   B:TbaseAr;//Auto init
  120.   R:PRecArrays;
  121. begin
  122.   GetMem(R,Sizeof(TRecArrays));  //Gets free'd when block exits.
  123.   R^.PB := @AByte; //Point to a test area
  124.   B.F.Add(R);   //Add this to the internal list
  125.   For R in B Do
  126.    Begin
  127.      Caption := R^.PB^.ToString;
  128.      //..............//
  129.    end;
  130. { Run HeapTrc to varify cleanup}
  131. end;
  132.  
  133. end.
  134.  
  135.  
The only true wisdom is knowing you know nothing

LemonParty

  • Hero Member
  • *****
  • Posts: 557
Re: Array of structure -> structure of arrays
« Reply #19 on: June 06, 2026, 07:10:43 pm »
jamie, you seems not quite understand the problem.

I want a function that look like this:
Code: Pascal  [Select][+][-]
  1. type
  2.   TPointers = array of Pointer;
  3. function UnZip(constref R: TAnyRecord; Count: SizeUInt): TPointers;
The difficulty is that compiler should accept a "random" record type, then slice it onto simple arrays base on type information and return the resulting array of arrays. This is difficult because any unique record should produce an unique UnZip function.
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

jamie

  • Hero Member
  • *****
  • Posts: 7829
Re: Array of structure -> structure of arrays
« Reply #20 on: June 06, 2026, 07:56:27 pm »
You are correct, I don't understand what you are saying because you are using terms, names etc. that point elsewhere.

You use the word "UnZip" and that alone just throws a monkey wrench in the whole thought process.

The compiler has VARIANTS, that holds data and indicates type of data sitting in there.

Open arrays also the same and if those aren't enough you can make your own.

I most likely can duplicate to a degree the posted example in D-Lang because I see nothing special there, just the use of TYPEINFO in the Generic creation, but at this, I need my time for something else.

Good luck, I have a massive C/C++ cad program I am porting over and that is loaded with Templates and needs my attention.
Jamie

The only true wisdom is knowing you know nothing

Seenkao

  • Hero Member
  • *****
  • Posts: 766
    • New ZenGL.
Re: Array of structure -> structure of arrays
« Reply #21 on: June 06, 2026, 09:44:44 pm »
Transformation should work like this:
Code: Pascal  [Select][+][-]
  1. type
  2.   TRec = record
  3.     D: DWord;
  4.     B: Byte;
  5.   end;
  6.  
  7.   TRecArrays = record
  8.     PD: PDWord;
  9.     PB: PByte;
  10.   end;
  11. var
  12.   i: Integer;
  13.   Arr: array of TRec;
  14.   RArr: TRecArrays;
  15. begin
  16.   RArr.PD:= GetMem(Length(Arr) * SizeOf(DWord));
  17.   RArr.PB:= GetMem(Length(Arr) * SizeOf(Byte));
  18.   for i:= 0 to High(Arr) do begin
  19.     RArr.PD[i]:= Arr[i].D;
  20.     RArr.PB[i]:= Arr[i].B;
  21.   end;
  22. end.
As you can see in this code I done it by hand, but I am interesting if there is an automatic way to do that.
Если мы создали структуру, то к данным структуры можно сразу обращаться через указатель. Например, добавить указатель PRec := ^TRec и работать от него. Например:

----------------------------------------------------
If we've created a structure, we can directly access the structure's data via a pointer. For example, we can add a pointer PRec := ^TRec and work from it. For example:
Code: Pascal  [Select][+][-]
  1. type
  2.   PRec = ^TRec;
  3.   TRec = record
  4.     D: DWord;
  5.     B: Byte;
  6.   end;
  7.  
  8. var
  9.   i: Integer;
  10.   PArr: array of PRec;
  11.  
не забываем выделить память.

------------------------------------------------
don't forget to allocate memory.


Если вы желаете, вы можете объявить обычный массив и устанавливать указатель на начало массива или на начало позиции в массиве. Так можно менять позицию в массиве и получать нужный элемент. Если вы ошибётесь, то вы будете обращаться не к тем данным.

Можно выставить указатель один раз и смещать его в нужную сторону. Можно каждый раз указателю давать новый адрес.
--------------------------------------------------

If you prefer, you can declare a regular array and set the pointer to the beginning of the array or to the beginning of a position within the array. This way, you can change the position in the array and retrieve the desired element. If you make a mistake, you'll access the wrong data.

You can set the pointer once and move it in the desired direction. You can also assign a new address to the pointer each time.

Code: Pascal  [Select][+][-]
  1. type
  2.   PRec = ^TRec;
  3.   TRec = record
  4.     D: DWord;
  5.     B: Byte;
  6.   end;
  7.  
  8. var
  9.   i: Integer;
  10.   PArr: PRec;
  11.   Arr: array of Rec;
  12.  
  13. begin
  14.   ...
  15.   PArr := @Arr[0];
  16.   PArr := @Arr[10];
  17.   ...
  18. // or
  19.   ...
  20.   PArr := @Arr[0];
  21.   inc(PArr, 10);                     // There might be a mistake here, perhaps you'll need to use sizeof
  22.   ...
  23. end;
  24.  
« Last Edit: June 06, 2026, 09:51:38 pm by Seenkao »
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

 

TinyPortal © 2005-2018