153 lines
3.6 KiB
ObjectPascal
153 lines
3.6 KiB
ObjectPascal
unit Myc.Data.Types.Decimal;
|
|
|
|
interface
|
|
|
|
uses
|
|
Myc.Data.Types;
|
|
|
|
type
|
|
// Concrete implementation of the IDataDecimalType interface.
|
|
TImplDataDecimalType = class(TInterfacedObject, IDataDecimalType)
|
|
private
|
|
FScale: Integer;
|
|
strict private
|
|
class var
|
|
// Pre-cached instances for scales 0-18.
|
|
FDecimalTypes: TArray<IDataDecimalType>;
|
|
public
|
|
constructor Create(const AScale: Integer);
|
|
|
|
class constructor CreateClass;
|
|
class destructor DestroyClass;
|
|
|
|
// Returns a cached instance for the specified scale.
|
|
class function GetInstance(const AScale: Integer): IDataDecimalType; static;
|
|
|
|
// IDataType
|
|
function GetName: String;
|
|
function GetKind: TDataKind;
|
|
|
|
// IDataDecimalType
|
|
function GetScale: Integer;
|
|
function CreateValue(const AValue: Int64): IDataDecimalValue;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
System.SysUtils,
|
|
System.Math;
|
|
|
|
type
|
|
TDataDecimalValue = class(TInterfacedObject, IDataDecimalValue)
|
|
private
|
|
FDataType: IDataDecimalType;
|
|
FValue: Int64;
|
|
public
|
|
constructor Create(const AValue: Int64; const ADataType: IDataDecimalType);
|
|
|
|
// IDataValue
|
|
function GetDataType: IDataType;
|
|
function GetAsString: string;
|
|
|
|
// IDataDecimalValue
|
|
function GetValue: Int64;
|
|
end;
|
|
|
|
{ TImplDataDecimalType }
|
|
|
|
constructor TImplDataDecimalType.Create(const AScale: Integer);
|
|
begin
|
|
inherited Create;
|
|
FScale := AScale;
|
|
end;
|
|
|
|
class constructor TImplDataDecimalType.CreateClass;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
// Create and cache singleton instances for each supported scale.
|
|
SetLength(FDecimalTypes, 19);
|
|
for i := 0 to High(FDecimalTypes) do
|
|
FDecimalTypes[i] := TImplDataDecimalType.Create(i);
|
|
end;
|
|
|
|
class destructor TImplDataDecimalType.DestroyClass;
|
|
begin
|
|
FDecimalTypes := nil;
|
|
end;
|
|
|
|
class function TImplDataDecimalType.GetInstance(const AScale: Integer): IDataDecimalType;
|
|
begin
|
|
if (AScale < 0) or (AScale > High(FDecimalTypes)) then
|
|
raise EArgumentException.CreateFmt('Scale for decimal must be between 0 and %d.', [High(FDecimalTypes)]);
|
|
Result := FDecimalTypes[AScale];
|
|
end;
|
|
|
|
function TImplDataDecimalType.CreateValue(const AValue: Int64): IDataDecimalValue;
|
|
begin
|
|
Result := TDataDecimalValue.Create(AValue, Self);
|
|
end;
|
|
|
|
function TImplDataDecimalType.GetKind: TDataKind;
|
|
begin
|
|
Result := dkDecimal;
|
|
end;
|
|
|
|
function TImplDataDecimalType.GetName: String;
|
|
begin
|
|
Result := Format('Decimal(18, %d)', [FScale]);
|
|
end;
|
|
|
|
function TImplDataDecimalType.GetScale: Integer;
|
|
begin
|
|
Result := FScale;
|
|
end;
|
|
|
|
{ TDataDecimalValue }
|
|
|
|
constructor TDataDecimalValue.Create(const AValue: Int64; const ADataType: IDataDecimalType);
|
|
begin
|
|
inherited Create;
|
|
FValue := AValue;
|
|
FDataType := ADataType;
|
|
end;
|
|
|
|
function TDataDecimalValue.GetAsString: string;
|
|
var
|
|
s: string;
|
|
scale: Integer;
|
|
insertPos: Integer;
|
|
begin
|
|
s := IntToStr(abs(FValue));
|
|
scale := FDataType.Scale;
|
|
|
|
if scale > 0 then
|
|
begin
|
|
if Length(s) <= scale then
|
|
s := StringOfChar('0', scale - Length(s) + 1) + s;
|
|
|
|
insertPos := Length(s) - scale;
|
|
Result := Copy(s, 1, insertPos) + '.' + Copy(s, insertPos + 1, MaxInt);
|
|
end
|
|
else
|
|
begin
|
|
Result := s;
|
|
end;
|
|
|
|
if FValue < 0 then
|
|
Result := '-' + Result;
|
|
end;
|
|
|
|
function TDataDecimalValue.GetDataType: IDataType;
|
|
begin
|
|
Result := FDataType;
|
|
end;
|
|
|
|
function TDataDecimalValue.GetValue: Int64;
|
|
begin
|
|
Result := FValue;
|
|
end;
|
|
|
|
end.
|