mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-06 14:05:58 +02:00
LazUtils: improve TDictionaryStringList
git-svn-id: trunk@40525 -
This commit is contained in:
parent
a0e36fb682
commit
d3515b51b0
@ -16,26 +16,20 @@
|
||||
|
||||
Abstract:
|
||||
This is an unsorted StringList with a fast lookup feature.
|
||||
Internally it uses a map container (TStringToPointerTree) to store the string again
|
||||
as key and string's index as value.
|
||||
It is then used for Contains, IndexOf and Find methods.
|
||||
Internally it uses a string->integer map container to store
|
||||
the string again as key and string's index as value.
|
||||
It is then used for InserItem, Contains, IndexOf and Find methods.
|
||||
|
||||
The extra container does not reserve too much memory because the strings are
|
||||
reference counted and not really copied.
|
||||
|
||||
The list cannot have duplicates.
|
||||
Duplicates property values dupIgnore and dupError are fully supported,
|
||||
unlike in unsorted StringList.
|
||||
|
||||
This list cannot be sorted. For a sorted list you should use normal TStringList.
|
||||
This class is useful only when you must preserve the order in list,
|
||||
but also need to do fast lookups to see if a string exists.
|
||||
|
||||
"Duplicates" values dupIgnore and dupError are supported, unlike in unsorted StringList.
|
||||
|
||||
Insert, Delete and Exchange are not supported yet. They require the map's
|
||||
index values to be adjusted. There are at least 3 ways to solve it:
|
||||
1. Adjust only the changed indexes after each operation.
|
||||
2. Mark the map's index values as "dirty" after those operations.
|
||||
Adjust all the indexes when IndexOf() or Find() is called for the first time.
|
||||
3. Decide that those operations are not needed.
|
||||
This is a very specialized container after all.
|
||||
This class is useful only when you must preserve the order in list, but
|
||||
also need to do fast lookups to see if a string exists, or must prevent duplicates.
|
||||
}
|
||||
unit DictionaryStringList;
|
||||
|
||||
@ -53,16 +47,17 @@ type
|
||||
TDictionaryStringList = class(TStringList)
|
||||
private
|
||||
FMap: TStringToPointerTree;
|
||||
function GetDuplicates: TDuplicates;
|
||||
function GetSorted: Boolean;
|
||||
procedure SetDuplicates(AValue: TDuplicates);
|
||||
procedure SetSorted(AValue: Boolean);
|
||||
procedure AdjustMap(StartIndex, Offset: Integer);
|
||||
protected
|
||||
// procedure InsertItem(Index: Integer; const S: string); override;
|
||||
// procedure InsertItem(Index: Integer; const S: string; O: TObject); override;
|
||||
procedure InsertItem(Index: Integer; const S: string); override;
|
||||
procedure InsertItem(Index: Integer; const S: string; O: TObject); override;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
function Add(const S: string): Integer; override;
|
||||
procedure Insert(Index: Integer; const S: string); override;
|
||||
procedure Clear; override;
|
||||
procedure Delete(Index: Integer); override;
|
||||
procedure Exchange(Index1, Index2: Integer); override;
|
||||
@ -70,7 +65,9 @@ type
|
||||
function Find(const S: string; out Index: Integer): Boolean; override;
|
||||
function IndexOf(const S: string): Integer; override;
|
||||
procedure Sort; override;
|
||||
procedure ValidateMap; // For debugging purposes only
|
||||
public
|
||||
property Duplicates: TDuplicates read GetDuplicates write SetDuplicates;
|
||||
property Sorted: Boolean read GetSorted write SetSorted;
|
||||
end;
|
||||
|
||||
@ -91,39 +88,20 @@ begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TDictionaryStringList.Add(const S: string): Integer;
|
||||
procedure TDictionaryStringList.AdjustMap(StartIndex, Offset: Integer);
|
||||
// Adjust all indexes >= startindex in map.
|
||||
// This is needed after inserting or deleting an item.
|
||||
var
|
||||
i: PtrInt;
|
||||
i: Integer;
|
||||
Ind: PtrInt;
|
||||
begin
|
||||
Result := -1;
|
||||
if Duplicates <> dupAccept then
|
||||
if IndexOf(S) <> -1 then
|
||||
case Duplicates of
|
||||
DupIgnore : Exit;
|
||||
DupError : raise Exception.Create('TDictionaryStringList.Add: Duplicates are not allowed.');
|
||||
end;
|
||||
Result := inherited Add(S);
|
||||
i := Result;
|
||||
FMap[S] := Pointer(i); // Store index to map.
|
||||
for i := StartIndex to Count-1 do
|
||||
begin
|
||||
Ind := PtrInt(FMap[Strings[i]]);
|
||||
FMap[Strings[i]] := Pointer(Ind + Offset);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDictionaryStringList.Insert(Index: Integer; const S: string);
|
||||
begin
|
||||
raise Exception.Create('TDictionaryStringList.Insert is not implemented yet.');
|
||||
inherited Insert(Index, S);
|
||||
// ToDo: adjust all indexes in FMap after the item is inserted.
|
||||
end;
|
||||
{
|
||||
procedure TDictionaryStringList.InsertItem(Index: Integer; const S: string);
|
||||
begin
|
||||
inherited InsertItem(Index, S);
|
||||
end;
|
||||
|
||||
procedure TDictionaryStringList.InsertItem(Index: Integer; const S: string; O: TObject);
|
||||
begin
|
||||
inherited InsertItem(Index, S, O);
|
||||
end;
|
||||
}
|
||||
procedure TDictionaryStringList.Clear;
|
||||
begin
|
||||
inherited Clear;
|
||||
@ -132,16 +110,45 @@ end;
|
||||
|
||||
procedure TDictionaryStringList.Delete(Index: Integer);
|
||||
begin
|
||||
raise Exception.Create('TDictionaryStringList.Delete is not implemented yet.');
|
||||
inherited Delete(Index);
|
||||
// ToDo: adjust all indexes in FMap after the item is deleted.
|
||||
// Decrement Indexes in map above the deleted item.
|
||||
AdjustMap(Index, -1);
|
||||
end;
|
||||
|
||||
procedure TDictionaryStringList.Exchange(Index1, Index2: Integer);
|
||||
var
|
||||
s1, s2: string;
|
||||
begin
|
||||
raise Exception.Create('TDictionaryStringList.Exchange is not implemented yet.');
|
||||
S1 := Strings[Index1];
|
||||
S2 := Strings[Index2];
|
||||
inherited Exchange(Index1, Index2);
|
||||
// ToDo: adjust all indexes in FMap after Exchange.
|
||||
// Exchange Indexes in map, too.
|
||||
FMap[s1] := Pointer(PtrInt(Index2));
|
||||
FMap[s2] := Pointer(PtrInt(Index1));
|
||||
end;
|
||||
|
||||
procedure TDictionaryStringList.InsertItem(Index: Integer; const S: string);
|
||||
var
|
||||
i: PtrInt;
|
||||
begin
|
||||
if Duplicates <> dupAccept then
|
||||
if IndexOf(S) <> -1 then
|
||||
case Duplicates of
|
||||
DupIgnore : Exit;
|
||||
DupError : raise Exception.Create('TDictionaryStringList.InsertItem:'
|
||||
+' Duplicates are not allowed.');
|
||||
end;
|
||||
inherited InsertItem(Index, S);
|
||||
i := Index;
|
||||
FMap[S] := Pointer(i); // Store index to map.
|
||||
// Increment Indexes in map above the inserted item.
|
||||
AdjustMap(Index+1, 1);
|
||||
end;
|
||||
|
||||
procedure TDictionaryStringList.InsertItem(Index: Integer; const S: string; O: TObject);
|
||||
begin
|
||||
raise Exception.Create('TDictionaryStringList.InsertItem: is this needed?');
|
||||
//inherited InsertItem(Index, S, O);
|
||||
end;
|
||||
|
||||
function TDictionaryStringList.Contains(const S: string): Boolean;
|
||||
@ -163,20 +170,48 @@ begin
|
||||
Result := -1
|
||||
end;
|
||||
|
||||
procedure TDictionaryStringList.ValidateMap;
|
||||
// For debugging purposes only
|
||||
var
|
||||
i, Ind: Integer;
|
||||
s: String;
|
||||
begin
|
||||
for i := 0 to Count-1 do
|
||||
begin
|
||||
s := Strings[i];
|
||||
Ind := integer(PtrInt(FMap[s]));
|
||||
if Ind <> i then
|
||||
raise Exception.CreateFmt('Indexes for string "%s" differ, list:%d, map:%d.',
|
||||
[s, i, Ind]);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDictionaryStringList.Sort;
|
||||
begin
|
||||
raise Exception.Create('This list is not meant to be sorted. Use TStringList instead.');
|
||||
end;
|
||||
|
||||
function TDictionaryStringList.GetSorted: Boolean;
|
||||
begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
procedure TDictionaryStringList.SetSorted(AValue: Boolean);
|
||||
begin
|
||||
if AValue then
|
||||
Sort; // Raise an exception here, too.
|
||||
end;
|
||||
|
||||
function TDictionaryStringList.GetSorted: Boolean;
|
||||
function TDictionaryStringList.GetDuplicates: TDuplicates;
|
||||
begin
|
||||
Result := False;
|
||||
Result := inherited Duplicates;
|
||||
end;
|
||||
|
||||
procedure TDictionaryStringList.SetDuplicates(AValue: TDuplicates);
|
||||
begin
|
||||
if AValue = dupAccept then
|
||||
raise Exception.Create('Sorry, TDictionaryStringList does not support duplicates.');
|
||||
inherited Duplicates := AValue;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user