mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-17 00:29:28 +02:00
MG: accelerated dynhasharray, fixed codetools defines editor initial resize
git-svn-id: trunk@1527 -
This commit is contained in:
parent
43f1cb10d1
commit
0feefa6634
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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+}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user