| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- {
- This file is part of the Free Pascal FCL library.
- BSD parts (c) 2011 Vlado Boza
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY;without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$mode objfpc}
- unit ghashmap;
- interface
- uses gvector, gutil, garrayutils;
- const baseFDataSize = 8;
- {Thash should have one class function hash(a:TKey, n:longint):longint which return uniformly distributed
- value in range <0,n-1> base only on arguments, n will be always power of 2}
- type
- generic THashmapIterator<TKey, TValue, T, TTable>=class
- public
- type PValue=^TValue;
- var
- Fh,Fp:SizeUInt;
- FData:TTable;
- function Next:boolean;inline;
- function GetData:T;inline;
- function GetKey:TKey;inline;
- function GetValue:TValue;inline;
- function GetMutable:PValue;inline;
- procedure SetValue(value:TValue);inline;
- property Data:T read GetData;
- property Key:TKey read GetKey;
- property Value:TValue read GetValue write SetValue;
- property MutableValue:PValue read GetMutable;
- end;
- generic THashmap<TKey, TValue, Thash>=class
- public
- type
- TPair=record
- Value:TValue;
- Key:TKey;
- end;
- var
- private
- type
- TContainer = specialize TVector<TPair>;
- TTable = specialize TVector<TContainer>;
- var
- FData:TTable;
- FDataSize:SizeUInt;
- procedure EnlargeTable;
- public
- type
- TIterator = specialize THashmapIterator<TKey, TValue, TPair, TTable>;
- constructor create;
- destructor destroy;override;
- procedure insert(key:TKey;value:TValue);inline;
- function contains(key:TKey):boolean;inline;
- function size:SizeUInt;inline;
- procedure delete(key:TKey);inline;
- function IsEmpty:boolean;inline;
- function GetData(key:TKey):TValue;inline;
- property Items[i : TKey]: TValue read GetData write Insert; default;
- function Iterator:TIterator;
- end;
- implementation
- function THashmap.Size:SizeUInt;inline;
- begin
- Size:=FDataSize;
- end;
- destructor THashmap.Destroy;
- var i:SizeUInt;
- begin
- for i:=0 to FData.size-1 do
- (FData[i]).Destroy;
- FData.Destroy;
- end;
- function THashmap.IsEmpty():boolean;inline;
- begin
- if Size()=0 then
- IsEmpty:=true
- else
- IsEmpty:=false;
- end;
- procedure THashmap.EnlargeTable;
- var i,j,h,oldDataSize:SizeUInt;
- value:TPair;
- begin
- oldDataSize:=FData.size;
- FData.resize(FData.size*2);
- for i:=oldDataSize to FData.size-1 do
- FData[i] := TContainer.create;
- for i:=oldDataSize-1 downto 0 do begin
- j := 0;
- while j < (FData[i]).size do begin
- value := (FData[i])[j];
- h:=Thash.hash(value.key,FData.size);
- if (h <> i) then begin
- (FData[i])[j] := (FData[i]).back;
- (FData[i]).popback;
- (FData[h]).pushback(value);
- end else
- inc(j);
- end;
- end;
- end;
- constructor THashmap.create;
- var i:longint;
- begin
- FDataSize:=0;
- FData:=TTable.create;
- FData.resize(baseFDataSize);
- for i:=0 to baseFDataSize-1 do
- FData[i]:=TContainer.create;
- end;
- function THashmap.contains(key:TKey):boolean;inline;
- var i,h,bs:longint;
- begin
- h:=Thash.hash(key,FData.size);
- bs:=(FData[h]).size;
- for i:=0 to bs-1 do begin
- if (((FData[h])[i]).Key=key) then exit(true);
- end;
- exit(false);
- end;
- function THashmap.GetData(key:TKey):TValue;inline;
- var i,h,bs:longint;
- begin
- h:=Thash.hash(key,FData.size);
- bs:=(FData[h]).size;
- for i:=0 to bs-1 do begin
- if (((FData[h])[i]).Key=key) then exit(((FData[h])[i]).Value);
- end;
- end;
- procedure THashmap.insert(key:TKey;value:TValue);inline;
- var pair:TPair; i,h,bs:longint;
- begin
- h:=Thash.hash(key,FData.size);
- bs:=(FData[h]).size;
- for i:=0 to bs-1 do begin
- if (((FData[h])[i]).Key=key) then begin
- ((FData[h]).mutable[i])^.value := value;
- exit;
- end;
- end;
- pair.Key := key;
- pair.Value := value;
- inc(FDataSize);
- (FData[h]).pushback(pair);
- if (FDataSize > 5*FData.size) then
- EnlargeTable;
- end;
- procedure THashmap.delete(key:TKey);inline;
- var h,i:SizeUInt;
- begin
- h:=Thash.hash(key,FData.size);
- i:=0;
- while i < (FData[h]).size do begin
- if (((FData[h])[i]).key=key) then begin
- (FData[h])[i] := (FData[h]).back;
- (FData[h]).popback;
- dec(FDataSize);
- exit;
- end;
- inc(i);
- end;
- end;
- function THashmapIterator.Next:boolean;
- begin
- inc(Fp);
- if (Fp = (FData[Fh]).size) then begin
- Fp:=0; inc(Fh);
- while Fh < FData.size do begin
- if ((FData[Fh]).size > 0) then break;
- inc(Fh);
- end;
- if (Fh = FData.size) then exit(false);
- end;
- Next := true;
- end;
- function THashmapIterator.GetData:T;
- begin
- GetData:=(FData[Fh])[Fp];
- end;
- function THashmap.Iterator:TIterator;
- var h,p:SizeUInt;
- begin
- h:=0;
- p:=0;
- while h < FData.size do begin
- if ((FData[h]).size > 0) then break;
- inc(h);
- end;
- if (h = FData.size) then exit(nil);
- Iterator := TIterator.create;
- Iterator.Fh := h;
- Iterator.Fp := p;
- Iterator.FData := FData;
- end;
- function THashmapIterator.GetKey:TKey;inline;
- begin
- GetKey:=((FData[Fh])[Fp]).Key;
- end;
- function THashmapIterator.GetValue:TValue;inline;
- begin
- GetValue:=((FData[Fh])[Fp]).Value;
- end;
- function THashmapIterator.GetMutable:PValue;inline;
- begin
- GetMutable:=@((FData[Fh]).Mutable[Fp]^.Value);
- end;
- procedure THashmapIterator.SetValue(value:TValue);inline;
- begin
- ((FData[Fh]).mutable[Fp])^.Value := value;
- end;
- end.
|