Recent

Author Topic: How to create variable sized arrays within a generic record at compile time  (Read 1397 times)

jamie

  • Hero Member
  • *****
  • Posts: 6507
Consider this

Code: Pascal  [Select][+][-]
  1. Generic TmyArray<T,V>= Record
  2.   A:Array[0..V] of T;
  3. End;                        
  4.  

and later on..

Code: Pascal  [Select][+][-]
  1. TMyRecord = Record
  2.   some_Fixed_Fields:...
  3.   AVariableTypeAndSizeArray :TmyArray<Dword, 10> // 10 would be 10 octives/Slices of type Dword
  4.   someOtherFiledsMaybe...
  5.  End;
  6.  

 I want this at compile time so I can create variable sizes of these records and also they will have class functions etc.
 
 I don't need to use generics but would like a way to indicate the size of the array from just outside the inners of the record so I can have the compiler construct a record of each with variable sizes.

 I know this is most likely out of the ordinary, but it seems I've seen this somewhere in my coding career.
The only true wisdom is knowing you know nothing

Peacoor

  • New member
  • *
  • Posts: 7
see https://wiki.freepascal.org/FPC_New_Features_Trunk#Support_for_constant_parameters_in_generics

Code: Pascal  [Select][+][-]
  1. Generic TmyArray<T; const V:Integer>= Record
  2.   A:Array[0..V-1] of T;
  3. End;

Thaddy

  • Hero Member
  • *****
  • Posts: 15488
  • Censorship about opinions does not belong here.
You can use length for the number of elements (duh)
Also have a look at DynArrayBounds and DynArrayDim in system.
With these you can retrieve all the information needed about a dynamic array at runtime.
But the above code is nice if you want to uses static arrays and works pretty good. Needs trunk, though.
« Last Edit: June 30, 2024, 08:26:58 am by Thaddy »
My great hero has found the key to the highway. Rest in peace John Mayall.
Playing: "Broken Wings" in your honour. As well as taking out some mouth organs.

jamie

  • Hero Member
  • *****
  • Posts: 6507
see https://wiki.freepascal.org/FPC_New_Features_Trunk#Support_for_constant_parameters_in_generics

Code: Pascal  [Select][+][-]
  1. Generic TmyArray<T; const V:Integer>= Record
  2.   A:Array[0..V-1] of T;
  3. End;

Ok, so what's the hold up?

I would have thought this simple operation of a Generic would have been there long ago!

Makes it difficult to translate C/C++ code. :(


The only true wisdom is knowing you know nothing

Thaddy

  • Hero Member
  • *****
  • Posts: 15488
  • Censorship about opinions does not belong here.
The part is the const, which is unique to fpc.
you can also do this in trunk:
Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. type
  3.   TmyArray<T; const l,h:Integer>= Record
  4.     A:Array[l..h-1] of T;
  5.   end;
  6.  
  7.  var
  8.   anArray = TMyArray<integer,3,15>;
where both low and high can be defined as const, probably more dimensions as well. It is a real, actually untyped const, not a true integer. See the feature announcement.
All this is at compile time.
« Last Edit: June 30, 2024, 03:20:39 pm by Thaddy »
My great hero has found the key to the highway. Rest in peace John Mayall.
Playing: "Broken Wings" in your honour. As well as taking out some mouth organs.

jamie

  • Hero Member
  • *****
  • Posts: 6507
Hmm, it seems for the time being I can use this absolute hackery slop code.
Code: Pascal  [Select][+][-]
  1. TSize10Type = array[1..10] of char;
  2.  Generic TmyGen <T,Size_T> = Record
  3.   //.....
  4.    A:Array[0..SizeOf(Size_T)-1] of T;
  5.   //......
  6.  end;
  7.  
  8. ...
  9. Var
  10.  A:specialize TmyGen<Char, TSize10Type>;                                  
  11.  
The only true wisdom is knowing you know nothing

440bx

  • Hero Member
  • *****
  • Posts: 4471
Makes it difficult to translate C/C++ code. :(
Can you provide an example of the C/C++ code that you are trying to translate ?... maybe there is another way.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 15488
  • Censorship about opinions does not belong here.
Hmm, it seems for the time being I can use this absolute hackery slop code.
Code: Pascal  [Select][+][-]
  1. TSize10Type = array[1..10] of char;
  2.  Generic TmyGen <T,Size_T> = Record
  3.   //.....
  4.    A:Array[0..SizeOf(Size_T)-1] of T;
  5.   //......
  6.  end;
  7.  
  8. ...
  9. Var
  10.  A:specialize TmyGen<Char, TSize10Type>;                                  
  11.  
When you are not using trunk that is a work-around. When you are using trunk it is less apropiate use of the new language features.
« Last Edit: June 30, 2024, 05:51:57 pm by Thaddy »
My great hero has found the key to the highway. Rest in peace John Mayall.
Playing: "Broken Wings" in your honour. As well as taking out some mouth organs.

jamie

  • Hero Member
  • *****
  • Posts: 6507
Makes it difficult to translate C/C++ code. :(
Can you provide an example of the C/C++ code that you are trying to translate ?... maybe there is another way.

Go here
https://learn.microsoft.com/en-us/cpp/cpp/templates-cpp?view=msvc-170

scroll down to "Non Type Parameters"

That is what I am dealing with.

If it were just a couple here and there I would hard code it but these templates are being used through out the app with lots of different sizes.
There is more than one array per unit for each generic (template) that references this size.

This is a large CAD program and I already tried using dynamic methods in the translation which seem to be working but I noticed a slowdown and the static methods of doing this seems to work much faster. There is lots of code doing complete structure copies from one to the other, etc.

 I am not even sure at the completion of this, if the compiler will handle all of the translations without a memory elapse!
The only true wisdom is knowing you know nothing

Thaddy

  • Hero Member
  • *****
  • Posts: 15488
  • Censorship about opinions does not belong here.
It is definitely not the non-type parameters, since this is exactly that:
Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. type
  3.   TmyArray<T; const lowbound,highbound:Integer>= Record
  4.     a:Array[lowbound..highbound] of T;
  5.   end;
  6.  
  7. var
  8.   a:TMyArray<integer,3,14>;
  9. begin
  10.   writeln('nr of elements is: ',length(a.a));
  11.   writeln('bounds are: ', low(a.a):4,high(a.a):4);
  12. end.
There is a limitation as opposed to C++17 and higher, though.
Sven wrote this about it:
Code: Text  [Select][+][-]
  1. "Important: Unlike C++ FPC does not support default specializations, thus doing recursive specializations together with operations on constants will result in out of stack exceptions or infinite loops:"

But then the C++ code must explicitly use that last feature.
Before C++17 it was also not supported in C++.

What you probably mean is "Default template arguments"

The link is:
https://lists.freepascal.org/pipermail/fpc-devel/2020-April/042708.html
« Last Edit: June 30, 2024, 07:11:49 pm by Thaddy »
My great hero has found the key to the highway. Rest in peace John Mayall.
Playing: "Broken Wings" in your honour. As well as taking out some mouth organs.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5644
  • Compiler Developer
see https://wiki.freepascal.org/FPC_New_Features_Trunk#Support_for_constant_parameters_in_generics

Code: Pascal  [Select][+][-]
  1. Generic TmyArray<T; const V:Integer>= Record
  2.   A:Array[0..V-1] of T;
  3. End;

Ok, so what's the hold up?

There is no hold up, because the feature already exists in trunk/main/3.3.1.

I would have thought this simple operation of a Generic would have been there long ago!

There aren't that many languages that support constants for whatever mechanism they have for generics. Delphi for example doesn't and that is what FPC's generic implementation is mainly driven by (even if it predates the Delphi one).

Makes it difficult to translate C/C++ code. :(

Might be, but the goal of the generics is not to be able to translate C++ code (it can't be C code, because C code does not support templates), but to write type safe, generic Pascal code.

Thaddy

  • Hero Member
  • *****
  • Posts: 15488
  • Censorship about opinions does not belong here.
For completeness, you don't need the record notation we all used.
You can simply write it like this:
Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. type
  3.    TStaticArray<T; const lowbound,highbound: Integer> = array[lowbound..highbound] of T;
  4. var
  5.   a:TStaticArray<integer,3,14>;
  6. begin
  7.   writeln('number of elements is: ',length(a));
  8.   writeln('bounds are: ', low(a):4,high(a):4);
  9. end.
My great hero has found the key to the highway. Rest in peace John Mayall.
Playing: "Broken Wings" in your honour. As well as taking out some mouth organs.

 

TinyPortal © 2005-2018