Keyword mapping refactoring

This commit is contained in:
Michael Schimmel
2025-12-09 13:12:37 +01:00
parent f8dc5b945c
commit 76c92fa355
6 changed files with 62 additions and 81 deletions
File diff suppressed because one or more lines are too long
+1 -2
View File
@@ -36,8 +36,7 @@ uses
Myc.Fmx.AstEditor.Handlers.Lists in '..\Src\AST\Myc.Fmx.AstEditor.Handlers.Lists.pas',
Myc.Fmx.AstEditor.Handlers.Primitives in '..\Src\AST\Myc.Fmx.AstEditor.Handlers.Primitives.pas',
Myc.Fmx.AstEditor.Handlers.Control in '..\Src\AST\Myc.Fmx.AstEditor.Handlers.Control.pas',
Myc.Fmx.AstEditor.Handlers.Data in '..\Src\AST\Myc.Fmx.AstEditor.Handlers.Data.pas',
Myc.Data.Records in '..\Src\Data\Myc.Data.Records.pas';
Myc.Fmx.AstEditor.Handlers.Data in '..\Src\AST\Myc.Fmx.AstEditor.Handlers.Data.pas';
{$R *.res}
-1
View File
@@ -167,7 +167,6 @@
<DCCReference Include="..\Src\AST\Myc.Fmx.AstEditor.Handlers.Primitives.pas"/>
<DCCReference Include="..\Src\AST\Myc.Fmx.AstEditor.Handlers.Control.pas"/>
<DCCReference Include="..\Src\AST\Myc.Fmx.AstEditor.Handlers.Data.pas"/>
<DCCReference Include="..\Src\Data\Myc.Data.Records.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
+2 -4
View File
@@ -78,8 +78,7 @@ uses
Myc.Data.Decimal,
Myc.Data.Series,
Myc.Data.Scalar.JSON,
Myc.Ast.Types,
Myc.Data.Records;
Myc.Ast.Types;
// Helper type for TCO via trampolining.
type
@@ -499,8 +498,7 @@ begin
genFields[i] := TPair<IKeyword, TDataValue>.Create(field.Key.Value, field.Value.Accept(Self));
end;
var dynRec := TDynamicRecord.Create(genFields);
Result := TDataValue.FromGenericRecord(dynRec);
Result := TDataValue.FromGenericRecord(TKeywordMapping<TDataValue>.Create(genFields));
end
else if Assigned(Node.ScalarDefinition) then
begin
+58
View File
@@ -96,6 +96,19 @@ type
class function Intern(const AFields: TArray<TPair<IKeyword, T>>): IKeywordMapping<T>; static;
end;
TKeywordMapping<T> = class(TInterfacedObject, IKeywordMapping<T>)
private
FFields: TArray<TPair<IKeyword, T>>;
// IKeywordMapping implementation
function GetItems(Idx: Integer): TPair<IKeyword, T>;
function GetFields(const Key: IKeyword): T;
function GetCount: Integer;
public
constructor Create(const AFields: TArray<TPair<IKeyword, T>>);
function IndexOf(const Key: IKeyword): Integer;
end;
implementation
{ TKeywordRegistry.TKeyword }
@@ -280,4 +293,49 @@ begin
end;
end;
{ TKeywordMapping }
constructor TKeywordMapping<T>.Create(const AFields: TArray<TPair<IKeyword, T>>);
begin
inherited Create;
FFields := AFields;
end;
function TKeywordMapping<T>.GetCount: Integer;
begin
Result := Length(FFields);
end;
function TKeywordMapping<T>.GetFields(const Key: IKeyword): T;
var
idx: Integer;
begin
idx := IndexOf(Key);
if idx < 0 then
raise EArgumentException.CreateFmt('Field "%s" not found in dynamic record.', [Key.Name]);
Result := FFields[idx].Value;
end;
function TKeywordMapping<T>.GetItems(Idx: Integer): TPair<IKeyword, T>;
begin
Result := FFields[Idx];
end;
function TKeywordMapping<T>.IndexOf(const Key: IKeyword): Integer;
var
i: Integer;
begin
// Linear search (O(n)). Fast enough for typical records.
// Keyword comparison is integer-based (Idx), so this is efficient.
for i := 0 to High(FFields) do
begin
if FFields[i].Key.Idx = Key.Idx then
begin
Result := i;
exit;
end;
end;
Result := -1;
end;
end.
-73
View File
@@ -1,73 +0,0 @@
unit Myc.Data.Records;
interface
uses
System.SysUtils,
System.Generics.Collections,
Myc.Data.Keyword,
Myc.Data.Value;
type
// Runtime implementation for generic records using linear search (optimized for small record sizes)
TDynamicRecord = class(TInterfacedObject, IKeywordMapping<TDataValue>)
private
FFields: TArray<TPair<IKeyword, TDataValue>>;
// IKeywordMapping implementation
function GetItems(Idx: Integer): TPair<IKeyword, TDataValue>;
function GetFields(const Key: IKeyword): TDataValue;
function GetCount: Integer;
public
constructor Create(const AFields: TArray<TPair<IKeyword, TDataValue>>);
function IndexOf(const Key: IKeyword): Integer;
end;
implementation
{ TDynamicRecord }
constructor TDynamicRecord.Create(const AFields: TArray<TPair<IKeyword, TDataValue>>);
begin
inherited Create;
FFields := AFields;
end;
function TDynamicRecord.GetCount: Integer;
begin
Result := Length(FFields);
end;
function TDynamicRecord.GetFields(const Key: IKeyword): TDataValue;
var
idx: Integer;
begin
idx := IndexOf(Key);
if idx < 0 then
raise EArgumentException.CreateFmt('Field "%s" not found in dynamic record.', [Key.Name]);
Result := FFields[idx].Value;
end;
function TDynamicRecord.GetItems(Idx: Integer): TPair<IKeyword, TDataValue>;
begin
Result := FFields[Idx];
end;
function TDynamicRecord.IndexOf(const Key: IKeyword): Integer;
var
i: Integer;
begin
// Linear search (O(n)). Fast enough for typical records.
// Keyword comparison is integer-based (Idx), so this is efficient.
for i := 0 to High(FFields) do
begin
if FFields[i].Key.Idx = Key.Idx then
begin
Result := i;
exit;
end;
end;
Result := -1;
end;
end.