| 1 | #pragma once | 
|---|
| 2 |  | 
|---|
| 3 | #include <type_traits> | 
|---|
| 4 |  | 
|---|
| 5 | #include <Core/Types.h> | 
|---|
| 6 | #include <Common/UInt128.h> | 
|---|
| 7 |  | 
|---|
| 8 |  | 
|---|
| 9 | namespace DB | 
|---|
| 10 | { | 
|---|
| 11 |  | 
|---|
| 12 | /** Allows get the result type of the functions +, -, *, /, %, intDiv (integer division). | 
|---|
| 13 | * The rules are different from those used in C++. | 
|---|
| 14 | */ | 
|---|
| 15 |  | 
|---|
| 16 | namespace NumberTraits | 
|---|
| 17 | { | 
|---|
| 18 |  | 
|---|
| 19 | struct Error {}; | 
|---|
| 20 |  | 
|---|
| 21 | constexpr size_t max(size_t x, size_t y) | 
|---|
| 22 | { | 
|---|
| 23 | return x > y ? x : y; | 
|---|
| 24 | } | 
|---|
| 25 |  | 
|---|
| 26 | constexpr size_t min(size_t x, size_t y) | 
|---|
| 27 | { | 
|---|
| 28 | return x < y ? x : y; | 
|---|
| 29 | } | 
|---|
| 30 |  | 
|---|
| 31 | constexpr size_t nextSize(size_t size) | 
|---|
| 32 | { | 
|---|
| 33 | return min(size * 2, 8); | 
|---|
| 34 | } | 
|---|
| 35 |  | 
|---|
| 36 | template <bool is_signed, bool is_floating, size_t size> | 
|---|
| 37 | struct Construct | 
|---|
| 38 | { | 
|---|
| 39 | using Type = Error; | 
|---|
| 40 | }; | 
|---|
| 41 |  | 
|---|
| 42 | template <> struct Construct<false, false, 1> { using Type = UInt8; }; | 
|---|
| 43 | template <> struct Construct<false, false, 2> { using Type = UInt16; }; | 
|---|
| 44 | template <> struct Construct<false, false, 4> { using Type = UInt32; }; | 
|---|
| 45 | template <> struct Construct<false, false, 8> { using Type = UInt64; }; | 
|---|
| 46 | template <> struct Construct<false, true, 1> { using Type = Float32; }; | 
|---|
| 47 | template <> struct Construct<false, true, 2> { using Type = Float32; }; | 
|---|
| 48 | template <> struct Construct<false, true, 4> { using Type = Float32; }; | 
|---|
| 49 | template <> struct Construct<false, true, 8> { using Type = Float64; }; | 
|---|
| 50 | template <> struct Construct<true, false, 1> { using Type = Int8; }; | 
|---|
| 51 | template <> struct Construct<true, false, 2> { using Type = Int16; }; | 
|---|
| 52 | template <> struct Construct<true, false, 4> { using Type = Int32; }; | 
|---|
| 53 | template <> struct Construct<true, false, 8> { using Type = Int64; }; | 
|---|
| 54 | template <> struct Construct<true, true, 1> { using Type = Float32; }; | 
|---|
| 55 | template <> struct Construct<true, true, 2> { using Type = Float32; }; | 
|---|
| 56 | template <> struct Construct<true, true, 4> { using Type = Float32; }; | 
|---|
| 57 | template <> struct Construct<true, true, 8> { using Type = Float64; }; | 
|---|
| 58 |  | 
|---|
| 59 |  | 
|---|
| 60 | /** The result of addition or multiplication is calculated according to the following rules: | 
|---|
| 61 | * - if one of the arguments is floating-point, the result is a floating point, otherwise - the whole; | 
|---|
| 62 | * - if one of the arguments is signed, the result is signed, otherwise it is unsigned; | 
|---|
| 63 | * - the result contains more bits (not only meaningful) than the maximum in the arguments | 
|---|
| 64 | *   (for example, UInt8 + Int32 = Int64). | 
|---|
| 65 | */ | 
|---|
| 66 | template <typename A, typename B> struct ResultOfAdditionMultiplication | 
|---|
| 67 | { | 
|---|
| 68 | using Type = typename Construct< | 
|---|
| 69 | is_signed_v<A> || is_signed_v<B>, | 
|---|
| 70 | std::is_floating_point_v<A> || std::is_floating_point_v<B>, | 
|---|
| 71 | nextSize(max(sizeof(A), sizeof(B)))>::Type; | 
|---|
| 72 | }; | 
|---|
| 73 |  | 
|---|
| 74 | template <typename A, typename B> struct ResultOfSubtraction | 
|---|
| 75 | { | 
|---|
| 76 | using Type = typename Construct< | 
|---|
| 77 | true, | 
|---|
| 78 | std::is_floating_point_v<A> || std::is_floating_point_v<B>, | 
|---|
| 79 | nextSize(max(sizeof(A), sizeof(B)))>::Type; | 
|---|
| 80 | }; | 
|---|
| 81 |  | 
|---|
| 82 | /** When dividing, you always get a floating-point number. | 
|---|
| 83 | */ | 
|---|
| 84 | template <typename A, typename B> struct ResultOfFloatingPointDivision | 
|---|
| 85 | { | 
|---|
| 86 | using Type = Float64; | 
|---|
| 87 | }; | 
|---|
| 88 |  | 
|---|
| 89 | /** For integer division, we get a number with the same number of bits as in divisible. | 
|---|
| 90 | */ | 
|---|
| 91 | template <typename A, typename B> struct ResultOfIntegerDivision | 
|---|
| 92 | { | 
|---|
| 93 | using Type = typename Construct< | 
|---|
| 94 | is_signed_v<A> || is_signed_v<B>, | 
|---|
| 95 | false, | 
|---|
| 96 | sizeof(A)>::Type; | 
|---|
| 97 | }; | 
|---|
| 98 |  | 
|---|
| 99 | /** Division with remainder you get a number with the same number of bits as in divisor. | 
|---|
| 100 | */ | 
|---|
| 101 | template <typename A, typename B> struct ResultOfModulo | 
|---|
| 102 | { | 
|---|
| 103 | using Type = typename Construct< | 
|---|
| 104 | is_signed_v<A> || is_signed_v<B>, | 
|---|
| 105 | false, | 
|---|
| 106 | sizeof(B)>::Type; | 
|---|
| 107 | }; | 
|---|
| 108 |  | 
|---|
| 109 | template <typename A> struct ResultOfNegate | 
|---|
| 110 | { | 
|---|
| 111 | using Type = typename Construct< | 
|---|
| 112 | true, | 
|---|
| 113 | std::is_floating_point_v<A>, | 
|---|
| 114 | is_signed_v<A> ? sizeof(A) : nextSize(sizeof(A))>::Type; | 
|---|
| 115 | }; | 
|---|
| 116 |  | 
|---|
| 117 | template <typename A> struct ResultOfAbs | 
|---|
| 118 | { | 
|---|
| 119 | using Type = typename Construct< | 
|---|
| 120 | false, | 
|---|
| 121 | std::is_floating_point_v<A>, | 
|---|
| 122 | sizeof(A)>::Type; | 
|---|
| 123 | }; | 
|---|
| 124 |  | 
|---|
| 125 | /** For bitwise operations, an integer is obtained with number of bits is equal to the maximum of the arguments. | 
|---|
| 126 | */ | 
|---|
| 127 | template <typename A, typename B> struct ResultOfBit | 
|---|
| 128 | { | 
|---|
| 129 | using Type = typename Construct< | 
|---|
| 130 | is_signed_v<A> || is_signed_v<B>, | 
|---|
| 131 | false, | 
|---|
| 132 | std::is_floating_point_v<A> || std::is_floating_point_v<B> ? 8 : max(sizeof(A), sizeof(B))>::Type; | 
|---|
| 133 | }; | 
|---|
| 134 |  | 
|---|
| 135 | template <typename A> struct ResultOfBitNot | 
|---|
| 136 | { | 
|---|
| 137 | using Type = typename Construct< | 
|---|
| 138 | is_signed_v<A>, | 
|---|
| 139 | false, | 
|---|
| 140 | sizeof(A)>::Type; | 
|---|
| 141 | }; | 
|---|
| 142 |  | 
|---|
| 143 |  | 
|---|
| 144 | /** Type casting for `if` function: | 
|---|
| 145 | * UInt<x>,  UInt<y>   ->  UInt<max(x,y)> | 
|---|
| 146 | * Int<x>,   Int<y>    ->   Int<max(x,y)> | 
|---|
| 147 | * Float<x>, Float<y>  -> Float<max(x, y)> | 
|---|
| 148 | * UInt<x>,  Int<y>    ->   Int<max(x*2, y)> | 
|---|
| 149 | * Float<x>, [U]Int<y> -> Float<max(x, y*2)> | 
|---|
| 150 | * Decimal<x>, Decimal<y> -> Decimal<max(x,y)> | 
|---|
| 151 | * UUID, UUID          -> UUID | 
|---|
| 152 | * UInt64 ,  Int<x>    -> Error | 
|---|
| 153 | * Float<x>, [U]Int64  -> Error | 
|---|
| 154 | */ | 
|---|
| 155 | template <typename A, typename B> | 
|---|
| 156 | struct ResultOfIf | 
|---|
| 157 | { | 
|---|
| 158 | static constexpr bool has_float = std::is_floating_point_v<A> || std::is_floating_point_v<B>; | 
|---|
| 159 | static constexpr bool has_integer = is_integral_v<A> || is_integral_v<B>; | 
|---|
| 160 | static constexpr bool has_signed = is_signed_v<A> || is_signed_v<B>; | 
|---|
| 161 | static constexpr bool has_unsigned = !is_signed_v<A> || !is_signed_v<B>; | 
|---|
| 162 |  | 
|---|
| 163 | static constexpr size_t max_size_of_unsigned_integer = max(is_signed_v<A> ? 0 : sizeof(A), is_signed_v<B> ? 0 : sizeof(B)); | 
|---|
| 164 | static constexpr size_t max_size_of_signed_integer = max(is_signed_v<A> ? sizeof(A) : 0, is_signed_v<B> ? sizeof(B) : 0); | 
|---|
| 165 | static constexpr size_t max_size_of_integer = max(is_integral_v<A> ? sizeof(A) : 0, is_integral_v<B> ? sizeof(B) : 0); | 
|---|
| 166 | static constexpr size_t max_size_of_float = max(std::is_floating_point_v<A> ? sizeof(A) : 0, std::is_floating_point_v<B> ? sizeof(B) : 0); | 
|---|
| 167 |  | 
|---|
| 168 | using ConstructedType = typename Construct<has_signed, has_float, | 
|---|
| 169 | ((has_float && has_integer && max_size_of_integer >= max_size_of_float) | 
|---|
| 170 | || (has_signed && has_unsigned && max_size_of_unsigned_integer >= max_size_of_signed_integer)) | 
|---|
| 171 | ? max(sizeof(A), sizeof(B)) * 2 | 
|---|
| 172 | : max(sizeof(A), sizeof(B))>::Type; | 
|---|
| 173 |  | 
|---|
| 174 | using ConstructedWithUUID = std::conditional_t<std::is_same_v<A, UInt128> && std::is_same_v<B, UInt128>, A, ConstructedType>; | 
|---|
| 175 |  | 
|---|
| 176 | using Type = std::conditional_t<!IsDecimalNumber<A> && !IsDecimalNumber<B>, ConstructedWithUUID, | 
|---|
| 177 | std::conditional_t<IsDecimalNumber<A> && IsDecimalNumber<B>, std::conditional_t<(sizeof(A) > sizeof(B)), A, B>, Error>>; | 
|---|
| 178 | }; | 
|---|
| 179 |  | 
|---|
| 180 | /** Before applying operator `%` and bitwise operations, operands are casted to whole numbers. */ | 
|---|
| 181 | template <typename A> struct ToInteger | 
|---|
| 182 | { | 
|---|
| 183 | using Type = typename Construct< | 
|---|
| 184 | is_signed_v<A>, | 
|---|
| 185 | false, | 
|---|
| 186 | std::is_floating_point_v<A> ? 8 : sizeof(A)>::Type; | 
|---|
| 187 | }; | 
|---|
| 188 |  | 
|---|
| 189 |  | 
|---|
| 190 | // CLICKHOUSE-29. The same depth, different signs | 
|---|
| 191 | // NOTE: This case is applied for 64-bit integers only (for backward compatibility), but could be used for any-bit integers | 
|---|
| 192 | template <typename A, typename B> | 
|---|
| 193 | constexpr bool LeastGreatestSpecialCase = | 
|---|
| 194 | is_integral_v<A> && is_integral_v<B> | 
|---|
| 195 | && (8 == sizeof(A) && sizeof(A) == sizeof(B)) | 
|---|
| 196 | && (is_signed_v<A> ^ is_signed_v<B>); | 
|---|
| 197 |  | 
|---|
| 198 | template <typename A, typename B> | 
|---|
| 199 | using ResultOfLeast = std::conditional_t<LeastGreatestSpecialCase<A, B>, | 
|---|
| 200 | typename Construct<true, false, sizeof(A)>::Type, | 
|---|
| 201 | typename ResultOfIf<A, B>::Type>; | 
|---|
| 202 |  | 
|---|
| 203 | template <typename A, typename B> | 
|---|
| 204 | using ResultOfGreatest = std::conditional_t<LeastGreatestSpecialCase<A, B>, | 
|---|
| 205 | typename Construct<false, false, sizeof(A)>::Type, | 
|---|
| 206 | typename ResultOfIf<A, B>::Type>; | 
|---|
| 207 |  | 
|---|
| 208 | } | 
|---|
| 209 |  | 
|---|
| 210 | } | 
|---|
| 211 |  | 
|---|