Refactoring Keyword mapping, introducing tuples
This commit is contained in:
@@ -6,7 +6,8 @@ uses
|
||||
System.SysUtils,
|
||||
System.Generics.Collections,
|
||||
System.Generics.Defaults,
|
||||
System.SyncObjs;
|
||||
System.SyncObjs,
|
||||
Myc.Data.Tuple;
|
||||
|
||||
type
|
||||
// The runtime representation of an interned keyword
|
||||
@@ -49,17 +50,18 @@ type
|
||||
// Defines a mapping from Keywords to a generic value T
|
||||
IKeywordMapping<T> = interface
|
||||
{$region 'private'}
|
||||
function GetItems(Idx: Integer): TPair<IKeyword, T>;
|
||||
function GetItems(Idx: Integer): T;
|
||||
function GetFields(const Key: IKeyword): T;
|
||||
function GetCount: Integer;
|
||||
function GetKeywords(Idx: Integer): IKeyword;
|
||||
{$endregion}
|
||||
// Finds the 0-based index for a given keyword. Returns -1 if not found.
|
||||
function IndexOf(const Key: IKeyword): Integer;
|
||||
|
||||
// Access value by Keyword (raises exception if not found)
|
||||
property Keywords[Idx: Integer]: IKeyword read GetKeywords;
|
||||
property Fields[const Key: IKeyword]: T read GetFields;
|
||||
// Access Key-Value pair by Index (0..Count-1)
|
||||
property Items[Idx: Integer]: TPair<IKeyword, T> read GetItems; default;
|
||||
property Items[Idx: Integer]: T read GetItems; default;
|
||||
|
||||
property Count: Integer read GetCount;
|
||||
end;
|
||||
|
||||
@@ -74,8 +76,9 @@ type
|
||||
FFields: TArray<TPair<IKeyword, T>>;
|
||||
FFirst, FLast: Integer;
|
||||
|
||||
function GetItems(Idx: Integer): TPair<IKeyword, T>;
|
||||
function GetItems(Idx: Integer): T;
|
||||
function GetFields(const Key: IKeyword): T;
|
||||
function GetKeywords(Idx: Integer): IKeyword;
|
||||
function GetCount: Integer;
|
||||
public
|
||||
// Expects AFields to be in the desired (canonical) order
|
||||
@@ -100,7 +103,8 @@ type
|
||||
FFields: TArray<TPair<IKeyword, T>>;
|
||||
|
||||
// IKeywordMapping implementation
|
||||
function GetItems(Idx: Integer): TPair<IKeyword, T>;
|
||||
function GetItems(Idx: Integer): T;
|
||||
function GetKeywords(Idx: Integer): IKeyword;
|
||||
function GetFields(const Key: IKeyword): T;
|
||||
function GetCount: Integer;
|
||||
public
|
||||
@@ -224,9 +228,9 @@ begin
|
||||
end;
|
||||
|
||||
// Interface method for Items property
|
||||
function TKeywordMappingRegistry<T>.TKeywordMapping.GetItems(Idx: Integer): TPair<IKeyword, T>;
|
||||
function TKeywordMappingRegistry<T>.TKeywordMapping.GetItems(Idx: Integer): T;
|
||||
begin
|
||||
Result := FFields[Idx];
|
||||
Result := FFields[Idx].Value;
|
||||
end;
|
||||
|
||||
// Interface method for Fields property
|
||||
@@ -240,6 +244,11 @@ begin
|
||||
Result := FFields[idx].Value;
|
||||
end;
|
||||
|
||||
function TKeywordMappingRegistry<T>.TKeywordMapping.GetKeywords(Idx: Integer): IKeyword;
|
||||
begin
|
||||
Result := FFields[Idx].Key;
|
||||
end;
|
||||
|
||||
function TKeywordMappingRegistry<T>.TKeywordMapping.IndexOf(const Key: IKeyword): Integer;
|
||||
var
|
||||
keyIdx, mapIdx: Integer;
|
||||
@@ -312,9 +321,14 @@ begin
|
||||
Result := FFields[idx].Value;
|
||||
end;
|
||||
|
||||
function TKeywordMapping<T>.GetItems(Idx: Integer): TPair<IKeyword, T>;
|
||||
function TKeywordMapping<T>.GetItems(Idx: Integer): T;
|
||||
begin
|
||||
Result := FFields[Idx];
|
||||
Result := FFields[Idx].Value;
|
||||
end;
|
||||
|
||||
function TKeywordMapping<T>.GetKeywords(Idx: Integer): IKeyword;
|
||||
begin
|
||||
Result := FFields[Idx].Key;
|
||||
end;
|
||||
|
||||
function TKeywordMapping<T>.IndexOf(const Key: IKeyword): Integer;
|
||||
|
||||
@@ -136,14 +136,7 @@ type
|
||||
TScalarRecordField = TPair<IKeyword, TScalar.TKind>;
|
||||
IScalarRecordDefinition = IKeywordMapping<TScalar.TKind>;
|
||||
|
||||
IScalarRecord = interface(IKeywordMapping<TScalar>)
|
||||
{$region 'private'}
|
||||
function GetDef: IScalarRecordDefinition;
|
||||
{$endregion}
|
||||
property Def: IScalarRecordDefinition read GetDef;
|
||||
end;
|
||||
|
||||
TScalarRecord = class(TInterfacedObject, IKeywordMapping<TScalar>, IScalarRecord)
|
||||
TScalarRecord = class(TInterfacedObject, IKeywordMapping<TScalar>)
|
||||
type
|
||||
TRegistry = TKeywordMappingRegistry<TScalar.TKind>;
|
||||
private
|
||||
@@ -152,12 +145,11 @@ type
|
||||
|
||||
function IndexOf(const Key: IKeyword): Integer;
|
||||
function GetCount: Integer;
|
||||
function GetDef: IScalarRecordDefinition;
|
||||
function GetItems(Idx: Integer): TPair<IKeyword, TScalar>;
|
||||
function GetItems(Idx: Integer): TScalar;
|
||||
function GetFields(const Key: IKeyword): TScalar;
|
||||
function GetKeywords(Idx: Integer): IKeyword;
|
||||
public
|
||||
constructor Create(const ADef: IScalarRecordDefinition; const AData: TArray<TScalar.TValue>);
|
||||
property Def: IScalarRecordDefinition read GetDef;
|
||||
end;
|
||||
|
||||
ISeries = interface
|
||||
@@ -228,7 +220,8 @@ type
|
||||
FFields: TArray<TMemberSeries>;
|
||||
FTotalCount: Int64;
|
||||
|
||||
function GetItems(Idx: Integer): TPair<IKeyword, ISeries>;
|
||||
function GetItems(Idx: Integer): ISeries;
|
||||
function GetKeywords(Idx: Integer): IKeyword;
|
||||
function GetCount: Integer;
|
||||
function IndexOf(const Key: IKeyword): Integer;
|
||||
|
||||
@@ -824,8 +817,8 @@ begin
|
||||
var lb := FDef.Count * Integer(Lookback);
|
||||
for var i := 0 to FDef.Count - 1 do
|
||||
begin
|
||||
Assert(Item[i].Key = FDef[i].Key, 'Mapping does not fit series definition');
|
||||
FArray.Add(Item[i].Value.Value, lb);
|
||||
Assert(Item.Keywords[i] = FDef.Keywords[i], 'Mapping does not fit series definition');
|
||||
FArray.Add(Item[i].Value, lb);
|
||||
end;
|
||||
inc(FTotalCount);
|
||||
end;
|
||||
@@ -875,10 +868,14 @@ begin
|
||||
Result := Length(FFields);
|
||||
end;
|
||||
|
||||
function TScalarRecordSeries.GetItems(Idx: Integer): TPair<IKeyword, ISeries>;
|
||||
function TScalarRecordSeries.GetItems(Idx: Integer): ISeries;
|
||||
begin
|
||||
Result.Key := FDef.Items[Idx].Key;
|
||||
Result.Value := FFields[Idx];
|
||||
Result := FFields[Idx];
|
||||
end;
|
||||
|
||||
function TScalarRecordSeries.GetKeywords(Idx: Integer): IKeyword;
|
||||
begin
|
||||
Result := FDef.Keywords[Idx];
|
||||
end;
|
||||
|
||||
function TScalarRecordSeries.IndexOf(const Key: IKeyword): Integer;
|
||||
@@ -946,7 +943,7 @@ end;
|
||||
constructor TScalarRecordSeries.TMemberSeries.Create(ARecordSeries: TScalarRecordSeries; AElementIdx: Integer);
|
||||
begin
|
||||
inherited Create(ARecordSeries);
|
||||
FKind := ARecordSeries.FDef[AElementIdx].Value;
|
||||
FKind := ARecordSeries.FDef[AElementIdx];
|
||||
FOffset := sizeof(TScalar.TValue) * AElementIdx;
|
||||
end;
|
||||
|
||||
@@ -1043,11 +1040,6 @@ begin
|
||||
Result := FDef.Count;
|
||||
end;
|
||||
|
||||
function TScalarRecord.GetDef: IScalarRecordDefinition;
|
||||
begin
|
||||
Result := FDef;
|
||||
end;
|
||||
|
||||
function TScalarRecord.GetFields(const Key: IKeyword): TScalar;
|
||||
var
|
||||
idx: Integer;
|
||||
@@ -1057,15 +1049,19 @@ begin
|
||||
exit(Default(TScalar));
|
||||
|
||||
// Return the raw TValue at the offset
|
||||
Result.Kind := FDef[idx].Value;
|
||||
Result.Kind := FDef[idx];
|
||||
Result.Value := FData[idx];
|
||||
end;
|
||||
|
||||
function TScalarRecord.GetItems(Idx: Integer): TPair<IKeyword, TScalar>;
|
||||
function TScalarRecord.GetItems(Idx: Integer): TScalar;
|
||||
begin
|
||||
Result.Key := FDef[Idx].Key;
|
||||
Result.Value.Kind := FDef[idx].Value;
|
||||
Result.Value.Value := FData[idx];
|
||||
Result.Kind := FDef[idx];
|
||||
Result.Value := FData[idx];
|
||||
end;
|
||||
|
||||
function TScalarRecord.GetKeywords(Idx: Integer): IKeyword;
|
||||
begin
|
||||
Result := FDef.Keywords[Idx];
|
||||
end;
|
||||
|
||||
function TScalarRecord.IndexOf(const Key: IKeyword): Integer;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
unit Myc.Data.Tuple;
|
||||
|
||||
interface
|
||||
|
||||
type
|
||||
ITuple<T> = interface
|
||||
{$region 'private'}
|
||||
function GetItems(Idx: Integer): T;
|
||||
function GetCount: Integer;
|
||||
{$endregion}
|
||||
property Items[Idx: Integer]: T read GetItems; default;
|
||||
property Count: Integer read GetCount;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
||||
+29
-24
@@ -14,23 +14,31 @@ uses
|
||||
|
||||
type
|
||||
TDataValueKind = (
|
||||
// base types
|
||||
vkVoid,
|
||||
vkScalar,
|
||||
vkText,
|
||||
vkMethod,
|
||||
// generic structured types
|
||||
vkTuple,
|
||||
vkRecord,
|
||||
// scalar structured types
|
||||
// vkScalarTuple, (later)
|
||||
vkScalarRecord,
|
||||
// Series and streams
|
||||
vkSeries,
|
||||
vkRecordSeries,
|
||||
vkScalarRecord,
|
||||
vkGenericRecord,
|
||||
vkStream,
|
||||
// internal types
|
||||
vkManagedObject,
|
||||
vkMethod,
|
||||
vkInterface,
|
||||
vkPointer,
|
||||
vkStream,
|
||||
vkGeneric
|
||||
);
|
||||
|
||||
TDataValue = record
|
||||
type
|
||||
TTuple = TArray<TDataValue>;
|
||||
TFunc = reference to function(const ArgNodes: TArray<TDataValue>): TDataValue;
|
||||
|
||||
private
|
||||
@@ -84,7 +92,7 @@ type
|
||||
class function Map(const SourceSeries: ISeries; const MapperFunc: TFunc): ISeries; static;
|
||||
|
||||
class function FromRecordSeries(const AValue: IWriteableScalarRecordSeries): TDataValue; static; inline;
|
||||
class function FromScalarRecord(const AValue: IScalarRecord): TDataValue; static; inline;
|
||||
class function FromScalarRecord(const AValue: IKeywordMapping<TScalar>): TDataValue; static; inline;
|
||||
class function FromGenericRecord(const AValue: IKeywordMapping<TDataValue>): TDataValue; static; inline;
|
||||
class function FromSeries(const AValue: ISeries): TDataValue; static; inline;
|
||||
class function FromStream(const AStream: IStream): TDataValue; static; inline;
|
||||
@@ -94,8 +102,8 @@ type
|
||||
function AsMethod: TFunc; inline;
|
||||
function AsText: String; inline;
|
||||
function AsRecordSeries: IWriteableScalarRecordSeries; inline;
|
||||
function AsScalarRecord: IScalarRecord; inline;
|
||||
function AsGenericRecord: IKeywordMapping<TDataValue>; inline;
|
||||
function AsScalarRecord: IKeywordMapping<TScalar>; inline;
|
||||
function AsRecord: IKeywordMapping<TDataValue>; inline;
|
||||
function AsSeries: ISeries; inline;
|
||||
function AsObject: TObject; overload; inline;
|
||||
|
||||
@@ -141,7 +149,7 @@ begin
|
||||
vkSeries: Result := 'Series';
|
||||
vkRecordSeries: Result := 'RecordSeries';
|
||||
vkScalarRecord: Result := 'ScalarRecord';
|
||||
vkGenericRecord: Result := 'GenericRecord';
|
||||
vkRecord: Result := 'Record';
|
||||
vkManagedObject: Result := 'Object';
|
||||
vkMethod: Result := 'Method';
|
||||
vkInterface: Result := 'Interface';
|
||||
@@ -268,7 +276,7 @@ begin
|
||||
Result.FInterface := AValue;
|
||||
end;
|
||||
|
||||
class function TDataValue.FromScalarRecord(const AValue: IScalarRecord): TDataValue;
|
||||
class function TDataValue.FromScalarRecord(const AValue: IKeywordMapping<TScalar>): TDataValue;
|
||||
begin
|
||||
Result.FKind := vkScalarRecord;
|
||||
Result.FInterface := AValue;
|
||||
@@ -276,7 +284,7 @@ end;
|
||||
|
||||
class function TDataValue.FromGenericRecord(const AValue: IKeywordMapping<TDataValue>): TDataValue;
|
||||
begin
|
||||
Result.FKind := vkGenericRecord;
|
||||
Result.FKind := vkRecord;
|
||||
Result.FInterface := AValue;
|
||||
end;
|
||||
|
||||
@@ -350,17 +358,17 @@ begin
|
||||
Result := Pointer(FScalar.Value.AsInt64);
|
||||
end;
|
||||
|
||||
function TDataValue.AsScalarRecord: IScalarRecord;
|
||||
function TDataValue.AsScalarRecord: IKeywordMapping<TScalar>;
|
||||
begin
|
||||
if (FKind <> vkScalarRecord) then
|
||||
raise EInvalidCast.Create('Cannot read value as Record.');
|
||||
Result := IScalarRecord(FInterface);
|
||||
Result := IKeywordMapping<TScalar>(FInterface);
|
||||
end;
|
||||
|
||||
function TDataValue.AsGenericRecord: IKeywordMapping<TDataValue>;
|
||||
function TDataValue.AsRecord: IKeywordMapping<TDataValue>;
|
||||
begin
|
||||
if (FKind <> vkGenericRecord) then
|
||||
raise EInvalidCast.Create('Cannot read value as GenericRecord.');
|
||||
if (FKind <> vkRecord) then
|
||||
raise EInvalidCast.Create('Cannot read value as Record.');
|
||||
Result := IKeywordMapping<TDataValue>(FInterface);
|
||||
end;
|
||||
|
||||
@@ -388,7 +396,6 @@ end;
|
||||
function TDataValue.ToString: String;
|
||||
var
|
||||
sb: TStringBuilder;
|
||||
field: TScalarRecordField;
|
||||
genField: TPair<IKeyword, TDataValue>;
|
||||
first: Boolean;
|
||||
i: Integer;
|
||||
@@ -412,8 +419,7 @@ begin
|
||||
begin
|
||||
if not first then
|
||||
sb.Append(',');
|
||||
field := series.Def[i];
|
||||
sb.Append(field.Key.Name);
|
||||
sb.Append(series.Def.Keywords[i].Name);
|
||||
first := False;
|
||||
end;
|
||||
sb.Append('}');
|
||||
@@ -433,7 +439,7 @@ begin
|
||||
begin
|
||||
if not first then
|
||||
sb.Append(',');
|
||||
sb.Append(rec[i].Key.Name);
|
||||
sb.Append(rec.Keywords[i].Name);
|
||||
first := False;
|
||||
end;
|
||||
sb.Append('}');
|
||||
@@ -442,9 +448,9 @@ begin
|
||||
sb.Free;
|
||||
end;
|
||||
end;
|
||||
vkGenericRecord:
|
||||
vkRecord:
|
||||
begin
|
||||
var rec := AsGenericRecord;
|
||||
var rec := AsRecord;
|
||||
sb := TStringBuilder.Create;
|
||||
try
|
||||
sb.Append('{');
|
||||
@@ -453,12 +459,11 @@ begin
|
||||
begin
|
||||
if not first then
|
||||
sb.Append(',');
|
||||
genField := rec[i];
|
||||
sb.Append(genField.Key.Name);
|
||||
sb.Append(rec.Keywords[i].Name);
|
||||
first := False;
|
||||
end;
|
||||
sb.Append('}');
|
||||
Result := Format('<generic_record%s>', [sb.ToString]);
|
||||
Result := Format('<record%s>', [sb.ToString]);
|
||||
finally
|
||||
sb.Free;
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user