#pragma once #include "common/extended_types.h" #if !defined(NO_SANITIZE_UNDEFINED) #if defined(__clang__) #define NO_SANITIZE_UNDEFINED __attribute__((__no_sanitize__("undefined"))) #else #define NO_SANITIZE_UNDEFINED #endif #endif namespace DB { template struct Decimal; class DateTime64; using Decimal32 = Decimal; using Decimal64 = Decimal; using Decimal128 = Decimal; using Decimal256 = Decimal; template concept is_decimal = std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; template concept is_over_big_int = std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; template struct NativeTypeT { using Type = T; }; template struct NativeTypeT { using Type = typename T::NativeType; }; template using NativeType = typename NativeTypeT::Type; /// Own FieldType for Decimal. /// It is only a "storage" for decimal. /// To perform operations, you also have to provide a scale (number of digits after point). template struct Decimal { using NativeType = T; constexpr Decimal() = default; constexpr Decimal(Decimal &&) = default; constexpr Decimal(const Decimal &) = default; constexpr Decimal(const T & value_): value(value_) {} template constexpr Decimal(const Decimal & x): value(x.value) {} constexpr Decimal & operator = (Decimal &&) = default; constexpr Decimal & operator = (const Decimal &) = default; constexpr operator T () const { return value; } template constexpr U convertTo() const { if constexpr (is_decimal) return convertTo(); else return static_cast(value); } const Decimal & operator += (const T & x) { value += x; return *this; } const Decimal & operator -= (const T & x) { value -= x; return *this; } const Decimal & operator *= (const T & x) { value *= x; return *this; } const Decimal & operator /= (const T & x) { value /= x; return *this; } const Decimal & operator %= (const T & x) { value %= x; return *this; } template const Decimal & operator += (const Decimal & x) { value += x.value; return *this; } template const Decimal & operator -= (const Decimal & x) { value -= x.value; return *this; } template const Decimal & operator *= (const Decimal & x) { value *= x.value; return *this; } template const Decimal & operator /= (const Decimal & x) { value /= x.value; return *this; } template const Decimal & operator %= (const Decimal & x) { value %= x.value; return *this; } /// This is to avoid UB for sumWithOverflow() void NO_SANITIZE_UNDEFINED addOverflow(const T & x) { value += x; } T value; }; template inline bool operator< (const Decimal & x, const Decimal & y) { return x.value < y.value; } template inline bool operator> (const Decimal & x, const Decimal & y) { return x.value > y.value; } template inline bool operator<= (const Decimal & x, const Decimal & y) { return x.value <= y.value; } template inline bool operator>= (const Decimal & x, const Decimal & y) { return x.value >= y.value; } template inline bool operator== (const Decimal & x, const Decimal & y) { return x.value == y.value; } template inline bool operator!= (const Decimal & x, const Decimal & y) { return x.value != y.value; } template inline Decimal operator+ (const Decimal & x, const Decimal & y) { return x.value + y.value; } template inline Decimal operator- (const Decimal & x, const Decimal & y) { return x.value - y.value; } template inline Decimal operator* (const Decimal & x, const Decimal & y) { return x.value * y.value; } template inline Decimal operator/ (const Decimal & x, const Decimal & y) { return x.value / y.value; } template inline Decimal operator- (const Decimal & x) { return -x.value; } /// Distinguishable type to allow function resolution/deduction based on value type, /// but also relatively easy to convert to/from Decimal64. class DateTime64 : public Decimal64 { public: using Base = Decimal64; using Base::Base; using NativeType = Base::NativeType; constexpr DateTime64(const Base & v): Base(v) {} }; } constexpr DB::UInt64 max_uint_mask = std::numeric_limits::max(); namespace std { template struct hash> { size_t operator()(const DB::Decimal & x) const { return hash()(x.value); } }; template <> struct hash { size_t operator()(const DB::Decimal128 & x) const { return std::hash()(x.value >> 64) ^ std::hash()(x.value & max_uint_mask); } }; template <> struct hash { size_t operator()(const DB::DateTime64 & x) const { return std::hash()(x); } }; template <> struct hash { size_t operator()(const DB::Decimal256 & x) const { // FIXME temp solution return std::hash()(static_cast(x.value >> 64 & max_uint_mask)) ^ std::hash()(static_cast(x.value & max_uint_mask)); } }; }