interface uses RecordList_Unit,Windows; type TOnRomveHash = procedure(Buf:Pointer) of object; //槽结构 THashSlot = record FKey : String; //Hash的Key FItem : Pointer; //内容 FInUse: Boolean; //是否在使用 end; PHashSlot = ^THashSlot; type THashClass = class private FHashCS:TRTLCriticalSection; FCount:Integer; FTable : TRecordList; FOnRomve: TOnRomveHash; function HashFunc(FKey:String;FTableSize:Integer):Integer; function IndexOf(FKey:String;var FItem:Pointer):Integer; procedure SetTableSize(FTableSize:Integer); function GetPrime(N:Integer):Integer; //得到最接近的质数 procedure SetOnRomve(const Value: TOnRomveHash); public constructor Create(TableSize:Integer = 1024); destructor Destroy; override; (****方法****) function Delete(FKey:String):Boolean; function Find(FKey:String;var FItem:Pointer):Boolean; function Insert(const FKey:String;FItem:Pointer):Boolean; procedure Clear; published property OnRomve:TOnRomveHash read FOnRomve write SetOnRomve; property Count:Integer read FCount; end; implementation { THashClass } procedure THashClass.Clear; var Inx : integer; begin EnterCriticalSection(FHashCS); try if FCount<>0 then begin for Inx := 0 to pred(FTable.Count) do begin if PHashSlot(FTable[Inx])^.FInUse then begin PHashSlot(FTable[Inx])^.FKey:=''; //抛出清空Hash中有数据的槽事件 if Assigned(OnRomve) then begin OnRomve(PHashSlot(FTable[Inx])^.FItem); end; end; PHashSlot(FTable[Inx])^.FInUse:=false; end; FCount := 0; end; finally LeaveCriticalSection(FHashCS); end; end; constructor THashClass.Create(TableSize:Integer); begin InitializeCriticalSection(FHashCS); FTable:=TRecordList.Create(SizeOf(THashSlot)); FTable.Name:=''; FTable.Count:=GetPrime(TableSize); end; function THashClass.Delete(FKey: String):Boolean; var Inx:Integer; ItemSlot : Pointer; Slot : PHashSlot; Key : string; Item : pointer; begin EnterCriticalSection(FHashCS); try Result:=true; Inx := IndexOf(FKey, ItemSlot); if (Inx = -1) then begin //没有找到 Result:=false; Exit; end; //Dispose(PHashSlot(ItemSlot).FItem); PHashSlot(ItemSlot).FInUse:=False; PHashSlot(ItemSlot).FKey:=''; dec(FCount); inc(Inx); if (Inx = FTable.Count) then begin Inx := 0; end; Slot := PHashSlot(FTable[Inx]); while Slot^.FInUse do begin Item := Slot^.FItem; Key := Slot^.FKey; Slot^.FKey := ''; Slot^.FInUse := False; dec(FCount); Insert(Key, Item); {move to the next slot} inc(Inx); if (Inx = FTable.Count) then begin Inx := 0; end; Slot := PHashSlot(FTable[Inx]); end; finally LeaveCriticalSection(FHashCS); end; end; destructor THashClass.Destroy; begin if (FTable <> nil) then begin Clear; FTable.Destroy; end; DeleteCriticalSection(FHashCS); inherited Destroy; end; function THashClass.Find(FKey: String; var FItem: Pointer): Boolean; var Slot : Pointer; begin EnterCriticalSection(FHashCS); try if IndexOf(FKey,Slot)<>-1 then begin Result:=true; FItem:=PHashSlot(Slot).FItem; end else begin Result:=False; FItem:=nil; end; finally LeaveCriticalSection(FHashCS); end; end; function THashClass.GetPrime(N: Integer): Integer; {$I TDPrimes.inc} const Forever = true; var L, R, M : integer; RootN : integer; IsPrime : boolean; DivisorIndex : integer; begin EnterCriticalSection(FHashCS); try if (N = 2) then begin Result := N; Exit; end; if Odd(N) then begin Result := N; end else begin Result := succ(N); end; if (Result <= MaxPrime) then begin L := 0; R := pred(PrimeCount); while (L <= R) do begin M := (L + R) div 2; if (Result = Primes[M]) then begin Exit; end else if (Result < Primes[M]) then begin R := pred(M); end else begin L := succ(M); end; end; Result := Primes[L]; Exit; end; if (Result <= (MaxPrime * MaxPrime)) then begin while Forever do begin RootN := round(Sqrt(Result)); DivisorIndex := 1; {ignore the prime number 2} IsPrime := true; while (DivisorIndex < PrimeCount) and (RootN > Primes[DivisorIndex]) do begin if ((Result div Primes[DivisorIndex]) * Primes[DivisorIndex] = Result) then begin IsPrime := false; Break; end; inc(DivisorIndex); end; if IsPrime then begin Exit; end; inc(Result, 2); end; end; finally LeaveCriticalSection(FHashCS); end; end; function THashClass.HashFunc(FKey: String; FTableSize: Integer): Integer; var G:Longint; I:Integer; Hash:Longint; begin Result:=0; Hash:=0; for I:=0 to Length(FKey) do begin Hash:=(Hash shl 4) + Ord(FKey[I]); G:=Hash and $F0000000; if (G<>0) then begin Hash:=Hash xor (G shr 24) xor G; end; Result:=Hash mod FTableSize; end; end; function THashClass.IndexOf(FKey: String; var FItem: Pointer): Integer; var Inx:Integer; CurSlot : PHashSlot; FirstInx : integer; begin EnterCriticalSection(FHashCS); try //计算此KEY的Index Inx:=HashFunc(FKey,FTable.Count); FirstInx := Inx; while True do begin CurSlot := PHashSlot(FTable[Inx]); if not CurSlot.FInUse then begin FItem:=CurSlot; Result:=-1; Exit; end else begin if CurSlot^.FKey = FKey then begin FItem:=CurSlot; Result:=Inx; Exit; end; end; //没有找到,需要循环 Inc(Inx); if (Inx = FTable.Count) then begin Inx := 0; end else if (Inx = FirstInx) then begin FItem := nil; Result := -1; Exit; end; end; finally LeaveCriticalSection(FHashCS); end; end; function THashClass.Insert(const FKey: String; FItem: Pointer):Boolean; var Slot:Pointer; begin EnterCriticalSection(FHashCS); try //加入HASH表中 Result:=true; if IndexOf(FKey,Slot)<>-1 then begin //已经存在 Result:=false; Exit; end; if Slot = nil then begin //Hash表已经满了 Result:=false; Exit; end; PHashSlot(Slot).FKey:=FKey; PHashSlot(Slot).FItem:=FItem; PHashSlot(Slot).FInUse:=true; Inc(FCount); if FCount * 3 > (FTable.Count * 2) then begin //已经大于2/3需要扩展Hash表 SetTableSize(GetPrime(succ(FTable.Count * 2))) end; finally LeaveCriticalSection(FHashCS); end; end; procedure THashClass.SetOnRomve(const Value: TOnRomveHash); begin FOnRomve := Value; end; procedure THashClass.SetTableSize(FTableSize: Integer); var Inx:Integer; OldTable:TRecordList; begin OldTable := FTable; FTable := TRecordList.Create(sizeof(THashSlot)); try FTable.Count := FTableSize; FCount := 0; for Inx := 0 to pred(OldTable.Count) do begin with PHashSlot(OldTable[Inx])^ do begin if FInUse then begin Insert(FKey, FItem); FKey := ''; end; end; end; except FTable.Free; FTable := OldTable; raise; end; OldTable.Free; end; end.