Recent

Author Topic: How to avoid copying  (Read 1506 times)

Amir61

  • New Member
  • *
  • Posts: 32
    • http://Amir.Aavani.net
How to avoid copying
« on: January 17, 2025, 07:08:50 pm »
Hi,

 I have a record of records data structure, like, the following:
Code: Pascal  [Select][+][-]
  1. type TTuple = record
  2.   Entry: TEntry; // TEntry is a record
  3.   Other fields
  4. end;
  5.  
and I have a function that gets a 'TTuple' and does some stuff with its Entry. For my case, it does not make sense to define a separate function that gets 'Entry' as its input.

Code: Pascal  [Select][+][-]
  1. function F(constref Tuple: TTuple): Boolean;
  2.  

Since this function is going to be called a lot, in my code, I am looking for an efficient (and readable) implementation to access 'Tuple.Entry'.

Here are my few options (none of them is great!).
Code: Pascal  [Select][+][-]
  1. function F(constref Tuple: TTuple): Boolean;
  2. var
  3.   Entry: TEntry;
  4. begin
  5.   Entry := Tuple.Entry;
  6.   // Work with Entry rather than Tuple.Entry
  7.  

This requires memory allocation as well as run time overhead of  copying of Tuple.Entry to Entry.

The other option is to use Tuple.Entry through out the function (which is not really a nice solution).

Another option is use EntryPtr := @Tuple.Entry; , but this requires to use EntryPtr^ in the function. I believe this is the best option.

Wondering if there is any other solution? 

cdbc

  • Hero Member
  • *****
  • Posts: 1871
    • http://www.cdbc.dk
Re: How to avoid copying
« Reply #1 on: January 17, 2025, 07:19:31 pm »
Hi
I'd stay with the pointer-solution and then at the top of the unit add this:
Code: Pascal  [Select][+][-]
  1. {$modeswitch autoderef}
That way you don't have to write a lot of 'hats' ^
HTH
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10835
  • Debugger - SynEdit - and more
    • wiki
Re: How to avoid copying
« Reply #2 on: January 17, 2025, 07:25:38 pm »
Code: Pascal  [Select][+][-]
  1.     function F(constref Tuple: TTuple): Boolean;
  2.     var
  3.       Entry: TEntry absolute Tuple.Entry;
  4.     begin
  5.  

Amir61

  • New Member
  • *
  • Posts: 32
    • http://Amir.Aavani.net
Re: How to avoid copying
« Reply #3 on: January 17, 2025, 07:55:16 pm »
Thanks!

PascalDragon

  • Hero Member
  • *****
  • Posts: 5870
  • Compiler Developer
Re: How to avoid copying
« Reply #4 on: January 18, 2025, 05:02:08 pm »
Code: Pascal  [Select][+][-]
  1. function F(constref Tuple: TTuple): Boolean;
  2.  

Not related to your question, but I'd suggest you to use const instead of constref. While for this specific example it does not make a difference there are cases where you don't want to enforce a reference, because the compiler could instead pass it in a register or two (e.g. if you have a record containing two 32-bit values). Use constref only if you really need a constant reference.

Amir61

  • New Member
  • *
  • Posts: 32
    • http://Amir.Aavani.net
Re: How to avoid copying
« Reply #5 on: February 14, 2025, 06:02:23 am »
How about this case:

Code: Pascal  [Select][+][-]
  1. TPair = record
  2.   First: TKey;
  3.    Second: Tvalue;
  4. end;
  5.  
  6. PPair = ^TPair;
  7.  
  8. function Compare(P1, P2: Pointer): Integer;
  9. var
  10.   K1, K2: TKey;
  11.  
  12. begin
  13.   K1 := PPair(P1).Key;
  14.   K2 := PPair(P2).Key;
  15.  
  16.   // ....
  17.  
  18. end;
  19.  

The best I could do is the following:

Code: Pascal  [Select][+][-]
  1. function CompareTPairs(const P1, P2: TPair): Integer; inline;
  2. var
  3.   Key1: TKey absolute P1.First;
  4.   Key2: TKey absolute P2.First;
  5.  
  6. begin
  7. ....
  8. end;
  9.  
  10. function ComparePPairs(P1, P2: PPair): Integer; inline;
  11. begin
  12.   Result := CompareTPairs(P1^, P2^);
  13.  
  14. end;
  15.  
  16. function ComparePointers(P1, P2: Pointer): Integer;
  17. begin
  18.   Result := ComparePPairs(PPair(P1), PPair(P2));
  19. end;
  20.  
  21.  

cdbc

  • Hero Member
  • *****
  • Posts: 1871
    • http://www.cdbc.dk
Re: How to avoid copying
« Reply #6 on: February 14, 2025, 12:22:01 pm »
Wow!
That's a whole heap of beating around the bush ...for a simple compare?!?
How about this:
Code: Pascal  [Select][+][-]
  1. function PairKeyCompare(P1, P2: Pointer): Integer;
  2. var
  3.   pa1: PPair absolute P1;
  4.   pa2: PPair absolute P2;
  5. begin
  6.   if pa1^.Key.First < pa2^.Key.First then Result:= -1
  7.   else if pa1^.Key.First = pa2^.Key.First then Result:= 0
  8.   else Result:= 1;
  9. end;
No copying of data, just pointers - should be snappy  ;D
Regards Benny
edited: added '.First' to the comparison, 'cause 'Key' is a record <15.02>
« Last Edit: February 15, 2025, 10:13:15 am by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Amir61

  • New Member
  • *
  • Posts: 32
    • http://Amir.Aavani.net
Re: How to avoid copying
« Reply #7 on: February 14, 2025, 06:39:10 pm »
Since I am using inline, I assume the final generated code for the two approaches are going to be very similar if not the same.

cdbc

  • Hero Member
  • *****
  • Posts: 1871
    • http://www.cdbc.dk
Re: How to avoid copying
« Reply #8 on: February 14, 2025, 06:48:17 pm »
Hi
Hmmm... I think the call to your last 'CompareTPairs' will result in a copy..., but I could be mistaken.
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

BrunoK

  • Hero Member
  • *****
  • Posts: 671
  • Retired programmer
Re: How to avoid copying
« Reply #9 on: February 14, 2025, 06:49:51 pm »
Since I am using inline, I assume the final generated code for the two approaches are going to be very similar if not the same.
Wow!
That's a whole heap of beating around the bush ...for a simple compare?!?
cdbc's code is much cleaner and is very likely faster. Check his/your version in assembler window.

Amir61

  • New Member
  • *
  • Posts: 32
    • http://Amir.Aavani.net
Re: How to avoid copying
« Reply #10 on: February 15, 2025, 06:11:54 am »
It is not cleaner if Key is a record itself

cdbc

  • Hero Member
  • *****
  • Posts: 1871
    • http://www.cdbc.dk
Re: How to avoid copying
« Reply #11 on: February 15, 2025, 10:06:43 am »
Hi
edit: Sorry, two words: {$advancedrecords}  ...and
One word: "class operators"
HTH
Regards Benny
« Last Edit: February 15, 2025, 10:08:31 am by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

cdbc

  • Hero Member
  • *****
  • Posts: 1871
    • http://www.cdbc.dk
Re: How to avoid copying
« Reply #12 on: February 15, 2025, 10:14:55 am »
Hi again
Another way is to write the code like I've changed post #6 into...
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

d2010

  • Full Member
  • ***
  • Posts: 103
Re: How to avoid copying
« Reply #13 on: February 15, 2025, 10:26:36 am »
How about this case:
Code: Pascal  [Select][+][-]
  1. TPair = record
  2.   First: TKey;
  3.    Second: Tvalue;
  4. end;
  5. Const RTFAIL=-5103;
  6.          RTGOOD= 5200;
  7.  
  8.  
  9.  
  10. PPair = ^TPair;
  11.  
  12. function Compare(P1, P2: Pointer): Integer;
  13. var
  14.   K1, K2: TKey;
  15.  
  16. begin
  17.   if (P1=nil) or (P2=Nil) then Begin result:=RTFAIL; exit;end;
  18.   K1 := PPair(P1).Key;
  19.   K2 := PPair(P2).Key;
  20.  
  21.   // ....
  22.    result:=RTGOOD;
  23. end;
  24.  
The best I could do is the following:
Eu multumesc tie ArsenieBoca.
Code: Pascal  [Select][+][-]
  1. function ComparePointers(P1, P2: Pointer;ElseError): Integer;
  2. begin
  3.    result:=ElseError;
  4.    if (P1=nil) or (P2=nil) then  else
  5.      if (P1<>NIL) and (P2<>nil) and (Cardinal(P1)=Cardinal (P2)) then
  6.     Begin  Writeln('More BetterSpeed Here');  
  7.              result:=RTEQUAL; End else
  8.     Result := ComparePPairs(PPair(P1), PPair(P2));
  9. end;
  10.  

cdbc

  • Hero Member
  • *****
  • Posts: 1871
    • http://www.cdbc.dk
Re: How to avoid copying
« Reply #14 on: February 15, 2025, 10:39:37 am »
Hi
@d2010: What a load of utter crap and nonsense!!!
I think you're in over your paygrade, sorry mate...
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

 

TinyPortal © 2005-2018