📄 stdict.pas
字号:
procedure TStDictionary.Clear;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
if FCount <> 0 then begin
Iterate(DestroyNode, nil);
FCount := 0;
FillChar(dySymbols^, LongInt(FHashSize)*SizeOf(TStDictNode), 0);
end;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
constructor TStDictionary.Create(AHashSize : Integer);
begin
CreateContainer(TStDictNode, 0);
{FHashSize := 0;}
{$IFDEF WStrings}
FEqual := AnsiCompareTextShort32;
{$ELSE}
FEqual := AnsiCompareText;
{$ENDIF}
FHash := AnsiHashText;
HashSize := AHashSize;
end;
procedure TStDictionary.Delete(const Name : string);
var
H : Integer;
P, T : TStDictNode;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
dyFindNode(Name, H, P, T);
if Assigned(T) then begin
if Assigned(P) then
P.dnNext := T.dnNext
else
dySymbols^[H] := T.dnNext;
DestroyNode(Self, T, nil);
Dec(FCount);
end;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
destructor TStDictionary.Destroy;
begin
if conNodeProt = 0 then
Clear;
if Assigned(dySymbols) then
FreeMem(dySymbols, LongInt(FHashSize)*SizeOf(TStDictNode));
IncNodeProtection;
inherited Destroy;
end;
function TStDictionary.DoEqual(const String1, String2 : string) : Integer;
begin
Result := 0;
if Assigned(FOnEqual) then
FOnEqual(Self, String1, String2, Result)
else if Assigned(FEqual) then
Result := FEqual(String1, String2);
end;
procedure TStDictionary.dyFindNode(const Name : string; var H : Integer;
var Prev, This : TStDictNode);
var
P, T : TStDictNode;
begin
Prev := nil;
This := nil;
H := Hash(Name, HashSize);
T := dySymbols^[H];
P := nil;
while Assigned(T) do begin
{$IFDEF HStrings}
if DoEqual(Name, T.dnName) = 0 then begin
{$ELSE}
if DoEqual(Name, T.dnName^) = 0 then begin
{$ENDIF}
Prev := P;
This := T;
Exit;
end;
P := T;
T := T.dnNext;
end;
{Not found}
This := nil;
end;
procedure TStDictionary.dySetEqual(E : TStringCompareFunc);
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
if Count = 0 then
FEqual := E;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
procedure TStDictionary.dySetHash(H : TDictHashFunc);
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
if Count = 0 then
FHash := H;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
procedure TStDictionary.dySetHashSize(Size : Integer);
var
H, OldSize : Integer;
TableSize : LongInt;
T, N : TStDictNode;
OldSymbols : PSymbolArray;
OldDisposeData : TDisposeDataProc;
OldOnDisposeData : TStDisposeDataEvent;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
TableSize := LongInt(Size)*SizeOf(TStDictNode);
if (Size <= 0) {or (TableSize > MaxBlockSize)} then
RaiseContainerError(stscBadSize);
if Size <> FHashSize then begin
OldSymbols := dySymbols;
OldSize := FHashSize;
{Get a new hash table}
GetMem(dySymbols, TableSize);
FillChar(dySymbols^, TableSize, 0);
FCount := 0;
FHashSize := Size;
if OldSize <> 0 then begin
{Prevent disposing of the user data while transferring elements}
OldDisposeData := DisposeData;
DisposeData := nil;
OldOnDisposeData := OnDisposeData;
OnDisposeData := nil;
{Add old symbols into new hash table}
for H := 0 to OldSize-1 do begin
T := OldSymbols^[H];
while Assigned(T) do begin
{$IFDEF HStrings}
Add(T.dnName, T.Data);
{$ELSE}
Add(T.dnName^, T.Data);
{$ENDIF}
N := T.dnNext;
{free the node just transferred}
T.Free;
T := N;
end;
end;
{Dispose of old hash table}
FreeMem(OldSymbols, OldSize*SizeOf(TStDictNode));
{Reassign the dispose data routine}
DisposeData := OldDisposeData;
OnDisposeData := OldOnDisposeData;
end;
{FHashSize := Size;}
end;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
function TStDictionary.Exists(const Name : string; var Data : Pointer) : Boolean;
var
H : Integer;
P, T : TStDictNode;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
dyFindNode(Name, H, P, T);
if Assigned(T) then begin
if Assigned(P) then begin
{Move T to front of list}
P.dnNext := T.dnNext;
T.dnNext := dySymbols^[H];
dySymbols^[H] := T;
end;
Result := True;
Data := T.Data;
end else
Result := False;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
function TStDictionary.Find(Data : Pointer; var Name : string) : Boolean;
var
T : TStDictNode;
begin
Name := '';
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
T := Iterate(FindNodeData, Data);
if Assigned(T) then begin
Result := True;
{$IFDEF HStrings}
Name := T.dnName;
{$ELSE}
Name := T.dnName^;
{$ENDIF}
end else
Result := False;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
procedure TStDictionary.GetItems(S : TStrings);
var
H : Integer;
T : TStDictNode;
begin
S.Clear;
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
if FCount <> 0 then begin
for H := 0 to FHashSize-1 do begin
T := dySymbols^[H];
while Assigned(T) do begin
S.AddObject(T.Name, T.Data);
T := T.dnNext;
end;
end;
end;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
procedure TStDictionary.SetItems(S : TStrings);
var
I : Integer;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
Clear;
for I := 0 to S.Count-1 do
Add(S.Strings[I], S.Objects[I]);
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
function TStDictionary.Iterate(Action : TIterateFunc;
OtherData : Pointer) : TStDictNode;
var
H : Integer;
T, N : TStDictNode;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
if FCount <> 0 then begin
for H := 0 to FHashSize-1 do begin
T := dySymbols^[H];
while Assigned(T) do begin
N := T.dnNext;
if Action(Self, T, OtherData) then
T := N
else begin
Result := T;
Exit;
end;
end;
end;
end;
Result := nil;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
procedure TStDictionary.Join(D : TStDictionary; IgnoreDups : Boolean);
begin
{$IFDEF ThreadSafe}
EnterClassCS;
EnterCS;
D.EnterCS;
try
{$ENDIF}
dyIgnoreDups := IgnoreDups;
D.Iterate(JoinNode, Self);
{Dispose of D, but not its nodes}
D.IncNodeProtection;
D.Free;
{$IFDEF ThreadSafe}
finally
D.LeaveCS;
LeaveCS;
LeaveClassCS;
end;
{$ENDIF}
end;
procedure TStDictionary.Update(const Name : string; Data : Pointer);
var
H : Integer;
P, T : TStDictNode;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
dyFindNode(Name, H, P, T);
if Assigned(T) then
T.Data := Data;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
procedure TStDictionary.LoadFromStream(S : TStream);
var
Data : pointer;
Reader : TReader;
StreamedClass : TPersistentClass;
StreamedNodeClass : TPersistentClass;
StreamedClassName : string;
StreamedNodeClassName : string;
St : string;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
Clear;
Reader := TReader.Create(S, 1024);
try
with Reader do
begin
StreamedClassName := ReadString;
StreamedClass := GetClass(StreamedClassName);
if (StreamedClass = nil) then
RaiseContainerErrorFmt(stscUnknownClass, [StreamedClassName]);
if (StreamedClass <> Self.ClassType) then
RaiseContainerError(stscWrongClass);
StreamedNodeClassName := ReadString;
StreamedNodeClass := GetClass(StreamedNodeClassName);
if (StreamedNodeClass = nil) then
RaiseContainerErrorFmt(stscUnknownNodeClass, [StreamedNodeClassName]);
if (StreamedNodeClass <> conNodeClass) then
RaiseContainerError(stscWrongNodeClass);
HashSize := ReadInteger;
ReadListBegin;
while not EndOfList do
begin
St := ReadString;
Data := DoLoadData(Reader);
Add(St, Data);
end;
ReadListEnd;
end;
finally
Reader.Free;
end;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
procedure TStDictionary.StoreToStream(S : TStream);
var
H : Integer;
Walker : TStDictNode;
Writer : TWriter;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
Writer := TWriter.Create(S, 1024);
try
with Writer do
begin
WriteString(Self.ClassName);
WriteString(conNodeClass.ClassName);
WriteInteger(HashSize);
WriteListBegin;
if (Count <> 0) then
for H := 0 to FHashSize-1 do
begin
Walker := dySymbols^[H];
while Assigned(Walker) do
begin
{$IFDEF HStrings}
WriteString(Walker.dnName);
{$ELSE}
WriteString(Walker.dnName^);
{$ENDIF}
DoStoreData(Writer, Walker.Data);
Walker := Walker.dnNext;
end;
end;
WriteListEnd;
end;
finally
Writer.Free;
end;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
{$IFDEF ThreadSafe}
initialization
Windows.InitializeCriticalSection(ClassCritSect);
finalization
Windows.DeleteCriticalSection(ClassCritSect);
{$ENDIF}
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -