ClickHouse
129 строк · 5.4 Кб
1#include <Functions/FunctionFactory.h>2#include <Functions/FunctionBinaryArithmetic.h>3
4#include "divide/divide.h"5
6
7namespace DB8{
9namespace ErrorCodes10{
11extern const int ILLEGAL_DIVISION;12}
13
14namespace
15{
16
17/// Optimizations for integer division by a constant.
18
19template <typename A, typename B>20struct DivideIntegralByConstantImpl21: BinaryOperation<A, B, DivideIntegralImpl<A, B>>22{
23using Op = DivideIntegralImpl<A, B>;24using ResultType = typename Op::ResultType;25static const constexpr bool allow_fixed_string = false;26static const constexpr bool allow_string_integer = false;27
28template <OpCase op_case>29static void NO_INLINE process(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t size, const NullMap * right_nullmap)30{31if constexpr (op_case == OpCase::RightConstant)32{33if (right_nullmap && (*right_nullmap)[0])34return;35
36vectorConstant(a, *b, c, size);37}38else39{40if (right_nullmap)41{42for (size_t i = 0; i < size; ++i)43if ((*right_nullmap)[i])44c[i] = ResultType();45else46apply<op_case>(a, b, c, i);47}48else49for (size_t i = 0; i < size; ++i)50apply<op_case>(a, b, c, i);51}52}53
54static ResultType process(A a, B b) { return Op::template apply<ResultType>(a, b); }55
56static void NO_INLINE NO_SANITIZE_UNDEFINED vectorConstant(const A * __restrict a_pos, B b, ResultType * __restrict c_pos, size_t size)57{58/// Division by -1. By the way, we avoid FPE by division of the largest negative number by -1.59if (unlikely(is_signed_v<B> && b == -1))60{61for (size_t i = 0; i < size; ++i)62c_pos[i] = -make_unsigned_t<A>(a_pos[i]); /// Avoid UBSan report in signed integer overflow.63return;64}65
66/// Division with too large divisor.67if (unlikely(b > std::numeric_limits<A>::max()68|| (std::is_signed_v<A> && std::is_signed_v<B> && b < std::numeric_limits<A>::lowest())))69{70for (size_t i = 0; i < size; ++i)71c_pos[i] = 0;72return;73}74
75if (unlikely(static_cast<A>(b) == 0))76throw Exception(ErrorCodes::ILLEGAL_DIVISION, "Division by zero");77
78divideImpl(a_pos, b, c_pos, size);79}80
81private:82template <OpCase op_case>83static inline void apply(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t i)84{85if constexpr (op_case == OpCase::Vector)86c[i] = Op::template apply<ResultType>(a[i], b[i]);87else88c[i] = Op::template apply<ResultType>(*a, b[i]);89}90};91
92/** Specializations are specified for dividing numbers of the type UInt64, UInt32, Int64, Int32 by the numbers of the same sign.
93* Can be expanded to all possible combinations, but more code is needed.
94*/
95
96}
97
98namespace impl_99{
100template <> struct BinaryOperationImpl<UInt64, UInt8, DivideIntegralImpl<UInt64, UInt8>> : DivideIntegralByConstantImpl<UInt64, UInt8> {};101template <> struct BinaryOperationImpl<UInt64, UInt16, DivideIntegralImpl<UInt64, UInt16>> : DivideIntegralByConstantImpl<UInt64, UInt16> {};102template <> struct BinaryOperationImpl<UInt64, UInt32, DivideIntegralImpl<UInt64, UInt32>> : DivideIntegralByConstantImpl<UInt64, UInt32> {};103template <> struct BinaryOperationImpl<UInt64, UInt64, DivideIntegralImpl<UInt64, UInt64>> : DivideIntegralByConstantImpl<UInt64, UInt64> {};104
105template <> struct BinaryOperationImpl<UInt32, UInt8, DivideIntegralImpl<UInt32, UInt8>> : DivideIntegralByConstantImpl<UInt32, UInt8> {};106template <> struct BinaryOperationImpl<UInt32, UInt16, DivideIntegralImpl<UInt32, UInt16>> : DivideIntegralByConstantImpl<UInt32, UInt16> {};107template <> struct BinaryOperationImpl<UInt32, UInt32, DivideIntegralImpl<UInt32, UInt32>> : DivideIntegralByConstantImpl<UInt32, UInt32> {};108template <> struct BinaryOperationImpl<UInt32, UInt64, DivideIntegralImpl<UInt32, UInt64>> : DivideIntegralByConstantImpl<UInt32, UInt64> {};109
110template <> struct BinaryOperationImpl<Int64, Int8, DivideIntegralImpl<Int64, Int8>> : DivideIntegralByConstantImpl<Int64, Int8> {};111template <> struct BinaryOperationImpl<Int64, Int16, DivideIntegralImpl<Int64, Int16>> : DivideIntegralByConstantImpl<Int64, Int16> {};112template <> struct BinaryOperationImpl<Int64, Int32, DivideIntegralImpl<Int64, Int32>> : DivideIntegralByConstantImpl<Int64, Int32> {};113template <> struct BinaryOperationImpl<Int64, Int64, DivideIntegralImpl<Int64, Int64>> : DivideIntegralByConstantImpl<Int64, Int64> {};114
115template <> struct BinaryOperationImpl<Int32, Int8, DivideIntegralImpl<Int32, Int8>> : DivideIntegralByConstantImpl<Int32, Int8> {};116template <> struct BinaryOperationImpl<Int32, Int16, DivideIntegralImpl<Int32, Int16>> : DivideIntegralByConstantImpl<Int32, Int16> {};117template <> struct BinaryOperationImpl<Int32, Int32, DivideIntegralImpl<Int32, Int32>> : DivideIntegralByConstantImpl<Int32, Int32> {};118template <> struct BinaryOperationImpl<Int32, Int64, DivideIntegralImpl<Int32, Int64>> : DivideIntegralByConstantImpl<Int32, Int64> {};119}
120
121struct NameIntDiv { static constexpr auto name = "intDiv"; };122using FunctionIntDiv = BinaryArithmeticOverloadResolver<DivideIntegralImpl, NameIntDiv, false>;123
124REGISTER_FUNCTION(IntDiv)125{
126factory.registerFunction<FunctionIntDiv>();127}
128
129}
130