Recent

Author Topic: How to port TArray.Sort?  (Read 511 times)

domasz

  • Hero Member
  • *****
  • Posts: 601
How to port TArray.Sort?
« on: November 09, 2025, 06:50:59 am »
I want to port Delphi library to Lazarus but don't know how to replace TArray.Sort. Or maybe it's gonna be in Lazarus 4.0?

Thaddy

  • Hero Member
  • *****
  • Posts: 18519
  • Here stood a man who saw the Elbe and jumped it.
Re: How to port TArray.Sort?
« Reply #1 on: November 09, 2025, 07:31:35 am »
TArray<T> sort is in generics.collections.
I gave an example this week.
It is not quite compatible with fpc yet, but the missing features as documented in the sources for TArrayHelper are now largely resolved, so the feature can also be adapted to be Delphi compatible now.

The basic differences are small:
Delphi: TArray (w/o <T>) is a class containing only generic class methods, its equivalent in FPC is TArrayHelper<T>
You need to maintain very small code changes between them. Will add example later.
« Last Edit: November 09, 2025, 08:03:34 am by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

domasz

  • Hero Member
  • *****
  • Posts: 601
Re: How to port TArray.Sort?
« Reply #2 on: November 09, 2025, 07:41:23 am »
Thank you, Thaddy. I think I got:
TArrayHelper<>.Sort(SearchRects, TComparer<>.Construct(@CompareFun));
« Last Edit: November 09, 2025, 08:07:00 am by domasz »

Thaddy

  • Hero Member
  • *****
  • Posts: 18519
  • Here stood a man who saw the Elbe and jumped it.
Re: How to port TArray.Sort?
« Reply #3 on: November 09, 2025, 08:06:31 am »
generics.collections is in Lazarus since at least 3.2.0. The changes over time are fixed compiler bugs.
3.2.4 fixes has one major fix -> constref has become const in generics.collections.
As I wrote, I will add a small example on how to make it compatible;
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Thaddy

  • Hero Member
  • *****
  • Posts: 18519
  • Here stood a man who saw the Elbe and jumped it.
Re: How to port TArray.Sort?
« Reply #4 on: November 09, 2025, 08:19:20 am »
Here the example to show difference between Delphi and FPC dynamic array sort:
needs just one line changed between Delphi 12.1 and FPC 3.3.1, possibly 3.2.3 too:
Code: Pascal  [Select][+][-]
  1. // sorting dynamic arrays in Freepascal and Delphi
  2. {$ifdef fpc}{$mode delphi}{$endif}
  3. uses
  4.    classes,generics.defaults,generics.collections;
  5.  
  6. type
  7.  
  8.   TARecord = record
  9.     min,
  10.     max:integer;
  11.   end;
  12.  
  13.   TMinComparer = class(TInterfacedObject,IComparer<TARecord>)
  14.     function Compare(const Left, Right: TARecord): Integer; overload;
  15.   end;
  16.  
  17.   function TMinComparer.Compare(const left,right:TARecord):integer;
  18.   begin
  19.     result := 0;
  20.     if right.min > left.min then result := -1
  21.     else if right.min < left.min then result := 1;
  22.   end;
  23.  
  24. var
  25.   RecordArray:TArray<TARecord> = nil;
  26.   MinComparer:IComparer<TARecord>;
  27.   R:TARecord;
  28.   Idx:nativeint;
  29. begin
  30.   MinComparer   := TMinComparer.Create;
  31.   SetLength(RecordArray,4000);
  32.  
  33.   for idx := 0 to High(RecordArray) do
  34.   begin
  35.     RecordArray[idx].min := random(40);
  36.     RecordArray[idx].max := random(40);
  37.   end;
  38.  {$ifdef fpc}
  39.   TArrayHelper<TARecord>.Sort(RecordArray,MinComparer);  // current fpc syntax
  40.   {$else delphi}
  41.   TArray.Sort<TArecord>(RecordArray,MinComparer); // current delphi syntax
  42.   {$endif}
  43.   for R in RecordArray do write(R.Min:3);
  44.   writeln;
  45.   readln;
  46. end.
It is likely that the  syntax in Delphi mode will later converge: It only needs a rework from TArrayHelper <T> to TArray class, but that is not done yet.
Example adapted from the example I gave elsewhere this week.
« Last Edit: November 09, 2025, 08:40:54 am by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Thaddy

  • Hero Member
  • *****
  • Posts: 18519
  • Here stood a man who saw the Elbe and jumped it.
Re: How to port TArray.Sort?
« Reply #5 on: November 09, 2025, 08:42:48 am »
To demonstrate the original issue, that is now solved on the compiler level:
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode delphi}{$endif}
  2. uses generics.defaults;
  3. type
  4.   // the delphi style syntax is now accepted!!!
  5.   TArray = class
  6.   public
  7.     class procedure Sort<T>(var Arr:TArray<T>;const Comparer:IComparer<T>);overload;
  8.   end;
  9.  
  10.   class procedure TArray.Sort<T>(var Arr:TArray<T>;const Comparer:IComparer<T>);
  11.   begin
  12.   end;
  13. begin
  14. end.
That means that the TArrayHelper class can be reworked into the TArray class, but as I wrote: that has not been done yet. Bugs  #24254 are/seems  fixed.
« Last Edit: November 09, 2025, 09:16:40 am by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

domasz

  • Hero Member
  • *****
  • Posts: 601
Re: How to port TArray.Sort?
« Reply #6 on: November 09, 2025, 08:56:18 am »
Great, thank you!

Thaddy

  • Hero Member
  • *****
  • Posts: 18519
  • Here stood a man who saw the Elbe and jumped it.
Re: How to port TArray.Sort?
« Reply #7 on: November 09, 2025, 09:43:06 am »
@domasz

One could use a proxy unit for now.
An example unit would like like this:
Code: Pascal  [Select][+][-]
  1. unit generics.proxies;
  2. {$ifndef fpc}{$error this compatibility unit is not needed for Delphi, only for FPC 3.2.3 or higher}{$endif}
  3. {$mode delphi}
  4. interface
  5. uses
  6.   generics.defaults, generics.collections;
  7. type
  8.  
  9.   TArray = class
  10.   public
  11.     class procedure Sort<T>(var Arr:TArray<T>;const Comparer:IComparer<T>);overload;
  12.     class procedure Sort<T>(var AValues: array of T); overload;
  13.     class procedure Sort<T>(var AValues: array of T;
  14.       const AComparer: IComparer<T>);   overload;
  15.     class procedure Sort<T>(var AValues: array of T;
  16.       const AComparer: IComparer<T>; AIndex, ACount: NativeInt); overload;
  17.     class function BinarySearch<T>(const AValues: array of T; const AItem: T;
  18.       out AFoundIndex: NativeInt; const AComparer: IComparer<T>): Boolean; overload;
  19.     class function BinarySearch<T>(const AValues: array of T; const AItem: T;
  20.       out AFoundIndex: NativeInt): Boolean; overload;
  21.     class function BinarySearch<T>(const AValues: array of T; const AItem: T;
  22.       out ASearchResult: TBinarySearchResult; const AComparer: IComparer<T>): Boolean; overload;
  23.     class function BinarySearch<T>(const AValues: array of T; const AItem: T;
  24.       out ASearchResult: TBinarySearchResult): Boolean; overload;
  25.     class procedure Copy<T>(const aSource: array of T; var aDestination: array of T; aCount: NativeInt); overload;
  26.     class procedure Copy<T>(const aSource: array of T; var aDestination: array of T; aSourceIndex, aDestIndex, aCount: SizeInt); overload;
  27.  
  28.     // Add more to proxy more..
  29.   end;
  30.    
  31. implementation  
  32.  
  33.     class procedure TArray.Sort<T>(var Arr:TArray<T>;const Comparer:IComparer<T>);overload;
  34.     begin
  35.       TArrayHelper<T>.Sort(Arr,Comparer);
  36.     end;
  37.    
  38.     class procedure TArray.Sort<T>(var AValues: array of T); overload;
  39.     begin
  40.       TArrayHelper<T>.Sort(AValues);
  41.     end;
  42.    
  43.     class procedure TArray.Sort<T>(var AValues: array of T;
  44.       const AComparer: IComparer<T>);   overload;
  45.     begin
  46.       TArrayHelper<T>.Sort(AValues,AComparer);
  47.     end;
  48.    
  49.     class procedure TArray.Sort<T>(var AValues: array of T;
  50.       const AComparer: IComparer<T>; AIndex, ACount: NativeInt); overload;
  51.     begin
  52.       TArrayHelper<T>.Sort(AValues,AComparer,AIndex,ACount);
  53.     end;
  54.    
  55.     class function TArray.BinarySearch<T>(const AValues: array of T; const AItem: T;
  56.       out AFoundIndex: NativeInt; const AComparer: IComparer<T>): Boolean; overload;
  57.     begin
  58.       Result := TArrayHelper<T>.BinarySearch(AValues,AItem, AFoundIndex,AComparer);
  59.     end;
  60.    
  61.     class function TArray.BinarySearch<T>(const AValues: array of T; const AItem: T;
  62.       out AFoundIndex: NativeInt): Boolean; overload;
  63.     begin
  64.       Result := TArrayHelper<T>.BinarySearch(AValues, AItem,AFoundIndex);
  65.     end;
  66.  
  67.     class function TArray.BinarySearch<T>(const AValues: array of T; const AItem: T;
  68.       out ASearchResult: TBinarySearchResult; const AComparer: IComparer<T>): Boolean; overload;
  69.     begin
  70.       Result := TArrayHelper<T>.BinarySearch(AValues,AItem,ASearchResult, AComparer);
  71.     end;
  72.      
  73.     class function TArray.BinarySearch<T>(const AValues: array of T; const AItem: T;
  74.       out ASearchResult: TBinarySearchResult): Boolean; overload;
  75.     begin
  76.       Result := TArrayHelper<T>.BinarySearch(AValues,AItem,ASearchResult);
  77.     end;
  78.  
  79.     class procedure TArray.Copy<T>(const aSource: array of T; var aDestination: array of T; aCount: NativeInt); overload;
  80.     begin
  81.       TArrayHelper<T>.Copy(aSource, aDestination, aCount);
  82.     end;
  83.    
  84.     class procedure TArray.Copy<T>(const aSource: array of T; var aDestination: array of T; aSourceIndex, aDestIndex,            aCount: SizeInt); overload;
  85.     begin
  86.        TArrayHelper<T>.Copy(aSource, aDestination, aSourceIndex, aDestIndex, aCount);
  87.     end;
  88.  
  89.  
  90. end.
Simply add this unit for FreePascal only and sort, copy and binarysearch will be Delphi compatible from fpc version 3.2.3 onwards.

The example becomes then:
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode delphi}{$endif}
  2. uses
  3.    classes,generics.defaults, generics.collections
  4.    {$ifdef fpc}, generics.proxies{$endif};
  5. type
  6.  
  7.   TARecord = record
  8.     min,
  9.     max:integer;
  10.   end;
  11.  
  12.   TMinComparer = class(TInterfacedObject,IComparer<TARecord>)
  13.     function Compare(const Left, Right: TARecord): Integer; overload;
  14.   end;
  15.  
  16.   function TMinComparer.Compare(const left,right:TARecord):integer;
  17.   begin
  18.     result := 0;
  19.     if right.min > left.min then result := -1
  20.     else if right.min < left.min then result := 1;
  21.   end;
  22.  
  23. var
  24.   RecordArray:TArray<TARecord> = nil;
  25.   MinComparer:IComparer<TARecord>;
  26.   R:TARecord;
  27.   Idx:nativeint;
  28. begin
  29.   MinComparer   := TMinComparer.Create;
  30.   SetLength(RecordArray,4000);
  31.  
  32.   for idx := 0 to High(RecordArray) do
  33.   begin
  34.     RecordArray[idx].min := random(40);
  35.     RecordArray[idx].max := random(40);
  36.   end;
  37.   TArray.Sort<TArecord>(RecordArray,MinComparer);
  38.   for R in RecordArray do write(R.Min:3);
  39.   writeln;
  40.   readln;
  41. end.
And compiles in both Delphi12.1+ and Freepascal 3.2.3 + by using just the proxies unit.

« Last Edit: November 10, 2025, 08:46:46 am by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Thaddy

  • Hero Member
  • *****
  • Posts: 18519
  • Here stood a man who saw the Elbe and jumped it.
Re: How to port TArray.Sort?
« Reply #8 on: November 09, 2025, 12:20:36 pm »
Note, I just noticed I only implemented the parts from Delphi's TArray for which TArrayHelper<T> already provides an implementation. It is in that sense not complete yet, but what is provided in the generics.proxies unit is Delphi compatible.
« Last Edit: November 09, 2025, 12:40:53 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

 

TinyPortal © 2005-2018