Delphi: fast Pos with 64-bit

前端 未结 2 529
感动是毒
感动是毒 2020-12-15 14:29

Is there any code for a Pos() version that\'s as fast in 64-bit than the current 32-bit?

To my understanding, the 32-bit version in Delphi (tested up to XE5) adopted

相关标签:
2条回答
  • 2020-12-15 14:49

    Using Fastcoders purepascal PosEx_Sha_Pas_2 algorithm (modified to fit x64):

    function PosEx_Sha_Pas_2(const SubStr, S: string; Offset: Integer = 1): Integer;
    Type
      PInteger =^Integer;
    var
      len, lenSub: Integer;
      ch: char;
      p, pSub, pStart, pStop: pchar;
    label
      Loop0, Loop4,
      TestT, Test0, Test1, Test2, Test3, Test4,
      AfterTestT, AfterTest0,
      Ret, Exit;
    begin;
      pSub := pointer(SubStr);
      p := pointer(S);
    
      if (p = nil) or (pSub = nil) or (Offset < 1) then
      begin;
        Result := 0;
        goto Exit;
      end;
    
      lenSub := PLongInt(PByte(pSub) - 4)^ - 1; // <- Modified
      len := PLongInt(PByte(p) - 4)^; // <- Modified
      if (len < lenSub + Offset) or (lenSub < 0) then
      begin;
        Result := 0;
        goto Exit;
      end;
    
      pStop := p + len;
      p := p + lenSub;
      pSub := pSub + lenSub;
      pStart := p;
      p := p + Offset + 3;
    
      ch := pSub[0];
      lenSub := -lenSub;
      if p < pStop then
        goto Loop4;
      p := p - 4;
      goto Loop0;
    
    Loop4:
      if ch = p[-4] then
        goto Test4;
      if ch = p[-3] then
        goto Test3;
      if ch = p[-2] then
        goto Test2;
      if ch = p[-1] then
        goto Test1;
    Loop0:
      if ch = p[0] then
        goto Test0;
    AfterTest0:
      if ch = p[1] then
        goto TestT;
    AfterTestT:
      p := p + 6;
      if p < pStop then
        goto Loop4;
      p := p - 4;
      if p < pStop then
        goto Loop0;
      Result := 0;
      goto Exit;
    
    Test3:
      p := p - 2;
    Test1:
      p := p - 2;
    TestT:
      len := lenSub;
      if lenSub <> 0 then
        repeat
          ;
          if (pSub[len] <> p[len + 1]) or (pSub[len + 1] <> p[len + 2]) then
            goto AfterTestT;
          len := len + 2;
        until len >= 0;
      p := p + 2;
      if p <= pStop then
        goto Ret;
      Result := 0;
      goto Exit;
    
    Test4:
      p := p - 2;
    Test2:
      p := p - 2;
    Test0:
      len := lenSub;
      if lenSub <> 0 then
        repeat
          ;
          if (pSub[len] <> p[len]) or (pSub[len + 1] <> p[len + 1]) then
            goto AfterTest0;
          len := len + 2;
        until len >= 0;
      Inc(p);
    Ret:
      Result := p - pStart;
    Exit:
    end;
    

    And the result using David's test case (x64 release):

    System.Pos       18427
    wcsstr            8122
    PosEx_Sha_Pas_2   2282
    

    For the x32 release the results are:

    System.Pos        2171
    wcsstr            9634
    PosEx_Sha_Pas_2   1868
    

    Conclusion:

    PosEx_Sha_Pas_2 is almost as fast in x64 bit mode as Pos in x32 bit mode. Additionally it seems as PosEx_Sha_Pas_2 is faster than Pos in x32 bit mode.

    All tests here is with the XE4 version.


    Improve purepascal System.Pos() still open in Tokyo 10.2.

    0 讨论(0)
  • 2020-12-15 14:57

    The C runtime function wcsstr as implemented in the system provided msvcrt.dll is better than Delphi RTL Pos for 64 bit code.

    {$APPTYPE CONSOLE}
    
    uses
      SysUtils, Diagnostics;
    
    function wcsstr(const str, strsearch: PWideChar): PWideChar; cdecl; external 'msvcrt.dll';
    
    var
      i, j: Integer;
      Stopwatch: TStopwatch;
      str: string;
      P: PWideChar;
    
    const
      N = 50000000;
    
    begin
      str := 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do '
        + 'eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim '
        + 'ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut '
        + 'aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit '
        + 'in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur '
        + 'sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt '
        + 'mollit anim id est laborum.';
    
      Stopwatch := TStopwatch.StartNew;
      for i := 1 to N do
      begin
        j := Pos('tempor', str);
        if j=0 then
          Beep;
      end;
      Writeln('Pos: ' + IntToStr(Stopwatch.ElapsedMilliseconds));
    
      Stopwatch := TStopwatch.StartNew;
      for i := 1 to N do
      begin
        P := wcsstr(PChar(str), 'tempor');
        if P=nil then
          Beep;
      end;
      Writeln('wcsstr: ' + IntToStr(Stopwatch.ElapsedMilliseconds));
    
      Readln;
    end.
    

    32 bit release build

    Pos: 1930
    wcsstr: 6951
    

    64 bit release build

    Pos: 18384
    wcsstr: 6701
    

    Interestingly, the 32 bit Pos is clearly very well implemented.

    My system is running Win7 x64 on i5-2300.

    0 讨论(0)
提交回复
热议问题