[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/RoutineOp/DelphiAST/master/Source/StringPool.pas [Back]  [Original]

unit StringPool;

{$IFDEF FPC}{$MODE Delphi}{$ENDIF}

interface

type
  TStringBucket = record
    Hash: Cardinal;
    Value: string;
  end;
  PStringBucket = ^TStringBucket;
  TStringBuckets = array of TStringBucket;

  TStringPool = class
  private
    FBuckets: TStringBuckets;
    FCount: Integer;
    FGrowth: Integer;
    FCapacity: Integer;
    procedure Grow;
  public
    procedure StringIntern(var s: string);

    procedure Clear;
    property Count: Integer read FCount;
  end;

implementation

{ TStringPool }

procedure TStringPool.Clear;
begin
  SetLength(FBuckets, 0);
  FCount := 0;
  FGrowth := 0;
  FCapacity := 0;
end;

procedure TStringPool.Grow;
var
  i, j, n: Integer;
  oldBuckets: TStringBuckets;
begin
  if FCapacity = 0 then
    FCapacity := 32
  else
    FCapacity := FCapacity * 2;
  FGrowth := (FCapacity * 3) div 4 - FCount;

  oldBuckets := FBuckets;
  FBuckets := nil;
  SetLength(FBuckets, FCapacity);

  n := FCapacity - 1;
  for i := 0 to High(oldBuckets) do
  begin
    if oldBuckets[i].Hash = 0 then
      Continue;
    j := oldBuckets[i].Hash and (FCapacity - 1);
    while FBuckets[j].Hash  0 do
      j := (j + 1) and n;
    FBuckets[j].Hash := oldBuckets[i].Hash;
    FBuckets[j].Value := oldBuckets[i].Value;
  end;
end;

procedure TStringPool.StringIntern(var s: string);

{$OVERFLOWCHECKS OFF}

  function HashString(const s: string): Cardinal; inline;
  var
    i: Integer;
  begin
    // modified FNV-1a using length as seed
    Result := Length(s);
    for i := 1 to Result do
      Result := (Result xor Ord(s[i])) * 16777619;
  end;

{$OVERFLOWCHECKS ON}

var
  hash: Cardinal;
  i: Integer;
  bucket: PStringBucket;
begin
  if s = '' then
    Exit;

  if FGrowth = 0 then
    Grow;

  hash := HashString(s) shr 6;
  i := hash and (FCapacity - 1);

  repeat
    bucket := @FBuckets[i];
    if (bucket.Hash = hash) and (bucket.Value = s) then
    begin
      s := bucket.Value;
      Exit;
    end
    else if bucket.Hash = 0 then
    begin
      bucket.Hash := hash;
      bucket.Value := s;
      Inc(FCount);
      Dec(FGrowth);
      Exit;
    end;
    i := (i + 1) and (FCapacity - 1);
  until False;
end;

end.

Web Proxy Viewer  |  New URL  |  Original Page