mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-04 21:42:39 +00:00
Every function in its own file, part 7 [#CLICKHOUSE-2]
This commit is contained in:
parent
c77930fe30
commit
63d791e0a2
@ -1,10 +0,0 @@
|
||||
function(generate_function_register FUNCTION_AREA)
|
||||
foreach(FUNCTION IN LISTS ARGN)
|
||||
configure_file (registerFunction.h.in ${FUNCTIONS_GENERATED_DIR}register${FUNCTION}.h)
|
||||
configure_file (registerFunction.cpp.in ${FUNCTIONS_GENERATED_DIR}register${FUNCTION}.cpp)
|
||||
set(REGISTER_HEADERS "${REGISTER_HEADERS}#include \"register${FUNCTION}.h\"\n")
|
||||
set(REGISTER_FUNCTIONS "${REGISTER_FUNCTIONS} register${FUNCTION}(factory);\n")
|
||||
endforeach()
|
||||
|
||||
configure_file (registerFunctions_area.cpp.in ${FUNCTIONS_GENERATED_DIR}registerFunctions${FUNCTION_AREA}.cpp)
|
||||
endfunction()
|
@ -1,50 +1,8 @@
|
||||
include(${ClickHouse_SOURCE_DIR}/cmake/dbms_glob_sources.cmake)
|
||||
include(${ClickHouse_SOURCE_DIR}/cmake/dbms_generate_function.cmake)
|
||||
|
||||
set (FUNCTIONS_GENERATED_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated/)
|
||||
|
||||
generate_function_register(Arithmetic
|
||||
FunctionPlus
|
||||
FunctionMinus
|
||||
FunctionMultiply
|
||||
FunctionDivideFloating
|
||||
FunctionDivideIntegral
|
||||
FunctionDivideIntegralOrZero
|
||||
FunctionModulo
|
||||
FunctionNegate
|
||||
FunctionAbs
|
||||
FunctionBitAnd
|
||||
FunctionBitOr
|
||||
FunctionBitXor
|
||||
FunctionBitNot
|
||||
FunctionBitShiftLeft
|
||||
FunctionBitShiftRight
|
||||
FunctionBitRotateLeft
|
||||
FunctionBitRotateRight
|
||||
FunctionLeast
|
||||
FunctionGreatest
|
||||
FunctionBitTest
|
||||
FunctionBitTestAny
|
||||
FunctionBitTestAll
|
||||
FunctionGCD
|
||||
FunctionLCM
|
||||
FunctionIntExp2
|
||||
FunctionIntExp10
|
||||
)
|
||||
|
||||
generate_function_register(Projection
|
||||
FunctionOneOrZero
|
||||
FunctionProject
|
||||
FunctionBuildProjectionComposition
|
||||
FunctionRestoreProjection
|
||||
)
|
||||
|
||||
|
||||
add_headers_and_sources(clickhouse_functions .)
|
||||
add_headers_and_sources(clickhouse_functions ./GatherUtils)
|
||||
add_headers_and_sources(clickhouse_functions ./Conditional)
|
||||
#add_headers_and_sources(clickhouse_functions ${ClickHouse_BINARY_DIR}/dbms/src/Functions)
|
||||
add_headers_and_sources(clickhouse_functions ${FUNCTIONS_GENERATED_DIR})
|
||||
|
||||
|
||||
list(REMOVE_ITEM clickhouse_functions_sources IFunction.cpp FunctionFactory.cpp FunctionHelpers.cpp)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Functions/FunctionsArithmetic.h>
|
||||
#include <Functions/FunctionUnaryArithmetic.h>
|
||||
#include <Functions/FunctionHelpers.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
|
||||
@ -21,6 +21,9 @@ namespace DB
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
52
dbms/src/Functions/abs.cpp
Normal file
52
dbms/src/Functions/abs.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionUnaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A>
|
||||
struct AbsImpl
|
||||
{
|
||||
using ResultType = std::conditional_t<IsDecimalNumber<A>, A, typename NumberTraits::ResultOfAbs<A>::Type>;
|
||||
|
||||
static inline ResultType apply(A a)
|
||||
{
|
||||
if constexpr (IsDecimalNumber<A>)
|
||||
return a < 0 ? A(-a) : a;
|
||||
else if constexpr (std::is_integral_v<A> && std::is_signed_v<A>)
|
||||
return a < 0 ? static_cast<ResultType>(~a) + 1 : a;
|
||||
else if constexpr (std::is_integral_v<A> && std::is_unsigned_v<A>)
|
||||
return static_cast<ResultType>(a);
|
||||
else if constexpr (std::is_floating_point_v<A>)
|
||||
return static_cast<ResultType>(std::abs(a));
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// special type handling, some other time
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameAbs { static constexpr auto name = "abs"; };
|
||||
using FunctionAbs = FunctionUnaryArithmetic<AbsImpl, NameAbs, false>;
|
||||
|
||||
template <> struct FunctionUnaryArithmeticMonotonicity<NameAbs>
|
||||
{
|
||||
static bool has() { return true; }
|
||||
static IFunction::Monotonicity get(const Field & left, const Field & right)
|
||||
{
|
||||
Float64 left_float = left.isNull() ? -std::numeric_limits<Float64>::infinity() : applyVisitor(FieldVisitorConvertToNumber<Float64>(), left);
|
||||
Float64 right_float = right.isNull() ? std::numeric_limits<Float64>::infinity() : applyVisitor(FieldVisitorConvertToNumber<Float64>(), right);
|
||||
|
||||
if ((left_float < 0 && right_float > 0) || (left_float > 0 && right_float < 0))
|
||||
return {};
|
||||
|
||||
return { true, (left_float > 0) };
|
||||
}
|
||||
};
|
||||
|
||||
void registerFunctionAbs(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionAbs>();
|
||||
}
|
||||
|
||||
}
|
38
dbms/src/Functions/bitAnd.cpp
Normal file
38
dbms/src/Functions/bitAnd.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct BitAndImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfBit<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a) & static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#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())
|
||||
throw Exception("BitAndImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateAnd(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameBitAnd { static constexpr auto name = "bitAnd"; };
|
||||
using FunctionBitAnd = FunctionBinaryArithmetic<BitAndImpl, NameBitAnd>;
|
||||
|
||||
void registerFunctionBitAnd(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionBitAnd>();
|
||||
}
|
||||
|
||||
}
|
46
dbms/src/Functions/bitNot.cpp
Normal file
46
dbms/src/Functions/bitNot.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionUnaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A>
|
||||
struct BitNotImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfBitNot<A>::Type;
|
||||
|
||||
static inline ResultType apply(A a)
|
||||
{
|
||||
return ~static_cast<ResultType>(a);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * arg, bool)
|
||||
{
|
||||
if (!arg->getType()->isIntegerTy())
|
||||
throw Exception("BitNotImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateNot(arg);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameBitNot { static constexpr auto name = "bitNot"; };
|
||||
using FunctionBitNot = FunctionUnaryArithmetic<BitNotImpl, NameBitNot, true>;
|
||||
|
||||
template <> struct FunctionUnaryArithmeticMonotonicity<NameBitNot>
|
||||
{
|
||||
static bool has() { return false; }
|
||||
static IFunction::Monotonicity get(const Field &, const Field &)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
void registerFunctionBitNot(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionBitNot>();
|
||||
}
|
||||
|
||||
}
|
38
dbms/src/Functions/bitOr.cpp
Normal file
38
dbms/src/Functions/bitOr.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct BitOrImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfBit<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a) | static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#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())
|
||||
throw Exception("BitOrImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateOr(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameBitOr { static constexpr auto name = "bitOr"; };
|
||||
using FunctionBitOr = FunctionBinaryArithmetic<BitOrImpl, NameBitOr>;
|
||||
|
||||
void registerFunctionBitOr(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionBitOr>();
|
||||
}
|
||||
|
||||
}
|
41
dbms/src/Functions/bitRotateLeft.cpp
Normal file
41
dbms/src/Functions/bitRotateLeft.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct BitRotateLeftImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfBit<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return (static_cast<Result>(a) << static_cast<Result>(b))
|
||||
| (static_cast<Result>(a) >> ((sizeof(Result) * 8) - static_cast<Result>(b)));
|
||||
}
|
||||
|
||||
#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())
|
||||
throw Exception("BitRotateLeftImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
auto * size = llvm::ConstantInt::get(left->getType(), left->getType()->getPrimitiveSizeInBits());
|
||||
/// XXX how is this supposed to behave in signed mode?
|
||||
return b.CreateOr(b.CreateShl(left, right), b.CreateLShr(left, b.CreateSub(size, right)));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameBitRotateLeft { static constexpr auto name = "bitRotateLeft"; };
|
||||
using FunctionBitRotateLeft = FunctionBinaryArithmetic<BitRotateLeftImpl, NameBitRotateLeft>;
|
||||
|
||||
void registerFunctionBitRotateLeft(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionBitRotateLeft>();
|
||||
}
|
||||
|
||||
}
|
40
dbms/src/Functions/bitRotateRight.cpp
Normal file
40
dbms/src/Functions/bitRotateRight.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct BitRotateRightImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfBit<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return (static_cast<Result>(a) >> static_cast<Result>(b))
|
||||
| (static_cast<Result>(a) << ((sizeof(Result) * 8) - static_cast<Result>(b)));
|
||||
}
|
||||
|
||||
#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())
|
||||
throw Exception("BitRotateRightImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
auto * size = llvm::ConstantInt::get(left->getType(), left->getType()->getPrimitiveSizeInBits());
|
||||
return b.CreateOr(b.CreateLShr(left, right), b.CreateShl(left, b.CreateSub(size, right)));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameBitRotateRight { static constexpr auto name = "bitRotateRight"; };
|
||||
using FunctionBitRotateRight = FunctionBinaryArithmetic<BitRotateRightImpl, NameBitRotateRight>;
|
||||
|
||||
void registerFunctionBitRotateRight(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionBitRotateRight>();
|
||||
}
|
||||
|
||||
}
|
38
dbms/src/Functions/bitShiftLeft.cpp
Normal file
38
dbms/src/Functions/bitShiftLeft.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct BitShiftLeftImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfBit<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a) << static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#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())
|
||||
throw Exception("BitShiftLeftImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateShl(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameBitShiftLeft { static constexpr auto name = "bitShiftLeft"; };
|
||||
using FunctionBitShiftLeft = FunctionBinaryArithmetic<BitShiftLeftImpl, NameBitShiftLeft>;
|
||||
|
||||
void registerFunctionBitShiftLeft(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionBitShiftLeft>();
|
||||
}
|
||||
|
||||
}
|
38
dbms/src/Functions/bitShiftRight.cpp
Normal file
38
dbms/src/Functions/bitShiftRight.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct BitShiftRightImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfBit<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a) >> static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
struct NameBitShiftRight { static constexpr auto name = "bitShiftRight"; };
|
||||
using FunctionBitShiftRight = FunctionBinaryArithmetic<BitShiftRightImpl, NameBitShiftRight>;
|
||||
|
||||
void registerFunctionBitShiftRight(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionBitShiftRight>();
|
||||
}
|
||||
|
||||
}
|
31
dbms/src/Functions/bitTest.cpp
Normal file
31
dbms/src/Functions/bitTest.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct BitTestImpl
|
||||
{
|
||||
using ResultType = UInt8;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return (typename NumberTraits::ToInteger<A>::Type(a) >> typename NumberTraits::ToInteger<B>::Type(b)) & 1;
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// TODO
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameBitTest { static constexpr auto name = "bitTest"; };
|
||||
using FunctionBitTest = FunctionBinaryArithmetic<BitTestImpl, NameBitTest>;
|
||||
|
||||
void registerFunctionBitTest(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionBitTest>();
|
||||
}
|
||||
|
||||
}
|
21
dbms/src/Functions/bitTestAll.cpp
Normal file
21
dbms/src/Functions/bitTestAll.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBitTestMany.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
struct BitTestAllImpl
|
||||
{
|
||||
template <typename A, typename B>
|
||||
static inline UInt8 apply(A a, B b) { return (a & b) == b; }
|
||||
};
|
||||
|
||||
struct NameBitTestAll { static constexpr auto name = "bitTestAll"; };
|
||||
using FunctionBitTestAll = FunctionBitTestMany<BitTestAllImpl, NameBitTestAll>;
|
||||
|
||||
void registerFunctionBitTestAll(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionBitTestAll>();
|
||||
}
|
||||
|
||||
}
|
21
dbms/src/Functions/bitTestAny.cpp
Normal file
21
dbms/src/Functions/bitTestAny.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBitTestMany.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
struct BitTestAnyImpl
|
||||
{
|
||||
template <typename A, typename B>
|
||||
static inline UInt8 apply(A a, B b) { return (a & b) != 0; }
|
||||
};
|
||||
|
||||
struct NameBitTestAny { static constexpr auto name = "bitTestAny"; };
|
||||
using FunctionBitTestAny = FunctionBitTestMany<BitTestAnyImpl, NameBitTestAny>;
|
||||
|
||||
void registerFunctionBitTestAny(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionBitTestAny>();
|
||||
}
|
||||
|
||||
}
|
38
dbms/src/Functions/bitXor.cpp
Normal file
38
dbms/src/Functions/bitXor.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct BitXorImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfBit<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a) ^ static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#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())
|
||||
throw Exception("BitXorImpl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateXor(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameBitXor { static constexpr auto name = "bitXor"; };
|
||||
using FunctionBitXor = FunctionBinaryArithmetic<BitXorImpl, NameBitXor>;
|
||||
|
||||
void registerFunctionBitXor(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionBitXor>();
|
||||
}
|
||||
|
||||
}
|
17
dbms/src/Functions/castTypeToEither.h
Normal file
17
dbms/src/Functions/castTypeToEither.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <Common/typeid_cast.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
class IDataType;
|
||||
|
||||
template <typename... Ts, typename F>
|
||||
static bool castTypeToEither(const IDataType * type, F && f)
|
||||
{
|
||||
/// XXX can't use && here because gcc-7 complains about parentheses around && within ||
|
||||
return ((typeid_cast<const Ts *>(type) ? f(*typeid_cast<const Ts *>(type)) : false) || ...);
|
||||
}
|
||||
|
||||
}
|
39
dbms/src/Functions/divide.cpp
Normal file
39
dbms/src/Functions/divide.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct DivideFloatingImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfFloatingPointDivision<A, B>::Type;
|
||||
static const constexpr bool allow_decimal = true;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a) / b;
|
||||
}
|
||||
|
||||
#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())
|
||||
throw Exception("DivideFloatingImpl expected a floating-point type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateFDiv(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameDivide { static constexpr auto name = "divide"; };
|
||||
using FunctionDivide = FunctionBinaryArithmetic<DivideFloatingImpl, NameDivide>;
|
||||
|
||||
void registerFunctionDivide(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionDivide>();
|
||||
}
|
||||
|
||||
}
|
36
dbms/src/Functions/gcd.cpp
Normal file
36
dbms/src/Functions/gcd.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
#include <boost/integer/common_factor.hpp>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct GCDImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfAdditionMultiplication<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger<A>::Type(a), typename NumberTraits::ToInteger<B>::Type(b));
|
||||
throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger<B>::Type(b), typename NumberTraits::ToInteger<A>::Type(a));
|
||||
return boost::integer::gcd(
|
||||
typename NumberTraits::ToInteger<Result>::Type(a),
|
||||
typename NumberTraits::ToInteger<Result>::Type(b));
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// exceptions (and a non-trivial algorithm)
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameGCD { static constexpr auto name = "gcd"; };
|
||||
using FunctionGCD = FunctionBinaryArithmetic<GCDImpl, NameGCD, false>;
|
||||
|
||||
void registerFunctionGCD(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionGCD>();
|
||||
}
|
||||
|
||||
}
|
60
dbms/src/Functions/greatest.cpp
Normal file
60
dbms/src/Functions/greatest.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct GreatestBaseImpl
|
||||
{
|
||||
using ResultType = NumberTraits::ResultOfGreatest<A, B>;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a) > static_cast<Result>(b) ? static_cast<Result>(a) : static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#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())
|
||||
/// XXX maxnum is basically fmax(), it may or may not match whatever apply() does
|
||||
/// XXX CreateMaxNum is broken on LLVM 5.0 and 6.0 (generates minnum instead; fixed in 7)
|
||||
return b.CreateBinaryIntrinsic(llvm::Intrinsic::maxnum, left, right);
|
||||
return b.CreateSelect(is_signed ? b.CreateICmpSGT(left, right) : b.CreateICmpUGT(left, right), left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
struct GreatestSpecialImpl
|
||||
{
|
||||
using ResultType = std::make_unsigned_t<A>;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
static_assert(std::is_same_v<Result, ResultType>, "ResultType != Result");
|
||||
return accurate::greaterOp(a, b) ? static_cast<Result>(a) : static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// ???
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
using GreatestImpl = std::conditional_t<!NumberTraits::LeastGreatestSpecialCase<A, B>, GreatestBaseImpl<A, B>, GreatestSpecialImpl<A, B>>;
|
||||
|
||||
struct NameGreatest { static constexpr auto name = "greatest"; };
|
||||
using FunctionGreatest = FunctionBinaryArithmetic<GreatestImpl, NameGreatest>;
|
||||
|
||||
void registerFunctionGreatest(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionGreatest>();
|
||||
}
|
||||
|
||||
}
|
104
dbms/src/Functions/intDiv.cpp
Normal file
104
dbms/src/Functions/intDiv.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
#include <Functions/intDiv.h>
|
||||
|
||||
#if __SSE2__
|
||||
#define LIBDIVIDE_USE_SSE2 1
|
||||
#endif
|
||||
|
||||
#include <libdivide.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/// Optimizations for integer division by a constant.
|
||||
|
||||
template <typename A, typename B>
|
||||
struct DivideIntegralByConstantImpl
|
||||
: BinaryOperationImplBase<A, B, DivideIntegralImpl<A, B>>
|
||||
{
|
||||
using ResultType = typename DivideIntegralImpl<A, B>::ResultType;
|
||||
|
||||
static void vector_constant(const PaddedPODArray<A> & a, B b, PaddedPODArray<ResultType> & c)
|
||||
{
|
||||
if (unlikely(b == 0))
|
||||
throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION);
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
|
||||
if (unlikely(std::is_signed_v<B> && b == -1))
|
||||
{
|
||||
size_t size = a.size();
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
c[i] = -c[i];
|
||||
return;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
libdivide::divider<A> divider(b);
|
||||
|
||||
size_t size = a.size();
|
||||
const A * a_pos = a.data();
|
||||
const A * a_end = a_pos + size;
|
||||
ResultType * c_pos = c.data();
|
||||
|
||||
#if __SSE2__
|
||||
static constexpr size_t values_per_sse_register = 16 / sizeof(A);
|
||||
const A * a_end_sse = a_pos + size / values_per_sse_register * values_per_sse_register;
|
||||
|
||||
while (a_pos < a_end_sse)
|
||||
{
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(c_pos),
|
||||
_mm_loadu_si128(reinterpret_cast<const __m128i *>(a_pos)) / divider);
|
||||
|
||||
a_pos += values_per_sse_register;
|
||||
c_pos += values_per_sse_register;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (a_pos < a_end)
|
||||
{
|
||||
*c_pos = *a_pos / divider;
|
||||
++a_pos;
|
||||
++c_pos;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Specializations are specified for dividing numbers of the type UInt64 and UInt32 by the numbers of the same sign.
|
||||
* Can be expanded to all possible combinations, but more code is needed.
|
||||
*/
|
||||
|
||||
template <> struct BinaryOperationImpl<UInt64, UInt8, DivideIntegralImpl<UInt64, UInt8>> : DivideIntegralByConstantImpl<UInt64, UInt8> {};
|
||||
template <> struct BinaryOperationImpl<UInt64, UInt16, DivideIntegralImpl<UInt64, UInt16>> : DivideIntegralByConstantImpl<UInt64, UInt16> {};
|
||||
template <> struct BinaryOperationImpl<UInt64, UInt32, DivideIntegralImpl<UInt64, UInt32>> : DivideIntegralByConstantImpl<UInt64, UInt32> {};
|
||||
template <> struct BinaryOperationImpl<UInt64, UInt64, DivideIntegralImpl<UInt64, UInt64>> : DivideIntegralByConstantImpl<UInt64, UInt64> {};
|
||||
|
||||
template <> struct BinaryOperationImpl<UInt32, UInt8, DivideIntegralImpl<UInt32, UInt8>> : DivideIntegralByConstantImpl<UInt32, UInt8> {};
|
||||
template <> struct BinaryOperationImpl<UInt32, UInt16, DivideIntegralImpl<UInt32, UInt16>> : DivideIntegralByConstantImpl<UInt32, UInt16> {};
|
||||
template <> struct BinaryOperationImpl<UInt32, UInt32, DivideIntegralImpl<UInt32, UInt32>> : DivideIntegralByConstantImpl<UInt32, UInt32> {};
|
||||
template <> struct BinaryOperationImpl<UInt32, UInt64, DivideIntegralImpl<UInt32, UInt64>> : DivideIntegralByConstantImpl<UInt32, UInt64> {};
|
||||
|
||||
template <> struct BinaryOperationImpl<Int64, Int8, DivideIntegralImpl<Int64, Int8>> : DivideIntegralByConstantImpl<Int64, Int8> {};
|
||||
template <> struct BinaryOperationImpl<Int64, Int16, DivideIntegralImpl<Int64, Int16>> : DivideIntegralByConstantImpl<Int64, Int16> {};
|
||||
template <> struct BinaryOperationImpl<Int64, Int32, DivideIntegralImpl<Int64, Int32>> : DivideIntegralByConstantImpl<Int64, Int32> {};
|
||||
template <> struct BinaryOperationImpl<Int64, Int64, DivideIntegralImpl<Int64, Int64>> : DivideIntegralByConstantImpl<Int64, Int64> {};
|
||||
|
||||
template <> struct BinaryOperationImpl<Int32, Int8, DivideIntegralImpl<Int32, Int8>> : DivideIntegralByConstantImpl<Int32, Int8> {};
|
||||
template <> struct BinaryOperationImpl<Int32, Int16, DivideIntegralImpl<Int32, Int16>> : DivideIntegralByConstantImpl<Int32, Int16> {};
|
||||
template <> struct BinaryOperationImpl<Int32, Int32, DivideIntegralImpl<Int32, Int32>> : DivideIntegralByConstantImpl<Int32, Int32> {};
|
||||
template <> struct BinaryOperationImpl<Int32, Int64, DivideIntegralImpl<Int32, Int64>> : DivideIntegralByConstantImpl<Int32, Int64> {};
|
||||
|
||||
|
||||
struct NameDivideIntegral { static constexpr auto name = "intDiv"; };
|
||||
using FunctionDivideIntegral = FunctionBinaryArithmetic<DivideIntegralImpl, NameDivideIntegral, false>;
|
||||
|
||||
void registerFunctionDivideIntegral(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionDivideIntegral>();
|
||||
}
|
||||
|
||||
}
|
66
dbms/src/Functions/intDiv.h
Normal file
66
dbms/src/Functions/intDiv.h
Normal file
@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <common/likely.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/config.h>
|
||||
#include <DataTypes/NumberTraits.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_DIVISION;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
|
||||
template <typename A, typename B>
|
||||
inline void throwIfDivisionLeadsToFPE(A a, B b)
|
||||
{
|
||||
/// Is it better to use siglongjmp instead of checks?
|
||||
|
||||
if (unlikely(b == 0))
|
||||
throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION);
|
||||
|
||||
/// http://avva.livejournal.com/2548306.html
|
||||
if (unlikely(std::is_signed_v<A> && std::is_signed_v<B> && a == std::numeric_limits<A>::min() && b == -1))
|
||||
throw Exception("Division of minimal signed number by minus one", ErrorCodes::ILLEGAL_DIVISION);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool divisionLeadsToFPE(A a, B b)
|
||||
{
|
||||
if (unlikely(b == 0))
|
||||
return true;
|
||||
|
||||
if (unlikely(std::is_signed_v<A> && std::is_signed_v<B> && a == std::numeric_limits<A>::min() && b == -1))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
template <typename A, typename B>
|
||||
struct DivideIntegralImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfIntegerDivision<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
throwIfDivisionLeadsToFPE(a, b);
|
||||
return a / b;
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// don't know how to throw from LLVM IR
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
31
dbms/src/Functions/intDivOrZero.cpp
Normal file
31
dbms/src/Functions/intDivOrZero.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct DivideIntegralOrZeroImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfIntegerDivision<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return unlikely(divisionLeadsToFPE(a, b)) ? 0 : a / b;
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// TODO implement the checks
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameDivideIntegralOrZero { static constexpr auto name = "intDivOrZero"; };
|
||||
using FunctionDivideIntegralOrZero = FunctionBinaryArithmetic<DivideIntegralOrZeroImpl, NameDivideIntegralOrZero>;
|
||||
|
||||
void registerFunctionDivideIntegralOrZero(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionDivideIntegralOrZero>();
|
||||
}
|
||||
|
||||
}
|
46
dbms/src/Functions/intExp10.cpp
Normal file
46
dbms/src/Functions/intExp10.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionUnaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A>
|
||||
struct IntExp10Impl
|
||||
{
|
||||
using ResultType = UInt64;
|
||||
|
||||
static inline ResultType apply(A a)
|
||||
{
|
||||
return intExp10(a);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// library function
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameIntExp10 { static constexpr auto name = "intExp10"; };
|
||||
/// Assumed to be injective for the purpose of query optimization, but in fact it is not injective because of possible overflow.
|
||||
using FunctionIntExp10 = FunctionUnaryArithmetic<IntExp10Impl, NameIntExp10, true>;
|
||||
|
||||
template <> struct FunctionUnaryArithmeticMonotonicity<NameIntExp10>
|
||||
{
|
||||
static bool has() { return true; }
|
||||
static IFunction::Monotonicity get(const Field & left, const Field & right)
|
||||
{
|
||||
Float64 left_float = left.isNull() ? -std::numeric_limits<Float64>::infinity() : applyVisitor(FieldVisitorConvertToNumber<Float64>(), left);
|
||||
Float64 right_float = right.isNull() ? std::numeric_limits<Float64>::infinity() : applyVisitor(FieldVisitorConvertToNumber<Float64>(), right);
|
||||
|
||||
if (left_float < 0 || right_float > 19)
|
||||
return {};
|
||||
|
||||
return { true };
|
||||
}
|
||||
};
|
||||
|
||||
void registerFunctionIntExp10(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionIntExp10>();
|
||||
}
|
||||
|
||||
}
|
53
dbms/src/Functions/intExp2.cpp
Normal file
53
dbms/src/Functions/intExp2.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionUnaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A>
|
||||
struct IntExp2Impl
|
||||
{
|
||||
using ResultType = UInt64;
|
||||
|
||||
static inline ResultType apply(A a)
|
||||
{
|
||||
return intExp2(a);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * arg, bool)
|
||||
{
|
||||
if (!arg->getType()->isIntegerTy())
|
||||
throw Exception("IntExp2Impl expected an integral type", ErrorCodes::LOGICAL_ERROR);
|
||||
return b.CreateShl(llvm::ConstantInt::get(arg->getType(), 1), arg);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Assumed to be injective for the purpose of query optimization, but in fact it is not injective because of possible overflow.
|
||||
struct NameIntExp2 { static constexpr auto name = "intExp2"; };
|
||||
using FunctionIntExp2 = FunctionUnaryArithmetic<IntExp2Impl, NameIntExp2, true>;
|
||||
|
||||
template <> struct FunctionUnaryArithmeticMonotonicity<NameIntExp2>
|
||||
{
|
||||
static bool has() { return true; }
|
||||
static IFunction::Monotonicity get(const Field & left, const Field & right)
|
||||
{
|
||||
Float64 left_float = left.isNull() ? -std::numeric_limits<Float64>::infinity() : applyVisitor(FieldVisitorConvertToNumber<Float64>(), left);
|
||||
Float64 right_float = right.isNull() ? std::numeric_limits<Float64>::infinity() : applyVisitor(FieldVisitorConvertToNumber<Float64>(), right);
|
||||
|
||||
if (left_float < 0 || right_float > 63)
|
||||
return {};
|
||||
|
||||
return { true };
|
||||
}
|
||||
};
|
||||
|
||||
void registerFunctionIntExp2(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionIntExp2>();
|
||||
}
|
||||
|
||||
}
|
36
dbms/src/Functions/lcm.cpp
Normal file
36
dbms/src/Functions/lcm.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
#include <boost/integer/common_factor.hpp>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct LCMImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfAdditionMultiplication<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger<A>::Type(a), typename NumberTraits::ToInteger<B>::Type(b));
|
||||
throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger<B>::Type(b), typename NumberTraits::ToInteger<A>::Type(a));
|
||||
return boost::integer::lcm(
|
||||
typename NumberTraits::ToInteger<Result>::Type(a),
|
||||
typename NumberTraits::ToInteger<Result>::Type(b));
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// exceptions (and a non-trivial algorithm)
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameLCM { static constexpr auto name = "lcm"; };
|
||||
using FunctionLCM = FunctionBinaryArithmetic<LCMImpl, NameLCM, false>;
|
||||
|
||||
void registerFunctionLCM(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionLCM>();
|
||||
}
|
||||
|
||||
}
|
60
dbms/src/Functions/least.cpp
Normal file
60
dbms/src/Functions/least.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct LeastBaseImpl
|
||||
{
|
||||
using ResultType = NumberTraits::ResultOfLeast<A, B>;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
/** gcc 4.9.2 successfully vectorizes a loop from this function. */
|
||||
return static_cast<Result>(a) < static_cast<Result>(b) ? static_cast<Result>(a) : static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#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())
|
||||
/// XXX minnum is basically fmin(), it may or may not match whatever apply() does
|
||||
return b.CreateMinNum(left, right);
|
||||
return b.CreateSelect(is_signed ? b.CreateICmpSLT(left, right) : b.CreateICmpULT(left, right), left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
struct LeastSpecialImpl
|
||||
{
|
||||
using ResultType = std::make_signed_t<A>;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
static_assert(std::is_same_v<Result, ResultType>, "ResultType != Result");
|
||||
return accurate::lessOp(a, b) ? static_cast<Result>(a) : static_cast<Result>(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// ???
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
using LeastImpl = std::conditional_t<!NumberTraits::LeastGreatestSpecialCase<A, B>, LeastBaseImpl<A, B>, LeastSpecialImpl<A, B>>;
|
||||
|
||||
struct NameLeast { static constexpr auto name = "least"; };
|
||||
using FunctionLeast = FunctionBinaryArithmetic<LeastImpl, NameLeast>;
|
||||
|
||||
void registerFunctionLeast(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionLeast>();
|
||||
}
|
||||
|
||||
}
|
44
dbms/src/Functions/minus.cpp
Normal file
44
dbms/src/Functions/minus.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct MinusImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfSubtraction<A, B>::Type;
|
||||
static const constexpr bool allow_decimal = true;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a) - b;
|
||||
}
|
||||
|
||||
/// Apply operation and check overflow. It's used for Deciamal operations. @returns true if overflowed, false othervise.
|
||||
template <typename Result = ResultType>
|
||||
static inline bool apply(A a, B b, Result & c)
|
||||
{
|
||||
return common::subOverflow(static_cast<Result>(a), b, c);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
return left->getType()->isIntegerTy() ? b.CreateSub(left, right) : b.CreateFSub(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameMinus { static constexpr auto name = "minus"; };
|
||||
using FunctionMinus = FunctionBinaryArithmetic<MinusImpl, NameMinus>;
|
||||
|
||||
void registerFunctionMinus(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionMinus>();
|
||||
}
|
||||
|
||||
}
|
102
dbms/src/Functions/modulo.cpp
Normal file
102
dbms/src/Functions/modulo.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
#if __SSE2__
|
||||
#define LIBDIVIDE_USE_SSE2 1
|
||||
#endif
|
||||
|
||||
#include <libdivide.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_DIVISION;
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
struct ModuloImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfModulo<A, B>::Type;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger<A>::Type(a), typename NumberTraits::ToInteger<B>::Type(b));
|
||||
return typename NumberTraits::ToInteger<A>::Type(a) % typename NumberTraits::ToInteger<B>::Type(b);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = false; /// don't know how to throw from LLVM IR
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
struct ModuloByConstantImpl
|
||||
: BinaryOperationImplBase<A, B, ModuloImpl<A, B>>
|
||||
{
|
||||
using ResultType = typename ModuloImpl<A, B>::ResultType;
|
||||
|
||||
static void vector_constant(const PaddedPODArray<A> & a, B b, PaddedPODArray<ResultType> & c)
|
||||
{
|
||||
if (unlikely(b == 0))
|
||||
throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION);
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
|
||||
if (unlikely((std::is_signed_v<B> && b == -1) || b == 1))
|
||||
{
|
||||
size_t size = a.size();
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
c[i] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
libdivide::divider<A> divider(b);
|
||||
|
||||
/// Here we failed to make the SSE variant from libdivide give an advantage.
|
||||
size_t size = a.size();
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
c[i] = a[i] - (a[i] / divider) * b; /// NOTE: perhaps, the division semantics with the remainder of negative numbers is not preserved.
|
||||
}
|
||||
};
|
||||
|
||||
/** Specializations are specified for dividing numbers of the type UInt64 and UInt32 by the numbers of the same sign.
|
||||
* Can be expanded to all possible combinations, but more code is needed.
|
||||
*/
|
||||
|
||||
template <> struct BinaryOperationImpl<UInt64, UInt8, ModuloImpl<UInt64, UInt8>> : ModuloByConstantImpl<UInt64, UInt8> {};
|
||||
template <> struct BinaryOperationImpl<UInt64, UInt16, ModuloImpl<UInt64, UInt16>> : ModuloByConstantImpl<UInt64, UInt16> {};
|
||||
template <> struct BinaryOperationImpl<UInt64, UInt32, ModuloImpl<UInt64, UInt32>> : ModuloByConstantImpl<UInt64, UInt32> {};
|
||||
template <> struct BinaryOperationImpl<UInt64, UInt64, ModuloImpl<UInt64, UInt64>> : ModuloByConstantImpl<UInt64, UInt64> {};
|
||||
|
||||
template <> struct BinaryOperationImpl<UInt32, UInt8, ModuloImpl<UInt32, UInt8>> : ModuloByConstantImpl<UInt32, UInt8> {};
|
||||
template <> struct BinaryOperationImpl<UInt32, UInt16, ModuloImpl<UInt32, UInt16>> : ModuloByConstantImpl<UInt32, UInt16> {};
|
||||
template <> struct BinaryOperationImpl<UInt32, UInt32, ModuloImpl<UInt32, UInt32>> : ModuloByConstantImpl<UInt32, UInt32> {};
|
||||
template <> struct BinaryOperationImpl<UInt32, UInt64, ModuloImpl<UInt32, UInt64>> : ModuloByConstantImpl<UInt32, UInt64> {};
|
||||
|
||||
template <> struct BinaryOperationImpl<Int64, Int8, ModuloImpl<Int64, Int8>> : ModuloByConstantImpl<Int64, Int8> {};
|
||||
template <> struct BinaryOperationImpl<Int64, Int16, ModuloImpl<Int64, Int16>> : ModuloByConstantImpl<Int64, Int16> {};
|
||||
template <> struct BinaryOperationImpl<Int64, Int32, ModuloImpl<Int64, Int32>> : ModuloByConstantImpl<Int64, Int32> {};
|
||||
template <> struct BinaryOperationImpl<Int64, Int64, ModuloImpl<Int64, Int64>> : ModuloByConstantImpl<Int64, Int64> {};
|
||||
|
||||
template <> struct BinaryOperationImpl<Int32, Int8, ModuloImpl<Int32, Int8>> : ModuloByConstantImpl<Int32, Int8> {};
|
||||
template <> struct BinaryOperationImpl<Int32, Int16, ModuloImpl<Int32, Int16>> : ModuloByConstantImpl<Int32, Int16> {};
|
||||
template <> struct BinaryOperationImpl<Int32, Int32, ModuloImpl<Int32, Int32>> : ModuloByConstantImpl<Int32, Int32> {};
|
||||
template <> struct BinaryOperationImpl<Int32, Int64, ModuloImpl<Int32, Int64>> : ModuloByConstantImpl<Int32, Int64> {};
|
||||
|
||||
|
||||
struct NameModulo { static constexpr auto name = "modulo"; };
|
||||
using FunctionModulo = FunctionBinaryArithmetic<ModuloImpl, NameModulo, false>;
|
||||
|
||||
void registerFunctionModulo(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionModulo>();
|
||||
}
|
||||
|
||||
}
|
44
dbms/src/Functions/multiply.cpp
Normal file
44
dbms/src/Functions/multiply.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct MultiplyImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfAdditionMultiplication<A, B>::Type;
|
||||
static const constexpr bool allow_decimal = true;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
return static_cast<Result>(a) * b;
|
||||
}
|
||||
|
||||
/// Apply operation and check overflow. It's used for Deciamal operations. @returns true if overflowed, false othervise.
|
||||
template <typename Result = ResultType>
|
||||
static inline bool apply(A a, B b, Result & c)
|
||||
{
|
||||
return common::mulOverflow(static_cast<Result>(a), b, c);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
return left->getType()->isIntegerTy() ? b.CreateMul(left, right) : b.CreateFMul(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameMultiply { static constexpr auto name = "multiply"; };
|
||||
using FunctionMultiply = FunctionBinaryArithmetic<MultiplyImpl, NameMultiply>;
|
||||
|
||||
void registerFunctionMultiply(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionMultiply>();
|
||||
}
|
||||
|
||||
}
|
44
dbms/src/Functions/negate.cpp
Normal file
44
dbms/src/Functions/negate.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionUnaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A>
|
||||
struct NegateImpl
|
||||
{
|
||||
using ResultType = std::conditional_t<IsDecimalNumber<A>, A, typename NumberTraits::ResultOfNegate<A>::Type>;
|
||||
|
||||
static inline ResultType apply(A a)
|
||||
{
|
||||
return -static_cast<ResultType>(a);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * arg, bool)
|
||||
{
|
||||
return arg->getType()->isIntegerTy() ? b.CreateNeg(arg) : b.CreateFNeg(arg);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameNegate { static constexpr auto name = "negate"; };
|
||||
using FunctionNegate = FunctionUnaryArithmetic<NegateImpl, NameNegate, true>;
|
||||
|
||||
template <> struct FunctionUnaryArithmeticMonotonicity<NameNegate>
|
||||
{
|
||||
static bool has() { return true; }
|
||||
static IFunction::Monotonicity get(const Field &, const Field &)
|
||||
{
|
||||
return { true, false };
|
||||
}
|
||||
};
|
||||
|
||||
void registerFunctionNegate(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionNegate>();
|
||||
}
|
||||
|
||||
}
|
45
dbms/src/Functions/plus.cpp
Normal file
45
dbms/src/Functions/plus.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionBinaryArithmetic.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
template <typename A, typename B>
|
||||
struct PlusImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfAdditionMultiplication<A, B>::Type;
|
||||
static const constexpr bool allow_decimal = true;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
/// Next everywhere, static_cast - so that there is no wrong result in expressions of the form Int64 c = UInt32(a) * Int32(-1).
|
||||
return static_cast<Result>(a) + b;
|
||||
}
|
||||
|
||||
/// Apply operation and check overflow. It's used for Deciamal operations. @returns true if overflowed, false othervise.
|
||||
template <typename Result = ResultType>
|
||||
static inline bool apply(A a, B b, Result & c)
|
||||
{
|
||||
return common::addOverflow(static_cast<Result>(a), b, c);
|
||||
}
|
||||
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
static constexpr bool compilable = true;
|
||||
|
||||
static inline llvm::Value * compile(llvm::IRBuilder<> & b, llvm::Value * left, llvm::Value * right, bool)
|
||||
{
|
||||
return left->getType()->isIntegerTy() ? b.CreateAdd(left, right) : b.CreateFAdd(left, right);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NamePlus { static constexpr auto name = "plus"; };
|
||||
using FunctionPlus = FunctionBinaryArithmetic<PlusImpl, NamePlus>;
|
||||
|
||||
void registerFunctionPlus(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionPlus>();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user