Procházet zdrojové kódy

* force the size of TFPHashList always to a power of two, and use an "and"
instead of a "div" to truncate the hash to the table size
* prefetch the string we are looking for
- removed the optimization whereby the length and the last character are
checked before the entire string is compared during the hashtable
searching, because this does not help anymore (our hash funcion is
better than when this was added, and we also have a special "equals"
string comparison function nowadays that also first checks the length)

git-svn-id: trunk@15516 -

Jonas Maebe před 15 roky
rodič
revize
d432023cf6
1 změnil soubory, kde provedl 20 přidání a 18 odebrání
  1. 20 18
      compiler/cclasses.pas

+ 20 - 18
compiler/cclasses.pas

@@ -63,6 +63,7 @@ interface
 const
 const
    SListIndexError = 'List index exceeds bounds (%d)';
    SListIndexError = 'List index exceeds bounds (%d)';
    SListCapacityError = 'The maximum list capacity is reached (%d)';
    SListCapacityError = 'The maximum list capacity is reached (%d)';
+   SListCapacityPower2Error = 'The capacity has to be a power of 2, but is set to %d';
    SListCountError = 'List count too large (%d)';
    SListCountError = 'List count too large (%d)';
 type
 type
    EListError = class(Exception);
    EListError = class(Exception);
@@ -188,6 +189,7 @@ type
     FHashList     : PHashItemList;
     FHashList     : PHashItemList;
     FCount,
     FCount,
     FCapacity : Integer;
     FCapacity : Integer;
+    FCapacityMask: LongWord;
     { Hash }
     { Hash }
     FHashTable    : PHashTable;
     FHashTable    : PHashTable;
     FHashCapacity : Integer;
     FHashCapacity : Integer;
@@ -1194,8 +1196,13 @@ end;
 
 
 
 
 procedure TFPHashList.SetCapacity(NewCapacity: Integer);
 procedure TFPHashList.SetCapacity(NewCapacity: Integer);
+var
+  power: longint;
 begin
 begin
-  If (NewCapacity < FCount) or (NewCapacity > MaxHashListSize) then
+  { use a power of two to be able to quickly calculate the hash table index }
+  if NewCapacity <> 0 then
+    NewCapacity := nextpowerof2(NewCapacity div MaxItemsPerHash, power) * MaxItemsPerHash;
+  if (NewCapacity < FCount) or (NewCapacity > MaxHashListSize) then
      Error (SListCapacityError, NewCapacity);
      Error (SListCapacityError, NewCapacity);
   if NewCapacity = FCapacity then
   if NewCapacity = FCapacity then
     exit;
     exit;
@@ -1216,7 +1223,8 @@ begin
       If NewCount > FCapacity then
       If NewCount > FCapacity then
         SetCapacity(NewCount);
         SetCapacity(NewCount);
       If FCount < NewCount then
       If FCount < NewCount then
-        FillChar(FHashList^[FCount], (NewCount-FCount) div Sizeof(THashItem), 0);
+        { FCapacity is NewCount rounded up to the next power of 2 }
+        FillChar(FHashList^[FCount], (FCapacity-FCount) div Sizeof(THashItem), 0);
     end;
     end;
   FCount := Newcount;
   FCount := Newcount;
 end;
 end;
@@ -1234,13 +1242,19 @@ end;
 
 
 
 
 procedure TFPHashList.SetHashCapacity(NewCapacity: Integer);
 procedure TFPHashList.SetHashCapacity(NewCapacity: Integer);
+var
+  power: longint;
 begin
 begin
   If (NewCapacity < 1) then
   If (NewCapacity < 1) then
     Error (SListCapacityError, NewCapacity);
     Error (SListCapacityError, NewCapacity);
   if FHashCapacity=NewCapacity then
   if FHashCapacity=NewCapacity then
     exit;
     exit;
+  if (NewCapacity<>0) and
+     not ispowerof2(NewCapacity,power) then
+    Error(SListCapacityPower2Error, NewCapacity);
   FHashCapacity:=NewCapacity;
   FHashCapacity:=NewCapacity;
   ReallocMem(FHashTable, FHashCapacity*sizeof(Integer));
   ReallocMem(FHashTable, FHashCapacity*sizeof(Integer));
+  FCapacityMask:=(1 shl power)-1;
   ReHash;
   ReHash;
 end;
 end;
 
 
@@ -1291,7 +1305,7 @@ begin
     begin
     begin
       if not assigned(Data) then
       if not assigned(Data) then
         exit;
         exit;
-      HashIndex:=HashValue mod LongWord(FHashCapacity);
+      HashIndex:=HashValue and FCapacityMask;
       NextIndex:=FHashTable^[HashIndex];
       NextIndex:=FHashTable^[HashIndex];
       FHashTable^[HashIndex]:=Index;
       FHashTable^[HashIndex]:=Index;
     end;
     end;
@@ -1368,12 +1382,6 @@ begin
   if FCount < FCapacity then
   if FCount < FCapacity then
     exit;
     exit;
   IncSize := sizeof(ptrint)*2;
   IncSize := sizeof(ptrint)*2;
-  if FCapacity > 127 then
-    Inc(IncSize, FCapacity shr 2)
-  else if FCapacity > sizeof(ptrint)*3 then
-    Inc(IncSize, FCapacity shr 1)
-  else if FCapacity >= sizeof(ptrint) then
-    inc(IncSize,sizeof(ptrint));
   SetCapacity(FCapacity + IncSize);
   SetCapacity(FCapacity + IncSize);
 end;
 end;
 
 
@@ -1410,13 +1418,9 @@ end;
 function TFPHashList.InternalFind(AHash:LongWord;const AName:shortstring;out PrevIndex:Integer):Integer;
 function TFPHashList.InternalFind(AHash:LongWord;const AName:shortstring;out PrevIndex:Integer):Integer;
 var
 var
   HashIndex : Integer;
   HashIndex : Integer;
-  Len,
-  LastChar  : Char;
 begin
 begin
-  HashIndex:=AHash mod LongWord(FHashCapacity);
-  Result:=FHashTable^[HashIndex];
-  Len:=Char(Length(AName));
-  LastChar:=AName[Byte(Len)];
+  prefetch(AName);
+  Result:=FHashTable^[AHash and FCapacityMask];
   PrevIndex:=-1;
   PrevIndex:=-1;
   while Result<>-1 do
   while Result<>-1 do
     begin
     begin
@@ -1424,8 +1428,6 @@ begin
         begin
         begin
           if assigned(Data) and
           if assigned(Data) and
              (HashValue=AHash) and
              (HashValue=AHash) and
-             (Len=FStrs[StrIndex]) and
-             (LastChar=FStrs[StrIndex+Byte(Len)]) and
              (AName=PShortString(@FStrs[StrIndex])^) then
              (AName=PShortString(@FStrs[StrIndex])^) then
             exit;
             exit;
           PrevIndex:=Result;
           PrevIndex:=Result;
@@ -1484,7 +1486,7 @@ begin
   if PrevIndex<>-1 then
   if PrevIndex<>-1 then
     FHashList^[PrevIndex].NextIndex:=FHashList^[Index].NextIndex
     FHashList^[PrevIndex].NextIndex:=FHashList^[Index].NextIndex
   else
   else
-    FHashTable^[OldHash mod LongWord(FHashCapacity)]:=FHashList^[Index].NextIndex;
+    FHashTable^[OldHash and FCapacityMask]:=FHashList^[Index].NextIndex;
   { Set new name and hash }
   { Set new name and hash }
   with FHashList^[Index] do
   with FHashList^[Index] do
     begin
     begin