1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-07-29 08:21:15 +03:00

MCOL-4409 Moved static Decimal conversion methods into VDecimal class

MCOL-4409 This patch combines VDecimal and Decimal and makes
IDB_Decimal an alias for the result class

MCOL-4409 More boilerplate reduction in Func_mod

Removed couple TSInt128::toType() methods
This commit is contained in:
Roman Nozdrin
2020-11-24 15:28:38 +00:00
parent 2003417a89
commit 494bde61e1
27 changed files with 760 additions and 929 deletions

View File

@ -630,7 +630,7 @@ int TypeHandlerSLongDouble::storeValueToField(rowgroup::Row &row, int pos,
int TypeHandlerXDecimal::storeValueToField64(rowgroup::Row &row, int pos,
StoreField *f) const
{
return f->store_decimal64(datatypes::VDecimal(row.getIntField(pos),
return f->store_decimal64(datatypes::Decimal(row.getIntField(pos),
f->scale(),
f->precision()));
}
@ -640,7 +640,7 @@ int TypeHandlerXDecimal::storeValueToField128(rowgroup::Row &row, int pos,
StoreField *f) const
{
int128_t* decPtr = row.getBinaryField<int128_t>(pos);
return f->store_decimal128(datatypes::VDecimal(0,
return f->store_decimal128(datatypes::Decimal(0,
f->scale(),
f->precision(),
decPtr));
@ -782,7 +782,7 @@ TypeHandlerXDecimal::format128(const SimpleValue &v,
const
{
idbassert(isValidXDecimal128(attr));
datatypes::VDecimal dec(0, attr.scale, attr.precision, v.toSInt128());
datatypes::Decimal dec(0, attr.scale, attr.precision, v.toSInt128());
return dec.toString(true);
}

View File

@ -727,8 +727,8 @@ public:
virtual int store_float(float val) = 0;
virtual int store_double(double val) = 0;
virtual int store_long_double(long double val) = 0;
virtual int store_decimal64(const datatypes::VDecimal& dec) = 0;
virtual int store_decimal128(const datatypes::VDecimal& dec) = 0;
virtual int store_decimal64(const datatypes::Decimal& dec) = 0;
virtual int store_decimal128(const datatypes::Decimal& dec) = 0;
virtual int store_lob(const char *str, size_t length) = 0;
};

View File

@ -49,9 +49,9 @@ namespace datatypes
template<typename BinaryOperation,
typename OpOverflowCheck,
typename MultiplicationOverflowCheck>
void addSubtractExecute(const VDecimal& l,
const VDecimal& r,
VDecimal& result,
void addSubtractExecute(const Decimal& l,
const Decimal& r,
Decimal& result,
BinaryOperation op,
OpOverflowCheck opOverflowCheck,
MultiplicationOverflowCheck mulOverflowCheck)
@ -109,9 +109,9 @@ namespace datatypes
template<typename OpOverflowCheck,
typename MultiplicationOverflowCheck>
void divisionExecute(const VDecimal& l,
const VDecimal& r,
VDecimal& result,
void divisionExecute(const Decimal& l,
const Decimal& r,
Decimal& result,
OpOverflowCheck opOverflowCheck,
MultiplicationOverflowCheck mulOverflowCheck)
{
@ -148,9 +148,9 @@ namespace datatypes
template<typename OpOverflowCheck,
typename MultiplicationOverflowCheck>
void multiplicationExecute(const VDecimal& l,
const VDecimal& r,
VDecimal& result,
void multiplicationExecute(const Decimal& l,
const Decimal& r,
Decimal& result,
OpOverflowCheck opOverflowCheck,
MultiplicationOverflowCheck mulOverflowCheck)
{
@ -195,7 +195,7 @@ namespace datatypes
}
}
int Decimal::compare(const VDecimal& l, const VDecimal& r)
int Decimal::compare(const Decimal& l, const Decimal& r)
{
int128_t divisorL, divisorR;
getScaleDivisor(divisorL, l.scale);
@ -242,8 +242,8 @@ namespace datatypes
// no overflow check
template<>
void Decimal::addition<int128_t, false>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::addition<int128_t, false>(const Decimal& l,
const Decimal& r, Decimal& result)
{
std::plus<int128_t> add;
NoOverflowCheck noOverflowCheck;
@ -252,8 +252,8 @@ namespace datatypes
// with overflow check
template<>
void Decimal::addition<int128_t, true>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::addition<int128_t, true>(const Decimal& l,
const Decimal& r, Decimal& result)
{
std::plus<int128_t> add;
AdditionOverflowCheck overflowCheck;
@ -263,8 +263,8 @@ namespace datatypes
// no overflow check
template<>
void Decimal::addition<int64_t, false>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::addition<int64_t, false>(const Decimal& l,
const Decimal& r, Decimal& result)
{
if (result.scale == l.scale && result.scale == r.scale)
{
@ -293,8 +293,8 @@ namespace datatypes
// with overflow check
template<>
void Decimal::addition<int64_t, true>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::addition<int64_t, true>(const Decimal& l,
const Decimal& r, Decimal& result)
{
AdditionOverflowCheck additionOverflowCheck;
MultiplicationOverflowCheck mulOverflowCheck;
@ -328,8 +328,8 @@ namespace datatypes
// no overflow check
template<>
void Decimal::subtraction<int128_t, false>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::subtraction<int128_t, false>(const Decimal& l,
const Decimal& r, Decimal& result)
{
std::minus<int128_t> subtract;
NoOverflowCheck noOverflowCheck;
@ -338,8 +338,8 @@ namespace datatypes
// with overflow check
template<>
void Decimal::subtraction<int128_t, true>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::subtraction<int128_t, true>(const Decimal& l,
const Decimal& r, Decimal& result)
{
std::minus<int128_t> subtract;
SubtractionOverflowCheck overflowCheck;
@ -349,8 +349,8 @@ namespace datatypes
// no overflow check
template<>
void Decimal::subtraction<int64_t, false>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::subtraction<int64_t, false>(const Decimal& l,
const Decimal& r, Decimal& result)
{
if (result.scale == l.scale && result.scale == r.scale)
{
@ -379,8 +379,8 @@ namespace datatypes
// with overflow check
template<>
void Decimal::subtraction<int64_t, true>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::subtraction<int64_t, true>(const Decimal& l,
const Decimal& r, Decimal& result)
{
SubtractionOverflowCheck subtractionOverflowCheck;
MultiplicationOverflowCheck mulOverflowCheck;
@ -414,8 +414,8 @@ namespace datatypes
// no overflow check
template<>
void Decimal::division<int128_t, false>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::division<int128_t, false>(const Decimal& l,
const Decimal& r, Decimal& result)
{
NoOverflowCheck noOverflowCheck;
divisionExecute(l, r, result, noOverflowCheck, noOverflowCheck);
@ -423,8 +423,8 @@ namespace datatypes
// With overflow check
template<>
void Decimal::division<int128_t, true>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::division<int128_t, true>(const Decimal& l,
const Decimal& r, Decimal& result)
{
DivisionOverflowCheck overflowCheck;
MultiplicationOverflowCheck mulOverflowCheck;
@ -434,8 +434,8 @@ namespace datatypes
// no overflow check
// We rely on the zero check from ArithmeticOperator::execute
template<>
void Decimal::division<int64_t, false>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::division<int64_t, false>(const Decimal& l,
const Decimal& r, Decimal& result)
{
if (result.scale >= l.scale - r.scale)
result.value = (int64_t)(( (l.value > 0 && r.value > 0) || (l.value < 0 && r.value < 0) ?
@ -449,8 +449,8 @@ namespace datatypes
// With overflow check
template<>
void Decimal::division<int64_t, true>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::division<int64_t, true>(const Decimal& l,
const Decimal& r, Decimal& result)
{
DivisionOverflowCheck divisionOverflowCheck;
@ -469,8 +469,8 @@ namespace datatypes
// no overflow check
template<>
void Decimal::multiplication<int128_t, false>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::multiplication<int128_t, false>(const Decimal& l,
const Decimal& r, Decimal& result)
{
MultiplicationNoOverflowCheck noOverflowCheck;
multiplicationExecute(l, r, result, noOverflowCheck, noOverflowCheck);
@ -478,8 +478,8 @@ namespace datatypes
// With overflow check
template<>
void Decimal::multiplication<int128_t, true>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::multiplication<int128_t, true>(const Decimal& l,
const Decimal& r, Decimal& result)
{
MultiplicationOverflowCheck mulOverflowCheck;
multiplicationExecute(l, r, result, mulOverflowCheck, mulOverflowCheck);
@ -487,8 +487,8 @@ namespace datatypes
// no overflow check
template<>
void Decimal::multiplication<int64_t, false>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::multiplication<int64_t, false>(const Decimal& l,
const Decimal& r, Decimal& result)
{
if (result.scale >= l.scale + r.scale)
result.value = l.value * r.value * mcs_pow_10[result.scale - (l.scale + r.scale)];
@ -500,8 +500,8 @@ namespace datatypes
// With overflow check
template<>
void Decimal::multiplication<int64_t, true>(const VDecimal& l,
const VDecimal& r, VDecimal& result)
void Decimal::multiplication<int64_t, true>(const Decimal& l,
const Decimal& r, Decimal& result)
{
MultiplicationOverflowCheck mulOverflowCheck;
@ -521,7 +521,7 @@ namespace datatypes
}
// Writes integer part of a Decimal using int128 argument provided
uint8_t VDecimal::writeIntPart(const int128_t& x,
uint8_t Decimal::writeIntPart(const int128_t& x,
char* buf,
const uint8_t buflen) const
{
@ -552,7 +552,7 @@ namespace datatypes
high = intPart / maxUint64divisor;
break;
default:
throw logging::QueryDataExcept("VDecimal::writeIntPart() bad scale",
throw logging::QueryDataExcept("Decimal::writeIntPart() bad scale",
logging::formatErr);
}
@ -560,14 +560,14 @@ namespace datatypes
uint8_t written = p - buf;
if (buflen <= written)
{
throw logging::QueryDataExcept("VDecimal::writeIntPart() char buffer overflow.",
throw logging::QueryDataExcept("Decimal::writeIntPart() char buffer overflow.",
logging::formatErr);
}
return written;
}
uint8_t VDecimal::writeFractionalPart(const int128_t& x,
uint8_t Decimal::writeFractionalPart(const int128_t& x,
char* buf,
const uint8_t buflen) const
{
@ -605,7 +605,7 @@ namespace datatypes
// The method writes Decimal based on TSInt128 with scale provided.
// It first writes sign, then extracts integer part
// prints delimiter and then decimal part.
std::string VDecimal::toStringTSInt128WithScale() const
std::string Decimal::toStringTSInt128WithScale() const
{
char buf[Decimal::MAXLENGTH16BYTES];
uint8_t left = sizeof(buf);
@ -633,13 +633,13 @@ namespace datatypes
uint8_t written = p - buf;
if (sizeof(buf) <= written)
{
throw logging::QueryDataExcept("VDecimal::toString() char buffer overflow.",
throw logging::QueryDataExcept("Decimal::toString() char buffer overflow.",
logging::formatErr);
}
return std::string(buf);
}
std::string VDecimal::toStringTSInt64() const
std::string Decimal::toStringTSInt64() const
{
char buf[Decimal::MAXLENGTH8BYTES];
// Need 19 digits maxium to hold a sum result of 18 digits decimal column.
@ -706,7 +706,7 @@ namespace datatypes
}
// Dispatcher method for toString() implementations
std::string VDecimal::toString(bool hasTSInt128) const
std::string Decimal::toString(bool hasTSInt128) const
{
// There must be no empty at this point though
if (isNull())
@ -730,7 +730,7 @@ namespace datatypes
return std::to_string(value);
}
std::ostream& operator<<(std::ostream& os, const VDecimal& dec)
std::ostream& operator<<(std::ostream& os, const Decimal& dec)
{
os << dec.toString();
return os;

View File

@ -26,11 +26,13 @@
#include "widedecimalutils.h"
#include "mcs_int128.h"
#include "mcs_float128.h"
#include "checks.h"
#include "branchpred.h"
namespace datatypes
{
class VDecimal;
class Decimal;
}
// A class by Fabio Fernandes pulled off of stackoverflow
@ -158,21 +160,16 @@ inline void getScaleDivisor(T& divisor, const int8_t scale)
}
}
/**
@brief Contains subset of decimal related operations.
Most of the methods are static to allow to call them from
the existing code.
The main purpose of the class is to collect methods for a
base Datatype class.
*/
class Decimal
// @brief The class for Decimal related operations
// The class contains Decimal related operations are scale and
// precision aware.
// This class will inherit from:
// DecimalMeta class that stores scale and precision
// Storage classes TSInt128 and int64
// !!! There are some static classes that will exists during transition period.
class Decimal: public TSInt128
{
public:
Decimal() { };
~Decimal() { };
static constexpr uint8_t MAXLENGTH16BYTES = TSInt128::maxLength();
static constexpr uint8_t MAXLENGTH8BYTES = 23;
@ -200,44 +197,44 @@ class Decimal
static constexpr int128_t maxInt128 = (int128_t(0x7FFFFFFFFFFFFFFFLL) << 64) + 0xFFFFFFFFFFFFFFFFLL;
/**
@brief Compares two VDecimal taking scale into account.
@brief Compares two Decimal taking scale into account.
*/
static int compare(const VDecimal& l, const VDecimal& r);
static int compare(const Decimal& l, const Decimal& r);
/**
@brief Addition template that supports overflow check and
two internal representations of decimal.
*/
template<typename T, bool overflow>
static void addition(const VDecimal& l,
const VDecimal& r,
VDecimal& result);
static void addition(const Decimal& l,
const Decimal& r,
Decimal& result);
/**
@brief Subtraction template that supports overflow check and
two internal representations of decimal.
*/
template<typename T, bool overflow>
static void subtraction(const VDecimal& l,
const VDecimal& r,
VDecimal& result);
static void subtraction(const Decimal& l,
const Decimal& r,
Decimal& result);
/**
@brief Division template that supports overflow check and
two internal representations of decimal.
*/
template<typename T, bool overflow>
static void division(const VDecimal& l,
const VDecimal& r,
VDecimal& result);
static void division(const Decimal& l,
const Decimal& r,
Decimal& result);
/**
@brief Multiplication template that supports overflow check and
two internal representations of decimal.
*/
template<typename T, bool overflow>
static void multiplication(const VDecimal& l,
const VDecimal& r,
VDecimal& result);
static void multiplication(const Decimal& l,
const Decimal& r,
Decimal& result);
/**
@brief The method detects whether decimal type is wide
@ -249,85 +246,6 @@ class Decimal
&& precision <= INT128MAXPRECISION;
}
/**
@brief The method converts a __float128 value to an int64_t.
*/
static inline int64_t getInt64FromFloat128(const __float128& value)
{
if (value > static_cast<__float128>(INT64_MAX))
return INT64_MAX;
else if (value < static_cast<__float128>(INT64_MIN))
return INT64_MIN;
return static_cast<int64_t>(value);
}
/**
@brief The method converts a __float128 value to an uint64_t.
*/
static inline uint64_t getUInt64FromFloat128(const __float128& value)
{
if (value > static_cast<__float128>(UINT64_MAX))
return UINT64_MAX;
else if (value < 0)
return 0;
return static_cast<uint64_t>(value);
}
/**
@brief The method converts a wide decimal value to an uint32_t.
*/
static inline uint32_t getUInt32FromWideDecimal(const int128_t& value)
{
if (value > static_cast<int128_t>(UINT32_MAX))
return UINT32_MAX;
else if (value < 0)
return 0;
return static_cast<uint32_t>(value);
}
/**
@brief The method converts a wide decimal value to an int32_t.
*/
static inline int32_t getInt32FromWideDecimal(const int128_t& value)
{
if (value > static_cast<int128_t>(INT32_MAX))
return INT32_MAX;
else if (value < static_cast<int128_t>(INT32_MIN))
return INT32_MIN;
return static_cast<int32_t>(value);
}
/**
@brief The method converts a wide decimal value to an uint64_t.
*/
static inline uint64_t getUInt64FromWideDecimal(const int128_t& value)
{
if (value > static_cast<int128_t>(UINT64_MAX))
return UINT64_MAX;
else if (value < 0)
return 0;
return static_cast<uint64_t>(value);
}
/**
@brief The method converts a wide decimal value to an int64_t,
saturating the value if necessary.
*/
static inline int64_t getInt64FromWideDecimal(const int128_t& value)
{
if (value > static_cast<int128_t>(INT64_MAX))
return INT64_MAX;
else if (value < static_cast<int128_t>(INT64_MIN))
return INT64_MIN;
return static_cast<int64_t>(value);
}
/**
@brief MDB increases scale by up to 4 digits calculating avg()
*/
@ -340,7 +258,461 @@ class Decimal
scale += (scaleAvailable >= MAXSCALEINC4AVG) ? MAXSCALEINC4AVG : scaleAvailable;
precision += (precisionAvailable >= MAXSCALEINC4AVG) ? MAXSCALEINC4AVG : precisionAvailable;
}
};
Decimal(): value(0), scale(0), precision(0)
{
}
Decimal(int64_t val, int8_t s, uint8_t p, const int128_t &val128 = 0) :
TSInt128(val128),
value(val),
scale(s),
precision(p)
{ }
Decimal(int64_t unused, int8_t s, uint8_t p, const int128_t* val128Ptr) :
TSInt128(val128Ptr),
value(unused),
scale(s),
precision(p)
{ }
Decimal(const TSInt128& val128, int8_t s, uint8_t p) :
TSInt128(val128),
value(0),
scale(s),
precision(p)
{ }
int decimalComp(const Decimal& d) const
{
lldiv_t d1 = lldiv(value, static_cast<int64_t>(mcs_pow_10[scale]));
lldiv_t d2 = lldiv(d.value, static_cast<int64_t>(mcs_pow_10[d.scale]));
int ret = 0;
if (d1.quot > d2.quot)
{
ret = 1;
}
else if (d1.quot < d2.quot)
{
ret = -1;
}
else
{
// rem carries the value's sign, but needs to be normalized.
int64_t s = scale - d.scale;
if (s < 0)
{
if ((d1.rem * static_cast<int64_t>(mcs_pow_10[-s])) > d2.rem)
ret = 1;
else if ((d1.rem * static_cast<int64_t>(mcs_pow_10[-s])) < d2.rem)
ret = -1;
}
else
{
if (d1.rem > (d2.rem * static_cast<int64_t>(mcs_pow_10[s])))
ret = 1;
else if (d1.rem < (d2.rem * static_cast<int64_t>(mcs_pow_10[s])))
ret = -1;
}
}
return ret;
}
inline TSInt128 toTSInt128() const
{
return TSInt128(s128Value);
}
inline TFloat128 toTFloat128() const
{
return TFloat128(s128Value);
}
inline double toDouble() const
{
int128_t scaleDivisor;
getScaleDivisor(scaleDivisor, scale);
datatypes::TFloat128 tmpval((__float128) s128Value / scaleDivisor);
return static_cast<double>(tmpval);
}
inline operator double() const
{
return toDouble();
}
inline long double toLongDouble() const
{
datatypes::TFloat128 y(s128Value);
return static_cast<long double>(y);
}
// This method returns integral part as a TSInt128 and
// fractional part as a TFloat128
inline std::pair<TSInt128, TFloat128> getIntegralAndDividedFractional() const
{
int128_t scaleDivisor;
getScaleDivisor(scaleDivisor, scale);
return std::make_pair(TSInt128(s128Value / scaleDivisor),
TFloat128((__float128)(s128Value % scaleDivisor) / scaleDivisor));
}
// This method returns integral part as a TSInt128 and
// fractional part as a TFloat128
inline std::pair<TSInt128, TSInt128> getIntegralAndFractional() const
{
int128_t scaleDivisor;
getScaleDivisor(scaleDivisor, scale);
return std::make_pair(TSInt128(s128Value / scaleDivisor),
TSInt128(s128Value % scaleDivisor));
}
inline std::tuple<TSInt128, TSInt128, TSInt128> getIntegralFractionalAndDivisor() const
{
int128_t scaleDivisor;
getScaleDivisor(scaleDivisor, scale);
return std::make_tuple(TSInt128(s128Value / scaleDivisor),
TSInt128(s128Value % scaleDivisor),
TSInt128(scaleDivisor));
}
inline TSInt128 getIntegralPart() const
{
int128_t scaleDivisor = 0;
if(LIKELY(utils::is_nonnegative(scale)))
{
return TSInt128(getIntegralPartNonNegativeScale(scaleDivisor));
}
return TSInt128(getIntegralPartNegativeScale(scaleDivisor));
}
// !!! This is a very hevyweight rouding style
// Argument determines if it is a ceil
// rounding or not. 0 - ceil rounding
inline TSInt128 getRoundedIntegralPart(const uint8_t roundingFactor = 0) const
{
int128_t flooredScaleDivisor = 0;
int128_t roundedValue = getIntegralPartNonNegativeScale(flooredScaleDivisor);
int128_t ceiledScaleDivisor = (flooredScaleDivisor <= 10) ? 1 : (flooredScaleDivisor / 10);
int128_t leftO = (s128Value - roundedValue * flooredScaleDivisor) / ceiledScaleDivisor;
if (leftO > roundingFactor)
{
roundedValue++;
}
return TSInt128(roundedValue);
}
inline TSInt128 getPosNegRoundedIntegralPart(const uint8_t roundingFactor = 0) const
{
int128_t flooredScaleDivisor = 0;
int128_t roundedValue = getIntegralPartNonNegativeScale(flooredScaleDivisor);
int128_t ceiledScaleDivisor = (flooredScaleDivisor <= 10) ? 1 : (flooredScaleDivisor / 10);
int128_t leftO = (s128Value - roundedValue * flooredScaleDivisor) / ceiledScaleDivisor;
if (utils::is_nonnegative(roundedValue) && leftO > roundingFactor)
{
roundedValue++;
}
if (utils::is_negative(roundedValue) && leftO < -roundingFactor)
{
roundedValue--;
}
return TSInt128(roundedValue);
}
// MOD operator for an integer divisor to be used
// for integer rhs
inline TSInt128 operator%(const TSInt128& div) const
{
if (!isScaled())
{
return s128Value % div.getValue();
}
// Scale the value and calculate
// (LHS.value % RHS.value) * LHS.scaleMultiplier + LHS.scale_div_remainder
auto integralFractionalDivisor = getIntegralFractionalAndDivisor();
return (std::get<0>(integralFractionalDivisor) % div.getValue()) * std::get<2>(integralFractionalDivisor) + std::get<1>(integralFractionalDivisor);
}
bool operator==(const Decimal& rhs) const
{
if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return s128Value == rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) == 0);
}
else if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision <= datatypes::INT64MAXPRECISION)
{
const_cast<Decimal&>(rhs).s128Value = rhs.value;
if (scale == rhs.scale)
return s128Value == rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) == 0);
}
else if (precision <= datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return (int128_t) value == rhs.s128Value;
else
return (datatypes::Decimal::compare(Decimal(0, scale, precision, (int128_t) value), rhs) == 0);
}
else
{
if (scale == rhs.scale)
return value == rhs.value;
else
return (decimalComp(rhs) == 0);
}
}
bool operator>(const Decimal& rhs) const
{
if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return s128Value > rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) > 0);
}
else if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision <= datatypes::INT64MAXPRECISION)
{
Decimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value);
if (scale == rhstmp.scale)
return s128Value > rhstmp.s128Value;
else
return (datatypes::Decimal::compare(*this, rhstmp) > 0);
}
else if (precision <= datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return (int128_t) value > rhs.s128Value;
else
return (datatypes::Decimal::compare(Decimal(0, scale, precision, (int128_t) value), rhs) > 0);
}
else
{
if (scale == rhs.scale)
return value > rhs.value;
else
return (decimalComp(rhs) > 0);
}
}
bool operator<(const Decimal& rhs) const
{
if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return s128Value < rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) < 0);
}
else if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision <= datatypes::INT64MAXPRECISION)
{
Decimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value);
if (scale == rhstmp.scale)
return s128Value < rhstmp.s128Value;
else
return (datatypes::Decimal::compare(*this, rhstmp) < 0);
}
else if (precision <= datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return (int128_t) value < rhs.s128Value;
else
return (datatypes::Decimal::compare(Decimal(0, scale, precision, (int128_t) value), rhs) < 0);
}
else
{
if (scale == rhs.scale)
return value < rhs.value;
else
return (decimalComp(rhs) < 0);
}
}
bool operator>=(const Decimal& rhs) const
{
if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return s128Value >= rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) >= 0);
}
else if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision <= datatypes::INT64MAXPRECISION)
{
Decimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value);
if (scale == rhstmp.scale)
return s128Value >= rhstmp.s128Value;
else
return (datatypes::Decimal::compare(*this, rhstmp) >= 0);
}
else if (precision <= datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return (int128_t) value >= rhs.s128Value;
else
return (datatypes::Decimal::compare(Decimal(0, scale, precision, (int128_t) value), rhs) >= 0);
}
else
{
if (scale == rhs.scale)
return value >= rhs.value;
else
return (decimalComp(rhs) >= 0);
}
}
bool operator<=(const Decimal& rhs) const
{
if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return s128Value <= rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) <= 0);
}
else if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision <= datatypes::INT64MAXPRECISION)
{
Decimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value);
if (scale == rhstmp.scale)
return s128Value <= rhstmp.s128Value;
else
return (datatypes::Decimal::compare(*this, rhstmp) <= 0);
}
else if (precision <= datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return (int128_t) value <= rhs.s128Value;
else
return (datatypes::Decimal::compare(Decimal(0, scale, precision, (int128_t) value), rhs) <= 0);
}
else
{
if (scale == rhs.scale)
return value <= rhs.value;
else
return (decimalComp(rhs) <= 0);
}
}
bool operator!=(const Decimal& rhs) const
{
if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return s128Value != rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) != 0);
}
else if (precision > datatypes::INT64MAXPRECISION &&
rhs.precision <= datatypes::INT64MAXPRECISION)
{
Decimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value);
if (scale == rhstmp.scale)
return s128Value != rhstmp.s128Value;
else
return (datatypes::Decimal::compare(*this, rhstmp) != 0);
}
else if (precision <= datatypes::INT64MAXPRECISION &&
rhs.precision > datatypes::INT64MAXPRECISION)
{
if (scale == rhs.scale)
return (int128_t) value != rhs.s128Value;
else
return (datatypes::Decimal::compare(Decimal(0, scale, precision, (int128_t) value), rhs) != 0);
}
else
{
if (scale == rhs.scale)
return value != rhs.value;
else
return (decimalComp(rhs) != 0);
}
}
inline bool isTSInt128ByPrecision() const
{
return precision > INT64MAXPRECISION
&& precision <= INT128MAXPRECISION;
}
inline bool isScaled() const
{
return scale != 0;
}
// hasTSInt128 explicitly tells to print int128 out in cases
// where precision can't detect decimal type properly, e.g.
// DECIMAL(10)/DECIMAL(38)
std::string toString(bool hasTSInt128 = false) const;
friend std::ostream& operator<<(std::ostream& os, const Decimal& dec);
int64_t value;
int8_t scale; // 0~38
uint8_t precision; // 1~38
// STRICTLY for unit tests!!!
void setTSInt64Value(const int64_t x) { value = x; }
void setTSInt128Value(const int128_t& x) { s128Value = x; }
void setScale(const uint8_t x) { scale = x; }
private:
uint8_t writeIntPart(const int128_t& x,
char* buf,
const uint8_t buflen) const;
uint8_t writeFractionalPart(const int128_t& x,
char* buf,
const uint8_t buflen) const;
std::string toStringTSInt128WithScale() const;
std::string toStringTSInt64() const;
inline int128_t getIntegralPartNonNegativeScale(int128_t& scaleDivisor) const
{
getScaleDivisor(scaleDivisor, scale);
return s128Value / scaleDivisor;
}
inline int128_t getIntegralPartNegativeScale(int128_t& scaleDivisor) const
{
getScaleDivisor(scaleDivisor, -scale);
// Calls for overflow check
return s128Value * scaleDivisor;
}
}; //end of Decimal
/**
@brief The structure contains an overflow check for int128
@ -480,330 +852,5 @@ struct NoOverflowCheck {
}
};
/**
* @brief VDecimal type
*
*/
class VDecimal: public TSInt128
{
public:
VDecimal(): value(0), scale(0), precision(0)
{
}
VDecimal(int64_t val, int8_t s, uint8_t p, const int128_t &val128 = 0) :
TSInt128(val128),
value(val),
scale(s),
precision(p)
{ }
VDecimal(int64_t unused, int8_t s, uint8_t p, const int128_t* val128Ptr) :
TSInt128(val128Ptr),
value(unused),
scale(s),
precision(p)
{ }
int decimalComp(const VDecimal& d) const
{
lldiv_t d1 = lldiv(value, static_cast<int64_t>(mcs_pow_10[scale]));
lldiv_t d2 = lldiv(d.value, static_cast<int64_t>(mcs_pow_10[d.scale]));
int ret = 0;
if (d1.quot > d2.quot)
{
ret = 1;
}
else if (d1.quot < d2.quot)
{
ret = -1;
}
else
{
// rem carries the value's sign, but needs to be normalized.
int64_t s = scale - d.scale;
if (s < 0)
{
if ((d1.rem * static_cast<int64_t>(mcs_pow_10[-s])) > d2.rem)
ret = 1;
else if ((d1.rem * static_cast<int64_t>(mcs_pow_10[-s])) < d2.rem)
ret = -1;
}
else
{
if (d1.rem > (d2.rem * static_cast<int64_t>(mcs_pow_10[s])))
ret = 1;
else if (d1.rem < (d2.rem * static_cast<int64_t>(mcs_pow_10[s])))
ret = -1;
}
}
return ret;
}
inline TSInt128 toTSInt128() const
{
return TSInt128(s128Value);
}
inline TFloat128 toTFloat128() const
{
return TFloat128(s128Value);
}
inline double toDouble() const
{
int128_t scaleDivisor;
getScaleDivisor(scaleDivisor, scale);
datatypes::TFloat128 tmpval((__float128) s128Value / scaleDivisor);
return static_cast<double>(tmpval);
}
inline operator double() const
{
return toDouble();
}
bool operator==(const VDecimal& rhs) const
{
if (isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return s128Value == rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) == 0);
}
else if (isTSInt128ByPrecision() && !rhs.isTSInt128ByPrecision())
{
const_cast<VDecimal&>(rhs).s128Value = rhs.value;
if (scale == rhs.scale)
return s128Value == rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) == 0);
}
else if (!isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return (int128_t) value == rhs.s128Value;
else
return (datatypes::Decimal::compare(VDecimal(0, scale, precision, (int128_t) value), rhs) == 0);
}
else
{
if (scale == rhs.scale)
return value == rhs.value;
else
return (decimalComp(rhs) == 0);
}
}
bool operator>(const VDecimal& rhs) const
{
if (isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return s128Value > rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) > 0);
}
else if (isTSInt128ByPrecision() && !rhs.isTSInt128ByPrecision())
{
VDecimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value);
if (scale == rhstmp.scale)
return s128Value > rhstmp.s128Value;
else
return (datatypes::Decimal::compare(*this, rhstmp) > 0);
}
else if (!isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return (int128_t) value > rhs.s128Value;
else
return (datatypes::Decimal::compare(VDecimal(0, scale, precision, (int128_t) value), rhs) > 0);
}
else
{
if (scale == rhs.scale)
return value > rhs.value;
else
return (decimalComp(rhs) > 0);
}
}
bool operator<(const VDecimal& rhs) const
{
if (isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return s128Value < rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) < 0);
}
else if (isTSInt128ByPrecision() && !rhs.isTSInt128ByPrecision())
{
VDecimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value);
if (scale == rhstmp.scale)
return s128Value < rhstmp.s128Value;
else
return (datatypes::Decimal::compare(*this, rhstmp) < 0);
}
else if (!isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return (int128_t) value < rhs.s128Value;
else
return (datatypes::Decimal::compare(VDecimal(0, scale, precision, (int128_t) value), rhs) < 0);
}
else
{
if (scale == rhs.scale)
return value < rhs.value;
else
return (decimalComp(rhs) < 0);
}
}
bool operator>=(const VDecimal& rhs) const
{
if (isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return s128Value >= rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) >= 0);
}
else if (isTSInt128ByPrecision() && !rhs.isTSInt128ByPrecision())
{
VDecimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value);
if (scale == rhstmp.scale)
return s128Value >= rhstmp.s128Value;
else
return (datatypes::Decimal::compare(*this, rhstmp) >= 0);
}
else if (!isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return (int128_t) value >= rhs.s128Value;
else
return (datatypes::Decimal::compare(VDecimal(0, scale, precision, (int128_t) value), rhs) >= 0);
}
else
{
if (scale == rhs.scale)
return value >= rhs.value;
else
return (decimalComp(rhs) >= 0);
}
}
bool operator<=(const VDecimal& rhs) const
{
if (isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return s128Value <= rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) <= 0);
}
else if (isTSInt128ByPrecision() && !rhs.isTSInt128ByPrecision())
{
VDecimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value);
if (scale == rhstmp.scale)
return s128Value <= rhstmp.s128Value;
else
return (datatypes::Decimal::compare(*this, rhstmp) <= 0);
}
else if (!isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return (int128_t) value <= rhs.s128Value;
else
return (datatypes::Decimal::compare(VDecimal(0, scale, precision, (int128_t) value), rhs) <= 0);
}
else
{
if (scale == rhs.scale)
return value <= rhs.value;
else
return (decimalComp(rhs) <= 0);
}
}
bool operator!=(const VDecimal& rhs) const
{
if (isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return s128Value != rhs.s128Value;
else
return (datatypes::Decimal::compare(*this, rhs) != 0);
}
else if (isTSInt128ByPrecision() && !rhs.isTSInt128ByPrecision())
{
VDecimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value);
if (scale == rhstmp.scale)
return s128Value != rhstmp.s128Value;
else
return (datatypes::Decimal::compare(*this, rhstmp) != 0);
}
else if (!isTSInt128ByPrecision() && rhs.isTSInt128ByPrecision())
{
if (scale == rhs.scale)
return (int128_t) value != rhs.s128Value;
else
return (datatypes::Decimal::compare(VDecimal(0, scale, precision, (int128_t) value), rhs) != 0);
}
else
{
if (scale == rhs.scale)
return value != rhs.value;
else
return (decimalComp(rhs) != 0);
}
}
inline bool isTSInt128ByPrecision() const
{
return precision > INT64MAXPRECISION
&& precision <= INT128MAXPRECISION;
}
// hasTSInt128 explicitly tells to print int128 out in cases
// where precision can't detect decimal type properly, e.g.
// DECIMAL(10)/DECIMAL(38)
std::string toString(bool hasTSInt128 = false) const;
friend std::ostream& operator<<(std::ostream& os, const VDecimal& dec);
int64_t value;
int8_t scale; // 0~38
uint8_t precision; // 1~38
// STRICTLY for unit tests!!!
void setTSInt64Value(const int64_t x) { value = x; }
void setTSInt128Value(const int128_t& x) { s128Value = x; }
void setScale(const uint8_t x) { scale = x; }
private:
uint8_t writeIntPart(const int128_t& x,
char* buf,
const uint8_t buflen) const;
uint8_t writeFractionalPart(const int128_t& x,
char* buf,
const uint8_t buflen) const;
std::string toStringTSInt128WithScale() const;
std::string toStringTSInt64() const;
};
} //end of namespace
#endif

View File

@ -25,9 +25,28 @@
namespace datatypes
{
//class TSInt128;
class TSInt128;
class TFloat128;
using int128_t = __int128;
// Type defined integral types
// for templates
template <typename T>
struct get_integral_type {
typedef T type;
};
template<>
struct get_integral_type<TFloat128>{
typedef __float128 type;
};
template<>
struct get_integral_type<TSInt128>{
typedef int128_t type;
};
class TFloat128
{
public:
@ -66,6 +85,40 @@ class TFloat128
return toLongDouble();
}
inline int64_t toTSInt64() const
{
if (value > static_cast<__float128>(INT64_MAX))
return INT64_MAX;
else if (value < static_cast<__float128>(INT64_MIN))
return INT64_MIN;
return static_cast<int64_t>(value);
}
inline operator int64_t() const
{
return toTSInt64();
}
inline int64_t toTUInt64() const
{
if (value > static_cast<__float128>(UINT64_MAX))
return UINT64_MAX;
else if (value < 0)
return 0;
return static_cast<uint64_t>(value);
}
inline operator uint64_t() const
{
return toTUInt64();
}
inline TFloat128 operator+(const TFloat128& rhs) const
{
return TFloat128(value + rhs.value);
}
inline long double toLongDouble() const
{

View File

@ -117,50 +117,5 @@ namespace datatypes
return os;
}
// The method converts a wide decimal s128Value to an int64_t,
// saturating the s128Value if necessary.
inline int64_t TSInt128::getInt64FromWideDecimal()
{
if (s128Value > static_cast<int128_t>(INT64_MAX))
return INT64_MAX;
else if (s128Value < static_cast<int128_t>(INT64_MIN))
return INT64_MIN;
return static_cast<int64_t>(s128Value);
}
// The method converts a wide decimal s128Value to an uint32_t.
inline uint32_t TSInt128::getUInt32FromWideDecimal()
{
if (s128Value > static_cast<int128_t>(UINT32_MAX))
return UINT32_MAX;
else if (s128Value < 0)
return 0;
return static_cast<uint32_t>(s128Value);
}
// The method converts a wide decimal s128Value to an uint64_t.
inline uint64_t TSInt128::getUInt64FromWideDecimal()
{
if (s128Value > static_cast<int128_t>(UINT64_MAX))
return UINT64_MAX;
else if (s128Value < 0)
return 0;
return static_cast<uint64_t>(s128Value);
}
// The method converts a wide decimal s128Value to an int32_t.
inline int32_t TSInt128::getInt32FromWideDecimal()
{
if (s128Value > static_cast<int128_t>(INT32_MAX))
return INT32_MAX;
else if (s128Value < static_cast<int128_t>(INT32_MIN))
return INT32_MIN;
return static_cast<int32_t>(s128Value);
}
} // end of namespace datatypes
// vim:ts=2 sw=2:

View File

@ -200,16 +200,81 @@ class TSInt128
return static_cast<long double>(s128Value);
}
inline operator int32_t() const
{
if (s128Value > static_cast<int128_t>(INT32_MAX))
return INT32_MAX;
if (s128Value < static_cast<int128_t>(INT32_MIN))
return INT32_MIN;
return static_cast<int32_t>(s128Value);
}
inline operator uint32_t() const
{
if (s128Value > static_cast<int128_t>(UINT32_MAX))
return UINT32_MAX;
if (s128Value < 0)
return 0;
return static_cast<uint32_t>(s128Value);
}
inline operator int64_t() const
{
if (s128Value > static_cast<int128_t>(INT64_MAX))
return INT64_MAX;
if (s128Value < static_cast<int128_t>(INT64_MIN))
return INT64_MIN;
return static_cast<int64_t>(s128Value);
}
inline operator uint64_t() const
{
if (s128Value > static_cast<int128_t>(UINT64_MAX))
return UINT64_MAX;
if (s128Value < 0)
return 0;
return static_cast<uint64_t>(s128Value);
}
inline operator TFloat128() const
{
return toTFloat128();
}
inline TSInt128 operator%(const int64_t& rhs) const
{
return TSInt128(s128Value % rhs);
}
inline TSInt128 operator%(const int128_t& rhs) const
{
return TSInt128(s128Value % rhs);
}
inline TSInt128 operator*(const TSInt128& rhs) const
{
return TSInt128(s128Value * rhs.s128Value);
}
inline TSInt128 operator+(const TSInt128& rhs) const
{
return TSInt128(s128Value + rhs.s128Value);
}
inline TFloat128 toTFloat128() const
{
return TFloat128(s128Value);
}
inline const int128_t& getValue() const
{
return s128Value;
}
// print int128_t parts represented as PODs
uint8_t printPodParts(char* buf,
const int128_t& high,
@ -226,19 +291,6 @@ class TSInt128
friend std::ostream& operator<<(std::ostream& os, const TSInt128& x);
// The method converts a wide decimal s128Value to an int64_t,
// saturating the s128Value if necessary.
inline int64_t getInt64FromWideDecimal();
// The method converts a wide decimal s128Value to an uint32_t.
inline uint32_t getUInt32FromWideDecimal();
// The method converts a wide decimal s128Value to an uint64_t.
inline uint64_t getUInt64FromWideDecimal();
// The method converts a wide decimal s128Value to an int32_t.
inline int32_t getInt32FromWideDecimal();
int128_t s128Value;
}; // end of class