2018-11-26 16:20:40 +00:00
# include <Functions/FunctionFactory.h>
# include <Functions/FunctionBinaryArithmetic.h>
namespace DB
{
2020-02-25 18:10:48 +00:00
namespace ErrorCodes
{
2020-08-19 11:52:17 +00:00
extern const int NOT_IMPLEMENTED ;
2020-02-25 18:10:48 +00:00
extern const int LOGICAL_ERROR ;
}
2018-11-26 16:20:40 +00:00
2020-09-07 18:00:37 +00:00
namespace
{
2018-11-26 16:20:40 +00:00
template < typename A , typename B >
struct BitShiftLeftImpl
{
using ResultType = typename NumberTraits : : ResultOfBit < A , B > : : Type ;
2020-02-14 07:11:37 +00:00
static const constexpr bool allow_fixed_string = false ;
2021-09-06 17:20:12 +00:00
static const constexpr bool allow_string_integer = true ;
2018-11-26 16:20:40 +00:00
template < typename Result = ResultType >
2020-08-19 11:52:17 +00:00
static inline NO_SANITIZE_UNDEFINED Result apply ( A a [[maybe_unused]], B b [[maybe_unused]] )
2018-11-26 16:20:40 +00:00
{
2020-08-19 11:52:17 +00:00
if constexpr ( is_big_int_v < B > )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : NOT_IMPLEMENTED , " BitShiftLeft is not implemented for big integers as second argument " ) ;
2020-09-01 09:54:50 +00:00
else if constexpr ( is_big_int_v < A > )
2021-01-26 19:04:03 +00:00
return static_cast < Result > ( a ) < < static_cast < UInt32 > ( b ) ;
2020-08-19 11:52:17 +00:00
else
return static_cast < Result > ( a ) < < static_cast < Result > ( b ) ;
2018-11-26 16:20:40 +00:00
}
2021-09-06 17:20:12 +00:00
/// For String
static 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 )
{
if constexpr ( is_big_int_v < B > )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : NOT_IMPLEMENTED , " BitShiftLeft is not implemented for big integers as second argument " ) ;
2021-09-06 17:20:12 +00:00
else
{
UInt8 word_size = 8 ;
/// To prevent overflow
if ( static_cast < double > ( b ) > = ( static_cast < double > ( end - pos ) * word_size ) | | b < 0 )
{
// insert default value
out_vec . push_back ( 0 ) ;
out_offsets . push_back ( out_offsets . back ( ) + 1 ) ;
return ;
}
size_t shift_left_bits = b % word_size ;
size_t shift_left_bytes = b / word_size ;
const UInt8 * begin = pos ;
const size_t old_size = out_vec . size ( ) ;
size_t length ;
if ( shift_left_bits )
length = end + shift_left_bytes - begin + 1 ; /// Moving to the left here will make a redundant byte to store the overflowing bits in the front
else
length = end + shift_left_bytes - begin ;
const size_t new_size = old_size + length + 1 ;
out_vec . resize ( new_size ) ;
out_vec [ old_size + length ] = 0 ;
UInt8 * op_pointer = const_cast < UInt8 * > ( begin ) ;
UInt8 * out = out_vec . data ( ) + old_size ;
UInt8 previous = 0 ;
while ( op_pointer < end )
{
if ( shift_left_bits )
{
/// The left b bit of the right byte is moved to the right b bit of this byte
2022-04-18 08:18:31 +00:00
* out = static_cast < UInt8 > ( static_cast < UInt8 > ( * ( op_pointer ) > > ( 8 - shift_left_bits ) ) | previous ) ;
2021-09-06 17:20:12 +00:00
previous = * op_pointer < < shift_left_bits ;
}
else
{
* out = * op_pointer ;
}
op_pointer + + ;
out + + ;
}
if ( shift_left_bits )
{
* out = * ( op_pointer - 1 ) < < shift_left_bits ;
out + + ;
}
for ( size_t i = 0 ; i < shift_left_bytes ; + + i )
* ( out + i ) = 0 ;
out_offsets . push_back ( new_size ) ;
}
}
/// For FixedString
static 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 )
{
if constexpr ( is_big_int_v < B > )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : NOT_IMPLEMENTED , " BitShiftLeft is not implemented for big integers as second argument " ) ;
2021-09-06 17:20:12 +00:00
else
{
UInt8 word_size = 8 ;
size_t n = end - pos ;
/// To prevent overflow
if ( static_cast < double > ( b ) > = ( static_cast < double > ( n ) * word_size ) | | b < 0 )
{
// insert default value
out_vec . resize_fill ( out_vec . size ( ) + n ) ;
return ;
}
size_t shift_left_bytes = b / word_size ;
size_t shift_left_bits = b % word_size ;
const UInt8 * begin = pos ;
const size_t old_size = out_vec . size ( ) ;
const size_t new_size = old_size + n ;
out_vec . resize ( new_size ) ;
UInt8 * op_pointer = const_cast < UInt8 * > ( begin + shift_left_bytes ) ;
UInt8 * out = out_vec . data ( ) + old_size ;
while ( op_pointer < end )
{
* out = * op_pointer < < shift_left_bits ;
if ( op_pointer + 1 < end )
{
/// The left b bit of the right byte is moved to the right b bit of this byte
2022-04-18 08:18:31 +00:00
* out = static_cast < UInt8 > ( static_cast < UInt8 > ( * ( op_pointer + 1 ) > > ( 8 - shift_left_bits ) ) | * out ) ;
2021-09-06 17:20:12 +00:00
}
op_pointer + + ;
out + + ;
}
for ( size_t i = 0 ; i < shift_left_bytes ; + + i )
* ( out + i ) = 0 ;
}
}
2018-11-26 16:20:40 +00:00
# if USE_EMBEDDED_COMPILER
static constexpr bool compilable = true ;
static inline llvm : : Value * compile ( llvm : : IRBuilder < > & b , llvm : : Value * left , llvm : : Value * right , bool )
{
if ( ! left - > getType ( ) - > isIntegerTy ( ) )
2023-01-23 21:13:58 +00:00
throw Exception ( ErrorCodes : : LOGICAL_ERROR , " BitShiftLeftImpl expected an integral type " ) ;
2018-11-26 16:20:40 +00:00
return b . CreateShl ( left , right ) ;
}
# endif
} ;
struct NameBitShiftLeft { static constexpr auto name = " bitShiftLeft " ; } ;
2021-01-30 04:13:49 +00:00
using FunctionBitShiftLeft = BinaryArithmeticOverloadResolver < BitShiftLeftImpl , NameBitShiftLeft , true , false > ;
2018-11-26 16:20:40 +00:00
2020-09-07 18:00:37 +00:00
}
2022-07-04 07:01:39 +00:00
REGISTER_FUNCTION ( BitShiftLeft )
2018-11-26 16:20:40 +00:00
{
factory . registerFunction < FunctionBitShiftLeft > ( ) ;
}
}