#pragma once #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_DIVISION; } /** Арифметические функции: +, -, *, /, %, * intDiv (целочисленное деление), унарный минус. * Битовые функции: |, &, ^, ~. */ template struct BinaryOperationImplBase { typedef ResultType_ ResultType; static void vector_vector(const PODArray & a, const PODArray & b, PODArray & c) { size_t size = a.size(); for (size_t i = 0; i < size; ++i) c[i] = Op::template apply(a[i], b[i]); } static void vector_constant(const PODArray & a, B b, PODArray & c) { size_t size = a.size(); for (size_t i = 0; i < size; ++i) c[i] = Op::template apply(a[i], b); } static void constant_vector(A a, const PODArray & b, PODArray & c) { size_t size = b.size(); for (size_t i = 0; i < size; ++i) c[i] = Op::template apply(a, b[i]); } static void constant_constant(A a, B b, ResultType & c) { c = Op::template apply(a, b); } }; template struct BinaryOperationImpl : BinaryOperationImplBase { }; template struct UnaryOperationImpl { typedef typename Op::ResultType ResultType; static void vector(const PODArray & a, PODArray & c) { size_t size = a.size(); for (size_t i = 0; i < size; ++i) c[i] = Op::apply(a[i]); } static void constant(A a, ResultType & c) { c = Op::apply(a); } }; template struct PlusImpl { typedef typename NumberTraits::ResultOfAdditionMultiplication::Type ResultType; template static inline Result apply(A a, B b) { /// Далее везде, static_cast - чтобы не было неправильного результата в выражениях вида Int64 c = UInt32(a) * Int32(-1). return static_cast(a) + b; } }; template struct MultiplyImpl { typedef typename NumberTraits::ResultOfAdditionMultiplication::Type ResultType; template static inline Result apply(A a, B b) { return static_cast(a) * b; } }; template struct MinusImpl { typedef typename NumberTraits::ResultOfSubtraction::Type ResultType; template static inline Result apply(A a, B b) { return static_cast(a) - b; } }; template struct DivideFloatingImpl { typedef typename NumberTraits::ResultOfFloatingPointDivision::Type ResultType; template static inline Result apply(A a, B b) { return static_cast(a) / b; } }; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" template inline void throwIfDivisionLeadsToFPE(A a, B b) { /// Возможно, лучше вместо проверок использовать siglongjmp? if (unlikely(b == 0)) throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION); /// http://avva.livejournal.com/2548306.html if (unlikely(std::is_signed::value && std::is_signed::value && a == std::numeric_limits::min() && b == -1)) throw Exception("Division of minimal signed number by minus one", ErrorCodes::ILLEGAL_DIVISION); } template inline bool divisionLeadsToFPE(A a, B b) { /// Возможно, лучше вместо проверок использовать siglongjmp? if (unlikely(b == 0)) return true; /// http://avva.livejournal.com/2548306.html if (unlikely(std::is_signed::value && std::is_signed::value && a == std::numeric_limits::min() && b == -1)) return true; return false; } #pragma GCC diagnostic pop template struct DivideIntegralImpl { typedef typename NumberTraits::ResultOfIntegerDivision::Type ResultType; template static inline Result apply(A a, B b) { throwIfDivisionLeadsToFPE(a, b); return static_cast(a) / b; } }; template struct DivideIntegralOrZeroImpl { typedef typename NumberTraits::ResultOfIntegerDivision::Type ResultType; template static inline Result apply(A a, B b) { return unlikely(divisionLeadsToFPE(a, b)) ? 0 : static_cast(a) / b; } }; template struct ModuloImpl { typedef typename NumberTraits::ResultOfModulo::Type ResultType; template static inline Result apply(A a, B b) { throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger::Type(a), typename NumberTraits::ToInteger::Type(b)); return typename NumberTraits::ToInteger::Type(a) % typename NumberTraits::ToInteger::Type(b); } }; template struct BitAndImpl { typedef typename NumberTraits::ResultOfBit::Type ResultType; template static inline Result apply(A a, B b) { return static_cast(a) & static_cast(b); } }; template struct BitOrImpl { typedef typename NumberTraits::ResultOfBit::Type ResultType; template static inline Result apply(A a, B b) { return static_cast(a) | static_cast(b); } }; template struct BitXorImpl { typedef typename NumberTraits::ResultOfBit::Type ResultType; template static inline Result apply(A a, B b) { return static_cast(a) ^ static_cast(b); } }; template struct BitShiftLeftImpl { typedef typename NumberTraits::ResultOfBit::Type ResultType; template static inline Result apply(A a, B b) { return static_cast(a) << static_cast(b); } }; template struct BitShiftRightImpl { typedef typename NumberTraits::ResultOfBit::Type ResultType; template static inline Result apply(A a, B b) { return static_cast(a) >> static_cast(b); } }; template struct LeastImpl { typedef typename NumberTraits::ResultOfIf::Type ResultType; template static inline Result apply(A a, B b) { /** gcc 4.9.2 успешно векторизует цикл из этой функции. */ return static_cast(a) < static_cast(b) ? static_cast(a) : static_cast(b); } }; template struct GreatestImpl { typedef typename NumberTraits::ResultOfIf::Type ResultType; template static inline Result apply(A a, B b) { return static_cast(a) > static_cast(b) ? static_cast(a) : static_cast(b); } }; template struct NegateImpl { typedef typename NumberTraits::ResultOfNegate::Type ResultType; static inline ResultType apply(A a) { return -static_cast(a); } }; template struct BitNotImpl { typedef typename NumberTraits::ResultOfBitNot::Type ResultType; static inline ResultType apply(A a) { return ~static_cast(a); } }; template struct AbsImpl { typedef typename NumberTraits::ResultOfAbs::Type ResultType; template static inline ResultType apply(T a, typename std::enable_if::value && std::is_signed::value, void>::type * = nullptr) { return a < 0 ? static_cast(~a) + 1 : a; } template static inline ResultType apply(T a, typename std::enable_if::value && std::is_unsigned::value, void>::type * = nullptr) { return static_cast(a); } template static inline ResultType apply(T a, typename std::enable_if::value, void>::type * = nullptr) { return static_cast(std::abs(a)); } }; /// this one is just for convenience template using If = typename std::conditional::type; /// these ones for better semantics template using Then = T; template using Else = T; /// Used to indicate undefined operation struct InvalidType; template <> struct DataTypeFromFieldType { using Type = InvalidType; }; template struct IsIntegral { static constexpr auto value = false; }; template <> struct IsIntegral { static constexpr auto value = true; }; template <> struct IsIntegral { static constexpr auto value = true; }; template <> struct IsIntegral { static constexpr auto value = true; }; template <> struct IsIntegral { static constexpr auto value = true; }; template <> struct IsIntegral { static constexpr auto value = true; }; template <> struct IsIntegral { static constexpr auto value = true; }; template <> struct IsIntegral { static constexpr auto value = true; }; template <> struct IsIntegral { static constexpr auto value = true; }; template struct IsFloating { static constexpr auto value = false; }; template <> struct IsFloating { static constexpr auto value = true; }; template <> struct IsFloating { static constexpr auto value = true; }; template struct IsNumeric { static constexpr auto value = IsIntegral::value || IsFloating::value; }; template struct IsDateOrDateTime { static constexpr auto value = false; }; template <> struct IsDateOrDateTime { static constexpr auto value = true; }; template <> struct IsDateOrDateTime { static constexpr auto value = true; }; /** Returns appropriate result type for binary operator on dates (or datetimes): * Date + Integral -> Date * Integral + Date -> Date * Date - Date -> Int32 * Date - Integral -> Date * least(Date, Date) -> Date * greatest(Date, Date) -> Date * All other operations are not defined and return InvalidType, operations on * distinct date types are also undefined (e.g. DataTypeDate - DataTypeDateTime) */ template