#pragma once #include #include #include #include namespace DB { /** Арифметические функции: +, -, *, /, %, * intDiv (целочисленное деление), унарный минус. * Битовые функции: |, &, ^, ~. */ template struct BinaryOperationImpl { typedef typename Op::ResultType ResultType; static void vector_vector(const std::vector & a, const std::vector & b, std::vector & c) { size_t size = a.size(); for (size_t i = 0; i < size; ++i) c[i] = Op::apply(a[i], b[i]); } static void vector_constant(const std::vector & a, B b, std::vector & c) { size_t size = a.size(); for (size_t i = 0; i < size; ++i) c[i] = Op::apply(a[i], b); } static void constant_vector(A a, const std::vector & b, std::vector & c) { size_t size = b.size(); for (size_t i = 0; i < size; ++i) c[i] = Op::apply(a, b[i]); } static void constant_constant(A a, B b, ResultType & c) { c = Op::apply(a, b); } }; template struct UnaryOperationImpl { typedef typename Op::ResultType ResultType; static void vector(const std::vector & a, std::vector & 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; static inline ResultType 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; static inline ResultType apply(A a, B b) { return static_cast(a) * b; } }; template struct MinusImpl { typedef typename NumberTraits::ResultOfSubtraction::Type ResultType; static inline ResultType apply(A a, B b) { return static_cast(a) - b; } }; template struct DivideFloatingImpl { typedef typename NumberTraits::ResultOfFloatingPointDivision::Type ResultType; static inline ResultType apply(A a, B b) { return static_cast(a) / b; } }; 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::tr1::is_signed::value && std::tr1::is_signed::value && a == std::numeric_limits::min() && b == -1)) throw Exception("Division of minimal signed number by minus one", ErrorCodes::ILLEGAL_DIVISION); } template struct DivideIntegralImpl { typedef typename NumberTraits::ResultOfIntegerDivision::Type ResultType; static inline ResultType apply(A a, B b) { throwIfDivisionLeadsToFPE(a, b); return static_cast(a) / b; } }; template struct ModuloImpl { typedef typename NumberTraits::ResultOfModulo::Type ResultType; static inline ResultType 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 BitwiseAndImpl { typedef typename NumberTraits::ResultOfBitwise::Type ResultType; static inline ResultType apply(A a, B b) { return static_cast(a) & static_cast(b); } }; template struct BitwiseOrImpl { typedef typename NumberTraits::ResultOfBitwise::Type ResultType; static inline ResultType apply(A a, B b) { return static_cast(a) | static_cast(b); } }; template struct BitwiseXorImpl { typedef typename NumberTraits::ResultOfBitwise::Type ResultType; static inline ResultType apply(A a, B b) { return static_cast(a) ^ static_cast(b); } }; template struct NegateImpl { typedef typename NumberTraits::ResultOfNegate::Type ResultType; static inline ResultType apply(A a) { return -a; } }; template struct BitwiseNotImpl { typedef typename NumberTraits::ResultOfBitwiseNot::Type ResultType; static inline ResultType apply(A a) { return ~static_cast(a); } }; template