ClickHouse
167 строк · 5.7 Кб
1#include <Functions/FunctionFactory.h>
2#include <Functions/FunctionBinaryArithmetic.h>
3
4namespace DB
5{
6namespace ErrorCodes
7{
8extern const int NOT_IMPLEMENTED;
9extern const int LOGICAL_ERROR;
10}
11
12namespace
13{
14
15template <typename A, typename B>
16struct BitShiftLeftImpl
17{
18using ResultType = typename NumberTraits::ResultOfBit<A, B>::Type;
19static const constexpr bool allow_fixed_string = false;
20static const constexpr bool allow_string_integer = true;
21
22template <typename Result = ResultType>
23static inline NO_SANITIZE_UNDEFINED Result apply(A a [[maybe_unused]], B b [[maybe_unused]])
24{
25if constexpr (is_big_int_v<B>)
26throw Exception(ErrorCodes::NOT_IMPLEMENTED, "BitShiftLeft is not implemented for big integers as second argument");
27else if constexpr (is_big_int_v<A>)
28return static_cast<Result>(a) << static_cast<UInt32>(b);
29else
30return static_cast<Result>(a) << static_cast<Result>(b);
31}
32
33/// For String
34static ALWAYS_INLINE NO_SANITIZE_UNDEFINED void apply(const UInt8 * pos [[maybe_unused]], const UInt8 * end [[maybe_unused]], const B & b [[maybe_unused]], ColumnString::Chars & out_vec, ColumnString::Offsets & out_offsets)
35{
36if constexpr (is_big_int_v<B>)
37throw Exception(ErrorCodes::NOT_IMPLEMENTED, "BitShiftLeft is not implemented for big integers as second argument");
38else
39{
40UInt8 word_size = 8;
41/// To prevent overflow
42if (static_cast<double>(b) >= (static_cast<double>(end - pos) * word_size) || b < 0)
43{
44// insert default value
45out_vec.push_back(0);
46out_offsets.push_back(out_offsets.back() + 1);
47return;
48}
49
50size_t shift_left_bits = b % word_size;
51size_t shift_left_bytes = b / word_size;
52
53const UInt8 * begin = pos;
54
55const size_t old_size = out_vec.size();
56size_t length;
57if (shift_left_bits)
58length = end + shift_left_bytes - begin + 1; /// Moving to the left here will make a redundant byte to store the overflowing bits in the front
59else
60length = end + shift_left_bytes - begin;
61
62const size_t new_size = old_size + length + 1;
63out_vec.resize(new_size);
64out_vec[old_size + length] = 0;
65
66UInt8 * op_pointer = const_cast<UInt8 *>(begin);
67UInt8 * out = out_vec.data() + old_size;
68
69UInt8 previous = 0;
70while (op_pointer < end)
71{
72if (shift_left_bits)
73{
74/// The left b bit of the right byte is moved to the right b bit of this byte
75*out = static_cast<UInt8>(static_cast<UInt8>(*(op_pointer) >> (8 - shift_left_bits)) | previous);
76previous = *op_pointer << shift_left_bits;
77}
78else
79{
80*out = *op_pointer;
81}
82op_pointer++;
83out++;
84}
85if (shift_left_bits)
86{
87*out = *(op_pointer - 1) << shift_left_bits;
88out++;
89}
90
91for (size_t i = 0; i < shift_left_bytes; ++i)
92*(out + i) = 0;
93
94out_offsets.push_back(new_size);
95}
96}
97
98/// For FixedString
99static ALWAYS_INLINE NO_SANITIZE_UNDEFINED void apply(const UInt8 * pos [[maybe_unused]], const UInt8 * end [[maybe_unused]], const B & b [[maybe_unused]], ColumnFixedString::Chars & out_vec)
100{
101if constexpr (is_big_int_v<B>)
102throw Exception(ErrorCodes::NOT_IMPLEMENTED, "BitShiftLeft is not implemented for big integers as second argument");
103else
104{
105UInt8 word_size = 8;
106size_t n = end - pos;
107/// To prevent overflow
108if (static_cast<double>(b) >= (static_cast<double>(n) * word_size) || b < 0)
109{
110// insert default value
111out_vec.resize_fill(out_vec.size() + n);
112return;
113}
114
115size_t shift_left_bytes = b / word_size;
116size_t shift_left_bits = b % word_size;
117
118const UInt8 * begin = pos;
119
120const size_t old_size = out_vec.size();
121const size_t new_size = old_size + n;
122
123out_vec.resize(new_size);
124
125UInt8 * op_pointer = const_cast<UInt8 *>(begin + shift_left_bytes);
126UInt8 * out = out_vec.data() + old_size;
127
128while (op_pointer < end)
129{
130*out = *op_pointer << shift_left_bits;
131if (op_pointer + 1 < end)
132{
133/// The left b bit of the right byte is moved to the right b bit of this byte
134*out = static_cast<UInt8>(static_cast<UInt8>(*(op_pointer + 1) >> (8 - shift_left_bits)) | *out);
135}
136op_pointer++;
137out++;
138}
139
140for (size_t i = 0; i < shift_left_bytes; ++i)
141*(out + i) = 0;
142}
143}
144
145#if USE_EMBEDDED_COMPILER
146static constexpr bool compilable = true;
147
148static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
149{
150if (!left->getType()->isIntegerTy())
151throw Exception(ErrorCodes::LOGICAL_ERROR, "BitShiftLeftImpl expected an integral type");
152return b.CreateShl(left, right);
153}
154#endif
155};
156
157struct NameBitShiftLeft { static constexpr auto name = "bitShiftLeft"; };
158using FunctionBitShiftLeft = BinaryArithmeticOverloadResolver<BitShiftLeftImpl, NameBitShiftLeft, true, false>;
159
160}
161
162REGISTER_FUNCTION(BitShiftLeft)
163{
164factory.registerFunction<FunctionBitShiftLeft>();
165}
166
167}
168