Keyword mapping refactoring

This commit is contained in:
Michael Schimmel
2025-12-09 12:59:36 +01:00
parent 43afbd6050
commit f8dc5b945c
13 changed files with 257 additions and 188 deletions
+47 -47
View File
@@ -20,26 +20,17 @@ uses
type
TImportConverter = reference to procedure(const Src: Pointer; Dst: TScalar.PValue);
// Interface representing a read-only view of a specific data row.
IScalarRecord = interface
function GetDef: IScalarRecordDefinition;
function GetItems(const Key: IKeyword): TScalar;
function ItemByIndex(Idx: Integer): TScalar;
property Def: IScalarRecordDefinition read GetDef;
property Items[const Key: IKeyword]: TScalar read GetItems; default;
end;
IScalarRecordFeed = interface
procedure ClearCache;
{$region 'private'}
function GetTicker: TProducer<IScalarRecord>;
{$endregion}
procedure SetImportOptions(RecordSize: Integer; const Converter: TImportConverter);
function EnumerateSymbols: TFuture<TArray<String>>;
// Streaming processing: Reads data from disk and broadcasts it via Ticker
function ProcessData(const Symbol: String; const Terminated: TState): TState;
function GetTicker: TProducer<IScalarRecord>;
property Ticker: TProducer<IScalarRecord> read GetTicker;
end;
@@ -79,7 +70,7 @@ type
FFileExtension: String;
FIsCompressed: Boolean;
FCachedFiles: TDataFileCache<TArray<TBatch>>;
FCachedFiles: IDataFileCache<TArray<TBatch>>;
FSymbols: TFuture<TDictionary<String, TArray<TDataFile>>>;
// Producer implementation
@@ -116,10 +107,14 @@ type
function GetTicker: TProducer<IScalarRecord>;
public
constructor Create(const APath: String; const AExtension: String; IsCompressed: Boolean; const ADef: IScalarRecordDefinition);
constructor Create(
const ACachedFiles: IDataFileCache<TArray<TBatch>>;
const APath, AExtension: String;
IsCompressed: Boolean;
const ADef: IScalarRecordDefinition
);
destructor Destroy; override;
procedure AfterConstruction; override;
procedure ClearCache;
procedure SetImportOptions(RecordSize: Integer; const Converter: TImportConverter);
function EnumerateSymbols: TFuture<TArray<String>>;
@@ -152,14 +147,15 @@ type
private
FDef: IScalarRecordDefinition;
FData: TScalar.PValue;
// IKeywordMapping<TScalar.TValue> implementation
function IndexOf(const Key: IKeyword): Integer;
function GetCount: Integer;
function GetItems(Idx: Integer): TPair<IKeyword, TScalar>;
function GetFields(const Key: IKeyword): TScalar;
public
constructor Create(const ADef: IScalarRecordDefinition);
procedure SetData(const AData: TScalar.PValue); inline;
function ItemByIndex(Idx: Integer): TScalar; inline;
function GetDef: IScalarRecordDefinition;
function GetItems(const Key: IKeyword): TScalar;
end;
{ TScalarRecordView }
@@ -175,26 +171,34 @@ begin
FData := AData;
end;
function TScalarRecordView.GetDef: IScalarRecordDefinition;
function TScalarRecordView.GetCount: Integer;
begin
Result := FDef;
Result := FDef.Count;
end;
function TScalarRecordView.GetItems(const Key: IKeyword): TScalar;
function TScalarRecordView.GetFields(const Key: IKeyword): TScalar;
var
idx: Integer;
begin
// Optimization: Depending on hot-path usage, one could cache the Fields array
// or use direct index access if the definition allows.
var idx := FDef.IndexOf(Key);
idx := FDef.IndexOf(Key);
if idx < 0 then
exit(TScalar.Create(TScalar.TKind.Ordinal, Default(TScalar.TValue)));
exit(Default(TScalar));
Result := ItemByIndex(idx);
// Return the raw TValue at the offset
Result.Kind := FDef[idx].Value;
Result.Value := TScalar.PValue(NativeUInt(FData) + NativeUInt(idx * SizeOf(TScalar.TValue)))^;
end;
function TScalarRecordView.ItemByIndex(Idx: Integer): TScalar;
function TScalarRecordView.GetItems(Idx: Integer): TPair<IKeyword, TScalar>;
begin
// Calculate pointer offset
Result.Create(FDef.Fields[Idx].Value, TScalar.PValue(NativeUInt(FData) + NativeUInt(idx * SizeOf(TScalar.TValue)))^);
Result.Key := FDef[Idx].Key;
Result.Value.Kind := FDef[idx].Value;
Result.Value.Value := TScalar.PValue(NativeUInt(FData) + NativeUInt(Idx * SizeOf(TScalar.TValue)))^;
end;
function TScalarRecordView.IndexOf(const Key: IKeyword): Integer;
begin
Result := FDef.IndexOf(Key);
end;
{ TScalarRecordFeed.TDataFile }
@@ -227,8 +231,8 @@ end;
{ TScalarRecordFeed }
constructor TScalarRecordFeed.Create(
const APath: String;
const AExtension: String;
const ACachedFiles: IDataFileCache<TArray<TBatch>>;
const APath, AExtension: String;
IsCompressed: Boolean;
const ADef: IScalarRecordDefinition
);
@@ -236,6 +240,7 @@ begin
inherited Create;
FPath := APath;
FDef := ADef;
FCachedFiles := ACachedFiles;
FFileExtension := AExtension;
FIsCompressed := IsCompressed;
FLookback := -1;
@@ -244,15 +249,12 @@ begin
FTicker := TMycContainedProducer<IScalarRecord>.Create(Self);
FCachedFiles :=
TDataFileCache<TArray<TBatch>>
.Create(function(const Filename: String): TFuture<TArray<TBatch>> begin Result := DoLoad(Filename, FLoadGate); end);
FCachedFiles := TDataFileCache<TArray<TBatch>>.Create;
end;
destructor TScalarRecordFeed.Destroy;
begin
ClearCache;
FCachedFiles.Free;
FCachedFiles.Clear;
FTicker.Free;
inherited Destroy;
end;
@@ -263,16 +265,10 @@ begin
UpdateSymbols;
end;
procedure TScalarRecordFeed.ClearCache;
begin
FCachedFiles.Clear;
end;
procedure TScalarRecordFeed.SetImportOptions(RecordSize: Integer; const Converter: TImportConverter);
begin
FImportRecordSize := RecordSize;
FImportConverter := Converter;
ClearCache;
end;
function TScalarRecordFeed.GetPath: String;
@@ -443,7 +439,11 @@ end;
function TScalarRecordFeed.LoadDataFile(const DataFile: TDataFile): TFuture<TArray<TBatch>>;
begin
if DataFile.IsValid then
Result := FCachedFiles.GetOrAdd(DataFile.GetFullFileName)
Result :=
FCachedFiles.GetOrAdd(
DataFile.GetFullFileName,
function(const Filename: String): TFuture<TArray<TBatch>> begin Result := DoLoad(Filename, FLoadGate); end
)
else
Result := TFuture<TArray<TBatch>>.Construct(TArray<TBatch>(nil));
end;
@@ -551,7 +551,7 @@ begin
InputStream.Position := 0;
fileSize := InputStream.Size;
fieldsPerRecord := Length(FDef.Fields);
fieldsPerRecord := FDef.Count;
internalRecordSize := fieldsPerRecord * sizeof(TScalar.TValue);
if (FImportRecordSize > 0) and Assigned(FImportConverter) then