#pragma once #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_DIVISION; extern const int LOGICAL_ERROR; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" template inline void throwIfDivisionLeadsToFPE(A a, B b) { /// Is it better to use siglongjmp instead of checks? if (unlikely(b == 0)) throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION); /// http://avva.livejournal.com/2548306.html if (unlikely(std::is_signed_v && std::is_signed_v && 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) { if (unlikely(b == 0)) return true; if (unlikely(std::is_signed_v && std::is_signed_v && a == std::numeric_limits::min() && b == -1)) return true; return false; } #pragma GCC diagnostic pop template struct DivideIntegralImpl { using ResultType = typename NumberTraits::ResultOfIntegerDivision::Type; template static inline Result apply(A a, B b) { throwIfDivisionLeadsToFPE(a, b); if constexpr (!std::is_same_v) { /// Otherwise overflow may occur due to integer promotion. Example: int8_t(-1) / uint64_t(2). /// NOTE: overflow is still possible when dividing large signed number to large unsigned number or vice-versa. But it's less harmful. if constexpr (std::is_integral_v && std::is_integral_v && (std::is_signed_v || std::is_signed_v)) return std::make_signed_t(a) / std::make_signed_t(b); else return a / b; } else throw Exception("Logical error: the types are not divisable", ErrorCodes::LOGICAL_ERROR); } #if USE_EMBEDDED_COMPILER static constexpr bool compilable = false; /// don't know how to throw from LLVM IR #endif }; }