Simple string hashing function

前端 未结 6 1273
情话喂你
情话喂你 2020-12-14 11:28

I\'m trying to hash a string into an integer for placing it in an array. However I do not know all too much about hashing functions, and that\'s why my current method is jus

6条回答
  •  死守一世寂寞
    2020-12-14 11:53

    See http://www.strchr.com/hash_functions for a very good panel of hashing functions.

    In Delphi implementation, here are several versions:

    The first coming to mind is the one used in TStringHash.HashOf method from official IniFiles.pas unit. Including a faster asm version:

    function HashOf(P: PByteArray; Len: integer): cardinal;
    // algorithm from IniFiles.TStringHash.HashOf
    {$ifdef PUREPASCAL}
    var I: Integer;
    begin
      Result := 0;
      for I := 1 to Len do
        Result := ((Result shl 2) or (Result shr (SizeOf(Result)*8-2))) xor P[I];
    end;
    {$else}
    asm // faster asm version by Synopse
        or edx,edx
        jz @z
        push ebx
        mov ebx,edx     // ebx = length(Key)
        mov edx,eax     // edx = Text
        xor eax,eax     // eax = Result
        xor ecx,ecx     // ecx = Result shl 2 = 0
    @1: shr eax,$1e     // eax = Result shr (SizeOf(Result) * 8 - 2))
        or ecx,eax      // ecx = ((Result shl 2) or (Result shr (SizeOf(Result)*8-2)))
        movzx eax,byte ptr [edx] // eax = ord(Key[i])
        inc edx
        xor eax,ecx     // eax = () xor ord(Key[i])
        dec ebx
        lea ecx,[eax*4] // ecx = Result shl 2
        jnz @1
        pop ebx
    @z:
    end;
    {$endif}
    

    The classic Kernighan & Ritchie hash from "The C programming Language", 3rd edition - not the best, but simple and efficient code.

    function kr32(crc: cardinal; buf: PAnsiChar; len: cardinal): cardinal;
    var i: integer;
    begin
      for i := 0 to len-1 do
        crc := ord(buf[i])+crc*31;
      result := crc;
    end;
    

    The fast "Adler" CRC as implemented in zlib - optimized asm version here:

    function Adler32Pas(Adler: cardinal; p: pointer; Count: Integer): cardinal;
    var s1, s2: cardinal;
        i, n: integer;
    begin
      s1 := LongRec(Adler).Lo;
      s2 := LongRec(Adler).Hi;
      while Count>0 do begin
        if Count<5552 then
          n := Count else
          n := 5552;
        for i := 1 to n do begin
          inc(s1,pByte(p)^);
          inc(cardinal(p));
          inc(s2,s1);
        end;
        s1 := s1 mod 65521;
        s2 := s2 mod 65521;
        dec(Count,n);
      end;
      result := word(s1)+cardinal(word(s2)) shl 16;
    end;
    

    My own faster variant - not re-entrant, but faster since it will read by DWORDs - and an even faster asm version here:

    function Hash32(Data: pointer; Len: integer): cardinal;
    function SubHash(P: PCardinalArray; L: integer): cardinal;
    {$ifdef HASINLINE}inline;{$endif}
    var s1,s2: cardinal;
        i: PtrInt;
    const Mask: array[0..3] of cardinal = (0,$ff,$ffff,$ffffff);
    begin
      if P<>nil then begin
        s1 := 0;
        s2 := 0;
        for i := 1 to L shr 4 do begin // 16 bytes (4 DWORD) by loop - aligned read
          inc(s1,P^[0]);
          inc(s2,s1);
          inc(s1,P^[1]);
          inc(s2,s1);
          inc(s1,P^[2]);
          inc(s2,s1);
          inc(s1,P^[3]);
          inc(s2,s1);
          inc(PtrUInt(P),16);
        end;
        for i := 1 to (L shr 2)and 3 do begin // 4 bytes (DWORD) by loop
          inc(s1,P^[0]);
          inc(s2,s1);
          inc(PtrUInt(P),4);
        end;
        inc(s1,P^[0] and Mask[L and 3]);      // remaining 0..3 bytes
        inc(s2,s1);
        result := s1 xor (s2 shl 16);
      end else
        result := 0;
    end;
    begin // use a sub function for better code generation under Delphi
      result := SubHash(Data,Len);
    end;
    

    The classic CRC32 version - you can find a very optimized asm version (using 8 tables) here:

    function UpdateCrc32(aCRC32: cardinal; inBuf: pointer; inLen: integer) : cardinal;
    var i: integer;
    begin
      result := aCRC32;
      // if we used a dynamic table, we assume we want shorter code size
      for i := 1 to inLen do begin
        result := crc32Tab[byte(result xor pByte(inBuf)^)] xor (result shr 8);
        inc(cardinal(inBuf));
      end;
    end;
    

提交回复
热议问题