Scalar operators
This commit is contained in:
@@ -93,6 +93,22 @@ type
|
||||
class function StringToKind(const AName: string): TScalarKind; static;
|
||||
|
||||
function ToString: String;
|
||||
|
||||
class operator Add(const A, B: TScalar): TScalar;
|
||||
class operator Divide(const A, B: TScalar): TScalar;
|
||||
class operator Equal(const A, B: TScalar): Boolean;
|
||||
|
||||
//TODO implementieren
|
||||
class operator GreaterThan(const A, B: TScalar): Boolean;
|
||||
class operator GreaterThanOrEqual(const A, B: TScalar): Boolean;
|
||||
class operator LessThan(const A, B: TScalar): Boolean;
|
||||
class operator LessThanOrEqual(const A, B: TScalar): Boolean;
|
||||
class operator Multiply(const A, B: TScalar): TScalar;
|
||||
class operator Negative(const A: TScalar): TScalar;
|
||||
class operator NotEqual(const A, B: TScalar): Boolean;
|
||||
class operator Round(const A: TScalar): TScalar;
|
||||
class operator Subtract(const A, B: TScalar): TScalar;
|
||||
class operator Trunc(const A: TScalar): TScalar;
|
||||
end;
|
||||
|
||||
TScalarKindHelper = record helper for TScalarKind
|
||||
@@ -443,6 +459,708 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class operator TScalar.Add(const A, B: TScalar): TScalar;
|
||||
begin
|
||||
// Fast path for identical types
|
||||
if (A.Kind = B.Kind) then
|
||||
begin
|
||||
Result.Kind := A.Kind;
|
||||
case A.Kind of
|
||||
skInteger: Result.Value.AsInteger := A.Value.AsInteger + B.Value.AsInteger;
|
||||
skInt64: Result.Value.AsInt64 := A.Value.AsInt64 + B.Value.AsInt64;
|
||||
skUInt64: Result.Value.AsUInt64 := A.Value.AsUInt64 + B.Value.AsUInt64;
|
||||
skSingle: Result.Value.AsSingle := A.Value.AsSingle + B.Value.AsSingle;
|
||||
skDouble: Result.Value.AsDouble := A.Value.AsDouble + B.Value.AsDouble;
|
||||
skDecimal: Result.Value.AsDecimal := A.Value.AsDecimal + B.Value.AsDecimal;
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Operator Add not supported for type %s', [A.Kind.ToString]);
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Slow path for mixed types with compatible conversion
|
||||
const FLOAT_KINDS: set of TScalarKind = [skSingle, skDouble];
|
||||
const ORDINAL_KINDS: set of TScalarKind = [skInteger, skInt64, skUInt64];
|
||||
const NUMERIC_KINDS: set of TScalarKind = FLOAT_KINDS + ORDINAL_KINDS + [skDecimal];
|
||||
|
||||
if not (((A.Kind in NUMERIC_KINDS) and (B.Kind in NUMERIC_KINDS))
|
||||
or ((A.Kind = skDateTime) and (B.Kind in ORDINAL_KINDS + FLOAT_KINDS))
|
||||
or ((B.Kind = skDateTime) and (A.Kind in ORDINAL_KINDS + FLOAT_KINDS))) then
|
||||
raise EArgumentException.CreateFmt('Operator Add requires compatible types, but got %s and %s', [A.Kind.ToString, B.Kind.ToString]);
|
||||
|
||||
if (A.Kind = skDecimal) or (B.Kind = skDecimal) then
|
||||
begin
|
||||
if (A.Kind in FLOAT_KINDS) or (B.Kind in FLOAT_KINDS) then
|
||||
raise EArgumentException
|
||||
.CreateFmt('Operator Add cannot mix Decimal and floating-point types (%s, %s)', [A.Kind.ToString, B.Kind.ToString]);
|
||||
|
||||
var valA, valB: TDecimal;
|
||||
case A.Kind of
|
||||
skInteger: valA := TDecimal.Create(A.Value.AsInteger, 0);
|
||||
skInt64: valA := TDecimal.Create(A.Value.AsInt64, 0);
|
||||
skUInt64: valA := TDecimal.Create(Int64(A.Value.AsUInt64), 0);
|
||||
skDecimal: valA := A.Value.AsDecimal;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: valB := TDecimal.Create(B.Value.AsInteger, 0);
|
||||
skInt64: valB := TDecimal.Create(B.Value.AsInt64, 0);
|
||||
skUInt64: valB := TDecimal.Create(Int64(B.Value.AsUInt64), 0);
|
||||
skDecimal: valB := B.Value.AsDecimal;
|
||||
end;
|
||||
Result := TScalar.FromDecimal(valA + valB);
|
||||
end
|
||||
else if (A.Kind = skDateTime) or (B.Kind = skDateTime) then
|
||||
begin
|
||||
if A.Kind = skDateTime then
|
||||
begin
|
||||
var dtPart := A.Value.AsDateTime;
|
||||
var numPart: Double := 0;
|
||||
case B.Kind of
|
||||
skInteger: numPart := B.Value.AsInteger;
|
||||
skInt64: numPart := B.Value.AsInt64;
|
||||
skUInt64: numPart := B.Value.AsUInt64;
|
||||
skSingle: numPart := B.Value.AsSingle;
|
||||
skDouble: numPart := B.Value.AsDouble;
|
||||
end;
|
||||
Result := TScalar.FromDateTime(dtPart + numPart);
|
||||
end
|
||||
else
|
||||
begin
|
||||
var dtPart := B.Value.AsDateTime;
|
||||
var numPart: Double := 0;
|
||||
case A.Kind of
|
||||
skInteger: numPart := A.Value.AsInteger;
|
||||
skInt64: numPart := A.Value.AsInt64;
|
||||
skUInt64: numPart := A.Value.AsUInt64;
|
||||
skSingle: numPart := A.Value.AsSingle;
|
||||
skDouble: numPart := A.Value.AsDouble;
|
||||
end;
|
||||
Result := TScalar.FromDateTime(dtPart + numPart);
|
||||
end;
|
||||
end
|
||||
else if (A.Kind = skDouble) or (B.Kind = skDouble) then
|
||||
begin
|
||||
var dblA: Double := 0;
|
||||
var dblB: Double := 0;
|
||||
case A.Kind of
|
||||
skInteger: dblA := A.Value.AsInteger;
|
||||
skInt64: dblA := A.Value.AsInt64;
|
||||
skUInt64: dblA := A.Value.AsUInt64;
|
||||
skSingle: dblA := A.Value.AsSingle;
|
||||
skDouble: dblA := A.Value.AsDouble;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: dblB := B.Value.AsInteger;
|
||||
skInt64: dblB := B.Value.AsInt64;
|
||||
skUInt64: dblB := B.Value.AsUInt64;
|
||||
skSingle: dblB := B.Value.AsSingle;
|
||||
skDouble: dblB := B.Value.AsDouble;
|
||||
end;
|
||||
Result := TScalar.FromDouble(dblA + dblB);
|
||||
end
|
||||
else if (A.Kind = skSingle) or (B.Kind = skSingle) then
|
||||
begin
|
||||
var sngA: Single := 0;
|
||||
var sngB: Single := 0;
|
||||
case A.Kind of
|
||||
skInteger: sngA := A.Value.AsInteger;
|
||||
skInt64: sngA := A.Value.AsInt64;
|
||||
skUInt64: sngA := A.Value.AsUInt64;
|
||||
skSingle: sngA := A.Value.AsSingle;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: sngB := B.Value.AsInteger;
|
||||
skInt64: sngB := B.Value.AsInt64;
|
||||
skUInt64: sngB := B.Value.AsUInt64;
|
||||
skSingle: sngB := B.Value.AsSingle;
|
||||
end;
|
||||
Result := TScalar.FromSingle(sngA + sngB);
|
||||
end
|
||||
else if (A.Kind = skUInt64) or (B.Kind = skUInt64) then
|
||||
begin
|
||||
var u64A: UInt64 := 0;
|
||||
var u64B: UInt64 := 0;
|
||||
case A.Kind of
|
||||
skInteger: u64A := UInt64(A.Value.AsInteger);
|
||||
skInt64: u64A := UInt64(A.Value.AsInt64);
|
||||
skUInt64: u64A := A.Value.AsUInt64;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: u64B := UInt64(B.Value.AsInteger);
|
||||
skInt64: u64B := UInt64(B.Value.AsInt64);
|
||||
skUInt64: u64B := B.Value.AsUInt64;
|
||||
end;
|
||||
Result := TScalar.FromUInt64(u64A + u64B);
|
||||
end
|
||||
else if (A.Kind = skInt64) or (B.Kind = skInt64) then
|
||||
begin
|
||||
var i64A: Int64 := 0;
|
||||
var i64B: Int64 := 0;
|
||||
case A.Kind of
|
||||
skInteger: i64A := A.Value.AsInteger;
|
||||
skInt64: i64A := A.Value.AsInt64;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: i64B := B.Value.AsInteger;
|
||||
skInt64: i64B := B.Value.AsInt64;
|
||||
end;
|
||||
Result := TScalar.FromInt64(i64A + i64B);
|
||||
end;
|
||||
end;
|
||||
|
||||
class operator TScalar.Divide(const A, B: TScalar): TScalar;
|
||||
begin
|
||||
// Fast path for identical types
|
||||
if (A.Kind = B.Kind) then
|
||||
begin
|
||||
case A.Kind of
|
||||
skInteger: Result := TScalar.FromDouble(A.Value.AsInteger / B.Value.AsInteger);
|
||||
skInt64: Result := TScalar.FromDouble(A.Value.AsInt64 / B.Value.AsInt64);
|
||||
skUInt64: Result := TScalar.FromDouble(A.Value.AsUInt64 / B.Value.AsUInt64);
|
||||
skSingle: Result := TScalar.FromSingle(A.Value.AsSingle / B.Value.AsSingle);
|
||||
skDouble: Result := TScalar.FromDouble(A.Value.AsDouble / B.Value.AsDouble);
|
||||
skDecimal: Result := TScalar.FromDecimal(A.Value.AsDecimal / B.Value.AsDecimal);
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Operator Divide not supported for type %s', [A.Kind.ToString]);
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Slow path for mixed types
|
||||
const FLOAT_KINDS: set of TScalarKind = [skSingle, skDouble];
|
||||
const NUMERIC_KINDS: set of TScalarKind = FLOAT_KINDS + [skInteger, skInt64, skUInt64, skDecimal];
|
||||
|
||||
if not ((A.Kind in NUMERIC_KINDS) and (B.Kind in NUMERIC_KINDS)) then
|
||||
raise EArgumentException.CreateFmt('Operator Divide not supported for types %s and %s', [A.Kind.ToString, B.Kind.ToString]);
|
||||
|
||||
if (A.Kind = skDecimal) or (B.Kind = skDecimal) then
|
||||
begin
|
||||
if (A.Kind in FLOAT_KINDS) or (B.Kind in FLOAT_KINDS) then
|
||||
raise EArgumentException
|
||||
.CreateFmt('Operator Divide cannot mix Decimal and floating-point types (%s, %s)', [A.Kind.ToString, B.Kind.ToString]);
|
||||
var valA, valB: TDecimal;
|
||||
case A.Kind of
|
||||
skInteger: valA := TDecimal.Create(A.Value.AsInteger, 0);
|
||||
skInt64: valA := TDecimal.Create(A.Value.AsInt64, 0);
|
||||
skUInt64: valA := TDecimal.Create(Int64(A.Value.AsUInt64), 0);
|
||||
skDecimal: valA := A.Value.AsDecimal;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: valB := TDecimal.Create(B.Value.AsInteger, 0);
|
||||
skInt64: valB := TDecimal.Create(B.Value.AsInt64, 0);
|
||||
skUInt64: valB := TDecimal.Create(Int64(B.Value.AsUInt64), 0);
|
||||
skDecimal: valB := B.Value.AsDecimal;
|
||||
end;
|
||||
Result := TScalar.FromDecimal(valA / valB);
|
||||
end
|
||||
else
|
||||
begin
|
||||
var dblA: Double := 0.0;
|
||||
var dblB: Double := 0.0;
|
||||
case A.Kind of
|
||||
skInteger: dblA := A.Value.AsInteger;
|
||||
skInt64: dblA := A.Value.AsInt64;
|
||||
skUInt64: dblA := A.Value.AsUInt64;
|
||||
skSingle: dblA := A.Value.AsSingle;
|
||||
skDouble: dblA := A.Value.AsDouble;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: dblB := B.Value.AsInteger;
|
||||
skInt64: dblB := B.Value.AsInt64;
|
||||
skUInt64: dblB := B.Value.AsUInt64;
|
||||
skSingle: dblB := B.Value.AsSingle;
|
||||
skDouble: dblB := B.Value.AsDouble;
|
||||
end;
|
||||
Result := TScalar.FromDouble(dblA / dblB);
|
||||
end;
|
||||
end;
|
||||
|
||||
class operator TScalar.Equal(const A, B: TScalar): Boolean;
|
||||
begin
|
||||
// Fast path for identical types
|
||||
if (A.Kind = B.Kind) then
|
||||
begin
|
||||
case A.Kind of
|
||||
skInteger: Result := (A.Value.AsInteger = B.Value.AsInteger);
|
||||
skInt64: Result := (A.Value.AsInt64 = B.Value.AsInt64);
|
||||
skUInt64: Result := (A.Value.AsUInt64 = B.Value.AsUInt64);
|
||||
skSingle: Result := (A.Value.AsSingle = B.Value.AsSingle);
|
||||
skDouble: Result := (A.Value.AsDouble = B.Value.AsDouble);
|
||||
skDateTime: Result := (A.Value.AsDateTime = B.Value.AsDateTime);
|
||||
skTimestamp:
|
||||
Result := (A.Value.AsTimestamp.Time = B.Value.AsTimestamp.Time) and (A.Value.AsTimestamp.Date = B.Value.AsTimestamp.Date);
|
||||
skBoolean: Result := (A.Value.AsBoolean = B.Value.AsBoolean);
|
||||
skChar: Result := (A.Value.AsChar = B.Value.AsChar);
|
||||
skPChar: Result := (StrComp(PChar(@A.Value.AsPChar), PChar(@B.Value.AsPChar)) = 0);
|
||||
skString: Result := (A.Value.AsString = B.Value.AsString);
|
||||
skBytes: Result := CompareMem(@A.Value.AsBytes, @B.Value.AsBytes, SizeOf(TScalarBytes));
|
||||
skDecimal: Result := (A.Value.AsDecimal = B.Value.AsDecimal);
|
||||
else
|
||||
Result := False;
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Slow path for mixed, but compatible, types
|
||||
const FLOAT_KINDS: set of TScalarKind = [skSingle, skDouble];
|
||||
const NUMERIC_KINDS: set of TScalarKind = FLOAT_KINDS + [skInteger, skInt64, skUInt64, skDecimal];
|
||||
|
||||
if not ((A.Kind in NUMERIC_KINDS) and (B.Kind in NUMERIC_KINDS)) then
|
||||
begin
|
||||
Result := False;
|
||||
exit;
|
||||
end;
|
||||
|
||||
if ((A.Kind = skDecimal) and (B.Kind in FLOAT_KINDS)) or ((B.Kind = skDecimal) and (A.Kind in FLOAT_KINDS)) then
|
||||
begin
|
||||
Result := False;
|
||||
exit;
|
||||
end;
|
||||
|
||||
if (A.Kind = skDecimal) or (B.Kind = skDecimal) then
|
||||
begin
|
||||
var valA, valB: TDecimal;
|
||||
case A.Kind of
|
||||
skInteger: valA := TDecimal.Create(A.Value.AsInteger, 0);
|
||||
skInt64: valA := TDecimal.Create(A.Value.AsInt64, 0);
|
||||
skUInt64: valA := TDecimal.Create(Int64(A.Value.AsUInt64), 0);
|
||||
skDecimal: valA := A.Value.AsDecimal;
|
||||
else
|
||||
Result := False;
|
||||
exit;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: valB := TDecimal.Create(B.Value.AsInteger, 0);
|
||||
skInt64: valB := TDecimal.Create(B.Value.AsInt64, 0);
|
||||
skUInt64: valB := TDecimal.Create(Int64(B.Value.AsUInt64), 0);
|
||||
skDecimal: valB := B.Value.AsDecimal;
|
||||
else
|
||||
Result := False;
|
||||
exit;
|
||||
end;
|
||||
Result := (valA = valB);
|
||||
end
|
||||
else
|
||||
begin
|
||||
var dblA: Double := 0.0;
|
||||
var dblB: Double := 0.0;
|
||||
case A.Kind of
|
||||
skInteger: dblA := A.Value.AsInteger;
|
||||
skInt64: dblA := A.Value.AsInt64;
|
||||
skUInt64: dblA := A.Value.AsUInt64;
|
||||
skSingle: dblA := A.Value.AsSingle;
|
||||
skDouble: dblA := A.Value.AsDouble;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: dblB := B.Value.AsInteger;
|
||||
skInt64: dblB := B.Value.AsInt64;
|
||||
skUInt64: dblB := B.Value.AsUInt64;
|
||||
skSingle: dblB := B.Value.AsSingle;
|
||||
skDouble: dblB := B.Value.AsDouble;
|
||||
end;
|
||||
Result := (dblA = dblB);
|
||||
end;
|
||||
end;
|
||||
|
||||
class operator TScalar.GreaterThan(const A, B: TScalar): Boolean;
|
||||
begin
|
||||
// Fast path for identical types
|
||||
if (A.Kind = B.Kind) then
|
||||
begin
|
||||
case A.Kind of
|
||||
skInteger: Result := (A.Value.AsInteger > B.Value.AsInteger);
|
||||
skInt64: Result := (A.Value.AsInt64 > B.Value.AsInt64);
|
||||
skUInt64: Result := (A.Value.AsUInt64 > B.Value.AsUInt64);
|
||||
skSingle: Result := (A.Value.AsSingle > B.Value.AsSingle);
|
||||
skDouble: Result := (A.Value.AsDouble > B.Value.AsDouble);
|
||||
skDateTime: Result := (A.Value.AsDateTime > B.Value.AsDateTime);
|
||||
skDecimal: Result := (A.Value.AsDecimal > B.Value.AsDecimal);
|
||||
skChar: Result := (A.Value.AsChar > B.Value.AsChar);
|
||||
skString: Result := (A.Value.AsString > B.Value.AsString);
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Operator GreaterThan not supported for type %s', [A.Kind.ToString]);
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Slow path for mixed, but compatible, types
|
||||
const FLOAT_KINDS: set of TScalarKind = [skSingle, skDouble];
|
||||
const NUMERIC_KINDS: set of TScalarKind = FLOAT_KINDS + [skInteger, skInt64, skUInt64, skDecimal];
|
||||
|
||||
if not ((A.Kind in NUMERIC_KINDS) and (B.Kind in NUMERIC_KINDS)) then
|
||||
raise EArgumentException.CreateFmt('Cannot compare %s and %s', [A.Kind.ToString, B.Kind.ToString]);
|
||||
|
||||
if ((A.Kind = skDecimal) and (B.Kind in FLOAT_KINDS)) or ((B.Kind = skDecimal) and (A.Kind in FLOAT_KINDS)) then
|
||||
raise EArgumentException.CreateFmt('Cannot compare Decimal and floating-point types (%s, %s)', [A.Kind.ToString, B.Kind.ToString]);
|
||||
|
||||
if (A.Kind = skDecimal) or (B.Kind = skDecimal) then
|
||||
begin
|
||||
var valA, valB: TDecimal;
|
||||
case A.Kind of
|
||||
skInteger: valA := TDecimal.Create(A.Value.AsInteger, 0);
|
||||
skInt64: valA := TDecimal.Create(A.Value.AsInt64, 0);
|
||||
skUInt64: valA := TDecimal.Create(Int64(A.Value.AsUInt64), 0);
|
||||
skDecimal: valA := A.Value.AsDecimal;
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Internal error comparing %s', [A.Kind.ToString]);
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: valB := TDecimal.Create(B.Value.AsInteger, 0);
|
||||
skInt64: valB := TDecimal.Create(B.Value.AsInt64, 0);
|
||||
skUInt64: valB := TDecimal.Create(Int64(B.Value.AsUInt64), 0);
|
||||
skDecimal: valB := B.Value.AsDecimal;
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Internal error comparing %s', [B.Kind.ToString]);
|
||||
end;
|
||||
Result := (valA > valB);
|
||||
end
|
||||
else
|
||||
begin
|
||||
var dblA, dblB: Double;
|
||||
dblA := 0.0;
|
||||
dblB := 0.0;
|
||||
case A.Kind of
|
||||
skInteger: dblA := A.Value.AsInteger;
|
||||
skInt64: dblA := A.Value.AsInt64;
|
||||
skUInt64: dblA := A.Value.AsUInt64;
|
||||
skSingle: dblA := A.Value.AsSingle;
|
||||
skDouble: dblA := A.Value.AsDouble;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: dblB := B.Value.AsInteger;
|
||||
skInt64: dblB := B.Value.AsInt64;
|
||||
skUInt64: dblB := B.Value.AsUInt64;
|
||||
skSingle: dblB := B.Value.AsSingle;
|
||||
skDouble: dblB := B.Value.AsDouble;
|
||||
end;
|
||||
Result := (dblA > dblB);
|
||||
end;
|
||||
end;
|
||||
|
||||
class operator TScalar.GreaterThanOrEqual(const A, B: TScalar): Boolean;
|
||||
begin
|
||||
Result := (A > B) or (A = B);
|
||||
end;
|
||||
|
||||
class operator TScalar.LessThan(const A, B: TScalar): Boolean;
|
||||
begin
|
||||
// Re-use GreaterThan logic to avoid code duplication
|
||||
Result := B > A;
|
||||
end;
|
||||
|
||||
class operator TScalar.LessThanOrEqual(const A, B: TScalar): Boolean;
|
||||
begin
|
||||
Result := (A < B) or (A = B);
|
||||
end;
|
||||
|
||||
class operator TScalar.Multiply(const A, B: TScalar): TScalar;
|
||||
begin
|
||||
// Fast path for identical types
|
||||
if (A.Kind = B.Kind) then
|
||||
begin
|
||||
Result.Kind := A.Kind;
|
||||
case A.Kind of
|
||||
skInteger: Result.Value.AsInteger := A.Value.AsInteger * B.Value.AsInteger;
|
||||
skInt64: Result.Value.AsInt64 := A.Value.AsInt64 * B.Value.AsInt64;
|
||||
skUInt64: Result.Value.AsUInt64 := A.Value.AsUInt64 * B.Value.AsUInt64;
|
||||
skSingle: Result.Value.AsSingle := A.Value.AsSingle * B.Value.AsSingle;
|
||||
skDouble: Result.Value.AsDouble := A.Value.AsDouble * B.Value.AsDouble;
|
||||
skDecimal: Result.Value.AsDecimal := A.Value.AsDecimal * B.Value.AsDecimal;
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Operator Multiply not supported for type %s', [A.Kind.ToString]);
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Slow path for mixed types
|
||||
const FLOAT_KINDS: set of TScalarKind = [skSingle, skDouble];
|
||||
const NUMERIC_KINDS: set of TScalarKind = FLOAT_KINDS + [skInteger, skInt64, skUInt64, skDecimal];
|
||||
|
||||
if not ((A.Kind in NUMERIC_KINDS) and (B.Kind in NUMERIC_KINDS)) then
|
||||
raise EArgumentException.CreateFmt('Operator Multiply not supported for types %s and %s', [A.Kind.ToString, B.Kind.ToString]);
|
||||
|
||||
if (A.Kind = skDecimal) or (B.Kind = skDecimal) then
|
||||
begin
|
||||
if (A.Kind in FLOAT_KINDS) or (B.Kind in FLOAT_KINDS) then
|
||||
raise EArgumentException
|
||||
.CreateFmt('Operator Multiply cannot mix Decimal and floating-point types (%s, %s)', [A.Kind.ToString, B.Kind.ToString]);
|
||||
var valA, valB: TDecimal;
|
||||
case A.Kind of
|
||||
skInteger: valA := TDecimal.Create(A.Value.AsInteger, 0);
|
||||
skInt64: valA := TDecimal.Create(A.Value.AsInt64, 0);
|
||||
skUInt64: valA := TDecimal.Create(Int64(A.Value.AsUInt64), 0);
|
||||
skDecimal: valA := A.Value.AsDecimal;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: valB := TDecimal.Create(B.Value.AsInteger, 0);
|
||||
skInt64: valB := TDecimal.Create(B.Value.AsInt64, 0);
|
||||
skUInt64: valB := TDecimal.Create(Int64(B.Value.AsUInt64), 0);
|
||||
skDecimal: valB := B.Value.AsDecimal;
|
||||
end;
|
||||
Result := TScalar.FromDecimal(valA * valB);
|
||||
end
|
||||
else if (A.Kind = skDouble) or (B.Kind = skDouble) then
|
||||
begin
|
||||
var dblA: Double := 0.0;
|
||||
var dblB: Double := 0.0;
|
||||
case A.Kind of
|
||||
skInteger: dblA := A.Value.AsInteger;
|
||||
skInt64: dblA := A.Value.AsInt64;
|
||||
skUInt64: dblA := A.Value.AsUInt64;
|
||||
skSingle: dblA := A.Value.AsSingle;
|
||||
skDouble: dblA := A.Value.AsDouble;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: dblB := B.Value.AsInteger;
|
||||
skInt64: dblB := B.Value.AsInt64;
|
||||
skUInt64: dblB := B.Value.AsUInt64;
|
||||
skSingle: dblB := B.Value.AsSingle;
|
||||
skDouble: dblB := B.Value.AsDouble;
|
||||
end;
|
||||
Result := TScalar.FromDouble(dblA * dblB);
|
||||
end
|
||||
else if (A.Kind = skSingle) or (B.Kind = skSingle) then
|
||||
begin
|
||||
var sngA: Single := 0.0;
|
||||
var sngB: Single := 0.0;
|
||||
case A.Kind of
|
||||
skInteger: sngA := A.Value.AsInteger;
|
||||
skInt64: sngA := A.Value.AsInt64;
|
||||
skUInt64: sngA := A.Value.AsUInt64;
|
||||
skSingle: sngA := A.Value.AsSingle;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: sngB := B.Value.AsInteger;
|
||||
skInt64: sngB := B.Value.AsInt64;
|
||||
skUInt64: sngB := B.Value.AsUInt64;
|
||||
skSingle: sngB := B.Value.AsSingle;
|
||||
end;
|
||||
Result := TScalar.FromSingle(sngA * sngB);
|
||||
end
|
||||
else if (A.Kind = skUInt64) or (B.Kind = skUInt64) then
|
||||
begin
|
||||
var u64A: UInt64 := 0;
|
||||
var u64B: UInt64 := 0;
|
||||
case A.Kind of
|
||||
skInteger: u64A := UInt64(A.Value.AsInteger);
|
||||
skInt64: u64A := UInt64(A.Value.AsInt64);
|
||||
skUInt64: u64A := A.Value.AsUInt64;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: u64B := UInt64(B.Value.AsInteger);
|
||||
skInt64: u64B := UInt64(B.Value.AsInt64);
|
||||
skUInt64: u64B := B.Value.AsUInt64;
|
||||
end;
|
||||
Result := TScalar.FromUInt64(u64A * u64B);
|
||||
end
|
||||
else if (A.Kind = skInt64) or (B.Kind = skInt64) then
|
||||
begin
|
||||
var i64A: Int64 := 0;
|
||||
var i64B: Int64 := 0;
|
||||
case A.Kind of
|
||||
skInteger: i64A := A.Value.AsInteger;
|
||||
skInt64: i64A := A.Value.AsInt64;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: i64B := B.Value.AsInteger;
|
||||
skInt64: i64B := B.Value.AsInt64;
|
||||
end;
|
||||
Result := TScalar.FromInt64(i64A * i64B);
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := TScalar.FromInteger(A.Value.AsInteger * B.Value.AsInteger);
|
||||
end;
|
||||
end;
|
||||
|
||||
class operator TScalar.Negative(const A: TScalar): TScalar;
|
||||
begin
|
||||
Result.Kind := A.Kind;
|
||||
case A.Kind of
|
||||
skInteger: Result.Value.AsInteger := -A.Value.AsInteger;
|
||||
skInt64: Result.Value.AsInt64 := -A.Value.AsInt64;
|
||||
skSingle: Result.Value.AsSingle := -A.Value.AsSingle;
|
||||
skDouble: Result.Value.AsDouble := -A.Value.AsDouble;
|
||||
skDecimal: Result.Value.AsDecimal := -A.Value.AsDecimal;
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Operator Negative not supported for type %s', [A.Kind.ToString]);
|
||||
end;
|
||||
end;
|
||||
|
||||
class operator TScalar.NotEqual(const A, B: TScalar): Boolean;
|
||||
begin
|
||||
Result := not (A = B);
|
||||
end;
|
||||
|
||||
class operator TScalar.Round(const A: TScalar): TScalar;
|
||||
begin
|
||||
case A.Kind of
|
||||
skSingle: Result := TScalar.FromInt64(System.Round(A.Value.AsSingle));
|
||||
skDouble: Result := TScalar.FromInt64(System.Round(A.Value.AsDouble));
|
||||
skDateTime: Result := TScalar.FromInt64(System.Round(A.Value.AsDateTime));
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Operator Round not supported for type %s', [A.Kind.ToString]);
|
||||
end;
|
||||
end;
|
||||
|
||||
class operator TScalar.Subtract(const A, B: TScalar): TScalar;
|
||||
begin
|
||||
// Fast path for identical types
|
||||
if (A.Kind = B.Kind) then
|
||||
begin
|
||||
if (A.Kind = skDateTime) then
|
||||
begin
|
||||
Result := TScalar.FromDouble(A.Value.AsDateTime - B.Value.AsDateTime);
|
||||
exit;
|
||||
end;
|
||||
Result.Kind := A.Kind;
|
||||
case A.Kind of
|
||||
skInteger: Result.Value.AsInteger := A.Value.AsInteger - B.Value.AsInteger;
|
||||
skInt64: Result.Value.AsInt64 := A.Value.AsInt64 - B.Value.AsInt64;
|
||||
skUInt64: Result.Value.AsUInt64 := A.Value.AsUInt64 - B.Value.AsUInt64;
|
||||
skSingle: Result.Value.AsSingle := A.Value.AsSingle - B.Value.AsSingle;
|
||||
skDouble: Result.Value.AsDouble := A.Value.AsDouble - B.Value.AsDouble;
|
||||
skDecimal: Result.Value.AsDecimal := A.Value.AsDecimal - B.Value.AsDecimal;
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Operator Subtract not supported for type %s', [A.Kind.ToString]);
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Slow path for mixed types
|
||||
const FLOAT_KINDS: set of TScalarKind = [skSingle, skDouble];
|
||||
const ORDINAL_KINDS: set of TScalarKind = [skInteger, skInt64, skUInt64];
|
||||
const NUMERIC_KINDS: set of TScalarKind = FLOAT_KINDS + ORDINAL_KINDS + [skDecimal];
|
||||
|
||||
if not (((A.Kind in NUMERIC_KINDS) and (B.Kind in NUMERIC_KINDS))
|
||||
or ((A.Kind = skDateTime) and (B.Kind in NUMERIC_KINDS + [skDateTime]))) then
|
||||
raise EArgumentException.CreateFmt('Operator Subtract not supported for types %s and %s', [A.Kind.ToString, B.Kind.ToString]);
|
||||
|
||||
if (A.Kind = skDecimal) or (B.Kind = skDecimal) then
|
||||
begin
|
||||
if (A.Kind in FLOAT_KINDS) or (B.Kind in FLOAT_KINDS) then
|
||||
raise EArgumentException
|
||||
.CreateFmt('Operator Subtract cannot mix Decimal and floating-point types (%s, %s)', [A.Kind.ToString, B.Kind.ToString]);
|
||||
var valA, valB: TDecimal;
|
||||
case A.Kind of
|
||||
skInteger: valA := TDecimal.Create(A.Value.AsInteger, 0);
|
||||
skInt64: valA := TDecimal.Create(A.Value.AsInt64, 0);
|
||||
skUInt64: valA := TDecimal.Create(Int64(A.Value.AsUInt64), 0);
|
||||
skDecimal: valA := A.Value.AsDecimal;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: valB := TDecimal.Create(B.Value.AsInteger, 0);
|
||||
skInt64: valB := TDecimal.Create(B.Value.AsInt64, 0);
|
||||
skUInt64: valB := TDecimal.Create(Int64(B.Value.AsUInt64), 0);
|
||||
skDecimal: valB := B.Value.AsDecimal;
|
||||
end;
|
||||
Result := TScalar.FromDecimal(valA - valB);
|
||||
end
|
||||
else if (A.Kind = skDateTime) then
|
||||
begin
|
||||
var numPart: Double := 0.0;
|
||||
case B.Kind of
|
||||
skInteger: numPart := B.Value.AsInteger;
|
||||
skInt64: numPart := B.Value.AsInt64;
|
||||
skUInt64: numPart := B.Value.AsUInt64;
|
||||
skSingle: numPart := B.Value.AsSingle;
|
||||
skDouble: numPart := B.Value.AsDouble;
|
||||
skDateTime: numPart := B.Value.AsDateTime;
|
||||
end;
|
||||
if B.Kind = skDateTime then
|
||||
Result := TScalar.FromDouble(A.Value.AsDateTime - numPart)
|
||||
else
|
||||
Result := TScalar.FromDateTime(A.Value.AsDateTime - numPart);
|
||||
end
|
||||
else if (B.Kind = skDateTime) then
|
||||
begin
|
||||
raise EArgumentException.CreateFmt('Operator Subtract not supported for types %s and %s', [A.Kind.ToString, B.Kind.ToString]);
|
||||
end
|
||||
else if (A.Kind = skDouble) or (B.Kind = skDouble) then
|
||||
begin
|
||||
var dblA: Double := 0.0;
|
||||
var dblB: Double := 0.0;
|
||||
case A.Kind of
|
||||
skInteger: dblA := A.Value.AsInteger;
|
||||
skInt64: dblA := A.Value.AsInt64;
|
||||
skUInt64: dblA := A.Value.AsUInt64;
|
||||
skSingle: dblA := A.Value.AsSingle;
|
||||
skDouble: dblA := A.Value.AsDouble;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: dblB := B.Value.AsInteger;
|
||||
skInt64: dblB := B.Value.AsInt64;
|
||||
skUInt64: dblB := B.Value.AsUInt64;
|
||||
skSingle: dblB := B.Value.AsSingle;
|
||||
skDouble: dblB := B.Value.AsDouble;
|
||||
end;
|
||||
Result := TScalar.FromDouble(dblA - dblB);
|
||||
end
|
||||
else if (A.Kind = skSingle) or (B.Kind = skSingle) then
|
||||
begin
|
||||
var sngA: Single := 0.0;
|
||||
var sngB: Single := 0.0;
|
||||
case A.Kind of
|
||||
skInteger: sngA := A.Value.AsInteger;
|
||||
skInt64: sngA := A.Value.AsInt64;
|
||||
skUInt64: sngA := A.Value.AsUInt64;
|
||||
skSingle: sngA := A.Value.AsSingle;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: sngB := B.Value.AsInteger;
|
||||
skInt64: sngB := B.Value.AsInt64;
|
||||
skUInt64: sngB := B.Value.AsUInt64;
|
||||
skSingle: sngB := B.Value.AsSingle;
|
||||
end;
|
||||
Result := TScalar.FromSingle(sngA - sngB);
|
||||
end
|
||||
else if (A.Kind = skUInt64) or (B.Kind = skUInt64) then
|
||||
begin
|
||||
var u64A: UInt64 := 0;
|
||||
var u64B: UInt64 := 0;
|
||||
case A.Kind of
|
||||
skInteger: u64A := UInt64(A.Value.AsInteger);
|
||||
skInt64: u64A := UInt64(A.Value.AsInt64);
|
||||
skUInt64: u64A := A.Value.AsUInt64;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: u64B := UInt64(B.Value.AsInteger);
|
||||
skInt64: u64B := UInt64(B.Value.AsInt64);
|
||||
skUInt64: u64B := B.Value.AsUInt64;
|
||||
end;
|
||||
Result := TScalar.FromUInt64(u64A - u64B);
|
||||
end
|
||||
else if (A.Kind = skInt64) or (B.Kind = skInt64) then
|
||||
begin
|
||||
var i64A: Int64 := 0;
|
||||
var i64B: Int64 := 0;
|
||||
case A.Kind of
|
||||
skInteger: i64A := A.Value.AsInteger;
|
||||
skInt64: i64A := A.Value.AsInt64;
|
||||
end;
|
||||
case B.Kind of
|
||||
skInteger: i64B := B.Value.AsInteger;
|
||||
skInt64: i64B := B.Value.AsInt64;
|
||||
end;
|
||||
Result := TScalar.FromInt64(i64A - i64B);
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := TScalar.FromInteger(A.Value.AsInteger - B.Value.AsInteger);
|
||||
end;
|
||||
end;
|
||||
|
||||
class operator TScalar.Trunc(const A: TScalar): TScalar;
|
||||
begin
|
||||
case A.Kind of
|
||||
skSingle: Result := TScalar.FromInt64(System.Trunc(A.Value.AsSingle));
|
||||
skDouble: Result := TScalar.FromInt64(System.Trunc(A.Value.AsDouble));
|
||||
skDateTime: Result := TScalar.FromInt64(System.Trunc(A.Value.AsDateTime));
|
||||
else
|
||||
raise EArgumentException.CreateFmt('Operator Trunc not supported for type %s', [A.Kind.ToString]);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TScalarArray }
|
||||
|
||||
constructor TScalarArray.Create(AKind: TScalarKind; const AItems: TArray<TScalarValue>);
|
||||
|
||||
Reference in New Issue
Block a user