Recent

Author Topic: functions and duplicate code inside... can I get rid of the duplicate code?  (Read 481 times)

trn76

  • New Member
  • *
  • Posts: 34
I have some type helpers with functions that have duplicate implementation of the code... Is there a way to reference to the function by name so there won't be "duplicate" code?
...or a MACRO solution maybe?

Code: Pascal  [Select][+][-]
  1. interface
  2.  
  3. type
  4.  
  5.   TRGB565Helper = type helper for TRGB565
  6.     function      MaxRc(const C: uint32): uint32; inline;
  7.     function      MaxGc(const C: uint32): uint32; inline;
  8.     function      MaxBc(const C: uint32): uint32; inline;
  9.   end;
  10.  
  11.   TRGB8888Helper = type helper for TRGB8888
  12.     function      MaxRc(const C: uint32): uint32; inline;
  13.     function      MaxGc(const C: uint32): uint32; inline;
  14.     function      MaxBc(const C: uint32): uint32; inline;
  15.   end;
  16.  
  17. implementation
  18.  
  19. function TRGB565Helper.MaxRc(const C: uint32): uint32;
  20. begin
  21.   if (C < $1F) then Result := C else Result := $1F;
  22. end;
  23.  
  24. function TRGB565Helper.MaxGc(const C: uint32): uint32;
  25. begin
  26.   if (C < $3F) then Result := C else Result := $3F;
  27. end;
  28.  
  29. function TRGB565Helper.MaxBc(const C: uint32): uint32;
  30. begin
  31.   if (C < $1F) then Result := C else Result := $1F;
  32. end;
  33.  
  34. // -------------------------------------------------
  35.  
  36. function TRGB8888Helper.MaxRc(const C: uint32): uint32;
  37. begin
  38.   if (C < $FF) then Result := C else Result := $FF;
  39. end;
  40.  
  41. function TRGB8888Helper.MaxGc(const C: uint32): uint32;
  42. begin
  43.   if (C < $FF) then Result := C else Result := $FF;
  44. end;
  45.  
  46. function TRGB8888Helper.MaxBc(const C: uint32): uint32;
  47. begin
  48.   if (C < $FF) then Result := C else Result := $FF;
  49. end;
  50.  

...I was thinking about something like this:

Code: Pascal  [Select][+][-]
  1. interface
  2.  
  3. type
  4.  
  5.   TRGB565Helper = type helper for TRGB565
  6.     function MaxRc(const C: uint32): uint32; inline;
  7.     function MaxGc(const C: uint32): uint32; inline;
  8.     funcref  MaxBc(C); MaxRc;
  9.   end;
  10.  
  11.   TRGB8888Helper = type helper for TRGB8888
  12.     function MaxRc(const C: uint32): uint32; inline;
  13.     funcref  MaxGc(C); MaxRc;
  14.     funcref  MaxBc(C); MaxRc;
  15.   end;
  16.  
  17. implementation
  18.  
  19. function TRGB565Helper.MaxRc(const C: uint32): uint32;
  20. begin
  21.   if (C < $1F) then Result := C else Result := $1F;
  22. end;
  23.  
  24. function TRGB565Helper.MaxGc(const C: uint32): uint32;
  25. begin
  26.   if (C < $3F) then Result := C else Result := $3F;
  27. end;
  28.  
  29. // -------------------------------------------------
  30.  
  31. function TRGB8888Helper.MaxRc(const C: uint32): uint32;
  32. begin
  33.   if (C < $FF) then Result := C else Result := $FF;
  34. end;
  35.  

...anyone? :)
« Last Edit: July 13, 2020, 11:20:45 pm by trn76 »

jamie

  • Hero Member
  • *****
  • Posts: 3664
I haven't yet looked but the reserved word "Absolute" is used to point a variable NAME to another body of a variable so that there one variable but two names on it.

 Not sure if this will work with procedures/Functions etc... you could try it..

 Specify the function with tis prototype header and put the ABSOLUTE at the end pointing to another function body..

 I'll experiment off line here ..

 Or you could just do a INLINE call to a master function ..

Nope, cant use ABSOLUTE..

Just have the function body all a master body function, do it inline..

« Last Edit: July 13, 2020, 11:27:02 pm by jamie »
The only true wisdom is knowing you know nothing

PascalDragon

  • Hero Member
  • *****
  • Posts: 2268
  • Compiler Developer
You could do something like this:

Code: Pascal  [Select][+][-]
  1. interface
  2.  
  3. {$macro on}
  4.  
  5. type
  6.  
  7.   TRGB565Helper = type helper for TRGB565
  8.     function      MaxRc(const C: uint32): uint32; inline;
  9.     function      MaxGc(const C: uint32): uint32; inline;
  10.     function      MaxBc(const C: uint32): uint32; inline;
  11.   end;
  12.  
  13.   TRGB8888Helper = type helper for TRGB8888
  14.     function      MaxRc(const C: uint32): uint32; inline;
  15.     function      MaxGc(const C: uint32): uint32; inline;
  16.     function      MaxBc(const C: uint32): uint32; inline;
  17.   end;
  18.  
  19. implementation
  20.  
  21. {$define TypeName:=TRGB565Helper}
  22.  
  23. {$define MaxVal:=$1F}
  24. {$define FuncName:=MaxRc}
  25. {$include MaxFunc.inc}
  26. {$undef MaxVal}
  27. {$undef FuncName}
  28.  
  29. {$define MaxVal:=$3F}
  30. {$define FuncName:=MaxGc}
  31. {$include MaxFunc.inc}
  32. {$undef MaxVal}
  33. {$undef FuncName}
  34.  
  35. {$define MaxVal:=$1F}
  36. {$define FuncName:=MaxBc}
  37. {$include MaxFunc.inc}
  38. {$undef MaxVal}
  39. {$undef FuncName}
  40.  
  41. {$undef TypeName}
  42.  
  43. {$define TypeName:=TRGB8888Helper}
  44. {$define MaxVal:=$FF}
  45.  
  46. {$define FuncName:=MaxRc}
  47. {$include MaxFunc.inc}
  48.  
  49. {$define FuncName:=MaxGc}
  50. {$include MaxFunc.inc}
  51.  
  52. {$define FuncName:=MaxBc}
  53. {$include MaxFunc.inc}
  54.  
  55. {$undef MaxVal}
  56. {$undef TypeName}
  57.  
  58. end.

And the MaxFunc.inc:

Code: Pascal  [Select][+][-]
  1. function TypeName.Funcname(const C: uint32): uint32;
  2. begin
  3.   if (C < MaxVal) then Result := C else Result := MaxVal;
  4. end;

Though one can argue whether this is really less typing... Probably if you have more functions?

I should really implement generics for helper types, then you could use something like this:

Code: Pascal  [Select][+][-]
  1. type
  2.   generic TRGBBaseHelper<T; const MaxR, MaxG, MaxB: UInt32> = type helper for T
  3.     function MaxRc(const C: uint32): uint32; inline;
  4.     function MaxGc(const C: uint32): uint32; inline;
  5.     function MaxBc(const C: uint32): uint32; inline;
  6.   end;
  7.  
  8.   TRGB565Helper = specialize TRGBBaseHelper<TRGB565, $1F, $3F, $1F>;
  9.   TRGB8888Helper = specialize TRGBBaseHelper<TRGB8888, $FF, $FF, $FF>;
  10.  
  11. function TRGBBaseHelper.MaxRc(const C: uint32): uint32;
  12. begin
  13.   if (C < MaxR) then Result := C else Result := MaxR;
  14. end;
  15.  
  16. // etc. for the functions

Thaddy

  • Hero Member
  • *****
  • Posts: 10526
Your first technique is actually also used in the rtl, eg, for the float helpers in sysutils (syshelp.inc)

PascalDragon

  • Hero Member
  • *****
  • Posts: 2268
  • Compiler Developer
Yes, it is, though there the whole type is included and not only specific methods. Depending on the implementation of the methods (I doubt that the three MaxXX methods will be all ;) ) different approaches should be done...

trn76

  • New Member
  • *
  • Posts: 34
Thank you everyone... I ended up using a mix with macros and inline functions, this technique works pretty well for avoiding duplicate code  8-)

edit: PascalDragon your way is the way with generics, yepp I might convert my code to generics!

Code: Pascal  [Select][+][-]
  1. interface
  2.  
  3. {$MACRO ON}
  4.  
  5. {$DEFINE mINLINE := inline;}
  6.  
  7. type
  8.  
  9.   TRGB565Helper = type helper for TRGB565
  10.     function      MaxRc(const C: uint32): uint32; inline;
  11.     function      MaxGc(const C: uint32): uint32; inline;
  12.     function      MaxBc(const C: uint32): uint32; inline;
  13.   end;
  14.  
  15.   TRGB8888Helper = type helper for TRGB8888
  16.     function      MaxRc(const C: uint32): uint32; inline;
  17.     function      MaxGc(const C: uint32): uint32; inline;
  18.     function      MaxBc(const C: uint32): uint32; inline;
  19.   end;
  20.  
  21. implementation
  22.  
  23. function Max1F(const C: uint32): uint32; mINLINE
  24. begin
  25.   if C < $1F then Result := C else Result := $1F;
  26. end;
  27.  
  28. function Max3F(const C: uint32): uint32; mINLINE
  29. begin
  30.   if C < $3F then Result := C else Result := $3F;
  31. end;
  32.  
  33. function MaxFF(const C: uint32): uint32; mINLINE
  34. begin
  35.   if C < $FF then Result := C else Result := $FF;
  36. end;
  37.  
  38. // -------------------------------------------------
  39.  
  40. function TRGB565Helper.MaxRc(const C: uint32): uint32;
  41. begin
  42.   Result := Max1F(C);
  43. end;
  44.  
  45. function TRGB565Helper.MaxGc(const C: uint32): uint32;
  46. begin
  47.   Result := Max3F(C);
  48. end;
  49.  
  50. function TRGB565Helper.MaxBc(const C: uint32): uint32;
  51. begin
  52.   Result := Max1F(C);
  53. end;
  54.  
  55. // -------------------------------------------------
  56.  
  57. function TRGB8888Helper.MaxRc(const C: uint32): uint32;
  58. begin
  59.   Result := MaxFF(C);
  60. end;
  61.  
  62. function TRGB8888Helper.MaxGc(const C: uint32): uint32;
  63. begin
  64.   Result := MaxFF(C);
  65. end;
  66.  
  67. function TRGB8888Helper.MaxBc(const C: uint32): uint32;
  68. begin
  69.   Result := MaxFF(C);
  70. end;
  71.  
« Last Edit: July 16, 2020, 02:49:03 pm by trn76 »

PascalDragon

  • Hero Member
  • *****
  • Posts: 2268
  • Compiler Developer
Thank you everyone... I ended up using a mix with macros and inline functions, this technique works pretty well for avoiding duplicate code  8-)

Please note that in your example the 3.2 compiler will not inline the helper methods, because they reference local functions, only 3.3.1 handles that. As a workaround you'd have to make the local functions available in the interface section as well (or I think moving them to a separate unit should work as well).

 

TinyPortal © 2005-2018