1#include <Functions/FunctionFactory.h>
2#include <Functions/FunctionUnaryArithmetic.h>
3#include <DataTypes/NumberTraits.h>
4
5namespace DB
6{
7 namespace ErrorCodes
8 {
9 extern const int BAD_CAST;
10 }
11
12 /// Working with UInt8: last bit = can be true, previous = can be false (Like dbms/src/Storages/MergeTree/BoolMask.h).
13 /// This function provides "NOT" operation for BoolMasks by swapping last two bits ("can be true" <-> "can be false").
14 template <typename A>
15 struct BitSwapLastTwoImpl
16 {
17 using ResultType = UInt8;
18
19 static inline ResultType NO_SANITIZE_UNDEFINED apply(A a)
20 {
21 if constexpr (!std::is_same_v<A, ResultType>)
22 throw DB::Exception("It's a bug! Only UInt8 type is supported by __bitSwapLastTwo.", ErrorCodes::BAD_CAST);
23 return static_cast<ResultType>(
24 ((static_cast<ResultType>(a) & 1) << 1) | ((static_cast<ResultType>(a) >> 1) & 1));
25 }
26
27#if USE_EMBEDDED_COMPILER
28 static constexpr bool compilable = true;
29
30 static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * arg, bool)
31 {
32 if (!arg->getType()->isIntegerTy())
33 throw Exception("__bitSwapLastTwo expected an integral type", ErrorCodes::LOGICAL_ERROR);
34 return b.CreateOr(
35 b.CreateShl(b.CreateAnd(arg, 1), 1),
36 b.CreateAnd(b.CreateLShr(arg, 1), 1)
37 );
38 }
39#endif
40 };
41
42 struct NameBitSwapLastTwo { static constexpr auto name = "__bitSwapLastTwo"; };
43 using FunctionBitSwapLastTwo = FunctionUnaryArithmetic<BitSwapLastTwoImpl, NameBitSwapLastTwo, true>;
44
45 template <> struct FunctionUnaryArithmeticMonotonicity<NameBitSwapLastTwo>
46 {
47 static bool has() { return false; }
48 static IFunction::Monotonicity get(const Field &, const Field &)
49 {
50 return {};
51 }
52 };
53
54 void registerFunctionBitSwapLastTwo(FunctionFactory & factory)
55 {
56 factory.registerFunction<FunctionBitSwapLastTwo>();
57 }
58
59}
60