2018-11-26 16:20:40 +00:00
# include <Functions/FunctionFactory.h>
# include <Functions/FunctionBinaryArithmetic.h>
2021-08-30 06:37:23 +00:00
# include <Common/hex.h>
2018-11-26 16:20:40 +00:00
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 BitShiftRightImpl
{
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-08-30 06:37:23 +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 > )
2020-09-04 13:33:02 +00:00
throw Exception ( " BitShiftRight is not implemented for big integers as second argument " , ErrorCodes : : NOT_IMPLEMENTED ) ;
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
static inline NO_SANITIZE_UNDEFINED void bitShiftRightForBytes ( const UInt8 * op_pointer , const UInt8 * begin , UInt8 * out , const size_t shift_right_bits )
2021-09-04 16:41:52 +00:00
{
while ( op_pointer > begin )
{
op_pointer - - ;
out - - ;
* out = * op_pointer > > shift_right_bits ;
if ( op_pointer - 1 > = begin )
{
2021-09-06 17:20:12 +00:00
/// The right b bit of the left byte is moved to the left b bit of this byte
2021-09-04 16:41:52 +00:00
* out = UInt8 ( UInt8 ( * ( op_pointer - 1 ) < < ( 8 - shift_right_bits ) ) | * out ) ;
}
}
}
/// 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 )
2021-08-30 06:37:23 +00:00
{
if constexpr ( is_big_int_v < B > )
throw Exception ( " BitShiftRight is not implemented for big integers as second argument " , ErrorCodes : : NOT_IMPLEMENTED ) ;
else
{
UInt8 word_size = 8 ;
2021-09-06 17:20:12 +00:00
/// To prevent overflow
if ( static_cast < double > ( b ) > = ( static_cast < double > ( end - pos ) * word_size ) | | b < 0 )
2021-08-30 06:37:23 +00:00
{
2021-09-06 17:20:12 +00:00
/// insert default value
2021-08-30 06:37:23 +00:00
out_vec . push_back ( 0 ) ;
out_offsets . push_back ( out_offsets . back ( ) + 1 ) ;
return ;
}
size_t shift_right_bytes = b / word_size ;
size_t shift_right_bits = b % word_size ;
const UInt8 * begin = pos ;
const UInt8 * shift_right_end = end - shift_right_bytes ;
const size_t old_size = out_vec . size ( ) ;
size_t length = shift_right_end - begin ;
const size_t new_size = old_size + length + 1 ;
out_vec . resize ( new_size ) ;
2021-09-04 16:41:52 +00:00
out_vec [ old_size + length ] = 0 ;
2021-08-30 06:37:23 +00:00
2021-09-04 16:41:52 +00:00
/// We start from the byte on the right and shift right shift_right_bits bit by byte
2021-08-30 06:37:23 +00:00
UInt8 * op_pointer = const_cast < UInt8 * > ( shift_right_end ) ;
UInt8 * out = out_vec . data ( ) + old_size + length ;
2021-09-04 16:41:52 +00:00
bitShiftRightForBytes ( op_pointer , begin , out , shift_right_bits ) ;
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 > )
throw Exception ( " BitShiftRight is not implemented for big integers as second argument " , ErrorCodes : : NOT_IMPLEMENTED ) ;
else
{
UInt8 word_size = 8 ;
size_t n = end - pos ;
2021-09-06 17:20:12 +00:00
/// To prevent overflow
if ( static_cast < double > ( b ) > = ( static_cast < double > ( n ) * word_size ) | | b < 0 )
2021-08-30 06:37:23 +00:00
{
2021-09-04 16:41:52 +00:00
// insert default value
out_vec . resize_fill ( out_vec . size ( ) + n ) ;
return ;
2021-08-30 06:37:23 +00:00
}
2021-09-04 16:41:52 +00:00
size_t shift_right_bytes = b / word_size ;
size_t shift_right_bits = b % word_size ;
const UInt8 * begin = pos ;
const UInt8 * shift_right_end = end - shift_right_bytes ;
const size_t old_size = out_vec . size ( ) ;
const size_t new_size = old_size + n ;
/// Fill 0 to the left
out_vec . resize_fill ( out_vec . size ( ) + old_size + shift_right_bytes ) ;
out_vec . resize ( new_size ) ;
/// We start from the byte on the right and shift right shift_right_bits bit by byte
UInt8 * op_pointer = const_cast < UInt8 * > ( shift_right_end ) ;
UInt8 * out = out_vec . data ( ) + new_size ;
bitShiftRightForBytes ( op_pointer , begin , out , shift_right_bits ) ;
2021-08-30 06:37:23 +00:00
}
}
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 is_signed )
{
if ( ! left - > getType ( ) - > isIntegerTy ( ) )
throw Exception ( " BitShiftRightImpl expected an integral type " , ErrorCodes : : LOGICAL_ERROR ) ;
return is_signed ? b . CreateAShr ( left , right ) : b . CreateLShr ( left , right ) ;
}
# endif
} ;
2021-08-30 06:37:23 +00:00
2018-11-26 16:20:40 +00:00
struct NameBitShiftRight { static constexpr auto name = " bitShiftRight " ; } ;
2021-01-30 04:13:49 +00:00
using FunctionBitShiftRight = BinaryArithmeticOverloadResolver < BitShiftRightImpl , NameBitShiftRight , true , false > ;
2018-11-26 16:20:40 +00:00
2020-09-07 18:00:37 +00:00
}
2018-11-26 16:20:40 +00:00
void registerFunctionBitShiftRight ( FunctionFactory & factory )
{
factory . registerFunction < FunctionBitShiftRight > ( ) ;
}
}