Murmurhash 哈希算法

Murmurhash 哈希算法

MurmurHash 是一种非加密型哈希函数,适用于一般的哈希检索操作。 由Austin Appleby在2008年发明, 并出现了多个变种,都已经发布到了公有领域(public domain)。与其它流行的哈希函数相比,对于规律性较强的key,MurmurHash的随机分布特征表现更良好。

Redis在实现字典时用到了两种不同的哈希算法,MurmurHash便是其中一种(另一种是djb),在Redis中应用十分广泛,包括数据库、集群、哈希键、阻塞操作等功能都用到了这个算法。发明算法的作者被邀到google工作,该算法最新版本是MurmurHash3,基于MurmurHash2改进了一些小瑕疵,使得速度更快,实现了32位(低延时)、128位HashKey,尤其对大块的数据,具有较高的平衡性与低碰撞率。

unit Grijjy.Hash;

{$INCLUDE 'Grijjy.inc'}

{$OVERFLOWCHECKS OFF} // required since overflow checks will fail (code works ok w/o checking on)

interface

type
  { Incremental Murmur-2 hash.
      See https://sites.google.com/site/murmurhash/
    Uses the CMurmurHash2A variant, which can be used incrementally.
    The results are *not* the same as for goMurmurHash2 in Grijjy.SysUtils }
  TgoHashMurmur2 = record
  {$REGION 'Internal Declarations'}
  private const
    M = $5bd1e995;
    R = 24;
  private
    FHash: Cardinal;
    FTail: Cardinal;
    FCount: Cardinal;
    FSize: Cardinal;
  private
    class procedure Mix(var H, K: Cardinal); static; inline;
  private
    procedure MixTail(var AData: PByte; var ALength: Integer);
  {$ENDREGION 'Internal Declarations'}
  public
    { Starts a new hash.

      Parameters:
        ASeed: (optional) seed value for the hash.

      This is identical to calling Reset. }
    class function Create(const ASeed: Integer = 0): TgoHashMurmur2; static; inline;

    { Restarts the hash

      Parameters:
        ASeed: (optional) seed value for the hash.

      This is identical to using Create. }
    procedure Reset(const ASeed: Integer = 0); inline;

    { Updates the hash with new data.

      Parameters:
        AData: the data to hash
        ALength: the size of the data in bytes. }
    procedure Update(const AData; ALength: Integer);

    { Finishes the hash and returns the hash code.

      Returns:
        The hash code }
    function Finish: Cardinal;
  end;

implementation

{ TgoHashMurmur2 }

class function TgoHashMurmur2.Create(const ASeed: Integer): TgoHashMurmur2;
begin
  Result.Reset(ASeed);
end;

function TgoHashMurmur2.Finish: Cardinal;
begin
  Mix(FHash, FTail);
  Mix(FHash, FSize);

  FHash := FHash xor (FHash shr 13);
  FHash := FHash * M;
  FHash := FHash xor (FHash shr 15);

  Result := FHash;
end;

class procedure TgoHashMurmur2.Mix(var H, K: Cardinal);
begin
  K := K * M;
  K := K xor (K shr R);
  K := K * M;
  H := H * M;
  H := H xor K;
end;

procedure TgoHashMurmur2.MixTail(var AData: PByte; var ALength: Integer);
begin
  while (ALength <> 0) and ((ALength < 4) or (FCount <> 0)) do
  begin
    FTail := FTail or (AData^ shl (FCount * 8));
    Inc(AData);
    Inc(FCount);
    Dec(ALength);

    if (FCount = 4) then
    begin
      Mix(FHash, FTail);
      FTail := 0;
      FCount := 0;
    end;
  end;
end;

procedure TgoHashMurmur2.Reset(const ASeed: Integer);
begin
  FHash := ASeed;
  FTail := 0;
  FCount := 0;
  FSize := 0;
end;

procedure TgoHashMurmur2.Update(const AData; ALength: Integer);
var
  Data: PByte;
  K: Cardinal;
begin
  Inc(FSize, ALength);
  Data := @AData;
  MixTail(Data, ALength);
  while (ALength >= 4) do
  begin
    K := PCardinal(Data)^;
    Mix(FHash, K);
    Inc(Data, 4);
    Dec(ALength, 4);
  end;
  MixTail(Data, ALength);
end;

end.

  

posted @ 2021-01-04 08:58  delphi中间件  阅读(536)  评论(0编辑  收藏  举报