MG: accelerated dynhasharray, fixed codetools defines editor initial resize

git-svn-id: trunk@1527 -
This commit is contained in:
lazarus 2002-03-20 16:38:37 +00:00
parent 43f1cb10d1
commit 0feefa6634
5 changed files with 302 additions and 79 deletions

View File

@ -208,7 +208,7 @@ type
procedure SetShortCut(Value: TShortCut); procedure SetShortCut(Value: TShortCut);
public public
constructor Create(AOwner: TComponent); override; constructor Create(AOwner: TComponent); override;
destructor destroy; override; destructor Destroy; override;
property Editors[i: integer]: TCustomSynEdit read GetEditor; property Editors[i: integer]: TCustomSynEdit read GetEditor;
procedure AddEditor(aEditor: TCustomSynEdit); procedure AddEditor(aEditor: TCustomSynEdit);
function RemoveEditor(aEditor: TCustomSynEdit): boolean; function RemoveEditor(aEditor: TCustomSynEdit): boolean;
@ -260,8 +260,10 @@ type
procedure PrettyTextOut(c: TCanvas; x, y: integer; s: string); procedure PrettyTextOut(c: TCanvas; x, y: integer; s: string);
implementation implementation
uses uses
SynEditStrConst; SynEditStrConst;
@ -273,7 +275,7 @@ begin
CreateNew(AOwner, 0); CreateNew(AOwner, 0);
{$ELSE} {$ELSE}
{$IFDEF FPC} {$IFDEF FPC}
CreateNew(AOwner,0); CreateNew(AOwner,0);
{$ELSE} {$ELSE}
CreateNew(AOwner); CreateNew(AOwner);
{$ENDIF} {$ENDIF}
@ -613,10 +615,15 @@ begin
OnValidate(Form, []); OnValidate(Form, []);
exit; exit;
end; end;
// ToDo: redirect the Editor input to the form
Form.SetBounds(x,y,Form.Width,Form.Height);
{$ELSE}
Form.Left:=x;
Form.Top:=y;
{$ENDIF} {$ENDIF}
form.top := y; Form.Show;
form.left := x;
form.Show;
end; end;
function TSynBaseCompletion.GetCurrentString: string; function TSynBaseCompletion.GetCurrentString: string;

View File

@ -1538,7 +1538,7 @@ begin
CreateComponents; CreateComponents;
end; end;
FDefineTree:=TDefineTree.Create; FDefineTree:=TDefineTree.Create;
Resize; FormResize(Self);
end; end;
destructor TCodeToolsDefinesEditor.Destroy; destructor TCodeToolsDefinesEditor.Destroy;

View File

@ -67,7 +67,6 @@ type
FirstLine, LastLine: integer); override; FirstLine, LastLine: integer); override;
procedure LinesInserted(FirstLine, Count: integer); override; procedure LinesInserted(FirstLine, Count: integer); override;
procedure LinesDeleted(FirstLine, Count: integer); override; procedure LinesDeleted(FirstLine, Count: integer); override;
protected
public public
property OnLinesInserted : TOnLinesInsertedDeleted read FOnLinesinserted write FOnLinesInserted; property OnLinesInserted : TOnLinesInsertedDeleted read FOnLinesinserted write FOnLinesInserted;
property OnLinesDeleted : TOnLinesInsertedDeleted read FOnLinesDeleted write FOnLinesDeleted; property OnLinesDeleted : TOnLinesInsertedDeleted read FOnLinesDeleted write FOnLinesDeleted;
@ -3017,8 +3016,7 @@ begin
FHintTimer.Enabled := False; FHintTimer.Enabled := False;
FHintTimer.Enabled := EditorOpts.AutoToolTipSymbTools FHintTimer.Enabled := EditorOpts.AutoToolTipSymbTools
and (not ((ssLeft in Shift) or (ssRight in Shift) and ([ssLeft,ssRight,ssMiddle]*Shift=[]);
or (ssMiddle in Shift)));
end; end;
Procedure TSourceNotebook.HintTimer(sender : TObject); Procedure TSourceNotebook.HintTimer(sender : TObject);
@ -3074,7 +3072,6 @@ begin
Rect.Right := Rect.Left + Rect.Right+3; Rect.Right := Rect.Left + Rect.Right+3;
Rect.Bottom := Rect.Top + Rect.Bottom+3; Rect.Bottom := Rect.Top + Rect.Bottom+3;
FHintWindow.ActivateHint(Rect,AHint); FHintWindow.ActivateHint(Rect,AHint);
end; end;
Procedure TSourceNotebook.EditorMouseDown(Sender : TObject; Procedure TSourceNotebook.EditorMouseDown(Sender : TObject;
@ -3186,32 +3183,6 @@ begin
if (Key=VK_ESCAPE) then ModalResult:=mrCancel; if (Key=VK_ESCAPE) then ModalResult:=mrCancel;
end; end;
//-----------------------------------------------------------------------------
procedure InternalInit;
var h: TLazSyntaxHighlighter;
begin
for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do
Highlighters[h]:=nil;
aCompletion:=nil;
scompl:=nil;
GotoDialog:=nil;
IdentCompletionTimer:=nil;
AWordCompletion:=nil;
end;
procedure InternalFinal;
var h: TLazSyntaxHighlighter;
begin
for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do begin
Highlighters[h].Free;
Highlighters[h]:=nil;
end;
aWordCompletion.Free;
aWordCompletion:=nil;
end;
{ TSynEditPlugin1 } { TSynEditPlugin1 }
constructor TSynEditPlugin1.Create(AOwner: TCustomSynEdit); constructor TSynEditPlugin1.Create(AOwner: TCustomSynEdit);
@ -3238,7 +3209,33 @@ begin
OnLinesInserted(self,Firstline,Count); OnLinesInserted(self,Firstline,Count);
end; end;
initialization //-----------------------------------------------------------------------------
procedure InternalInit;
var h: TLazSyntaxHighlighter;
begin
for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do
Highlighters[h]:=nil;
aCompletion:=nil;
scompl:=nil;
GotoDialog:=nil;
IdentCompletionTimer:=nil;
AWordCompletion:=nil;
end;
procedure InternalFinal;
var h: TLazSyntaxHighlighter;
begin
for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do begin
Highlighters[h].Free;
Highlighters[h]:=nil;
end;
aWordCompletion.Free;
aWordCompletion:=nil;
end;
initialization
InternalInit; InternalInit;
{$I images/bookmark.lrs} {$I images/bookmark.lrs}
@ -3248,5 +3245,3 @@ finalization
end. end.

View File

@ -7,7 +7,7 @@
It supports Add, Remove, Contains, First, Count and Clear. It supports Add, Remove, Contains, First, Count and Clear.
Because of the hashing nature the operations adding, removing and finding is Because of the hashing nature the operations adding, removing and finding is
done in constant time on average. done in constant time on average.
Inner structure: Inner structure:
There are three parts: There are three parts:
1. The array itself (FItems). Every entry is a pointer to the first 1. The array itself (FItems). Every entry is a pointer to the first
@ -27,6 +27,9 @@
Issues: Issues:
The maximum capacity is the PrimeNumber. You can store more items, but the The maximum capacity is the PrimeNumber. You can store more items, but the
performance decreases. The best idea is to provide your own hash function. performance decreases. The best idea is to provide your own hash function.
Important: Items in the TDynHashArray must not change their key.
When changing the key of an item, remove it and add it after the change.
} }
unit DynHashArray; unit DynHashArray;
@ -35,10 +38,15 @@ unit DynHashArray;
interface interface
uses Classes; uses Classes, SysUtils;
type type
THashFunction = function(Item: Pointer): integer of object; TDynHashArray = class;
THashMethod = function(Sender: TDynHashArray; Item: Pointer): integer of object;
THashFunction = function(Sender: TDynHashArray; Item: Pointer): integer;
TOwnerHashFunction = function(Item: Pointer): integer of object;
TOnGetKeyForHashItem = function(Item: pointer): pointer;
PDynHashArrayItem = ^TDynHashArrayItem; PDynHashArrayItem = ^TDynHashArrayItem;
TDynHashArrayItem = record TDynHashArrayItem = record
@ -46,6 +54,9 @@ type
Next, Prior: PDynHashArrayItem; Next, Prior: PDynHashArrayItem;
IsOverflow: boolean; IsOverflow: boolean;
end; end;
TDynHashArrayOption = (dhaoCachingEnabled);
TDynHashArrayOptions = set of TDynHashArrayOption;
TDynHashArray = class TDynHashArray = class
private private
@ -57,33 +68,60 @@ type
FFreeCount: integer; FFreeCount: integer;
FFirstItem: PDynHashArrayItem; FFirstItem: PDynHashArrayItem;
FFirstFreeItem: PDynHashArrayItem; FFirstFreeItem: PDynHashArrayItem;
FHashCacheItem: Pointer;
FHashCacheIndex: integer;
FLowWaterMark: integer; FLowWaterMark: integer;
FHighWaterMark: integer; FHighWaterMark: integer;
FOwnerHashFunction: THashFunction; FCustomHashFunction: THashFunction;
function IndexOf(AnItem: Pointer): integer; FCustomHashMethod: THashMethod;
FOnGetKeyForHashItem: TOnGetKeyForHashItem;
FOptions: TDynHashArrayOptions;
FOwnerHashFunction: TOwnerHashFunction;
function NewHashItem: PDynHashArrayItem; function NewHashItem: PDynHashArrayItem;
procedure DisposeHashItem(ADynHashArrayItem: PDynHashArrayItem); procedure DisposeHashItem(ADynHashArrayItem: PDynHashArrayItem);
procedure DisposeFirstFreeItem; procedure DisposeFirstFreeItem;
procedure ComputeWaterMarks; procedure ComputeWaterMarks;
procedure SetCapacity(NewCapacity: integer); procedure SetCapacity(NewCapacity: integer);
procedure SetCustomHashFunction(const AValue: THashFunction);
procedure SetCustomHashMethod(const AValue: THashMethod);
procedure SetOnGetKeyForHashItem(const AValue: TOnGetKeyForHashItem);
procedure SetOptions(const AValue: TDynHashArrayOptions);
procedure SetOwnerHashFunction(const AValue: TOwnerHashFunction);
protected
procedure RebuildItems;
procedure SaveCacheItem(Item: Pointer; Index: integer);
public public
procedure Add(Item: Pointer); procedure Add(Item: Pointer);
function Contains(Item: Pointer): boolean; function Contains(Item: Pointer): boolean;
function ContainsKey(Key: Pointer): boolean;
procedure Remove(Item: Pointer); procedure Remove(Item: Pointer);
procedure Clear; procedure Clear;
procedure ClearCache;
function First: Pointer; function First: Pointer;
property Count: integer read fCount; property Count: integer read fCount;
function IndexOf(AnItem: Pointer): integer;
function IndexOfKey(Key: Pointer): integer;
function FindHashItem(Item: Pointer): PDynHashArrayItem; function FindHashItem(Item: Pointer): PDynHashArrayItem;
function FindHashItemWithKey(Key: Pointer): PDynHashArrayItem;
property FirstHashItem: PDynHashArrayItem read FFirstItem; property FirstHashItem: PDynHashArrayItem read FFirstItem;
function GetHashItem(HashIndex: integer): PDynHashArrayItem; function GetHashItem(HashIndex: integer): PDynHashArrayItem;
procedure Delete(ADynHashArrayItem: PDynHashArrayItem); procedure Delete(ADynHashArrayItem: PDynHashArrayItem);
property MinCapacity: integer read FMinCapacity write FMinCapacity; property MinCapacity: integer read FMinCapacity write FMinCapacity;
property MaxCapacity: integer read FMaxCapacity write FMaxCapacity; property MaxCapacity: integer read FMaxCapacity write FMaxCapacity;
property Capacity: integer read FCapacity; property Capacity: integer read FCapacity;
property OwnerHashFunction: THashFunction property CustomHashFunction: THashFunction
read FOwnerHashFunction write FOwnerHashFunction; read FCustomHashFunction write SetCustomHashFunction;
property CustomHashMethod: THashMethod
read FCustomHashMethod write SetCustomHashMethod;
property OwnerHashFunction: TOwnerHashFunction
read FOwnerHashFunction write SetOwnerHashFunction;
property OnGetKeyForHashItem: TOnGetKeyForHashItem
read FOnGetKeyForHashItem write SetOnGetKeyForHashItem;
property Options: TDynHashArrayOptions read FOptions write SetOptions;
constructor Create(InitialMinCapacity: integer); constructor Create(InitialMinCapacity: integer);
destructor Destroy; override; destructor Destroy; override;
function SlowAlternativeHashMethod(Sender: TDynHashArray;
Item: Pointer): integer;
function ConsistencyCheck: integer; function ConsistencyCheck: integer;
procedure WriteDebugReport; procedure WriteDebugReport;
end; end;
@ -97,10 +135,10 @@ const
{ TDynHashArray } { TDynHashArray }
procedure TDynHashArray.WriteDebugReport; procedure TDynHashArray.WriteDebugReport;
var i: integer; var i, RealHashIndex: integer;
HashItem: PDynHashArrayItem; HashItem: PDynHashArrayItem;
begin begin
writeln('Report: Consistency=',ConsistencyCheck); writeln('TDynHashArray.WriteDebugReport: Consistency=',ConsistencyCheck);
writeln(' Count=',FCount,' FreeCount=',FFreeCount,' Capacity=',FCapacity); writeln(' Count=',FCount,' FreeCount=',FFreeCount,' Capacity=',FCapacity);
for i:=0 to FCapacity-1 do begin for i:=0 to FCapacity-1 do begin
HashItem:=FItems[i]; HashItem:=FItems[i];
@ -108,6 +146,8 @@ begin
write(' Index=',i); write(' Index=',i);
while HashItem<>nil do begin while HashItem<>nil do begin
write(' ',HexStr(Cardinal(HashItem^.Item),8)); write(' ',HexStr(Cardinal(HashItem^.Item),8));
RealHashIndex:=IndexOf(HashItem^.Item);
if RealHashIndex<>i then write('(H=',RealHashIndex,')');
HashItem:=HashItem^.Next; HashItem:=HashItem^.Next;
if (HashItem<>nil) and (HashItem^.IsOverflow=false) then break; if (HashItem<>nil) and (HashItem^.IsOverflow=false) then break;
end; end;
@ -140,6 +180,7 @@ begin
FFirstItem:=nil; FFirstItem:=nil;
FFirstFreeItem:=nil; FFirstFreeItem:=nil;
ComputeWaterMarks; ComputeWaterMarks;
FHashCacheIndex:=-1;
end; end;
destructor TDynHashArray.Destroy; destructor TDynHashArray.Destroy;
@ -152,42 +193,84 @@ end;
function TDynHashArray.ConsistencyCheck: integer; function TDynHashArray.ConsistencyCheck: integer;
var RealCount, RealFreeCount, i: integer; var RealCount, RealFreeCount, i: integer;
HashItem: PDynHashArrayItem; HashItem, HashItem2: PDynHashArrayItem;
OldCacheItem: pointer;
OldCacheIndex: integer;
begin begin
RealCount:=0; RealCount:=0;
// check first item
if (FFirstItem<>nil) and (FFirstItem^.IsOverflow) then
exit(-1);
if (FItems=nil) and (FFirstItem<>nil) then
exit(-2);
// check for doubles and circles
HashItem:=FFirstItem;
while HashItem<>nil do begin
HashItem2:=HashItem^.Prior;
while HashItem2<>nil do begin
if HashItem=HashItem2 then
exit(-3); // circle
if HashItem^.Item=HashItem2^.Item then
exit(-4); // double item
HashItem2:=HashItem2^.Prior;
end;
HashItem2:=FFirstFreeItem;
while HashItem2<>nil do begin
if HashItem=HashItem2 then
exit(-5); // freed and used at the same time
HashItem2:=HashItem2^.Next;
end;
HashItem:=HashItem^.Next;
end;
// check chain
HashItem:=FFirstItem; HashItem:=FFirstItem;
while HashItem<>nil do begin while HashItem<>nil do begin
inc(RealCount); inc(RealCount);
if (HashItem^.Next<>nil) and (HashItem^.Next^.Prior<>HashItem) then if (HashItem^.Next<>nil) and (HashItem^.Next^.Prior<>HashItem) then
exit(-1); exit(-6);
if (HashItem^.Prior<>nil) and (HashItem^.Prior^.Next<>HashItem) then if (HashItem^.Prior<>nil) and (HashItem^.Prior^.Next<>HashItem) then
exit(-2); exit(-7);
if (HashItem^.IsOverflow=false) if (HashItem^.IsOverflow=false)
and (FItems[IndexOf(HashItem^.Item)]<>HashItem) then and (FItems[IndexOf(HashItem^.Item)]<>HashItem) then
exit (-3); exit(-8);
HashItem:=HashItem^.Next; HashItem:=HashItem^.Next;
end; end;
if RealCount<>FCount then exit(-4); // check count
if RealCount<>FCount then exit(-9);
RealFreeCount:=0; RealFreeCount:=0;
// check freed items
HashItem:=FFirstFreeItem; HashItem:=FFirstFreeItem;
while HashItem<>nil do begin while HashItem<>nil do begin
inc(RealFreeCount); inc(RealFreeCount);
if (HashItem^.Next<>nil) and (HashItem^.Next^.Prior<>HashItem) then if (HashItem^.Next<>nil) and (HashItem^.Next^.Prior<>HashItem) then
exit(-5); exit(-10);
if (HashItem^.Prior<>nil) and (HashItem^.Prior^.Next<>HashItem) then if (HashItem^.Prior<>nil) and (HashItem^.Prior^.Next<>HashItem) then
exit(-6); exit(-11);
HashItem:=HashItem^.Next; HashItem:=HashItem^.Next;
end; end;
if RealFreeCount<>FFreeCount then exit(-7); if RealFreeCount<>FFreeCount then exit(-12);
if FCount+FFreeCount>FCapacity then exit(-8); if FCount+FFreeCount>FCapacity then exit(-13);
// check FItems
RealCount:=0;
for i:=0 to FCapacity-1 do begin for i:=0 to FCapacity-1 do begin
HashItem:=FItems[i]; HashItem:=FItems[i];
while HashItem<>nil do begin while HashItem<>nil do begin
if IndexOf(HashItem^.Item)<>i then exit(-9); inc(RealCount);
if IndexOf(HashItem^.Item)<>i then exit(-14);
HashItem:=HashItem^.Next; HashItem:=HashItem^.Next;
if (HashItem<>nil) and (HashItem^.IsOverflow=false) then break; if (HashItem<>nil) and (HashItem^.IsOverflow=false) then break;
end; end;
end; end;
if RealCount<>FCount then exit(-15);
// check cache
if FHashCacheIndex>=0 then begin
OldCacheItem:=FHashCacheItem;
OldCacheIndex:=FHashCacheIndex;
ClearCache;
FHashCacheIndex:=IndexOfKey(OldCacheItem);
if FHashCacheIndex<>OldCacheIndex then exit(-16);
FHashCacheItem:=OldCacheItem;
end;
Result:=0; Result:=0;
end; end;
@ -199,20 +282,48 @@ end;
function TDynHashArray.IndexOf(AnItem: Pointer): integer; function TDynHashArray.IndexOf(AnItem: Pointer): integer;
begin begin
if AnItem=nil then exit(-1); if (AnItem=nil) or (FItems=nil) then exit(-1);
if Assigned(FOwnerHashFunction) then if Assigned(OnGetKeyForHashItem) then begin
Result:=FOwnerHashFunction(AnItem) AnItem:=OnGetKeyForHashItem(AnItem);
end;
Result:=IndexOfKey(AnItem);
end;
function TDynHashArray.IndexOfKey(Key: Pointer): integer;
begin
if (FItems=nil)
or ((not Assigned(OnGetKeyForHashItem)) and (Key=nil)) then exit(-1);
if (dhaoCachingEnabled in Options)
and (Key=FHashCacheItem) and (FHashCacheIndex>=0) then
exit(FHashCacheIndex);
if Assigned(FCustomHashFunction) then
Result:=FCustomHashFunction(Self,Key)
else if Assigned(FCustomHashMethod) then
Result:=FCustomHashMethod(Self,Key)
else if Assigned(FOwnerHashFunction) then
Result:=FOwnerHashFunction(Key)
else else
Result:=integer((Cardinal(AnItem) mod Cardinal(PrimeNumber)) Result:=integer((Cardinal(Key) mod Cardinal(PrimeNumber))
+(Cardinal(AnItem) mod 17) +(Cardinal(Key) mod 17)
) mod FCapacity; ) mod FCapacity;
{if (Key=FHashCacheItem) and (FHashCacheIndex>=0)
and (Result<>FHashCacheIndex) then begin
writeln(' DAMN: ',HexStr(Cardinal(Key),8),' ',FHashCacheIndex,'<>',Result);
raise Exception.Create('GROSSER MIST');
end;}
end; end;
procedure TDynHashArray.Clear; procedure TDynHashArray.Clear;
begin begin
ClearCache;
while FFirstItem<>nil do Delete(FFirstItem); while FFirstItem<>nil do Delete(FFirstItem);
end; end;
procedure TDynHashArray.ClearCache;
begin
FHashCacheIndex:=-1;
end;
procedure TDynHashArray.Add(Item: Pointer); procedure TDynHashArray.Add(Item: Pointer);
var Index: integer; var Index: integer;
HashItem: PDynHashArrayItem; HashItem: PDynHashArrayItem;
@ -240,16 +351,27 @@ begin
HashItem^.Prior^.Next:=HashItem; HashItem^.Prior^.Next:=HashItem;
end; end;
inc(FCount); inc(FCount);
SaveCacheItem(Item,Index);
end;
function TDynHashArray.SlowAlternativeHashMethod(Sender: TDynHashArray;
Item: Pointer): integer;
begin
Result:=integer((Cardinal(Item) mod Cardinal(PrimeNumber))
+(Cardinal(Item) mod 17)+(Cardinal(Item) mod 173)
+(Cardinal(Item) mod 521)
) mod FCapacity;
end; end;
procedure TDynHashArray.Remove(Item: Pointer); procedure TDynHashArray.Remove(Item: Pointer);
var Index: integer; var Index: integer;
OldNext, Old: PDynHashArrayItem; OldNext, Old: PDynHashArrayItem;
begin begin
if Item=nil then exit; if (Item=nil) or (FItems=nil) then exit;
Index:=IndexOf(Item); Index:=IndexOf(Item);
if (Index<0) or (FItems[Index]=nil) then exit; if (Index<0) then exit;
Old:=FItems[Index]; Old:=FItems[Index];
if Old=nil then exit;
if Old^.Item=Item then begin if Old^.Item=Item then begin
OldNext:=Old^.Next; OldNext:=Old^.Next;
if (OldNext=nil) or (OldNext^.IsOverflow) then if (OldNext=nil) or (OldNext^.IsOverflow) then
@ -269,7 +391,16 @@ end;
procedure TDynHashArray.Delete(ADynHashArrayItem: PDynHashArrayItem); procedure TDynHashArray.Delete(ADynHashArrayItem: PDynHashArrayItem);
begin begin
if ADynHashArrayItem=nil then exit; if ADynHashArrayItem=nil then exit;
if (ADynHashArrayItem^.IsOverflow=false) and (ADynHashArrayItem^.Next<>nil) then if (FHashCacheIndex>=0)
and ((ADynHashArrayItem^.Item=FHashCacheItem)
or (Assigned(OnGetKeyForHashItem)
and (OnGetKeyForHashItem(ADynHashArrayItem^.Item)=FHashCacheItem)))
then
// if the user removes an item, changes the key and readds it, the hash
// can change for it, so the cache must be cleared
ClearCache;
if (ADynHashArrayItem^.IsOverflow=false) and (ADynHashArrayItem^.Next<>nil)
then
ADynHashArrayItem^.Next^.IsOverflow:=false; ADynHashArrayItem^.Next^.IsOverflow:=false;
if FFirstItem=ADynHashArrayItem then if FFirstItem=ADynHashArrayItem then
FFirstItem:=FFirstItem^.Next; FFirstItem:=FFirstItem^.Next;
@ -344,18 +475,50 @@ begin
Result:=FindHashItem(Item)<>nil; Result:=FindHashItem(Item)<>nil;
end; end;
function TDynHashArray.ContainsKey(Key: Pointer): boolean;
begin
Result:=FindHashItemWithKey(Key)<>nil;
end;
function TDynHashArray.FindHashItem(Item: Pointer): PDynHashArrayItem; function TDynHashArray.FindHashItem(Item: Pointer): PDynHashArrayItem;
var Index: integer; var Index: integer;
begin begin
if Item=nil then exit(nil); if (Item=nil) or (FItems=nil) then exit(nil);
Index:=IndexOf(Item); Index:=IndexOf(Item);
Result:=FItems[Index]; Result:=FItems[Index];
if (Result=nil) or (Result^.Item=Item) then exit; if (Result=nil) then exit;
repeat while (Result^.Item<>Item) do begin
Result:=Result^.Next; Result:=Result^.Next;
if Result=nil then break; if Result=nil then exit;
if Result^.IsOverflow=false then Result:=nil; if Result^.IsOverflow=false then begin
until (Result=nil) or (Result^.Item=Item); Result:=nil;
exit;
end;
end;
SaveCacheItem(Item,Index);
end;
function TDynHashArray.FindHashItemWithKey(Key: Pointer): PDynHashArrayItem;
var Index: integer;
begin
if FItems=nil then exit(nil);
Index:=IndexOfKey(Key);
Result:=FItems[Index];
if (Result=nil) then exit;
if Assigned(OnGetKeyForHashItem) then begin
if OnGetKeyForHashItem(Result^.Item)=Key then exit;
// search in overflow hash items
Result:=Result^.Next;
while (Result<>nil) and (Result^.IsOverflow) do begin
if OnGetKeyForHashItem(Result^.Item)=Key then begin
FHashCacheIndex:=Index;
FHashCacheItem:=Key;
exit;
end;
Result:=Result^.Next;
end;
Result:=nil;
end;
end; end;
function TDynHashArray.GetHashItem(HashIndex: integer): PDynHashArrayItem; function TDynHashArray.GetHashItem(HashIndex: integer): PDynHashArrayItem;
@ -364,8 +527,7 @@ begin
end; end;
procedure TDynHashArray.SetCapacity(NewCapacity: integer); procedure TDynHashArray.SetCapacity(NewCapacity: integer);
var Size, Index: integer; var Size: integer;
CurHashItem, NextHashItem: PDynHashArrayItem;
begin begin
if NewCapacity<FMinCapacity then NewCapacity:=FMinCapacity; if NewCapacity<FMinCapacity then NewCapacity:=FMinCapacity;
if NewCapacity>FMaxCapacity then NewCapacity:=FMaxCapacity; if NewCapacity>FMaxCapacity then NewCapacity:=FMaxCapacity;
@ -373,11 +535,37 @@ begin
// resize FItems // resize FItems
FreeMem(FItems); FreeMem(FItems);
FCapacity:=NewCapacity; FCapacity:=NewCapacity;
Size:=FCapacity * SizeOf(TDynHashArrayItem); Size:=FCapacity * SizeOf(PDynHashArrayItem);
GetMem(FItems,Size); GetMem(FItems,Size);
FillChar(FItems^,Size,0);
ComputeWaterMarks; ComputeWaterMarks;
// rebuild hash table (FItems) // rebuild
RebuildItems;
end;
procedure TDynHashArray.SetCustomHashFunction(const AValue: THashFunction);
begin
if FCustomHashFunction=AValue then exit;
FCustomHashFunction:=AValue;
FCustomHashMethod:=nil;
FOwnerHashFunction:=nil;
RebuildItems;
end;
procedure TDynHashArray.SetCustomHashMethod(const AValue: THashMethod);
begin
if FCustomHashMethod=AValue then exit;
FCustomHashFunction:=nil;
FCustomHashMethod:=AValue;
FOwnerHashFunction:=nil;
RebuildItems;
end;
procedure TDynHashArray.RebuildItems;
var Index: integer;
CurHashItem, NextHashItem: PDynHashArrayItem;
begin
FillChar(FItems^,FCapacity * SizeOf(PDynHashArrayItem),0);
ClearCache;
CurHashItem:=FFirstItem; CurHashItem:=FFirstItem;
FFirstItem:=nil; FFirstItem:=nil;
while CurHashItem<>nil do begin while CurHashItem<>nil do begin
@ -404,4 +592,37 @@ begin
end; end;
end; end;
procedure TDynHashArray.SaveCacheItem(Item: Pointer; Index: integer);
// Important:
// !!! Only call this method for items, that exists in the list or for items
// that can't change their key
begin
if Assigned(OnGetKeyForHashItem) then Item:=OnGetKeyForHashItem(Item);
FHashCacheItem:=Item;
FHashCacheIndex:=Index;
end;
procedure TDynHashArray.SetOnGetKeyForHashItem(
const AValue: TOnGetKeyForHashItem);
begin
if FOnGetKeyForHashItem=AValue then exit;
FOnGetKeyForHashItem:=AValue;
RebuildItems;
end;
procedure TDynHashArray.SetOptions(const AValue: TDynHashArrayOptions);
begin
FOptions:=AValue;
end;
procedure TDynHashArray.SetOwnerHashFunction(const AValue: TOwnerHashFunction);
begin
if FOwnerHashFunction=AValue then exit;
FCustomHashFunction:=nil;
FCustomHashMethod:=nil;
FOwnerHashFunction:=AValue;
RebuildItems;
end;
end. end.

View File

@ -7,7 +7,7 @@
First and getting Last in O(1). First and getting Last in O(1).
Finding can be done in time O(n). Finding can be done in time O(n).
} }
unit lazqueue; unit LazQueue;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}