* fphashlist, update hashcapacity also if capacity is changed

git-svn-id: trunk@11699 -
This commit is contained in:
peter 2008-09-03 21:04:53 +00:00
parent 060bdbcb47
commit e90ce867d9
4 changed files with 131 additions and 61 deletions

1
.gitattributes vendored
View File

@ -7551,6 +7551,7 @@ tests/test/opt/tspace.pp svneol=native#text/plain
tests/test/packages/fcl-registry/tregistry1.pp svneol=native#text/plain
tests/test/packages/hash/tmdtest.pp svneol=native#text/plain
tests/test/packages/webtbs/tw10045.pp svneol=native#text/plain
tests/test/packages/webtbs/tw11142.pp svneol=native#text/plain
tests/test/packages/webtbs/tw11570.pp svneol=native#text/plain
tests/test/packages/webtbs/tw1808.pp svneol=native#text/plain
tests/test/packages/webtbs/tw3820.pp svneol=native#text/plain

View File

@ -216,6 +216,7 @@ type
procedure Clear;
function NameOfIndex(Index: Integer): ShortString; {$ifdef CCLASSESINLINE}inline;{$endif}
function HashOfIndex(Index: Integer): LongWord; {$ifdef CCLASSESINLINE}inline;{$endif}
function GetNextCollision(Index: Integer): Integer;
procedure Delete(Index: Integer);
class procedure Error(const Msg: string; Data: PtrInt);
function Expand: TFPHashList;
@ -283,6 +284,7 @@ type
function Add(const AName:shortstring;AObject: TObject): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
function NameOfIndex(Index: Integer): ShortString; {$ifdef CCLASSESINLINE}inline;{$endif}
function HashOfIndex(Index: Integer): LongWord; {$ifdef CCLASSESINLINE}inline;{$endif}
function GetNextCollision(Index: Integer): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
procedure Delete(Index: Integer);
function Expand: TFPHashObjectList; {$ifdef CCLASSESINLINE}inline;{$endif}
function Extract(Item: TObject): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
@ -1054,26 +1056,6 @@ end;
TFPHashList
*****************************************************************************}
function FPHash1(const s:shortstring):LongWord;
Var
g : LongWord;
p,pmax : pchar;
begin
result:=0;
p:=@s[1];
pmax:=@s[length(s)+1];
while (p<pmax) do
begin
result:=result shl 4 + LongWord(p^);
g:=result and LongWord($F0000000);
if g<>0 then
result:=result xor (g shr 24) xor g;
inc(p);
end;
If result=0 then
result:=$ffffffff;
end;
function FPHash(const s:shortstring):LongWord;
Var
p,pmax : pchar;
@ -1117,6 +1099,7 @@ end;
{$endif}
end;
procedure TFPHashList.RaiseIndexError(Index : Integer);
begin
Error(SListIndexError, Index);
@ -1161,6 +1144,14 @@ begin
end;
function TFPHashList.GetNextCollision(Index: Integer): Integer;
begin
Result:=-1;
if ((Index > -1) and (Index < FCount)) then
Result:=FHashList^[Index].NextIndex;
end;
function TFPHashList.Extract(item: Pointer): Pointer;
var
i : Integer;
@ -1183,6 +1174,9 @@ begin
exit;
ReallocMem(FHashList, NewCapacity*SizeOf(THashItem));
FCapacity := NewCapacity;
{ Maybe expand hash also }
if FCapacity>FHashCapacity*MaxItemsPerHash then
SetHashCapacity(FCapacity div MaxItemsPerHash);
end;
@ -1301,6 +1295,7 @@ begin
FHashList := nil;
end;
SetHashCapacity(1);
FHashTable^[0]:=longword(-1); // sethashcapacity does not always call rehash
if Assigned(FStrs) then
begin
FStrCount:=0;
@ -1353,9 +1348,6 @@ begin
else if FCapacity >= sizeof(ptrint) then
inc(IncSize,sizeof(ptrint));
SetCapacity(FCapacity + IncSize);
{ Maybe expand hash also }
if FCount>FHashCapacity*MaxItemsPerHash then
SetHashCapacity(FCount div MaxItemsPerHash);
end;
procedure TFPHashList.StrExpand(MinIncSize:Integer);
@ -1724,6 +1716,11 @@ begin
Result := FHashList.HashOfIndex(Index);
end;
function TFPHashObjectList.GetNextCollision(Index: Integer): Integer;
begin
Result := FHashList.GetNextCollision(Index);
end;
procedure TFPHashObjectList.Delete(Index: Integer);
begin
if OwnsObjects then
@ -1828,7 +1825,6 @@ begin
end;
{****************************************************************************
TLinkedListItem
****************************************************************************}

View File

@ -234,6 +234,7 @@ type
procedure Clear;
function NameOfIndex(Index: Integer): ShortString; {$ifdef CCLASSESINLINE}inline;{$endif}
function HashOfIndex(Index: Integer): LongWord; {$ifdef CCLASSESINLINE}inline;{$endif}
function GetNextCollision(Index: Integer): Integer;
procedure Delete(Index: Integer);
class procedure Error(const Msg: string; Data: PtrInt);
function Expand: TFPHashList;
@ -301,6 +302,7 @@ type
function Add(const AName:shortstring;AObject: TObject): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
function NameOfIndex(Index: Integer): ShortString; {$ifdef CCLASSESINLINE}inline;{$endif}
function HashOfIndex(Index: Integer): LongWord; {$ifdef CCLASSESINLINE}inline;{$endif}
function GetNextCollision(Index: Integer): Integer; {$ifdef CCLASSESINLINE}inline;{$endif}
procedure Delete(Index: Integer);
function Expand: TFPHashObjectList; {$ifdef CCLASSESINLINE}inline;{$endif}
function Extract(Item: TObject): TObject; {$ifdef CCLASSESINLINE}inline;{$endif}
@ -479,7 +481,7 @@ type
{ ---------------------------------------------------------------------
Bucket lists as in Delphi
---------------------------------------------------------------------}
Type
TBucketItem = record
@ -535,7 +537,7 @@ Type
{ ---------------------------------------------------------------------
TBucketList
---------------------------------------------------------------------}
TBucketListSizes = (bl2, bl4, bl8, bl16, bl32, bl64, bl128, bl256);
@ -553,7 +555,7 @@ Type
{ ---------------------------------------------------------------------
TObjectBucketList
---------------------------------------------------------------------}
{ TObjectBucketList }
TObjectBucketList = class(TBucketList)
@ -1144,26 +1146,6 @@ end;
TFPHashList
*****************************************************************************}
function FPHash1(const s:shortstring):LongWord;
Var
g : LongWord;
p,pmax : pchar;
begin
result:=0;
p:=@s[1];
pmax:=@s[length(s)+1];
while (p<pmax) do
begin
result:=result shl 4 + LongWord(p^);
g:=result and LongWord($F0000000);
if g<>0 then
result:=result xor (g shr 24) xor g;
inc(p);
end;
If result=0 then
result:=$ffffffff;
end;
function FPHash(const s:shortstring):LongWord;
Var
p,pmax : pchar;
@ -1177,7 +1159,28 @@ end;
pmax:=@s[length(s)+1];
while (p<pmax) do
begin
result:=LongWord((result shl 5) - result) xor LongWord(P^);
result:=LongWord(LongInt(result shl 5) - LongInt(result)) xor LongWord(P^);
inc(p);
end;
{$ifdef overflowon}
{$Q+}
{$undef overflowon}
{$endif}
end;
function FPHash(P: PChar; Len: Integer): LongWord;
Var
pmax : pchar;
begin
{$ifopt Q+}
{$define overflowon}
{$Q-}
{$endif}
result:=0;
pmax:=p+len;
while (p<pmax) do
begin
result:=LongWord(LongInt(result shl 5) - LongInt(result)) xor LongWord(P^);
inc(p);
end;
{$ifdef overflowon}
@ -1205,7 +1208,7 @@ procedure TFPHashList.Put(Index: Integer; Item: Pointer);
begin
if (Index < 0) or (Index >= FCount) then
RaiseIndexError(Index);
FHashList^[Index].Data:=Item;;
FHashList^[Index].Data:=Item;
end;
@ -1231,6 +1234,14 @@ begin
end;
function TFPHashList.GetNextCollision(Index: Integer): Integer;
begin
Result:=-1;
if ((Index > -1) and (Index < FCount)) then
Result:=FHashList^[Index].NextIndex;
end;
function TFPHashList.Extract(item: Pointer): Pointer;
var
i : Integer;
@ -1253,6 +1264,9 @@ begin
exit;
ReallocMem(FHashList, NewCapacity*SizeOf(THashItem));
FCapacity := NewCapacity;
{ Maybe expand hash also }
if FCapacity>FHashCapacity*MaxItemsPerHash then
SetHashCapacity(FCapacity div MaxItemsPerHash);
end;
@ -1424,9 +1438,6 @@ begin
else if FCapacity >= sizeof(ptrint) then
inc(IncSize,sizeof(ptrint));
SetCapacity(FCapacity + IncSize);
{ Maybe expand hash also }
if FCount>FHashCapacity*MaxItemsPerHash then
SetHashCapacity(FCount div MaxItemsPerHash);
end;
procedure TFPHashList.StrExpand(MinIncSize:Integer);
@ -1795,6 +1806,11 @@ begin
Result := FHashList.HashOfIndex(Index);
end;
function TFPHashObjectList.GetNextCollision(Index: Integer): Integer;
begin
Result := FHashList.GetNextCollision(Index);
end;
procedure TFPHashObjectList.Delete(Index: Integer);
begin
if OwnsObjects then
@ -2476,11 +2492,11 @@ end;
function TCustomBucketList.AddItem(ABucket: Integer; AItem, AData: Pointer
): Pointer;
Var
B : PBucket;
L : Integer;
begin
B:=@FBuckets[ABucket];
L:=Length(B^.Items);
@ -2502,11 +2518,11 @@ begin
end;
function TCustomBucketList.DeleteItem(ABucket: Integer; AIndex: Integer): Pointer;
Var
B : PBucket;
L : Integer;
begin
B:=@FBuckets[ABucket];
Result:=B^.Items[Aindex].Data;
@ -2528,11 +2544,11 @@ end;
function TCustomBucketList.FindItem(AItem: Pointer; out ABucket, AIndex: Integer
): Boolean;
Var
I : Integer;
B : TBucket;
begin
ABucket:=BucketFor(AItem);
B:=FBuckets[ABucket];
@ -2616,11 +2632,11 @@ end;
function TCustomBucketList.ForEach(AProc: TBucketProc; AInfo: Pointer
): Boolean;
Var
I,J,S : Integer;
Bu : TBucket;
begin
I:=0;
Result:=True;
@ -2690,7 +2706,7 @@ constructor TBucketList.Create(ABuckets: TBucketListSizes);
Var
L : Integer;
begin
Inherited Create;
L:=1 shl (Ord(Abuckets)+1);

View File

@ -0,0 +1,57 @@
{$mode objfpc}
uses
SysUtils,Contnrs;
var
colls : Integer;
// Test for Hashing
procedure Test;
var HL:TFPHashList;
i,n:integer;
dat:array[0..5]of pinteger;
begin
HL:=TFpHashList.Create;
HL.Capacity:=389;
// Create pointer for data
for i:=0 to 5 do
begin
dat[i]:=new(pinteger);
dat[i]^:=i;
end;
// add A..F with pointer
for i:=0 to 5 do
Writeln('HL.Add: '+chr(i+65)+' = Index: '
+IntToStr(HL.Add(chr(i+65),dat[i])));
// get collisions
for i:=0 to 5 do
begin
Writeln('--------------');
Writeln('Collision for Index: '+IntToStr(i));
n:=HL.FindIndexOf(chr(i+65));
while n>=0 do
begin
Writeln('Index: '+IntToStr(n)+
' | NameOfIndex: '+HL.NameOfIndex(n)+
' | HashOfIndex: '+IntToStr(HL.HashOfIndex(n))+
' | NextCollision: '+IntToStr(HL.GetNextCollision(n)));
n:=HL.GetNextCollision(n);
if n<>-1 then
inc(colls);
end; //while
end; //for
HL.Free;
for i:=0 to 5 do dispose(dat[i]);
end;
begin
Test;
if colls>0 then
halt(1);
end.