Keywords
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -769,7 +769,7 @@ var
|
|||||||
ast, callAst: IAstNode;
|
ast, callAst: IAstNode;
|
||||||
resultValue: TDataValue;
|
resultValue: TDataValue;
|
||||||
series: TScalarRecordSeries;
|
series: TScalarRecordSeries;
|
||||||
recordDef: TScalarRecordDefinition;
|
recordDef: IScalarRecordDefinition;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
scope: IExecutionScope;
|
scope: IExecutionScope;
|
||||||
values: TArray<TScalar.TValue>;
|
values: TArray<TScalar.TValue>;
|
||||||
|
|||||||
@@ -155,10 +155,10 @@ type
|
|||||||
|
|
||||||
TBoundRecordLiteralNode = class(TRecordLiteralNode)
|
TBoundRecordLiteralNode = class(TRecordLiteralNode)
|
||||||
private
|
private
|
||||||
FDefinition: TScalarRecordDefinition;
|
FDefinition: IScalarRecordDefinition;
|
||||||
public
|
public
|
||||||
constructor Create(const AFields: TArray<TRecordFieldLiteral>; const ADef: TScalarRecordDefinition);
|
constructor Create(const AFields: TArray<TRecordFieldLiteral>; const ADef: IScalarRecordDefinition);
|
||||||
property Definition: TScalarRecordDefinition read FDefinition;
|
property Definition: IScalarRecordDefinition read FDefinition;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -345,7 +345,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{ TBoundRecordLiteralNode }
|
{ TBoundRecordLiteralNode }
|
||||||
constructor TBoundRecordLiteralNode.Create(const AFields: TArray<TRecordFieldLiteral>; const ADef: TScalarRecordDefinition);
|
constructor TBoundRecordLiteralNode.Create(const AFields: TArray<TRecordFieldLiteral>; const ADef: IScalarRecordDefinition);
|
||||||
begin
|
begin
|
||||||
inherited Create(AFields);
|
inherited Create(AFields);
|
||||||
FDefinition := ADef;
|
FDefinition := ADef;
|
||||||
@@ -960,8 +960,8 @@ function TAstBinder.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataVal
|
|||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
boundFields: TArray<TRecordFieldLiteral>;
|
boundFields: TArray<TRecordFieldLiteral>;
|
||||||
defFields: TArray<TScalarRecordDefinition.TField>;
|
defFields: TArray<TScalarRecordField>;
|
||||||
def: TScalarRecordDefinition;
|
def: IScalarRecordDefinition;
|
||||||
staticType: IStaticType;
|
staticType: IStaticType;
|
||||||
boundNode: IRecordLiteralNode;
|
boundNode: IRecordLiteralNode;
|
||||||
valNode: IAstNode;
|
valNode: IAstNode;
|
||||||
@@ -997,7 +997,7 @@ begin
|
|||||||
defFields[i] := TScalarRecordField.Create(Node.Fields[i].Key.Value, scalarKind);
|
defFields[i] := TScalarRecordField.Create(Node.Fields[i].Key.Value, scalarKind);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
def := TScalarRecordDefinition.Create(defFields);
|
def := TScalarRecordRegistry.Intern(defFields);
|
||||||
staticType := TTypes.CreateRecord(def);
|
staticType := TTypes.CreateRecord(def);
|
||||||
boundNode := TBoundRecordLiteralNode.Create(boundFields, def);
|
boundNode := TBoundRecordLiteralNode.Create(boundFields, def);
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ end;
|
|||||||
function NativeCreateRecordSeries(const Args: TArray<TDataValue>): TDataValue;
|
function NativeCreateRecordSeries(const Args: TArray<TDataValue>): TDataValue;
|
||||||
var
|
var
|
||||||
jsonDef: string;
|
jsonDef: string;
|
||||||
recordDef: TScalarRecordDefinition;
|
recordDef: IScalarRecordDefinition;
|
||||||
series: IRecordSeries;
|
series: IRecordSeries;
|
||||||
begin
|
begin
|
||||||
if (Length(Args) <> 1) or (Args[0].Kind <> vkText) then
|
if (Length(Args) <> 1) or (Args[0].Kind <> vkText) then
|
||||||
@@ -421,14 +421,6 @@ begin
|
|||||||
Result := Items[Integer(index)];
|
Result := Items[Integer(index)];
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
vkRecordSeries:
|
|
||||||
begin
|
|
||||||
var series := baseValue.AsRecordSeries;
|
|
||||||
if (index < 0) or (index >= series.TotalCount) then
|
|
||||||
raise EArgumentException.CreateFmt('Index %d is out of bounds for series with %d elements.', [index, series.TotalCount]);
|
|
||||||
var recordValue := series.Items[Integer(index)];
|
|
||||||
Result := TDataValue.FromRecord(recordValue);
|
|
||||||
end;
|
|
||||||
else
|
else
|
||||||
raise EArgumentException.Create('Indexer `[]` is not supported for this value type.');
|
raise EArgumentException.Create('Indexer `[]` is not supported for this value type.');
|
||||||
end;
|
end;
|
||||||
@@ -441,7 +433,7 @@ begin
|
|||||||
baseValue := Node.Base.Accept(Self);
|
baseValue := Node.Base.Accept(Self);
|
||||||
|
|
||||||
case baseValue.Kind of
|
case baseValue.Kind of
|
||||||
vkRecordSeries: Result := TDataValue.FromSeries(baseValue.AsRecordSeries.CreateMemberSeries(Node.Member.Value));
|
vkRecordSeries: Result := TDataValue.FromSeries(baseValue.AsRecordSeries[Node.Member.Value]);
|
||||||
vkRecord: Result := baseValue.AsRecord[Node.Member.Value];
|
vkRecord: Result := baseValue.AsRecord[Node.Member.Value];
|
||||||
else
|
else
|
||||||
raise EArgumentException.Create('Member access operator `.` is not supported for this value type.');
|
raise EArgumentException.Create('Member access operator `.` is not supported for this value type.');
|
||||||
|
|||||||
+14
-14
@@ -46,7 +46,7 @@ type
|
|||||||
function GetKind: TStaticTypeKind;
|
function GetKind: TStaticTypeKind;
|
||||||
function GetElementType: IStaticType;
|
function GetElementType: IStaticType;
|
||||||
function GetSignature: IMethodSignature;
|
function GetSignature: IMethodSignature;
|
||||||
function GetDefinition: TScalarRecordDefinition;
|
function GetDefinition: IScalarRecordDefinition;
|
||||||
{$endregion}
|
{$endregion}
|
||||||
|
|
||||||
// The kind of type (e.g., Ordinal, Series, etc.)
|
// The kind of type (e.g., Ordinal, Series, etc.)
|
||||||
@@ -56,7 +56,7 @@ type
|
|||||||
// The signature (if Kind = stMethod)
|
// The signature (if Kind = stMethod)
|
||||||
property Signature: IMethodSignature read GetSignature;
|
property Signature: IMethodSignature read GetSignature;
|
||||||
// The definition (if Kind = stRecord or stRecordSeries)
|
// The definition (if Kind = stRecord or stRecordSeries)
|
||||||
property Definition: TScalarRecordDefinition read GetDefinition;
|
property Definition: IScalarRecordDefinition read GetDefinition;
|
||||||
|
|
||||||
// Checks for type equality
|
// Checks for type equality
|
||||||
function IsEqual(const Other: IStaticType): Boolean;
|
function IsEqual(const Other: IStaticType): Boolean;
|
||||||
@@ -94,8 +94,8 @@ type
|
|||||||
// Factory functions for complex types
|
// Factory functions for complex types
|
||||||
class function CreateSeries(const AElementType: IStaticType): IStaticType; static;
|
class function CreateSeries(const AElementType: IStaticType): IStaticType; static;
|
||||||
class function CreateMethod(const AParamTypes: TArray<IStaticType>; const AReturnType: IStaticType): IStaticType; static;
|
class function CreateMethod(const AParamTypes: TArray<IStaticType>; const AReturnType: IStaticType): IStaticType; static;
|
||||||
class function CreateRecord(const ADef: TScalarRecordDefinition): IStaticType; static;
|
class function CreateRecord(const ADef: IScalarRecordDefinition): IStaticType; static;
|
||||||
class function CreateRecordSeries(const ADef: TScalarRecordDefinition): IStaticType; static;
|
class function CreateRecordSeries(const ADef: IScalarRecordDefinition): IStaticType; static;
|
||||||
|
|
||||||
class function FromScalarKind(AKind: TScalar.TKind): IStaticType; static;
|
class function FromScalarKind(AKind: TScalar.TKind): IStaticType; static;
|
||||||
end;
|
end;
|
||||||
@@ -148,7 +148,7 @@ type
|
|||||||
function GetKind: TStaticTypeKind; virtual; abstract;
|
function GetKind: TStaticTypeKind; virtual; abstract;
|
||||||
function GetElementType: IStaticType; virtual;
|
function GetElementType: IStaticType; virtual;
|
||||||
function GetSignature: IMethodSignature; virtual;
|
function GetSignature: IMethodSignature; virtual;
|
||||||
function GetDefinition: TScalarRecordDefinition; virtual;
|
function GetDefinition: IScalarRecordDefinition; virtual;
|
||||||
function IsEqual(const Other: IStaticType): Boolean; virtual;
|
function IsEqual(const Other: IStaticType): Boolean; virtual;
|
||||||
function ToString: string; override;
|
function ToString: string; override;
|
||||||
end;
|
end;
|
||||||
@@ -163,10 +163,10 @@ begin
|
|||||||
Result := nil;
|
Result := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAbstractStaticType.GetDefinition: TScalarRecordDefinition;
|
function TAbstractStaticType.GetDefinition: IScalarRecordDefinition;
|
||||||
begin
|
begin
|
||||||
// Return an empty/invalid definition
|
// Return an empty/invalid definition
|
||||||
Result := Default(TScalarRecordDefinition);
|
Result := Default(IScalarRecordDefinition);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAbstractStaticType.IsEqual(const Other: IStaticType): Boolean;
|
function TAbstractStaticType.IsEqual(const Other: IStaticType): Boolean;
|
||||||
@@ -346,16 +346,16 @@ type
|
|||||||
TRecordType = class(TAbstractStaticType)
|
TRecordType = class(TAbstractStaticType)
|
||||||
private
|
private
|
||||||
FKind: TStaticTypeKind;
|
FKind: TStaticTypeKind;
|
||||||
FDefinition: TScalarRecordDefinition;
|
FDefinition: IScalarRecordDefinition;
|
||||||
public
|
public
|
||||||
constructor Create(AKind: TStaticTypeKind; ADef: TScalarRecordDefinition);
|
constructor Create(AKind: TStaticTypeKind; ADef: IScalarRecordDefinition);
|
||||||
function GetKind: TStaticTypeKind; override;
|
function GetKind: TStaticTypeKind; override;
|
||||||
function GetDefinition: TScalarRecordDefinition; override;
|
function GetDefinition: IScalarRecordDefinition; override;
|
||||||
function IsEqual(const Other: IStaticType): Boolean; override;
|
function IsEqual(const Other: IStaticType): Boolean; override;
|
||||||
function ToString: string; override;
|
function ToString: string; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
constructor TRecordType.Create(AKind: TStaticTypeKind; ADef: TScalarRecordDefinition);
|
constructor TRecordType.Create(AKind: TStaticTypeKind; ADef: IScalarRecordDefinition);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
Assert(AKind in [stRecord, stRecordSeries]);
|
Assert(AKind in [stRecord, stRecordSeries]);
|
||||||
@@ -368,7 +368,7 @@ begin
|
|||||||
Result := FKind;
|
Result := FKind;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TRecordType.GetDefinition: TScalarRecordDefinition;
|
function TRecordType.GetDefinition: IScalarRecordDefinition;
|
||||||
begin
|
begin
|
||||||
Result := FDefinition;
|
Result := FDefinition;
|
||||||
end;
|
end;
|
||||||
@@ -426,12 +426,12 @@ begin
|
|||||||
Result := TMethodType.Create(AParamTypes, AReturnType);
|
Result := TMethodType.Create(AParamTypes, AReturnType);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TTypes.CreateRecord(const ADef: TScalarRecordDefinition): IStaticType;
|
class function TTypes.CreateRecord(const ADef: IScalarRecordDefinition): IStaticType;
|
||||||
begin
|
begin
|
||||||
Result := TRecordType.Create(stRecord, ADef);
|
Result := TRecordType.Create(stRecord, ADef);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TTypes.CreateRecordSeries(const ADef: TScalarRecordDefinition): IStaticType;
|
class function TTypes.CreateRecordSeries(const ADef: IScalarRecordDefinition): IStaticType;
|
||||||
begin
|
begin
|
||||||
Result := TRecordType.Create(stRecordSeries, ADef);
|
Result := TRecordType.Create(stRecordSeries, ADef);
|
||||||
end;
|
end;
|
||||||
|
|||||||
+105
-23
@@ -10,7 +10,7 @@ uses
|
|||||||
|
|
||||||
type
|
type
|
||||||
// The runtime representation of an interned keyword
|
// The runtime representation of an interned keyword
|
||||||
IKeyword = interface(IInterface)
|
IKeyword = interface
|
||||||
function GetIdx: Integer;
|
function GetIdx: Integer;
|
||||||
function GetName: string;
|
function GetName: string;
|
||||||
property Idx: Integer read GetIdx;
|
property Idx: Integer read GetIdx;
|
||||||
@@ -42,26 +42,52 @@ type
|
|||||||
class function Intern(const AName: string): IKeyword; static;
|
class function Intern(const AName: string): IKeyword; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TKeywordMapping<T> = record
|
// Defines a mapping from Keywords to a generic value T
|
||||||
type
|
IKeywordMapping<T> = interface
|
||||||
TField = record
|
{$region 'private'}
|
||||||
Key: IKeyword;
|
function GetFields: TArray<TPair<IKeyword, T>>;
|
||||||
Value: T;
|
{$endregion}
|
||||||
public
|
// Finds the 0-based index for a given keyword. Returns -1 if not found.
|
||||||
constructor Create(const AKey: IKeyword; const AValue: T);
|
function IndexOf(const Key: IKeyword): Integer;
|
||||||
|
// Gets all fields in the mapping.
|
||||||
|
property Fields: TArray<TPair<IKeyword, T>> read GetFields;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Factory for creating IKeywordMapping instances
|
||||||
|
TKeywordMappingRegistry<T> = record
|
||||||
|
strict private
|
||||||
|
// Implementation class for IKeywordMapping
|
||||||
|
type
|
||||||
|
TKeywordMapping = class(TInterfacedObject, IKeywordMapping<T>)
|
||||||
private
|
private
|
||||||
FMap: TArray<Integer>;
|
FMap: TArray<Integer>;
|
||||||
FFields: TArray<TField>;
|
FFields: TArray<TPair<IKeyword, T>>;
|
||||||
FFirst, FLast: Integer;
|
FFirst, FLast: Integer;
|
||||||
|
function GetFields: TArray<TPair<IKeyword, T>>;
|
||||||
public
|
public
|
||||||
constructor Create(const AFields: TArray<TField>);
|
// Expects AFields to be in the desired (canonical) order
|
||||||
|
constructor Create(const AFields: TArray<TPair<IKeyword, T>>);
|
||||||
function IndexOf(const Key: IKeyword): Integer;
|
function IndexOf(const Key: IKeyword): Integer;
|
||||||
property Fields: TArray<TField> read FFields;
|
end;
|
||||||
|
strict private
|
||||||
|
// Cache implementation
|
||||||
|
class var
|
||||||
|
FLock: TSpinLock;
|
||||||
|
class var
|
||||||
|
FRegistry: TDictionary<TArray<Integer>, IKeywordMapping<T>>;
|
||||||
|
class constructor Create;
|
||||||
|
class destructor Destroy;
|
||||||
|
|
||||||
|
public
|
||||||
|
// Creates or gets the cached keyword mapping.
|
||||||
|
class function Intern(const AFields: TArray<TPair<IKeyword, T>>): IKeywordMapping<T>; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.Generics.Defaults; // For TComparer<Integer>
|
||||||
|
|
||||||
{ TKeywordRegistry.TKeyword }
|
{ TKeywordRegistry.TKeyword }
|
||||||
|
|
||||||
constructor TKeywordRegistry.TKeyword.Create(const AName: string; AIdx: Integer);
|
constructor TKeywordRegistry.TKeyword.Create(const AName: string; AIdx: Integer);
|
||||||
@@ -108,21 +134,25 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TKeywordMapping }
|
{ TKeywordMappingRegistry<T>.TKeywordMapping<T> }
|
||||||
|
|
||||||
constructor TKeywordMapping<T>.Create(const AFields: TArray<TField>);
|
constructor TKeywordMappingRegistry<T>.TKeywordMapping.Create(const AFields: TArray<TPair<IKeyword, T>>);
|
||||||
|
var
|
||||||
|
i, idx: Integer;
|
||||||
begin
|
begin
|
||||||
|
inherited Create;
|
||||||
FFields := AFields;
|
FFields := AFields;
|
||||||
FFirst := 0;
|
FFirst := 0;
|
||||||
FLast := -1;
|
FLast := -1;
|
||||||
if Length(FFields) = 0 then
|
if Length(FFields) = 0 then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
|
// Find min/max Idx for the map. Fields are *not* assumed to be sorted.
|
||||||
FFirst := FFields[0].Key.Idx;
|
FFirst := FFields[0].Key.Idx;
|
||||||
FLast := FFirst;
|
FLast := FFirst;
|
||||||
for var i := 1 to High(FFields) do
|
for i := 1 to High(FFields) do
|
||||||
begin
|
begin
|
||||||
var idx := FFields[i].Key.Idx;
|
idx := FFields[i].Key.Idx;
|
||||||
if FFirst > idx then
|
if FFirst > idx then
|
||||||
FFirst := idx;
|
FFirst := idx;
|
||||||
if FLast < idx then
|
if FLast < idx then
|
||||||
@@ -130,25 +160,77 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
SetLength(FMap, FLast - FFirst + 1);
|
SetLength(FMap, FLast - FFirst + 1);
|
||||||
for var i := 0 to High(FMap) do
|
for i := 0 to High(FMap) do
|
||||||
FMap[i] := -1;
|
FMap[i] := -1;
|
||||||
for var i := 0 to High(FFields) do
|
|
||||||
FMap[FFirst + FFields[i].Key.Idx] := i;
|
// Populate map based on the *original field order*
|
||||||
|
for i := 0 to High(FFields) do
|
||||||
|
FMap[FFields[i].Key.Idx - FFirst] := i;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TKeywordMapping<T>.IndexOf(const Key: IKeyword): Integer;
|
function TKeywordMappingRegistry<T>.TKeywordMapping.GetFields: TArray<TPair<IKeyword, T>>;
|
||||||
begin
|
begin
|
||||||
var idx := Key.Idx - FFirst;
|
Result := FFields;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TKeywordMappingRegistry<T>.TKeywordMapping.IndexOf(const Key: IKeyword): Integer;
|
||||||
|
var
|
||||||
|
idx: Integer;
|
||||||
|
begin
|
||||||
|
idx := Key.Idx - FFirst;
|
||||||
if (idx < 0) or (Idx > High(FMap)) then
|
if (idx < 0) or (Idx > High(FMap)) then
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
|
||||||
Result := FMap[idx];
|
Result := FMap[idx];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
constructor TKeywordMapping<T>.TField.Create(const AKey: IKeyword; const AValue: T);
|
{ TKeywordMappingRegistry<T> }
|
||||||
|
|
||||||
|
class constructor TKeywordMappingRegistry<T>.Create;
|
||||||
begin
|
begin
|
||||||
Key := AKey;
|
FLock := TSpinLock.Create(false);
|
||||||
Value := AValue;
|
FRegistry := TDictionary<TArray<Integer>, IKeywordMapping<T>>.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class destructor TKeywordMappingRegistry<T>.Destroy;
|
||||||
|
begin
|
||||||
|
FRegistry.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TKeywordMappingRegistry<T>.Intern(const AFields: TArray<TPair<IKeyword, T>>): IKeywordMapping<T>;
|
||||||
|
var
|
||||||
|
key: TArray<Integer>;
|
||||||
|
begin
|
||||||
|
SetLength(key, Length(AFields));
|
||||||
|
for var i := 0 to High(key) do
|
||||||
|
key[i] := AFields[i].Key.Idx;
|
||||||
|
|
||||||
|
// 2. Lock
|
||||||
|
FLock.Enter;
|
||||||
|
try
|
||||||
|
// 3. Check cache
|
||||||
|
if FRegistry.TryGetValue(key, Result) then
|
||||||
|
exit; // Found it, exit
|
||||||
|
finally
|
||||||
|
FLock.Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// 4. Not in cache. Create (O(N+M)) - OUTSIDE lock
|
||||||
|
var newMapping := TKeywordMapping.Create(AFields) as IKeywordMapping<T>;
|
||||||
|
|
||||||
|
// 5. Lock again to add
|
||||||
|
FLock.Enter;
|
||||||
|
try
|
||||||
|
// 6. Check again (double-check)
|
||||||
|
if FRegistry.TryGetValue(key, Result) then
|
||||||
|
exit; // Another thread won the race
|
||||||
|
|
||||||
|
// 7. Add our new mapping.
|
||||||
|
Result := newMapping;
|
||||||
|
FRegistry.Add(key, Result);
|
||||||
|
finally
|
||||||
|
FLock.Exit;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ type
|
|||||||
// Creates a JSON definition string from a record type info.
|
// Creates a JSON definition string from a record type info.
|
||||||
class function RecordDefinitionToJson<T: record>: string; static;
|
class function RecordDefinitionToJson<T: record>: string; static;
|
||||||
// Creates a record definition from a JSON string.
|
// Creates a record definition from a JSON string.
|
||||||
class function JsonToRecordDefinition(const AJson: string): TScalarRecordDefinition; static;
|
class function JsonToRecordDefinition(const AJson: string): IScalarRecordDefinition; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -30,7 +30,7 @@ uses
|
|||||||
|
|
||||||
{ TRttiAstHelper }
|
{ TRttiAstHelper }
|
||||||
|
|
||||||
class function TRttiAstHelper.JsonToRecordDefinition(const AJson: string): TScalarRecordDefinition;
|
class function TRttiAstHelper.JsonToRecordDefinition(const AJson: string): IScalarRecordDefinition;
|
||||||
var
|
var
|
||||||
jsonValue: TJSONValue;
|
jsonValue: TJSONValue;
|
||||||
fieldsArray: TJSONArray;
|
fieldsArray: TJSONArray;
|
||||||
@@ -63,7 +63,7 @@ begin
|
|||||||
|
|
||||||
fields[i] := TScalarRecordField.Create(fieldKey, TScalar.TKind(GetEnumValue(TypeInfo(TScalar.TKind), kindStr)));
|
fields[i] := TScalarRecordField.Create(fieldKey, TScalar.TKind(GetEnumValue(TypeInfo(TScalar.TKind), kindStr)));
|
||||||
end;
|
end;
|
||||||
Result := TScalarRecordDefinition.Create(fields);
|
Result := TScalarRecordRegistry.Intern(fields);
|
||||||
finally
|
finally
|
||||||
jsonValue.Free;
|
jsonValue.Free;
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
System.SysUtils,
|
System.SysUtils,
|
||||||
|
System.Generics.Collections,
|
||||||
|
System.Generics.Defaults,
|
||||||
Myc.Data.Decimal,
|
Myc.Data.Decimal,
|
||||||
Myc.Data.Series,
|
Myc.Data.Series,
|
||||||
Myc.Data.Keyword;
|
Myc.Data.Keyword;
|
||||||
@@ -92,21 +94,22 @@ type
|
|||||||
TScalarTuple = TArray<TScalar>;
|
TScalarTuple = TArray<TScalar>;
|
||||||
|
|
||||||
// A field definition for a scalar record.
|
// A field definition for a scalar record.
|
||||||
TScalarRecordField = TKeywordMapping<TScalar.TKind>.TField;
|
TScalarRecordField = TPair<IKeyword, TScalar.TKind>;
|
||||||
TScalarRecordDefinition = TKeywordMapping<TScalar.TKind>;
|
IScalarRecordDefinition = IKeywordMapping<TScalar.TKind>;
|
||||||
|
TScalarRecordRegistry = TKeywordMappingRegistry<TScalar.TKind>;
|
||||||
|
|
||||||
// A record of scalar values, based on a definition.
|
// A record of scalar values, based on a definition.
|
||||||
TScalarRecord = record
|
TScalarRecord = record
|
||||||
public
|
public
|
||||||
constructor Create(const ADef: TScalarRecordDefinition; const AFields: TArray<TScalar.TValue>);
|
constructor Create(const ADef: IScalarRecordDefinition; const AFields: TArray<TScalar.TValue>);
|
||||||
function GetDef: TScalarRecordDefinition; inline;
|
function GetDef: IScalarRecordDefinition; inline;
|
||||||
function GetFields: TArray<TScalar.TValue>; inline;
|
function GetFields: TArray<TScalar.TValue>; inline;
|
||||||
function GetKeys(const Key: IKeyword): TScalar;
|
function GetKeys(const Key: IKeyword): TScalar;
|
||||||
property Def: TScalarRecordDefinition read GetDef;
|
property Def: IScalarRecordDefinition read GetDef;
|
||||||
property Fields: TArray<TScalar.TValue> read GetFields;
|
property Fields: TArray<TScalar.TValue> read GetFields;
|
||||||
property Keys[const Key: IKeyword]: TScalar read GetKeys; default;
|
property Keys[const Key: IKeyword]: TScalar read GetKeys; default;
|
||||||
strict private
|
strict private
|
||||||
FDef: TScalarRecordDefinition;
|
FDef: IScalarRecordDefinition;
|
||||||
FFields: TArray<TScalar.TValue>;
|
FFields: TArray<TScalar.TValue>;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -142,22 +145,21 @@ type
|
|||||||
IRecordSeries = interface
|
IRecordSeries = interface
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
function GetCount: Int64;
|
function GetCount: Int64;
|
||||||
function GetDef: TScalarRecordDefinition;
|
function GetDef: IScalarRecordDefinition;
|
||||||
function GetItems(Idx: Integer): TScalarRecord;
|
|
||||||
function GetTotalCount: Int64;
|
function GetTotalCount: Int64;
|
||||||
|
function GetFields(const Key: IKeyword): ISeries;
|
||||||
{$endregion}
|
{$endregion}
|
||||||
procedure Add(const Item: TScalarRecord; Lookback: Int64 = -1);
|
procedure Add(const Item: TScalarRecord; Lookback: Int64 = -1);
|
||||||
function CreateMemberSeries(const Key: IKeyword): ISeries;
|
|
||||||
property Count: Int64 read GetCount;
|
property Count: Int64 read GetCount;
|
||||||
property Def: TScalarRecordDefinition read GetDef;
|
property Def: IScalarRecordDefinition read GetDef;
|
||||||
property Items[Idx: Integer]: TScalarRecord read GetItems; default;
|
property Fields[const Key: IKeyword]: ISeries read GetFields; default;
|
||||||
property TotalCount: Int64 read GetTotalCount;
|
property TotalCount: Int64 read GetTotalCount;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// A time series of scalar records, optimized for memory and access speed.
|
// A time series of scalar records, optimized for memory and access speed.
|
||||||
TScalarRecordSeries = class(TInterfacedObject, IRecordSeries)
|
TScalarRecordSeries = class(TInterfacedObject, IRecordSeries)
|
||||||
type
|
type
|
||||||
TMemberSeries = class(TInterfacedObject, ISeries)
|
TMemberSeries = class(TObject, ISeries)
|
||||||
private
|
private
|
||||||
FRecordSeries: TScalarRecordSeries;
|
FRecordSeries: TScalarRecordSeries;
|
||||||
FKind: TScalar.TKind;
|
FKind: TScalar.TKind;
|
||||||
@@ -165,26 +167,29 @@ type
|
|||||||
function GetCount: Int64;
|
function GetCount: Int64;
|
||||||
function GetItems(Idx: Integer): TScalar;
|
function GetItems(Idx: Integer): TScalar;
|
||||||
function GetTotalCount: Int64;
|
function GetTotalCount: Int64;
|
||||||
|
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
|
||||||
|
function _AddRef: Integer; stdcall;
|
||||||
|
function _Release: Integer; stdcall;
|
||||||
public
|
public
|
||||||
constructor Create(ARecordSeries: TScalarRecordSeries; AElementIdx: Integer);
|
constructor Create(ARecordSeries: TScalarRecordSeries; AElementIdx: Integer);
|
||||||
destructor Destroy; override;
|
|
||||||
end;
|
end;
|
||||||
private
|
private
|
||||||
FDef: TScalarRecordDefinition;
|
FDef: IScalarRecordDefinition;
|
||||||
FArray: TChunkArray<TScalar.TValue>;
|
FArray: TChunkArray<TScalar.TValue>;
|
||||||
|
FFields: TArray<TMemberSeries>;
|
||||||
FTotalCount: Int64;
|
FTotalCount: Int64;
|
||||||
function GetCount: Int64; inline;
|
function GetCount: Int64; inline;
|
||||||
function GetDef: TScalarRecordDefinition; inline;
|
function GetFields(const Key: IKeyword): ISeries;
|
||||||
function GetItems(Idx: Integer): TScalarRecord; inline;
|
function GetDef: IScalarRecordDefinition; inline;
|
||||||
function GetTotalCount: Int64; inline;
|
function GetTotalCount: Int64; inline;
|
||||||
function GetItemRef(Idx: Integer): TChunkArray<TScalar.TValue>.PT; inline;
|
function GetItemRef(Idx: Integer): TChunkArray<TScalar.TValue>.PT; inline;
|
||||||
public
|
public
|
||||||
constructor Create(const ADef: TScalarRecordDefinition);
|
constructor Create(const ADef: IScalarRecordDefinition);
|
||||||
|
destructor Destroy; override;
|
||||||
procedure Add(const Item: TScalarRecord; Lookback: Int64 = -1);
|
procedure Add(const Item: TScalarRecord; Lookback: Int64 = -1);
|
||||||
function CreateMemberSeries(const Key: IKeyword): ISeries;
|
|
||||||
property Count: Int64 read GetCount;
|
property Count: Int64 read GetCount;
|
||||||
property Def: TScalarRecordDefinition read GetDef;
|
property Fields[const Key: IKeyword]: ISeries read GetFields; default;
|
||||||
property Items[Idx: Integer]: TScalarRecord read GetItems; default;
|
property Def: IScalarRecordDefinition read GetDef;
|
||||||
property TotalCount: Int64 read GetTotalCount;
|
property TotalCount: Int64 read GetTotalCount;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -519,14 +524,14 @@ end;
|
|||||||
|
|
||||||
{ TScalarRecord }
|
{ TScalarRecord }
|
||||||
|
|
||||||
constructor TScalarRecord.Create(const ADef: TScalarRecordDefinition; const AFields: TArray<TScalar.TValue>);
|
constructor TScalarRecord.Create(const ADef: IScalarRecordDefinition; const AFields: TArray<TScalar.TValue>);
|
||||||
begin
|
begin
|
||||||
Assert(Length(ADef.Fields) = Length(AFields), 'Field definition and value count must match.');
|
Assert(Length(ADef.Fields) = Length(AFields), 'Field definition and value count must match.');
|
||||||
FDef := ADef;
|
FDef := ADef;
|
||||||
FFields := AFields;
|
FFields := AFields;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TScalarRecord.GetDef: TScalarRecordDefinition;
|
function TScalarRecord.GetDef: IScalarRecordDefinition;
|
||||||
begin
|
begin
|
||||||
Result := FDef;
|
Result := FDef;
|
||||||
end;
|
end;
|
||||||
@@ -549,11 +554,21 @@ end;
|
|||||||
|
|
||||||
{ TScalarRecordSeries }
|
{ TScalarRecordSeries }
|
||||||
|
|
||||||
constructor TScalarRecordSeries.Create(const ADef: TScalarRecordDefinition);
|
constructor TScalarRecordSeries.Create(const ADef: IScalarRecordDefinition);
|
||||||
begin
|
begin
|
||||||
Assert(Length(ADef.Fields) > 0);
|
Assert(Length(ADef.Fields) > 0);
|
||||||
FDef := ADef;
|
FDef := ADef;
|
||||||
FTotalCount := 0;
|
FTotalCount := 0;
|
||||||
|
SetLength(FFields, Length(FDef.Fields));
|
||||||
|
for var i := 0 to High(FFields) do
|
||||||
|
FFields[i] := TMemberSeries.Create(Self, i);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TScalarRecordSeries.Destroy;
|
||||||
|
begin
|
||||||
|
for var i := High(FFields) downto 0 do
|
||||||
|
FFields[i].Free;
|
||||||
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TScalarRecordSeries.Add(const Item: TScalarRecord; Lookback: Int64 = -1);
|
procedure TScalarRecordSeries.Add(const Item: TScalarRecord; Lookback: Int64 = -1);
|
||||||
@@ -562,13 +577,13 @@ begin
|
|||||||
inc(FTotalCount);
|
inc(FTotalCount);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TScalarRecordSeries.CreateMemberSeries(const Key: IKeyword): ISeries;
|
function TScalarRecordSeries.GetFields(const Key: IKeyword): ISeries;
|
||||||
begin
|
begin
|
||||||
var elem := FDef.IndexOf(Key);
|
var elem := FDef.IndexOf(Key);
|
||||||
if elem < 0 then
|
if elem < 0 then
|
||||||
raise EArgumentException.CreateFmt('Field ":%s" not found in record definition.', [Key.Name]);
|
raise EArgumentException.CreateFmt('Field ":%s" not found in record definition.', [Key.Name]);
|
||||||
|
|
||||||
Result := TMemberSeries.Create(Self, elem);
|
Result := FFields[elem];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TScalarRecordSeries.GetCount: Int64;
|
function TScalarRecordSeries.GetCount: Int64;
|
||||||
@@ -576,7 +591,7 @@ begin
|
|||||||
Result := FArray.Count div Length(FDef.Fields);
|
Result := FArray.Count div Length(FDef.Fields);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TScalarRecordSeries.GetDef: TScalarRecordDefinition;
|
function TScalarRecordSeries.GetDef: IScalarRecordDefinition;
|
||||||
begin
|
begin
|
||||||
Result := FDef;
|
Result := FDef;
|
||||||
end;
|
end;
|
||||||
@@ -587,15 +602,6 @@ begin
|
|||||||
Result := FArray.ItemRef[(FArray.Count - len) - (Idx * len)];
|
Result := FArray.ItemRef[(FArray.Count - len) - (Idx * len)];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TScalarRecordSeries.GetItems(Idx: Integer): TScalarRecord;
|
|
||||||
var
|
|
||||||
values: TArray<TScalar.TValue>;
|
|
||||||
begin
|
|
||||||
SetLength(values, Length(FDef.Fields));
|
|
||||||
Move(GetItemRef(Idx)^, values[0], sizeof(TScalar.TValue) * Length(values));
|
|
||||||
Result.Create(FDef, values);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TScalarRecordSeries.GetTotalCount: Int64;
|
function TScalarRecordSeries.GetTotalCount: Int64;
|
||||||
begin
|
begin
|
||||||
Result := FTotalCount;
|
Result := FTotalCount;
|
||||||
@@ -643,21 +649,16 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TScalarRecordSeries.TMemberSeries }
|
||||||
|
|
||||||
constructor TScalarRecordSeries.TMemberSeries.Create(ARecordSeries: TScalarRecordSeries; AElementIdx: Integer);
|
constructor TScalarRecordSeries.TMemberSeries.Create(ARecordSeries: TScalarRecordSeries; AElementIdx: Integer);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FRecordSeries := ARecordSeries;
|
FRecordSeries := ARecordSeries;
|
||||||
FRecordSeries._AddRef;
|
|
||||||
FKind := FRecordSeries.FDef.Fields[AElementIdx].Value;
|
FKind := FRecordSeries.FDef.Fields[AElementIdx].Value;
|
||||||
FOffset := sizeof(TScalar.TValue) * AElementIdx;
|
FOffset := sizeof(TScalar.TValue) * AElementIdx;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TScalarRecordSeries.TMemberSeries.Destroy;
|
|
||||||
begin
|
|
||||||
FRecordSeries._Release;
|
|
||||||
inherited;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TScalarRecordSeries.TMemberSeries.GetCount: Int64;
|
function TScalarRecordSeries.TMemberSeries.GetCount: Int64;
|
||||||
begin
|
begin
|
||||||
Result := FRecordSeries.Count;
|
Result := FRecordSeries.Count;
|
||||||
@@ -677,6 +678,24 @@ begin
|
|||||||
Result := FRecordSeries.TotalCount;
|
Result := FRecordSeries.TotalCount;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TScalarRecordSeries.TMemberSeries.QueryInterface(const IID: TGUID; out Obj): HResult;
|
||||||
|
begin
|
||||||
|
if GetInterface(IID, Obj) then
|
||||||
|
Result := S_OK
|
||||||
|
else
|
||||||
|
Result := E_NOINTERFACE;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TScalarRecordSeries.TMemberSeries._AddRef: Integer;
|
||||||
|
begin
|
||||||
|
Result := FRecordSeries._AddRef;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TScalarRecordSeries.TMemberSeries._Release: Integer;
|
||||||
|
begin
|
||||||
|
Result := FRecordSeries._Release;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TScalarSeries }
|
{ TScalarSeries }
|
||||||
|
|
||||||
constructor TScalarSeries.Create(AKind: TScalar.TKind);
|
constructor TScalarSeries.Create(AKind: TScalar.TKind);
|
||||||
|
|||||||
Reference in New Issue
Block a user