This commit is contained in:
Michael Schimmel
2025-10-30 20:27:44 +01:00
parent 798aa08f02
commit 0526ec8a24
17 changed files with 193 additions and 137 deletions
+74 -3
View File
@@ -11,7 +11,9 @@ uses
type
// The runtime representation of an interned keyword
IKeyword = interface(IInterface)
function GetIdx: Integer;
function GetName: string;
property Idx: Integer read GetIdx;
property Name: string read GetName;
end;
@@ -22,9 +24,11 @@ type
TKeyword = class(TInterfacedObject, IKeyword)
private
FName: string;
FIdx: Integer;
function GetName: string;
function GetIdx: Integer;
public
constructor Create(const AName: string);
constructor Create(const AName: string; AIdx: Integer);
end;
strict private
class var
@@ -38,14 +42,38 @@ type
class function Intern(const AName: string): IKeyword; static;
end;
TKeywordMapping<T> = record
type
TField = record
Key: IKeyword;
Value: T;
public
constructor Create(const AKey: IKeyword; const AValue: T);
end;
private
FMap: TArray<Integer>;
FFields: TArray<TField>;
FFirst, FLast: Integer;
public
constructor Create(const AFields: TArray<TField>);
function IndexOf(const Key: IKeyword): Integer;
property Fields: TArray<TField> read FFields;
end;
implementation
{ TKeywordRegistry.TKeyword }
constructor TKeywordRegistry.TKeyword.Create(const AName: string);
constructor TKeywordRegistry.TKeyword.Create(const AName: string; AIdx: Integer);
begin
inherited Create;
FName := AName;
FIdx := AIdx;
end;
function TKeywordRegistry.TKeyword.GetIdx: Integer;
begin
Result := FIdx;
end;
function TKeywordRegistry.TKeyword.GetName: string;
@@ -72,7 +100,7 @@ begin
try
if not FRegistry.TryGetValue(AName, Result) then
begin
Result := TKeyword.Create(AName);
Result := TKeyword.Create(AName, FRegistry.Count);
FRegistry.Add(AName, Result);
end;
finally
@@ -80,4 +108,47 @@ begin
end;
end;
{ TKeywordMapping }
constructor TKeywordMapping<T>.Create(const AFields: TArray<TField>);
begin
FFields := AFields;
FFirst := 0;
FLast := -1;
if Length(FFields) = 0 then
exit;
FFirst := FFields[0].Key.Idx;
FLast := FFirst;
for var i := 1 to High(FFields) do
begin
var idx := FFields[i].Key.Idx;
if FFirst > idx then
FFirst := idx;
if FLast < idx then
FLast := idx;
end;
SetLength(FMap, FLast - FFirst + 1);
for var i := 0 to High(FMap) do
FMap[i] := -1;
for var i := 0 to High(FFields) do
FMap[FFirst + FFields[i].Key.Idx] := i;
end;
function TKeywordMapping<T>.IndexOf(const Key: IKeyword): Integer;
begin
var idx := Key.Idx - FFirst;
if (idx < 0) or (Idx > High(FMap)) then
exit(-1);
Result := FMap[idx];
end;
constructor TKeywordMapping<T>.TField.Create(const AKey: IKeyword; const AValue: T);
begin
Key := AKey;
Value := AValue;
end;
end.