Streamlining dataflow
This commit is contained in:
@@ -234,19 +234,6 @@ begin
|
||||
end;
|
||||
|
||||
case seriesVar.Kind of
|
||||
vkSeries:
|
||||
begin
|
||||
if (itemValue.Kind <> vkScalar) then
|
||||
raise EArgumentException.Create('Can only add scalar values to a TScalarSeries.');
|
||||
|
||||
with seriesVar.AsSeries do
|
||||
begin
|
||||
if (itemValue.AsScalar.Kind <> Kind) then
|
||||
raise EArgumentException
|
||||
.CreateFmt('Type mismatch: Cannot add %s to a series of %s.', [itemValue.AsScalar.Kind.ToString, Kind.ToString]);
|
||||
Add(itemValue.AsScalar.Value, lookback);
|
||||
end;
|
||||
end;
|
||||
vkRecordSeries:
|
||||
begin
|
||||
if (itemValue.Kind <> vkRecord) then
|
||||
@@ -340,14 +327,6 @@ begin
|
||||
var recordValue := series.Items[Integer(index)];
|
||||
Result := TDataValue.FromRecord(recordValue);
|
||||
end;
|
||||
vkMemberSeries:
|
||||
begin
|
||||
var memberSeries := baseValue.AsMemberSeries;
|
||||
if (index < 0) or (index >= memberSeries.Count) then
|
||||
raise EArgumentException
|
||||
.CreateFmt('Index %d is out of bounds for member series with %d elements.', [index, memberSeries.Count]);
|
||||
Result := memberSeries.Items[Integer(index)];
|
||||
end;
|
||||
else
|
||||
raise EArgumentException.Create('Indexer `[]` is not supported for this value type.');
|
||||
end;
|
||||
@@ -362,21 +341,7 @@ begin
|
||||
memberName := Node.Member.Name;
|
||||
|
||||
case baseValue.Kind of
|
||||
vkSeries:
|
||||
begin
|
||||
with baseValue.AsSeries do
|
||||
begin
|
||||
if SameText(memberName, 'Count') then
|
||||
Result := TScalar.FromInt64(Count)
|
||||
else if SameText(memberName, 'TotalCount') then
|
||||
Result := TScalar.FromInt64(TotalCount)
|
||||
else if SameText(memberName, 'Kind') then
|
||||
Result := Kind.ToString
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Member "%s" not found on TScalarSeries.', [memberName]);
|
||||
end;
|
||||
end;
|
||||
vkRecordSeries: Result := TDataValue.FromMemberSeries(baseValue.AsRecordSeries.CreateMemberSeries(memberName));
|
||||
vkRecordSeries: Result := TDataValue.FromSeries(baseValue.AsRecordSeries.CreateMemberSeries(memberName));
|
||||
vkRecord: Result := baseValue.AsRecord.Items[memberName];
|
||||
else
|
||||
raise EArgumentException.Create('Member access operator `.` is not supported for this value type.');
|
||||
@@ -462,7 +427,6 @@ begin
|
||||
case seriesValue.Kind of
|
||||
vkSeries: len := seriesValue.AsSeries.Count;
|
||||
vkRecordSeries: len := seriesValue.AsRecordSeries.Count;
|
||||
vkMemberSeries: len := seriesValue.AsMemberSeries.Count;
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Cannot get length of type %s.', [GetEnumName(TypeInfo(TDataValueKind), Ord(seriesValue.Kind))]);
|
||||
end;
|
||||
|
||||
+73
-3
@@ -5,8 +5,6 @@ interface
|
||||
// This unit is intended to be included in a 'uses' clause.
|
||||
// It self-registers its functions via its initialization section.
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Math,
|
||||
@@ -17,6 +15,58 @@ uses
|
||||
Myc.Ast.Nodes,
|
||||
Myc.Ast.Scope;
|
||||
|
||||
implementation
|
||||
|
||||
type
|
||||
// Implements a lazily evaluated, read-only series based on a source series and a mapper function.
|
||||
TMapSeries = class(TInterfacedObject, ISeries)
|
||||
private
|
||||
FSourceSeries: ISeries;
|
||||
FMapperFunc: TDataValue.TFunc;
|
||||
// ISeries
|
||||
function GetCount: Int64;
|
||||
function GetTotalCount: Int64;
|
||||
function GetItems(Idx: Integer): TScalar;
|
||||
public
|
||||
constructor Create(const ASourceSeries: ISeries; const AMapperFunc: TDataValue.TFunc);
|
||||
end;
|
||||
|
||||
{ TMapSeries }
|
||||
|
||||
constructor TMapSeries.Create(const ASourceSeries: ISeries; const AMapperFunc: TDataValue.TFunc);
|
||||
begin
|
||||
inherited Create;
|
||||
FSourceSeries := ASourceSeries;
|
||||
FMapperFunc := AMapperFunc;
|
||||
end;
|
||||
|
||||
function TMapSeries.GetCount: Int64;
|
||||
begin
|
||||
Result := FSourceSeries.Count;
|
||||
end;
|
||||
|
||||
function TMapSeries.GetTotalCount: Int64;
|
||||
begin
|
||||
Result := FSourceSeries.TotalCount;
|
||||
end;
|
||||
|
||||
function TMapSeries.GetItems(Idx: Integer): TScalar;
|
||||
var
|
||||
sourceValue: TScalar;
|
||||
argArray: TArray<TDataValue>;
|
||||
mappedValue: TDataValue;
|
||||
begin
|
||||
// Get the original item, apply the mapper function, and return the result.
|
||||
sourceValue := FSourceSeries.Items[Idx];
|
||||
argArray := [TDataValue(sourceValue)];
|
||||
mappedValue := FMapperFunc(argArray);
|
||||
|
||||
if mappedValue.Kind <> vkScalar then
|
||||
raise EInvalidCast.Create('Map function did not return a scalar value.');
|
||||
|
||||
Result := mappedValue.AsScalar;
|
||||
end;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
//== Native Function Implementations
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -77,6 +127,7 @@ begin
|
||||
skInteger, skInt64: Result := arg; // Ceil on an integer is a no-op
|
||||
skSingle: Result := TScalar.FromInt64(Ceil(arg.Value.AsSingle));
|
||||
skDouble: Result := TScalar.FromInt64(Ceil(arg.Value.AsDouble));
|
||||
skDecimal: Result := TScalar.FromInt64(Ceil(Double(arg.Value.AsDecimal)));
|
||||
else
|
||||
raise EArgumentException.Create('Ceil requires a numeric argument.');
|
||||
end;
|
||||
@@ -91,7 +142,7 @@ begin
|
||||
skInteger, skInt64: Result := arg; // Floor on an integer is a no-op
|
||||
skSingle: Result := TScalar.FromInt64(Floor(arg.Value.AsSingle));
|
||||
skDouble: Result := TScalar.FromInt64(Floor(arg.Value.AsDouble));
|
||||
skDecimal: Result := TScalar.FromInt64(Trunc(arg.Value.AsDecimal));
|
||||
skDecimal: Result := TScalar.FromInt64(Floor(Double(arg.Value.AsDecimal)));
|
||||
else
|
||||
raise EArgumentException.Create('Floor requires a numeric argument.');
|
||||
end;
|
||||
@@ -113,6 +164,24 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// Maps a series to a new series by applying a function to each element.
|
||||
function NativeMap(const Args: TArray<TDataValue>): TDataValue;
|
||||
var
|
||||
sourceArg: TDataValue;
|
||||
begin
|
||||
if Length(Args) <> 2 then
|
||||
raise EArgumentException.Create('Map requires exactly two arguments: a series and a function.');
|
||||
|
||||
sourceArg := Args[0];
|
||||
if not (sourceArg.Kind in [vkSeries]) then
|
||||
raise EArgumentException.Create('The first argument to Map must be a series.');
|
||||
|
||||
if Args[1].Kind <> vkMethod then
|
||||
raise EArgumentException.Create('The second argument to Map must be a function.');
|
||||
|
||||
Result := TDataValue.FromSeries(TMapSeries.Create(sourceArg.AsSeries, Args[1].AsMethod()));
|
||||
end;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
//== Library Registration
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -124,6 +193,7 @@ begin
|
||||
AScope.Define('Ceil', TDataValue(NativeCeil));
|
||||
AScope.Define('Floor', TDataValue(NativeFloor));
|
||||
AScope.Define('Sign', TDataValue(NativeSign));
|
||||
AScope.Define('Map', TDataValue(NativeMap));
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
@@ -177,12 +177,10 @@ type
|
||||
{$region 'private'}
|
||||
function GetCount: Int64;
|
||||
function GetItems(Idx: Integer): TScalar;
|
||||
function GetKind: TScalarKind;
|
||||
function GetTotalCount: Int64;
|
||||
{$endregion}
|
||||
property Count: Int64 read GetCount;
|
||||
property Items[Idx: Integer]: TScalar read GetItems; default;
|
||||
property Kind: TScalarKind read GetKind;
|
||||
property TotalCount: Int64 read GetTotalCount;
|
||||
end;
|
||||
|
||||
@@ -197,7 +195,6 @@ type
|
||||
FArray: TChunkArray<TScalarValue>;
|
||||
FTotalCount: Int64;
|
||||
|
||||
function GetKind: TScalarKind; inline;
|
||||
function GetCount: Int64; inline;
|
||||
function GetItems(Idx: Integer): TScalar; inline;
|
||||
function GetTotalCount: Int64; inline;
|
||||
@@ -232,7 +229,6 @@ type
|
||||
FOffset: Integer;
|
||||
function GetCount: Int64;
|
||||
function GetItems(Idx: Integer): TScalar;
|
||||
function GetKind: TScalarKind;
|
||||
function GetTotalCount: Int64;
|
||||
public
|
||||
constructor Create(ARecordSeries: TScalarRecordSeries; AElementIdx: Integer);
|
||||
@@ -1524,11 +1520,6 @@ begin
|
||||
Result.Create(FKind, P^);
|
||||
end;
|
||||
|
||||
function TScalarRecordSeries.TMemberSeries.GetKind: TScalarKind;
|
||||
begin
|
||||
Result := FKind;
|
||||
end;
|
||||
|
||||
function TScalarRecordSeries.TMemberSeries.GetTotalCount: Int64;
|
||||
begin
|
||||
Result := FRecordSeries.TotalCount;
|
||||
@@ -1561,11 +1552,6 @@ begin
|
||||
Result.Create(FKind, FArray[FArray.Count - Idx - 1]);
|
||||
end;
|
||||
|
||||
function TScalarSeries.GetKind: TScalarKind;
|
||||
begin
|
||||
Result := FKind;
|
||||
end;
|
||||
|
||||
function TScalarSeries.GetTotalCount: Int64;
|
||||
begin
|
||||
Result := FTotalCount;
|
||||
|
||||
@@ -8,7 +8,7 @@ uses
|
||||
Myc.Data.Series;
|
||||
|
||||
type
|
||||
TDataValueKind = (vkVoid, vkScalar, vkText, vkSeries, vkRecordSeries, vkRecord, vkMemberSeries, vkMethod, vkGeneric);
|
||||
TDataValueKind = (vkVoid, vkScalar, vkText, vkSeries, vkRecordSeries, vkRecord, vkMethod, vkGeneric);
|
||||
|
||||
TDataValue = record
|
||||
type
|
||||
@@ -63,18 +63,16 @@ type
|
||||
|
||||
class function Defer(const Value: TDataValue; const Calc: TFunc): TDataValue; overload; static;
|
||||
|
||||
class function FromSeries(const AValue: IWriteableSeries): TDataValue; static; inline;
|
||||
class function FromRecordSeries(const AValue: IRecordSeries): TDataValue; static; inline;
|
||||
class function FromRecord(const [ref] AValue: TScalarRecord): TDataValue; static; inline;
|
||||
class function FromMemberSeries(const AValue: ISeries): TDataValue; static; inline;
|
||||
class function FromSeries(const AValue: ISeries): TDataValue; static; inline;
|
||||
|
||||
function AsScalar: TScalar; inline;
|
||||
function AsMethod: TFunc; inline;
|
||||
function AsText: String; inline;
|
||||
function AsRecordSeries: IRecordSeries; inline;
|
||||
function AsRecord: TScalarRecord; inline;
|
||||
function AsMemberSeries: ISeries; inline;
|
||||
function AsSeries: IWriteableSeries; inline;
|
||||
function AsSeries: ISeries; inline;
|
||||
|
||||
function ToString: String;
|
||||
property IsVoid: Boolean read GetIsVoid;
|
||||
@@ -186,11 +184,11 @@ begin
|
||||
Dest.FInterface := nil;
|
||||
end;
|
||||
|
||||
function TDataValue.AsMemberSeries: ISeries;
|
||||
function TDataValue.AsSeries: ISeries;
|
||||
begin
|
||||
if FKind = Ord(vkLazy) then
|
||||
exit(AsLazy.Value.AsMemberSeries);
|
||||
if (FKind <> Ord(vkMemberSeries)) then
|
||||
exit(AsLazy.Value.AsSeries);
|
||||
if (FKind <> Ord(vkSeries)) then
|
||||
raise EInvalidCast.Create('Cannot read value as MemberSeries.');
|
||||
Result := ISeries(FInterface);
|
||||
end;
|
||||
@@ -244,15 +242,6 @@ begin
|
||||
Result := FScalar;
|
||||
end;
|
||||
|
||||
function TDataValue.AsSeries: IWriteableSeries;
|
||||
begin
|
||||
if FKind = Ord(vkLazy) then
|
||||
exit(AsLazy.Value.AsSeries);
|
||||
if (FKind <> Ord(vkSeries)) then
|
||||
raise EInvalidCast.Create('Cannot read value as Series.');
|
||||
Result := IWriteableSeries(FInterface);
|
||||
end;
|
||||
|
||||
function TDataValue.AsText: String;
|
||||
begin
|
||||
if FKind = Ord(vkLazy) then
|
||||
@@ -297,9 +286,9 @@ begin
|
||||
Result.FInterface := TVal<T>.Create(AValue);
|
||||
end;
|
||||
|
||||
class function TDataValue.FromMemberSeries(const AValue: ISeries): TDataValue;
|
||||
class function TDataValue.FromSeries(const AValue: ISeries): TDataValue;
|
||||
begin
|
||||
Result.FKind := Ord(vkMemberSeries);
|
||||
Result.FKind := Ord(vkSeries);
|
||||
Result.FInterface := AValue;
|
||||
end;
|
||||
|
||||
@@ -315,12 +304,6 @@ begin
|
||||
Result.FInterface := AValue;
|
||||
end;
|
||||
|
||||
class function TDataValue.FromSeries(const AValue: IWriteableSeries): TDataValue;
|
||||
begin
|
||||
Result.FKind := Ord(vkSeries);
|
||||
Result.FInterface := AValue;
|
||||
end;
|
||||
|
||||
class operator TDataValue.Implicit(const AValue: TScalar): TDataValue;
|
||||
begin
|
||||
Result.FKind := Ord(vkScalar);
|
||||
@@ -359,7 +342,7 @@ begin
|
||||
begin
|
||||
var series := AsSeries;
|
||||
// Add type and count for series
|
||||
Result := Format('<series<%s>[%d]>', [series.Kind.ToString, series.Count]);
|
||||
Result := Format('<series[%d]>', [series.Count]);
|
||||
end;
|
||||
Ord(vkRecordSeries):
|
||||
begin
|
||||
@@ -403,12 +386,6 @@ begin
|
||||
sb.Free;
|
||||
end;
|
||||
end;
|
||||
Ord(vkMemberSeries):
|
||||
begin
|
||||
var series := AsMemberSeries;
|
||||
// Add type and count for member series
|
||||
Result := Format('<member_series<%s>[%d]>', [series.Kind.ToString, series.Count]);
|
||||
end;
|
||||
Ord(vkVoid): Result := '<void>';
|
||||
Ord(vkMethod): Result := '<method>';
|
||||
Ord(vkGeneric):
|
||||
@@ -447,7 +424,6 @@ begin
|
||||
vkSeries: Result := 'Series';
|
||||
vkRecordSeries: Result := 'RecordSeries';
|
||||
vkRecord: Result := 'Record';
|
||||
vkMemberSeries: Result := 'MemberSeries';
|
||||
vkMethod: Result := 'Method';
|
||||
else
|
||||
Result := 'unknown';
|
||||
|
||||
Reference in New Issue
Block a user