Data Types
This commit is contained in:
@@ -8,12 +8,11 @@ uses
|
||||
Myc.Data.Types;
|
||||
|
||||
type
|
||||
TImplDataArrayValue = class; // fwd
|
||||
|
||||
// Implements the array data type.
|
||||
TImplDataArrayType = class(TInterfacedObject, IDataType, IDataArrayType)
|
||||
TDataArrayType = class(TInterfacedObject, IDataType, IDataArrayType)
|
||||
private
|
||||
FElementType: IDataType;
|
||||
FEmptyValue: IDataArrayValue; // Cached empty array value for this type
|
||||
function GetElementType: IDataType;
|
||||
function GetName: String;
|
||||
function GetKind: TDataKind;
|
||||
@@ -22,8 +21,14 @@ type
|
||||
function CreateValue(const AItems: array of IDataValue): IDataArrayValue;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SyncObjs;
|
||||
|
||||
type
|
||||
// Implements the array data value.
|
||||
TImplDataArrayValue = class(TInterfacedObject, IDataValue, IDataArrayValue)
|
||||
TDataArrayValue = class(TInterfacedObject, IDataValue, IDataArrayValue)
|
||||
private
|
||||
FArrayType: IDataArrayType;
|
||||
FItems: TArray<IDataValue>;
|
||||
@@ -35,14 +40,34 @@ type
|
||||
constructor Create(const AArrayType: IDataArrayType; const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
implementation
|
||||
// Optimized implementation for an array with 0 elements.
|
||||
TDataArrayValue0 = class(TInterfacedObject, IDataValue, IDataArrayValue)
|
||||
private
|
||||
FArrayType: IDataArrayType;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetElementCount: Integer;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const AArrayType: IDataArrayType);
|
||||
end;
|
||||
|
||||
uses
|
||||
System.SyncObjs;
|
||||
// Optimized implementation for an array with 1 element.
|
||||
TDataArrayValue1 = class(TInterfacedObject, IDataValue, IDataArrayValue)
|
||||
private
|
||||
FArrayType: IDataArrayType;
|
||||
FItem0: IDataValue;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetElementCount: Integer;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const AArrayType: IDataArrayType; const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
{ TImplDataArrayValue }
|
||||
{ TDataArrayValue (generic implementation for N > 1 elements) }
|
||||
|
||||
constructor TImplDataArrayValue.Create(const AArrayType: IDataArrayType; const AItems: array of IDataValue);
|
||||
constructor TDataArrayValue.Create(const AArrayType: IDataArrayType; const AItems: array of IDataValue);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
@@ -53,12 +78,12 @@ begin
|
||||
FItems[i] := AItems[i];
|
||||
end;
|
||||
|
||||
function TImplDataArrayValue.GetDataType: IDataType;
|
||||
function TDataArrayValue.GetDataType: IDataType;
|
||||
begin
|
||||
Result := FArrayType;
|
||||
end;
|
||||
|
||||
function TImplDataArrayValue.GetAsString: string;
|
||||
function TDataArrayValue.GetAsString: string;
|
||||
var
|
||||
sb: TStringBuilder;
|
||||
i: Integer;
|
||||
@@ -79,28 +104,91 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TImplDataArrayValue.GetElementCount: Integer;
|
||||
function TDataArrayValue.GetElementCount: Integer;
|
||||
begin
|
||||
Result := Length(FItems);
|
||||
end;
|
||||
|
||||
function TImplDataArrayValue.GetItem(Idx: Integer): IDataValue;
|
||||
function TDataArrayValue.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
Result := FItems[Idx];
|
||||
end;
|
||||
|
||||
{ TImplDataArrayType }
|
||||
{ TDataArrayValue0 }
|
||||
|
||||
constructor TImplDataArrayType.Create(const AElementType: IDataType);
|
||||
constructor TDataArrayValue0.Create(const AArrayType: IDataArrayType);
|
||||
begin
|
||||
inherited Create;
|
||||
FArrayType := AArrayType;
|
||||
end;
|
||||
|
||||
function TDataArrayValue0.GetAsString: string;
|
||||
begin
|
||||
Result := '[]';
|
||||
end;
|
||||
|
||||
function TDataArrayValue0.GetDataType: IDataType;
|
||||
begin
|
||||
Result := FArrayType;
|
||||
end;
|
||||
|
||||
function TDataArrayValue0.GetElementCount: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
function TDataArrayValue0.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
raise EArgumentException.Create('Index out of bounds');
|
||||
end;
|
||||
|
||||
{ TDataArrayValue1 }
|
||||
|
||||
constructor TDataArrayValue1.Create(const AArrayType: IDataArrayType; const AItems: array of IDataValue);
|
||||
begin
|
||||
inherited Create;
|
||||
FArrayType := AArrayType;
|
||||
FItem0 := AItems[0];
|
||||
end;
|
||||
|
||||
function TDataArrayValue1.GetAsString: string;
|
||||
begin
|
||||
Result := '[' + FItem0.AsString + ']';
|
||||
end;
|
||||
|
||||
function TDataArrayValue1.GetDataType: IDataType;
|
||||
begin
|
||||
Result := FArrayType;
|
||||
end;
|
||||
|
||||
function TDataArrayValue1.GetElementCount: Integer;
|
||||
begin
|
||||
Result := 1;
|
||||
end;
|
||||
|
||||
function TDataArrayValue1.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
case Idx of
|
||||
0: Result := FItem0;
|
||||
else
|
||||
raise EArgumentException.Create('Index out of bounds');
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TDataArrayType }
|
||||
|
||||
constructor TDataArrayType.Create(const AElementType: IDataType);
|
||||
begin
|
||||
inherited Create;
|
||||
FElementType := AElementType;
|
||||
FEmptyValue := nil;
|
||||
end;
|
||||
|
||||
function TImplDataArrayType.CreateValue(const AItems: array of IDataValue): IDataArrayValue;
|
||||
function TDataArrayType.CreateValue(const AItems: array of IDataValue): IDataArrayValue;
|
||||
var
|
||||
item: IDataValue;
|
||||
i: Integer;
|
||||
newValue: IDataArrayValue;
|
||||
begin
|
||||
// Validate that all items match the element type of this array type.
|
||||
i := 0;
|
||||
@@ -112,20 +200,38 @@ begin
|
||||
[i, FElementType.Name, item.DataType.Name]);
|
||||
inc(i);
|
||||
end;
|
||||
Result := TImplDataArrayValue.Create(Self, AItems);
|
||||
|
||||
// Use optimized implementations for arrays with 0 or 1 elements.
|
||||
case Length(AItems) of
|
||||
0:
|
||||
begin
|
||||
// Thread-safe lazy initialization for the cached empty array value.
|
||||
if FEmptyValue = nil then
|
||||
begin
|
||||
newValue := TDataArrayValue0.Create(Self);
|
||||
if TInterlocked.CompareExchange(Pointer(FEmptyValue), Pointer(newValue), nil) <> nil then
|
||||
newValue := nil; // Another thread won, discard our instance.
|
||||
end;
|
||||
Result := FEmptyValue;
|
||||
end;
|
||||
1: Result := TDataArrayValue1.Create(Self, AItems);
|
||||
else
|
||||
// Use the generic implementation for arrays with more than 1 element.
|
||||
Result := TDataArrayValue.Create(Self, AItems);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TImplDataArrayType.GetElementType: IDataType;
|
||||
function TDataArrayType.GetElementType: IDataType;
|
||||
begin
|
||||
Result := FElementType;
|
||||
end;
|
||||
|
||||
function TImplDataArrayType.GetName: String;
|
||||
function TDataArrayType.GetName: String;
|
||||
begin
|
||||
Result := Format('Array<%s>', [FElementType.Name]);
|
||||
end;
|
||||
|
||||
function TImplDataArrayType.GetKind: TDataKind;
|
||||
function TDataArrayType.GetKind: TDataKind;
|
||||
begin
|
||||
Result := dkArray;
|
||||
end;
|
||||
|
||||
@@ -8,18 +8,7 @@ uses
|
||||
Myc.Data.Types;
|
||||
|
||||
type
|
||||
TImplDataEnumValue = class(TInterfacedObject, IDataEnumValue)
|
||||
private
|
||||
FDataType: IDataEnumType;
|
||||
FValue: Integer;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetValue: Integer;
|
||||
public
|
||||
constructor Create(const ADataType: IDataEnumType; const AValue: Integer);
|
||||
end;
|
||||
|
||||
TImplDataEnumType = class(TInterfacedObject, IDataEnumType)
|
||||
TDataEnumType = class(TInterfacedObject, IDataEnumType)
|
||||
private
|
||||
FName: string;
|
||||
FIdentifiers: TArray<string>;
|
||||
@@ -38,9 +27,21 @@ type
|
||||
|
||||
implementation
|
||||
|
||||
{ TImplDataEnumType }
|
||||
type
|
||||
TDataEnumValue = class(TInterfacedObject, IDataEnumValue)
|
||||
private
|
||||
FDataType: IDataEnumType;
|
||||
FValue: Integer;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetValue: Integer;
|
||||
public
|
||||
constructor Create(const ADataType: IDataEnumType; const AValue: Integer);
|
||||
end;
|
||||
|
||||
constructor TImplDataEnumType.Create(const AName: string; const AIdentifiers: array of string);
|
||||
{ TDataEnumType }
|
||||
|
||||
constructor TDataEnumType.Create(const AName: string; const AIdentifiers: array of string);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
@@ -57,46 +58,46 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
destructor TImplDataEnumType.Destroy;
|
||||
destructor TDataEnumType.Destroy;
|
||||
begin
|
||||
FIdentifierMap.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TImplDataEnumType.GetName: String;
|
||||
function TDataEnumType.GetName: String;
|
||||
begin
|
||||
Result := FName;
|
||||
end;
|
||||
|
||||
function TImplDataEnumType.GetKind: TDataKind;
|
||||
function TDataEnumType.GetKind: TDataKind;
|
||||
begin
|
||||
Result := dkEnum;
|
||||
end;
|
||||
|
||||
function TImplDataEnumType.GetIdentifier(Idx: Integer): string;
|
||||
function TDataEnumType.GetIdentifier(Idx: Integer): string;
|
||||
begin
|
||||
Result := FIdentifiers[Idx];
|
||||
end;
|
||||
|
||||
function TImplDataEnumType.GetIdentifierCount: Integer;
|
||||
function TDataEnumType.GetIdentifierCount: Integer;
|
||||
begin
|
||||
Result := Length(FIdentifiers);
|
||||
end;
|
||||
|
||||
function TImplDataEnumType.IndexOf(const AIdentifier: string): Integer;
|
||||
function TDataEnumType.IndexOf(const AIdentifier: string): Integer;
|
||||
begin
|
||||
if not FIdentifierMap.TryGetValue(AIdentifier, Result) then
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
function TImplDataEnumType.CreateValue(const AValue: Integer): IDataEnumValue;
|
||||
function TDataEnumType.CreateValue(const AValue: Integer): IDataEnumValue;
|
||||
begin
|
||||
if (AValue < 0) or (AValue >= Length(FIdentifiers)) then
|
||||
raise EArgumentException.Create('Invalid enum value');
|
||||
Result := TImplDataEnumValue.Create(Self, AValue);
|
||||
Result := TDataEnumValue.Create(Self, AValue);
|
||||
end;
|
||||
|
||||
function TImplDataEnumType.CreateValue(const AIdentifier: string): IDataEnumValue;
|
||||
function TDataEnumType.CreateValue(const AIdentifier: string): IDataEnumValue;
|
||||
var
|
||||
idx: Integer;
|
||||
begin
|
||||
@@ -106,25 +107,25 @@ begin
|
||||
Result := CreateValue(idx);
|
||||
end;
|
||||
|
||||
{ TImplDataEnumValue }
|
||||
{ TDataEnumValue }
|
||||
|
||||
constructor TImplDataEnumValue.Create(const ADataType: IDataEnumType; const AValue: Integer);
|
||||
constructor TDataEnumValue.Create(const ADataType: IDataEnumType; const AValue: Integer);
|
||||
begin
|
||||
FDataType := ADataType;
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
function TImplDataEnumValue.GetDataType: IDataType;
|
||||
function TDataEnumValue.GetDataType: IDataType;
|
||||
begin
|
||||
Result := FDataType;
|
||||
end;
|
||||
|
||||
function TImplDataEnumValue.GetAsString: string;
|
||||
function TDataEnumValue.GetAsString: string;
|
||||
begin
|
||||
Result := FDataType.Identifiers[FValue];
|
||||
end;
|
||||
|
||||
function TImplDataEnumValue.GetValue: Integer;
|
||||
function TDataEnumValue.GetValue: Integer;
|
||||
begin
|
||||
Result := FValue;
|
||||
end;
|
||||
|
||||
@@ -6,9 +6,30 @@ uses
|
||||
System.SysUtils,
|
||||
Myc.Data.Types;
|
||||
|
||||
type
|
||||
// Implements the float data type.
|
||||
TDataFloatType = class(TInterfacedObject, IDataType, IDataFloatType)
|
||||
strict private
|
||||
class var
|
||||
FSingleton: IDataFloatType;
|
||||
FZero: IDataFloatValue;
|
||||
FNaN: IDataFloatValue;
|
||||
class constructor CreateClass;
|
||||
public
|
||||
function GetName: String;
|
||||
function GetKind: TDataKind;
|
||||
function CreateValue(Init: Double): IDataFloatValue;
|
||||
class property Singleton: IDataFloatType read FSingleton;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.Math;
|
||||
|
||||
type
|
||||
// Implements the float data value.
|
||||
TImplDataFloatValue = class(TInterfacedObject, IDataValue, IDataFloatValue)
|
||||
TDataFloatValue = class(TInterfacedObject, IDataValue, IDataFloatValue)
|
||||
private
|
||||
FValue: Double;
|
||||
public
|
||||
@@ -22,64 +43,107 @@ type
|
||||
function GetValue: Double;
|
||||
end;
|
||||
|
||||
// Implements the float data type.
|
||||
TImplDataFloatType = class(TInterfacedObject, IDataType, IDataFloatType)
|
||||
strict private
|
||||
class var
|
||||
FSingleton: IDataFloatType;
|
||||
class constructor CreateClass;
|
||||
// Special implementation for the value 0.0 (Singleton)
|
||||
TDataFloatValueZero = class(TInterfacedObject, IDataValue, IDataFloatValue)
|
||||
public
|
||||
function GetName: String;
|
||||
function GetKind: TDataKind;
|
||||
function CreateValue(Init: Double): IDataFloatValue;
|
||||
class property Singleton: IDataFloatType read FSingleton;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetValue: Double;
|
||||
end;
|
||||
|
||||
implementation
|
||||
// Special implementation for NaN (Not a Number) (Singleton)
|
||||
TDataFloatValueNaN = class(TInterfacedObject, IDataValue, IDataFloatValue)
|
||||
public
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetValue: Double;
|
||||
end;
|
||||
|
||||
{ TImplDataFloatValue }
|
||||
{ TDataFloatValue }
|
||||
|
||||
constructor TImplDataFloatValue.Create(const AValue: Double);
|
||||
constructor TDataFloatValue.Create(const AValue: Double);
|
||||
begin
|
||||
inherited Create;
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
function TImplDataFloatValue.GetDataType: IDataType;
|
||||
function TDataFloatValue.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TImplDataFloatType.Singleton;
|
||||
Result := TDataFloatType.Singleton;
|
||||
end;
|
||||
|
||||
function TImplDataFloatValue.GetAsString: string;
|
||||
function TDataFloatValue.GetAsString: string;
|
||||
begin
|
||||
Result := FloatToStr(FValue);
|
||||
end;
|
||||
|
||||
function TImplDataFloatValue.GetValue: Double;
|
||||
function TDataFloatValue.GetValue: Double;
|
||||
begin
|
||||
Result := FValue;
|
||||
end;
|
||||
|
||||
{ TImplDataFloatType }
|
||||
{ TDataFloatValueZero }
|
||||
|
||||
class constructor TImplDataFloatType.CreateClass;
|
||||
function TDataFloatValueZero.GetAsString: string;
|
||||
begin
|
||||
FSingleton := TImplDataFloatType.Create;
|
||||
Result := '0';
|
||||
end;
|
||||
|
||||
function TImplDataFloatType.GetName: String;
|
||||
function TDataFloatValueZero.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TDataFloatType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataFloatValueZero.GetValue: Double;
|
||||
begin
|
||||
Result := 0.0;
|
||||
end;
|
||||
|
||||
{ TDataFloatValueNaN }
|
||||
|
||||
function TDataFloatValueNaN.GetAsString: string;
|
||||
begin
|
||||
Result := 'NaN';
|
||||
end;
|
||||
|
||||
function TDataFloatValueNaN.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TDataFloatType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataFloatValueNaN.GetValue: Double;
|
||||
begin
|
||||
Result := NaN;
|
||||
end;
|
||||
|
||||
{ TDataFloatType }
|
||||
|
||||
class constructor TDataFloatType.CreateClass;
|
||||
begin
|
||||
FSingleton := TDataFloatType.Create;
|
||||
FZero := TDataFloatValueZero.Create;
|
||||
FNaN := TDataFloatValueNaN.Create;
|
||||
end;
|
||||
|
||||
function TDataFloatType.GetName: String;
|
||||
begin
|
||||
Result := 'Float';
|
||||
end;
|
||||
|
||||
function TImplDataFloatType.GetKind: TDataKind;
|
||||
function TDataFloatType.GetKind: TDataKind;
|
||||
begin
|
||||
Result := dkFloat;
|
||||
end;
|
||||
|
||||
function TImplDataFloatType.CreateValue(Init: Double): IDataFloatValue;
|
||||
function TDataFloatType.CreateValue(Init: Double): IDataFloatValue;
|
||||
begin
|
||||
Result := TImplDataFloatValue.Create(Init);
|
||||
// Return singleton instances for 0.0 and NaN to avoid unnecessary allocations.
|
||||
if (Init = 0.0) then
|
||||
Result := FZero
|
||||
else if IsNaN(Init) then
|
||||
Result := FNaN
|
||||
else
|
||||
Result := TDataFloatValue.Create(Init);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
@@ -6,9 +6,26 @@ uses
|
||||
Myc.Data.Types,
|
||||
System.SysUtils;
|
||||
|
||||
type
|
||||
// Implements the ordinal data type.
|
||||
TDataOrdinalType = class(TInterfacedObject, IDataType, IDataOrdinalType)
|
||||
strict private
|
||||
class var
|
||||
FSingleton: IDataOrdinalType;
|
||||
FMinusOne, FZero, FOne: IDataOrdinalValue; // Singletons for -1, 0, 1
|
||||
class constructor CreateClass;
|
||||
public
|
||||
function GetName: String;
|
||||
function GetKind: TDataKind;
|
||||
function CreateValue(Init: Int64): IDataOrdinalValue;
|
||||
class property Singleton: IDataOrdinalType read FSingleton;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
type
|
||||
// Implements the ordinal data value.
|
||||
TImplDataOrdinalValue = class(TInterfacedObject, IDataValue, IDataOrdinalValue)
|
||||
TDataOrdinalValue = class(TInterfacedObject, IDataValue, IDataOrdinalValue)
|
||||
private
|
||||
FValue: Int64;
|
||||
public
|
||||
@@ -22,64 +39,134 @@ type
|
||||
function GetValue: Int64;
|
||||
end;
|
||||
|
||||
// Implements the ordinal data type.
|
||||
TImplDataOrdinalType = class(TInterfacedObject, IDataType, IDataOrdinalType)
|
||||
strict private
|
||||
class var
|
||||
FSingleton: IDataOrdinalType;
|
||||
class constructor CreateClass;
|
||||
// Specialized implementation for the value -1.
|
||||
TDataOrdinalValueMinusOne = class(TInterfacedObject, IDataValue, IDataOrdinalValue)
|
||||
public
|
||||
function GetName: String;
|
||||
function GetKind: TDataKind;
|
||||
function CreateValue(Init: Int64): IDataOrdinalValue;
|
||||
class property Singleton: IDataOrdinalType read FSingleton;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetValue: Int64;
|
||||
end;
|
||||
|
||||
implementation
|
||||
// Specialized implementation for the value 0.
|
||||
TDataOrdinalValueZero = class(TInterfacedObject, IDataValue, IDataOrdinalValue)
|
||||
public
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetValue: Int64;
|
||||
end;
|
||||
|
||||
{ TImplDataOrdinalValue }
|
||||
// Specialized implementation for the value 1.
|
||||
TDataOrdinalValueOne = class(TInterfacedObject, IDataValue, IDataOrdinalValue)
|
||||
public
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetValue: Int64;
|
||||
end;
|
||||
|
||||
constructor TImplDataOrdinalValue.Create(const AValue: Int64);
|
||||
{ TDataOrdinalValue }
|
||||
|
||||
constructor TDataOrdinalValue.Create(const AValue: Int64);
|
||||
begin
|
||||
inherited Create;
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
function TImplDataOrdinalValue.GetDataType: IDataType;
|
||||
function TDataOrdinalValue.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TImplDataOrdinalType.Singleton;
|
||||
Result := TDataOrdinalType.Singleton;
|
||||
end;
|
||||
|
||||
function TImplDataOrdinalValue.GetAsString: string;
|
||||
function TDataOrdinalValue.GetAsString: string;
|
||||
begin
|
||||
Result := FValue.ToString;
|
||||
end;
|
||||
|
||||
function TImplDataOrdinalValue.GetValue: Int64;
|
||||
function TDataOrdinalValue.GetValue: Int64;
|
||||
begin
|
||||
Result := FValue;
|
||||
end;
|
||||
|
||||
{ TImplDataOrdinalType }
|
||||
{ TDataOrdinalValueMinusOne }
|
||||
|
||||
class constructor TImplDataOrdinalType.CreateClass;
|
||||
function TDataOrdinalValueMinusOne.GetDataType: IDataType;
|
||||
begin
|
||||
FSingleton := TImplDataOrdinalType.Create;
|
||||
Result := TDataOrdinalType.Singleton;
|
||||
end;
|
||||
|
||||
function TImplDataOrdinalType.GetName: String;
|
||||
function TDataOrdinalValueMinusOne.GetAsString: string;
|
||||
begin
|
||||
Result := '-1';
|
||||
end;
|
||||
|
||||
function TDataOrdinalValueMinusOne.GetValue: Int64;
|
||||
begin
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
{ TDataOrdinalValueZero }
|
||||
|
||||
function TDataOrdinalValueZero.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TDataOrdinalType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataOrdinalValueZero.GetAsString: string;
|
||||
begin
|
||||
Result := '0';
|
||||
end;
|
||||
|
||||
function TDataOrdinalValueZero.GetValue: Int64;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
{ TDataOrdinalValueOne }
|
||||
|
||||
function TDataOrdinalValueOne.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TDataOrdinalType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataOrdinalValueOne.GetAsString: string;
|
||||
begin
|
||||
Result := '1';
|
||||
end;
|
||||
|
||||
function TDataOrdinalValueOne.GetValue: Int64;
|
||||
begin
|
||||
Result := 1;
|
||||
end;
|
||||
|
||||
{ TDataOrdinalType }
|
||||
|
||||
class constructor TDataOrdinalType.CreateClass;
|
||||
begin
|
||||
FSingleton := TDataOrdinalType.Create;
|
||||
FMinusOne := TDataOrdinalValueMinusOne.Create;
|
||||
FZero := TDataOrdinalValueZero.Create;
|
||||
FOne := TDataOrdinalValueOne.Create;
|
||||
end;
|
||||
|
||||
function TDataOrdinalType.GetName: String;
|
||||
begin
|
||||
Result := 'Integer';
|
||||
end;
|
||||
|
||||
function TImplDataOrdinalType.GetKind: TDataKind;
|
||||
function TDataOrdinalType.GetKind: TDataKind;
|
||||
begin
|
||||
Result := dkOrdinal;
|
||||
end;
|
||||
|
||||
function TImplDataOrdinalType.CreateValue(Init: Int64): IDataOrdinalValue;
|
||||
function TDataOrdinalType.CreateValue(Init: Int64): IDataOrdinalValue;
|
||||
begin
|
||||
Result := TImplDataOrdinalValue.Create(Init);
|
||||
// Use specialized singletons for common values.
|
||||
case Init of
|
||||
-1: Result := FMinusOne;
|
||||
0: Result := FZero;
|
||||
1: Result := FOne;
|
||||
else
|
||||
Result := TDataOrdinalValue.Create(Init);
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
@@ -17,10 +17,8 @@ type
|
||||
function GetHashCode(const Value: TArray<TRecordField>): Integer; reintroduce;
|
||||
end;
|
||||
|
||||
TImplDataRecordValue = class; // fwd
|
||||
|
||||
// Implements the record data type.
|
||||
TImplDataRecordType = class(TInterfacedObject, IDataType, IDataRecordType)
|
||||
TDataRecordType = class(TInterfacedObject, IDataType, IDataRecordType)
|
||||
private
|
||||
FFields: TArray<TRecordField>;
|
||||
FFieldMap: TDictionary<string, Integer>; // For fast lookups by name
|
||||
@@ -35,8 +33,14 @@ type
|
||||
function CreateValue(const AItems: array of IDataValue): IDataRecordValue;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SyncObjs;
|
||||
|
||||
type
|
||||
// Implements the record data value.
|
||||
TImplDataRecordValue = class(TInterfacedObject, IDataValue, IDataRecordValue)
|
||||
TDataRecordValue = class(TInterfacedObject, IDataValue, IDataRecordValue)
|
||||
private
|
||||
FDataType: IDataRecordType;
|
||||
FItems: TArray<IDataValue>;
|
||||
@@ -47,10 +51,40 @@ type
|
||||
constructor Create(const ADataType: IDataRecordType; const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
implementation
|
||||
// Optimized implementation for a record with 0 fields.
|
||||
TDataRecordValue0 = class(TInterfacedObject, IDataValue, IDataRecordValue)
|
||||
private
|
||||
FDataType: IDataRecordType;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const ADataType: IDataRecordType);
|
||||
end;
|
||||
|
||||
uses
|
||||
System.SyncObjs;
|
||||
// Optimized implementation for a record with 1 field.
|
||||
TDataRecordValue1 = class(TInterfacedObject, IDataValue, IDataRecordValue)
|
||||
private
|
||||
FDataType: IDataRecordType;
|
||||
FItem0: IDataValue;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const ADataType: IDataRecordType; const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
// Optimized implementation for a record with 2 fields.
|
||||
TDataRecordValue2 = class(TInterfacedObject, IDataValue, IDataRecordValue)
|
||||
private
|
||||
FDataType: IDataRecordType;
|
||||
FItem0, FItem1: IDataValue;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const ADataType: IDataRecordType; const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
{ TRecordFieldComparer }
|
||||
|
||||
@@ -80,9 +114,9 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TImplDataRecordValue }
|
||||
{ TDataRecordValue (generic implementation for N > 2 fields) }
|
||||
|
||||
constructor TImplDataRecordValue.Create(const ADataType: IDataRecordType; const AItems: array of IDataValue);
|
||||
constructor TDataRecordValue.Create(const ADataType: IDataRecordType; const AItems: array of IDataValue);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
@@ -93,12 +127,12 @@ begin
|
||||
FItems[i] := AItems[i];
|
||||
end;
|
||||
|
||||
function TImplDataRecordValue.GetDataType: IDataType;
|
||||
function TDataRecordValue.GetDataType: IDataType;
|
||||
begin
|
||||
Result := FDataType;
|
||||
end;
|
||||
|
||||
function TImplDataRecordValue.GetAsString: string;
|
||||
function TDataRecordValue.GetAsString: string;
|
||||
var
|
||||
sb: TStringBuilder;
|
||||
i: Integer;
|
||||
@@ -123,14 +157,116 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TImplDataRecordValue.GetItem(Idx: Integer): IDataValue;
|
||||
function TDataRecordValue.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
Result := FItems[Idx];
|
||||
end;
|
||||
|
||||
{ TImplDataRecordType }
|
||||
{ TDataRecordValue0 }
|
||||
|
||||
constructor TImplDataRecordType.Create(const AFields: array of TRecordField);
|
||||
constructor TDataRecordValue0.Create(const ADataType: IDataRecordType);
|
||||
begin
|
||||
inherited Create;
|
||||
FDataType := ADataType;
|
||||
end;
|
||||
|
||||
function TDataRecordValue0.GetAsString: string;
|
||||
begin
|
||||
Result := '<>';
|
||||
end;
|
||||
|
||||
function TDataRecordValue0.GetDataType: IDataType;
|
||||
begin
|
||||
Result := FDataType;
|
||||
end;
|
||||
|
||||
function TDataRecordValue0.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
raise EArgumentException.Create('Index out of bounds');
|
||||
end;
|
||||
|
||||
{ TDataRecordValue1 }
|
||||
|
||||
constructor TDataRecordValue1.Create(const ADataType: IDataRecordType; const AItems: array of IDataValue);
|
||||
begin
|
||||
inherited Create;
|
||||
FDataType := ADataType;
|
||||
FItem0 := AItems[0];
|
||||
end;
|
||||
|
||||
function TDataRecordValue1.GetAsString: string;
|
||||
var
|
||||
recordType: IDataRecordType;
|
||||
begin
|
||||
recordType := FDataType;
|
||||
Result := Format('<%s: %s>', [recordType.Fields[0].Name, FItem0.AsString]);
|
||||
end;
|
||||
|
||||
function TDataRecordValue1.GetDataType: IDataType;
|
||||
begin
|
||||
Result := FDataType;
|
||||
end;
|
||||
|
||||
function TDataRecordValue1.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
case Idx of
|
||||
0: Result := FItem0;
|
||||
else
|
||||
raise EArgumentException.Create('Index out of bounds');
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TDataRecordValue2 }
|
||||
|
||||
constructor TDataRecordValue2.Create(const ADataType: IDataRecordType; const AItems: array of IDataValue);
|
||||
begin
|
||||
inherited Create;
|
||||
FDataType := ADataType;
|
||||
FItem0 := AItems[0];
|
||||
FItem1 := AItems[1];
|
||||
end;
|
||||
|
||||
function TDataRecordValue2.GetAsString: string;
|
||||
var
|
||||
recordType: IDataRecordType;
|
||||
sb: TStringBuilder;
|
||||
begin
|
||||
recordType := FDataType;
|
||||
sb := TStringBuilder.Create;
|
||||
try
|
||||
sb.Append('<');
|
||||
sb.Append(recordType.Fields[0].Name);
|
||||
sb.Append(': ');
|
||||
sb.Append(FItem0.AsString);
|
||||
sb.Append(', ');
|
||||
sb.Append(recordType.Fields[1].Name);
|
||||
sb.Append(': ');
|
||||
sb.Append(FItem1.AsString);
|
||||
sb.Append('>');
|
||||
Result := sb.ToString;
|
||||
finally
|
||||
sb.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDataRecordValue2.GetDataType: IDataType;
|
||||
begin
|
||||
Result := FDataType;
|
||||
end;
|
||||
|
||||
function TDataRecordValue2.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
case Idx of
|
||||
0: Result := FItem0;
|
||||
1: Result := FItem1;
|
||||
else
|
||||
raise EArgumentException.Create('Index out of bounds');
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TDataRecordType }
|
||||
|
||||
constructor TDataRecordType.Create(const AFields: array of TRecordField);
|
||||
var
|
||||
i: Integer;
|
||||
field: TRecordField;
|
||||
@@ -148,13 +284,13 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
destructor TImplDataRecordType.Destroy;
|
||||
destructor TDataRecordType.Destroy;
|
||||
begin
|
||||
FFieldMap.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TImplDataRecordType.CreateValue(const AItems: array of IDataValue): IDataRecordValue;
|
||||
function TDataRecordType.CreateValue(const AItems: array of IDataValue): IDataRecordValue;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
@@ -168,20 +304,28 @@ begin
|
||||
'Invalid data type for field ''%s'' at index %d. Expected ''%s'', but got ''%s''.',
|
||||
[FFields[i].Name, i, FFields[i].DataType.Name, AItems[i].DataType.Name]);
|
||||
|
||||
Result := TImplDataRecordValue.Create(Self, AItems);
|
||||
// Use optimized implementations for records with 0, 1, or 2 fields.
|
||||
case Length(FFields) of
|
||||
0: Result := TDataRecordValue0.Create(Self);
|
||||
1: Result := TDataRecordValue1.Create(Self, AItems);
|
||||
2: Result := TDataRecordValue2.Create(Self, AItems);
|
||||
else
|
||||
// Use the generic implementation for records with more than 2 fields.
|
||||
Result := TDataRecordValue.Create(Self, AItems);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TImplDataRecordType.GetField(Idx: Integer): TRecordField;
|
||||
function TDataRecordType.GetField(Idx: Integer): TRecordField;
|
||||
begin
|
||||
Result := FFields[Idx];
|
||||
end;
|
||||
|
||||
function TImplDataRecordType.GetFieldCount: Integer;
|
||||
function TDataRecordType.GetFieldCount: Integer;
|
||||
begin
|
||||
Result := Length(FFields);
|
||||
end;
|
||||
|
||||
function TImplDataRecordType.GetName: String;
|
||||
function TDataRecordType.GetName: String;
|
||||
var
|
||||
i: Integer;
|
||||
sb: TStringBuilder;
|
||||
@@ -204,12 +348,12 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TImplDataRecordType.GetKind: TDataKind;
|
||||
function TDataRecordType.GetKind: TDataKind;
|
||||
begin
|
||||
Result := dkRecord;
|
||||
end;
|
||||
|
||||
function TImplDataRecordType.IndexOf(const AName: string): Integer;
|
||||
function TDataRecordType.IndexOf(const AName: string): Integer;
|
||||
begin
|
||||
if not FFieldMap.TryGetValue(AName, Result) then
|
||||
Result := -1;
|
||||
|
||||
@@ -7,7 +7,7 @@ uses
|
||||
Myc.Data.Types;
|
||||
|
||||
type
|
||||
TImplDataTextType = class(TInterfacedObject, IDataType, IDataTextType)
|
||||
TDataTextType = class(TInterfacedObject, IDataType, IDataTextType)
|
||||
strict private
|
||||
class var
|
||||
FSingleton: IDataTextType;
|
||||
@@ -19,7 +19,10 @@ type
|
||||
class property Singleton: IDataTextType read FSingleton;
|
||||
end;
|
||||
|
||||
TImplDataTextValue = class(TInterfacedObject, IDataValue, IDataTextValue)
|
||||
implementation
|
||||
|
||||
type
|
||||
TDataTextValue = class(TInterfacedObject, IDataValue, IDataTextValue)
|
||||
private
|
||||
FValue: string;
|
||||
function GetDataType: IDataType;
|
||||
@@ -29,51 +32,89 @@ type
|
||||
constructor Create(const AValue: string);
|
||||
end;
|
||||
|
||||
implementation
|
||||
// Singleton implementation for the empty string value.
|
||||
TDataTextValueEmpty = class(TInterfacedObject, IDataValue, IDataTextValue)
|
||||
strict private
|
||||
class var
|
||||
FSingleton: IDataTextValue;
|
||||
class constructor CreateClass;
|
||||
private
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetValue: string;
|
||||
public
|
||||
class property Singleton: IDataTextValue read FSingleton;
|
||||
end;
|
||||
|
||||
{ TImplDataTextType }
|
||||
{ TDataTextType }
|
||||
|
||||
class constructor TImplDataTextType.CreateClass;
|
||||
class constructor TDataTextType.CreateClass;
|
||||
begin
|
||||
FSingleton := TImplDataTextType.Create;
|
||||
FSingleton := TDataTextType.Create;
|
||||
end;
|
||||
|
||||
function TImplDataTextType.CreateValue(const AValue: string): IDataTextValue;
|
||||
function TDataTextType.CreateValue(const AValue: string): IDataTextValue;
|
||||
begin
|
||||
Result := TImplDataTextValue.Create(AValue);
|
||||
// Use the singleton for empty strings.
|
||||
if (AValue = '') then
|
||||
Result := TDataTextValueEmpty.Singleton
|
||||
else
|
||||
Result := TDataTextValue.Create(AValue);
|
||||
end;
|
||||
|
||||
function TImplDataTextType.GetName: String;
|
||||
function TDataTextType.GetName: String;
|
||||
begin
|
||||
Result := 'Text';
|
||||
end;
|
||||
|
||||
function TImplDataTextType.GetKind: TDataKind;
|
||||
function TDataTextType.GetKind: TDataKind;
|
||||
begin
|
||||
Result := dkText;
|
||||
end;
|
||||
|
||||
{ TImplDataTextValue }
|
||||
{ TDataTextValue }
|
||||
|
||||
constructor TImplDataTextValue.Create(const AValue: string);
|
||||
constructor TDataTextValue.Create(const AValue: string);
|
||||
begin
|
||||
inherited Create;
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
function TImplDataTextValue.GetDataType: IDataType;
|
||||
function TDataTextValue.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TImplDataTextType.Singleton;
|
||||
Result := TDataTextType.Singleton;
|
||||
end;
|
||||
|
||||
function TImplDataTextValue.GetAsString: string;
|
||||
function TDataTextValue.GetAsString: string;
|
||||
begin
|
||||
Result := FValue;
|
||||
end;
|
||||
|
||||
function TImplDataTextValue.GetValue: string;
|
||||
function TDataTextValue.GetValue: string;
|
||||
begin
|
||||
Result := FValue;
|
||||
end;
|
||||
|
||||
{ TDataTextValueEmpty }
|
||||
|
||||
class constructor TDataTextValueEmpty.CreateClass;
|
||||
begin
|
||||
FSingleton := TDataTextValueEmpty.Create;
|
||||
end;
|
||||
|
||||
function TDataTextValueEmpty.GetAsString: string;
|
||||
begin
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function TDataTextValueEmpty.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TDataTextType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataTextValueEmpty.GetValue: string;
|
||||
begin
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
@@ -7,7 +7,7 @@ uses
|
||||
Myc.Data.Types;
|
||||
|
||||
type
|
||||
TImplDataTimestampType = class(TInterfacedObject, IDataType, IDataTimestampType)
|
||||
TDataTimestampType = class(TInterfacedObject, IDataType, IDataTimestampType)
|
||||
strict private
|
||||
class var
|
||||
FSingleton: IDataTimestampType;
|
||||
@@ -19,7 +19,10 @@ type
|
||||
class property Singleton: IDataTimestampType read FSingleton;
|
||||
end;
|
||||
|
||||
TImplDataTimestampValue = class(TInterfacedObject, IDataValue, IDataTimestampValue)
|
||||
implementation
|
||||
|
||||
type
|
||||
TDataTimestampValue = class(TInterfacedObject, IDataValue, IDataTimestampValue)
|
||||
private
|
||||
FValue: TDateTime;
|
||||
function GetDataType: IDataType;
|
||||
@@ -29,49 +32,47 @@ type
|
||||
constructor Create(const AValue: TDateTime);
|
||||
end;
|
||||
|
||||
implementation
|
||||
{ TDataTimestampType }
|
||||
|
||||
{ TImplDataTimestampType }
|
||||
|
||||
class constructor TImplDataTimestampType.CreateClass;
|
||||
class constructor TDataTimestampType.CreateClass;
|
||||
begin
|
||||
FSingleton := TImplDataTimestampType.Create;
|
||||
FSingleton := TDataTimestampType.Create;
|
||||
end;
|
||||
|
||||
function TImplDataTimestampType.CreateValue(const AValue: TDateTime): IDataTimestampValue;
|
||||
function TDataTimestampType.CreateValue(const AValue: TDateTime): IDataTimestampValue;
|
||||
begin
|
||||
Result := TImplDataTimestampValue.Create(AValue);
|
||||
Result := TDataTimestampValue.Create(AValue);
|
||||
end;
|
||||
|
||||
function TImplDataTimestampType.GetName: String;
|
||||
function TDataTimestampType.GetName: String;
|
||||
begin
|
||||
Result := 'Timestamp';
|
||||
end;
|
||||
|
||||
function TImplDataTimestampType.GetKind: TDataKind;
|
||||
function TDataTimestampType.GetKind: TDataKind;
|
||||
begin
|
||||
Result := dkTimestamp;
|
||||
end;
|
||||
|
||||
{ TImplDataTimestampValue }
|
||||
{ TDataTimestampValue }
|
||||
|
||||
constructor TImplDataTimestampValue.Create(const AValue: TDateTime);
|
||||
constructor TDataTimestampValue.Create(const AValue: TDateTime);
|
||||
begin
|
||||
inherited Create;
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
function TImplDataTimestampValue.GetDataType: IDataType;
|
||||
function TDataTimestampValue.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TImplDataTimestampType.Singleton;
|
||||
Result := TDataTimestampType.Singleton;
|
||||
end;
|
||||
|
||||
function TImplDataTimestampValue.GetAsString: string;
|
||||
function TDataTimestampValue.GetAsString: string;
|
||||
begin
|
||||
Result := DateTimeToStr(FValue);
|
||||
end;
|
||||
|
||||
function TImplDataTimestampValue.GetValue: TDateTime;
|
||||
function TDataTimestampValue.GetValue: TDateTime;
|
||||
begin
|
||||
Result := FValue;
|
||||
end;
|
||||
|
||||
@@ -7,20 +7,8 @@ uses
|
||||
Myc.Data.Types;
|
||||
|
||||
type
|
||||
// Implements the simple tuple data value.
|
||||
TImplDataTupleValue = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||
private
|
||||
FItems: TArray<IDataValue>;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetItemCount: Integer;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
// Implements the singleton tuple data type.
|
||||
TImplDataTupleType = class(TInterfacedObject, IDataType, IDataTupleType)
|
||||
TDataTupleType = class(TInterfacedObject, IDataType, IDataTupleType)
|
||||
strict private
|
||||
class var
|
||||
FSingleton: IDataTupleType;
|
||||
@@ -35,9 +23,97 @@ type
|
||||
|
||||
implementation
|
||||
|
||||
{ TImplDataTupleValue }
|
||||
type
|
||||
// Implements the simple tuple data value.
|
||||
TDataTupleValue = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||
private
|
||||
FItems: TArray<IDataValue>;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetItemCount: Integer;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
constructor TImplDataTupleValue.Create(const AItems: array of IDataValue);
|
||||
// Optimized singleton implementation for a tuple with 0 elements.
|
||||
TDataTupleValue0 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||
strict private
|
||||
class var
|
||||
FSingleton: IDataTupleValue;
|
||||
class constructor CreateClass;
|
||||
private
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetItemCount: Integer;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
class property Singleton: IDataTupleValue read FSingleton;
|
||||
end;
|
||||
|
||||
// Optimized implementation for a tuple with 1 element.
|
||||
TDataTupleValue1 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||
private
|
||||
FItem0: IDataValue;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetItemCount: Integer;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
// Optimized implementation for a tuple with 2 elements.
|
||||
TDataTupleValue2 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||
private
|
||||
FItem0, FItem1: IDataValue;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetItemCount: Integer;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
// Optimized implementation for a tuple with 3 elements.
|
||||
TDataTupleValue3 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||
private
|
||||
FItem0, FItem1, FItem2: IDataValue;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetItemCount: Integer;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
// Optimized implementation for a tuple with 4 elements.
|
||||
TDataTupleValue4 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||
private
|
||||
FItem0, FItem1, FItem2, FItem3: IDataValue;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetItemCount: Integer;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
// Optimized implementation for a tuple with 5 elements.
|
||||
TDataTupleValue5 = class(TInterfacedObject, IDataValue, IDataTupleValue)
|
||||
private
|
||||
FItem0, FItem1, FItem2, FItem3, FItem4: IDataValue;
|
||||
function GetDataType: IDataType;
|
||||
function GetAsString: string;
|
||||
function GetItemCount: Integer;
|
||||
function GetItem(Idx: Integer): IDataValue;
|
||||
public
|
||||
constructor Create(const AItems: array of IDataValue);
|
||||
end;
|
||||
|
||||
{ TDataTupleValue (generic implementation for N > 5 elements) }
|
||||
|
||||
constructor TDataTupleValue.Create(const AItems: array of IDataValue);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
@@ -47,12 +123,12 @@ begin
|
||||
FItems[i] := AItems[i];
|
||||
end;
|
||||
|
||||
function TImplDataTupleValue.GetDataType: IDataType;
|
||||
function TDataTupleValue.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TImplDataTupleType.Singleton;
|
||||
Result := TDataTupleType.Singleton;
|
||||
end;
|
||||
|
||||
function TImplDataTupleValue.GetAsString: string;
|
||||
function TDataTupleValue.GetAsString: string;
|
||||
var
|
||||
sb: TStringBuilder;
|
||||
i: Integer;
|
||||
@@ -73,34 +149,300 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TImplDataTupleValue.GetItem(Idx: Integer): IDataValue;
|
||||
function TDataTupleValue.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
Result := FItems[Idx];
|
||||
end;
|
||||
|
||||
function TImplDataTupleValue.GetItemCount: Integer;
|
||||
function TDataTupleValue.GetItemCount: Integer;
|
||||
begin
|
||||
Result := Length(FItems);
|
||||
end;
|
||||
|
||||
{ TImplDataTupleType }
|
||||
{ TDataTupleValue0 }
|
||||
|
||||
class constructor TImplDataTupleType.CreateClass;
|
||||
class constructor TDataTupleValue0.CreateClass;
|
||||
begin
|
||||
FSingleton := TImplDataTupleType.Create;
|
||||
FSingleton := TDataTupleValue0.Create;
|
||||
end;
|
||||
|
||||
function TImplDataTupleType.CreateValue(const AItems: array of IDataValue): IDataTupleValue;
|
||||
function TDataTupleValue0.GetAsString: string;
|
||||
begin
|
||||
Result := TImplDataTupleValue.Create(AItems);
|
||||
Result := '()';
|
||||
end;
|
||||
|
||||
function TImplDataTupleType.GetName: String;
|
||||
function TDataTupleValue0.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TDataTupleType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataTupleValue0.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
raise EArgumentException.Create('Index out of bounds');
|
||||
end;
|
||||
|
||||
function TDataTupleValue0.GetItemCount: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
{ TDataTupleValue1 }
|
||||
|
||||
constructor TDataTupleValue1.Create(const AItems: array of IDataValue);
|
||||
begin
|
||||
inherited Create;
|
||||
FItem0 := AItems[0];
|
||||
end;
|
||||
|
||||
function TDataTupleValue1.GetAsString: string;
|
||||
begin
|
||||
Result := '(' + FItem0.AsString + ')';
|
||||
end;
|
||||
|
||||
function TDataTupleValue1.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TDataTupleType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataTupleValue1.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
case Idx of
|
||||
0: Result := FItem0;
|
||||
else
|
||||
raise EArgumentException.Create('Index out of bounds');
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDataTupleValue1.GetItemCount: Integer;
|
||||
begin
|
||||
Result := 1;
|
||||
end;
|
||||
|
||||
{ TDataTupleValue2 }
|
||||
|
||||
constructor TDataTupleValue2.Create(const AItems: array of IDataValue);
|
||||
begin
|
||||
inherited Create;
|
||||
FItem0 := AItems[0];
|
||||
FItem1 := AItems[1];
|
||||
end;
|
||||
|
||||
function TDataTupleValue2.GetAsString: string;
|
||||
begin
|
||||
Result := '(' + FItem0.AsString + ', ' + FItem1.AsString + ')';
|
||||
end;
|
||||
|
||||
function TDataTupleValue2.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TDataTupleType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataTupleValue2.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
case Idx of
|
||||
0: Result := FItem0;
|
||||
1: Result := FItem1;
|
||||
else
|
||||
raise EArgumentException.Create('Index out of bounds');
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDataTupleValue2.GetItemCount: Integer;
|
||||
begin
|
||||
Result := 2;
|
||||
end;
|
||||
|
||||
{ TDataTupleValue3 }
|
||||
|
||||
constructor TDataTupleValue3.Create(const AItems: array of IDataValue);
|
||||
begin
|
||||
inherited Create;
|
||||
FItem0 := AItems[0];
|
||||
FItem1 := AItems[1];
|
||||
FItem2 := AItems[2];
|
||||
end;
|
||||
|
||||
function TDataTupleValue3.GetAsString: string;
|
||||
var
|
||||
sb: TStringBuilder;
|
||||
begin
|
||||
sb := TStringBuilder.Create;
|
||||
try
|
||||
sb.Append('(');
|
||||
sb.Append(FItem0.AsString);
|
||||
sb.Append(', ');
|
||||
sb.Append(FItem1.AsString);
|
||||
sb.Append(', ');
|
||||
sb.Append(FItem2.AsString);
|
||||
sb.Append(')');
|
||||
Result := sb.ToString;
|
||||
finally
|
||||
sb.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDataTupleValue3.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TDataTupleType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataTupleValue3.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
case Idx of
|
||||
0: Result := FItem0;
|
||||
1: Result := FItem1;
|
||||
2: Result := FItem2;
|
||||
else
|
||||
raise EArgumentException.Create('Index out of bounds');
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDataTupleValue3.GetItemCount: Integer;
|
||||
begin
|
||||
Result := 3;
|
||||
end;
|
||||
|
||||
{ TDataTupleValue4 }
|
||||
|
||||
constructor TDataTupleValue4.Create(const AItems: array of IDataValue);
|
||||
begin
|
||||
inherited Create;
|
||||
FItem0 := AItems[0];
|
||||
FItem1 := AItems[1];
|
||||
FItem2 := AItems[2];
|
||||
FItem3 := AItems[3];
|
||||
end;
|
||||
|
||||
function TDataTupleValue4.GetAsString: string;
|
||||
var
|
||||
sb: TStringBuilder;
|
||||
begin
|
||||
sb := TStringBuilder.Create;
|
||||
try
|
||||
sb.Append('(');
|
||||
sb.Append(FItem0.AsString);
|
||||
sb.Append(', ');
|
||||
sb.Append(FItem1.AsString);
|
||||
sb.Append(', ');
|
||||
sb.Append(FItem2.AsString);
|
||||
sb.Append(', ');
|
||||
sb.Append(FItem3.AsString);
|
||||
sb.Append(')');
|
||||
Result := sb.ToString;
|
||||
finally
|
||||
sb.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDataTupleValue4.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TDataTupleType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataTupleValue4.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
case Idx of
|
||||
0: Result := FItem0;
|
||||
1: Result := FItem1;
|
||||
2: Result := FItem2;
|
||||
3: Result := FItem3;
|
||||
else
|
||||
raise EArgumentException.Create('Index out of bounds');
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDataTupleValue4.GetItemCount: Integer;
|
||||
begin
|
||||
Result := 4;
|
||||
end;
|
||||
|
||||
{ TDataTupleValue5 }
|
||||
|
||||
constructor TDataTupleValue5.Create(const AItems: array of IDataValue);
|
||||
begin
|
||||
inherited Create;
|
||||
FItem0 := AItems[0];
|
||||
FItem1 := AItems[1];
|
||||
FItem2 := AItems[2];
|
||||
FItem3 := AItems[3];
|
||||
FItem4 := AItems[4];
|
||||
end;
|
||||
|
||||
function TDataTupleValue5.GetAsString: string;
|
||||
var
|
||||
sb: TStringBuilder;
|
||||
begin
|
||||
sb := TStringBuilder.Create;
|
||||
try
|
||||
sb.Append('(');
|
||||
sb.Append(FItem0.AsString);
|
||||
sb.Append(', ');
|
||||
sb.Append(FItem1.AsString);
|
||||
sb.Append(', ');
|
||||
sb.Append(FItem2.AsString);
|
||||
sb.Append(', ');
|
||||
sb.Append(FItem3.AsString);
|
||||
sb.Append(', ');
|
||||
sb.Append(FItem4.AsString);
|
||||
sb.Append(')');
|
||||
Result := sb.ToString;
|
||||
finally
|
||||
sb.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDataTupleValue5.GetDataType: IDataType;
|
||||
begin
|
||||
Result := TDataTupleType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataTupleValue5.GetItem(Idx: Integer): IDataValue;
|
||||
begin
|
||||
case Idx of
|
||||
0: Result := FItem0;
|
||||
1: Result := FItem1;
|
||||
2: Result := FItem2;
|
||||
3: Result := FItem3;
|
||||
4: Result := FItem4;
|
||||
else
|
||||
raise EArgumentException.Create('Index out of bounds');
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDataTupleValue5.GetItemCount: Integer;
|
||||
begin
|
||||
Result := 5;
|
||||
end;
|
||||
|
||||
{ TDataTupleType }
|
||||
|
||||
class constructor TDataTupleType.CreateClass;
|
||||
begin
|
||||
FSingleton := TDataTupleType.Create;
|
||||
end;
|
||||
|
||||
function TDataTupleType.CreateValue(const AItems: array of IDataValue): IDataTupleValue;
|
||||
begin
|
||||
// Use optimized implementations for tuples with 0 to 5 elements.
|
||||
case Length(AItems) of
|
||||
0: Result := TDataTupleValue0.Singleton;
|
||||
1: Result := TDataTupleValue1.Create(AItems);
|
||||
2: Result := TDataTupleValue2.Create(AItems);
|
||||
3: Result := TDataTupleValue3.Create(AItems);
|
||||
4: Result := TDataTupleValue4.Create(AItems);
|
||||
5: Result := TDataTupleValue5.Create(AItems);
|
||||
else
|
||||
// Use the generic implementation for tuples with more than 5 elements.
|
||||
Result := TDataTupleValue.Create(AItems);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDataTupleType.GetName: String;
|
||||
begin
|
||||
Result := 'Tuple';
|
||||
end;
|
||||
|
||||
function TImplDataTupleType.GetKind: TDataKind;
|
||||
function TDataTupleType.GetKind: TDataKind;
|
||||
begin
|
||||
Result := dkTuple;
|
||||
end;
|
||||
|
||||
+13
-13
@@ -231,7 +231,7 @@ begin
|
||||
try
|
||||
if not FArrayTypeRegistry.TryGetValue(AElementType, Result) then
|
||||
begin
|
||||
Result := TImplDataArrayType.Create(AElementType);
|
||||
Result := TDataArrayType.Create(AElementType);
|
||||
FArrayTypeRegistry.Add(AElementType, Result);
|
||||
end;
|
||||
finally
|
||||
@@ -241,7 +241,7 @@ end;
|
||||
|
||||
class function TDataType.Float: IDataFloatType;
|
||||
begin
|
||||
Result := TImplDataFloatType.Singleton;
|
||||
Result := TDataFloatType.Singleton;
|
||||
end;
|
||||
|
||||
function TDataType.GetName: String;
|
||||
@@ -254,7 +254,7 @@ end;
|
||||
|
||||
class function TDataType.Ordinal: IDataOrdinalType;
|
||||
begin
|
||||
Result := TImplDataOrdinalType.Singleton;
|
||||
Result := TDataOrdinalType.Singleton;
|
||||
end;
|
||||
|
||||
class function TDataType.RecordOf(const Fields: TArray<TRecordField>): IDataRecordType;
|
||||
@@ -263,7 +263,7 @@ begin
|
||||
try
|
||||
if not FRecordTypeRegistry.TryGetValue(Fields, Result) then
|
||||
begin
|
||||
Result := TImplDataRecordType.Create(Fields);
|
||||
Result := TDataRecordType.Create(Fields);
|
||||
FRecordTypeRegistry.Add(Fields, Result);
|
||||
end;
|
||||
finally
|
||||
@@ -284,22 +284,22 @@ end;
|
||||
|
||||
class function TDataType.EnumOf(const AName: string; const AIdentifiers: array of string): IDataEnumType;
|
||||
begin
|
||||
Result := TImplDataEnumType.Create(AName, AIdentifiers);
|
||||
Result := TDataEnumType.Create(AName, AIdentifiers);
|
||||
end;
|
||||
|
||||
class function TDataType.Text: IDataTextType;
|
||||
begin
|
||||
Result := TImplDataTextType.Singleton;
|
||||
Result := TDataTextType.Singleton;
|
||||
end;
|
||||
|
||||
class function TDataType.Timestamp: IDataTimestampType;
|
||||
begin
|
||||
Result := TImplDataTimestampType.Singleton;
|
||||
Result := TDataTimestampType.Singleton;
|
||||
end;
|
||||
|
||||
class function TDataType.Tuple: IDataTupleType;
|
||||
begin
|
||||
Result := TImplDataTupleType.Singleton;
|
||||
Result := TDataTupleType.Singleton;
|
||||
end;
|
||||
|
||||
class operator TDataType.Implicit(const A: TDataType): IDataType;
|
||||
@@ -377,27 +377,27 @@ end;
|
||||
|
||||
class function TDataValue.FromOrdinal(const AValue: Int64): IDataOrdinalValue;
|
||||
begin
|
||||
Result := TImplDataOrdinalType.Singleton.CreateValue(AValue);
|
||||
Result := TDataOrdinalType.Singleton.CreateValue(AValue);
|
||||
end;
|
||||
|
||||
class function TDataValue.FromFloat(const AValue: Double): IDataFloatValue;
|
||||
begin
|
||||
Result := TImplDataFloatType.Singleton.CreateValue(AValue);
|
||||
Result := TDataFloatType.Singleton.CreateValue(AValue);
|
||||
end;
|
||||
|
||||
class function TDataValue.FromText(const AValue: string): IDataTextValue;
|
||||
begin
|
||||
Result := TImplDataTextType.Singleton.CreateValue(AValue);
|
||||
Result := TDataTextType.Singleton.CreateValue(AValue);
|
||||
end;
|
||||
|
||||
class function TDataValue.FromTimestamp(const AValue: TDateTime): IDataTimestampValue;
|
||||
begin
|
||||
Result := TImplDataTimestampType.Singleton.CreateValue(AValue);
|
||||
Result := TDataTimestampType.Singleton.CreateValue(AValue);
|
||||
end;
|
||||
|
||||
class function TDataValue.FromTuple(const AItems: array of IDataValue): IDataTupleValue;
|
||||
begin
|
||||
Result := TImplDataTupleType.Singleton.CreateValue(AItems);
|
||||
Result := TDataTupleType.Singleton.CreateValue(AItems);
|
||||
end;
|
||||
|
||||
function TDataValue.GetDataType: IDataType;
|
||||
|
||||
Reference in New Issue
Block a user