On 02.08.2013 17:01, Mattias Gaertner wrote:
On Fri, 02 Aug 2013 13:18:53 +0200
Sven Barth <pascaldra...@googlemail.com> wrote:

[...]
=== source begin ===

program tgenfuncs;

{$modeswitch result}

generic function IsIn<T>(aElement: T; const aArray: array of T): Boolean;
var
    elem: T;
begin
    for elem in aArray do
      if elem = aElement then
        Exit(True);
    Result := False;
end;

begin
    Writeln(specialize IsIn<LongInt>(42, [21, 42, 84]));
    Writeln(specialize IsIn<LongInt>(5, [21, 42, 84]));

What is the speed?
Is it much slower compared to a line of "if
(aElement=val) or (..)... then" or a "case" statement?

You can do the comparison yourself, as a "specialize IsIn<LongInt>" will generate a version of "IsIn<T>" where each "T" is replaced by "LongInt" and be completely reparsed. So it's the same as if you wrote the following from the beginning:

=== code begin ===

function IsIn(aElement: LongInt; const aArray: array of LongInt): Boolean;
var
  elem: LongInt;
begin
  for elem in aArray do
    if elem = aElement then
      Exit(True);
  Result := False;
end;

=== code end ===

AFAIK the compiler implements the for-in for arrays as a normal for-loop and thus I'd suspect that the "IsIn<T>" function is faster for a larger amount of elements (=> less jumps). Your approach with ifs is basically a loop unrolling which is better with fewer iterations. If you'd declare the "IsIn<T>" function as "inline" and the compiler would correctly handle this(*1) the compiler could in theory be able to fold the complete for-loop together in the example I gave (because only constants are used there). I don't know though whether the compiler is currently able to deduce this (I'll need to test that ^^).

(*1) The problem currently is that the implementation needs to be available when the call is parsed, but specializations are created at the end of parsing a unit. So this would need to be adjusted to allow inline generic functions to work correctly (I plan this, but not now).

What about code size?

The code size for one unit is the same as if you had (in that example) declared a variant of "IsIn" for each "LongInt" and "String". So for each "IsIn<T>" specialization with different types new code is generated if it does not yet exist in that unit. This means that if you call "IsIn<LongInt>" in different units you'll have a "IsIn<LongInt>" implementation in each unit. This is the same as for generic types btw.

Regards,
Sven
_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply via email to