clean code

This commit is contained in:
zhanglistar 2024-10-09 09:15:35 +08:00
parent e223d7a642
commit d58080742a
3 changed files with 144 additions and 46 deletions

View File

@ -55,6 +55,7 @@
#include <Common/FieldVisitorsAccurateComparison.h>
#include <Common/assert_cast.h>
#include <Common/typeid_cast.h>
#include "Core/ExternalResultDescription.h"
#if USE_EMBEDDED_COMPILER
# include <llvm/IR/IRBuilder.h>
@ -255,7 +256,7 @@ struct BinaryOperation
static const constexpr bool allow_string_integer = false;
template <OpCase op_case>
static void NO_INLINE process(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t size, const NullMap * right_nullmap = nullptr, NullMap * res_nullmap = nullptr)
static void NO_INLINE process(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t size, const NullMap * right_nullmap = nullptr, NullMap * res_nullmap [[maybe_unused]] = nullptr)
{
if constexpr (op_case == OpCase::RightConstant)
{
@ -269,41 +270,30 @@ struct BinaryOperation
{
if (right_nullmap)
{
assert(res_nullmap);
for (size_t i = 0; i < size; ++i)
if ((*right_nullmap)[i])
c[i] = ResultType();
else
apply<op_case, true>(a, b, c, i, &((*res_nullmap)[i]));
apply<op_case>(a, b, c, i);
}
else
for (size_t i = 0; i < size; ++i)
apply<op_case, false>(a, b, c, i);
apply<op_case>(a, b, c, i);
}
}
static ResultType process(A a, B b) { return Op::template apply<ResultType>(a, b); }
static ResultType process(A a, B b, NullMap::value_type * m) { return Op::template apply<ResultType>(a, b, m); }
static ResultType process(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr) { return Op::template apply<ResultType>(a, b, m); }
private:
template <OpCase op_case, bool nullable>
static void apply(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t i, NullMap::value_type * m = nullptr)
template <OpCase op_case>
static void apply(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t i)
{
if constexpr (nullable)
{
if constexpr (op_case == OpCase::Vector)
c[i] = Op::template apply<ResultType>(a[i], b[i], m);
else
c[i] = Op::template apply<ResultType>(*a, b[i], m);
}
if constexpr (op_case == OpCase::Vector)
c[i] = Op::template apply<ResultType>(a[i], b[i]);
else
{
if constexpr (op_case == OpCase::Vector)
c[i] = Op::template apply<ResultType>(a[i], b[i]);
else
c[i] = Op::template apply<ResultType>(*a, b[i]);
}
c[i] = Op::template apply<ResultType>(*a, b[i]);
}
};
@ -1761,7 +1751,7 @@ public:
else
type_res = std::make_shared<ResultDataType>();
if (is_divide_or_null || is_modulo_or_null)
if constexpr (is_divide_or_null || is_modulo_or_null)
type_res = std::make_shared<DataTypeNullable>(type_res);
return true;
@ -2241,14 +2231,6 @@ ColumnPtr executeStringInteger(const ColumnsWithTypeAndName & arguments, const A
return executeTupleNumberOperator(arguments, result_type, input_rows_count, function_builder);
}
/// Result can be nullable enven if input arguments are not nullable
if (is_divide_or_null || is_modulo_or_null)
{
NullMap res_null_map(input_rows_count, 0);
auto res = executeImpl2(arguments, result_type, input_rows_count, nullptr, &res_null_map);
return wrapInNullable(res, arguments, result_type, input_rows_count, &res_null_map);
}
return executeImpl2(arguments, result_type, input_rows_count);
}
@ -2266,11 +2248,19 @@ ColumnPtr executeStringInteger(const ColumnsWithTypeAndName & arguments, const A
bool is_const = checkColumnConst<ColumnNullable>(right_argument.column.get());
const ColumnNullable * nullable_column = is_const ? checkAndGetColumnConstData<ColumnNullable>(right_argument.column.get())
: checkAndGetColumn<ColumnNullable>(right_argument.column.get());
//NullMap res_null_map(input_rows_count, 0);
const auto & null_bytemap = nullable_column->getNullMapData();
auto res = executeImpl2(createBlockWithNestedColumns(arguments), removeNullable(result_type), input_rows_count, &null_bytemap, res_nullmap);
const auto & right_null_bytemap = nullable_column->getNullMapData();
NullMap res_null_map(right_null_bytemap.begin(), right_null_bytemap.end());
auto res = executeImpl2(createBlockWithNestedColumns(arguments), removeNullable(result_type), input_rows_count, &right_null_bytemap, &res_null_map);
return wrapInNullable(res, arguments, result_type, input_rows_count, res_nullmap);
}
/// Process special case when operation is divideOrNull and moduloOrNull
else if ((is_divide_or_null || is_modulo_or_null) && !res_nullmap)
{
std::cerr << "gethere 1" << std::endl;
NullMap res_null_map(input_rows_count, 0);
auto res = executeImpl2(arguments, result_type, input_rows_count, nullptr, &res_null_map);
return wrapInNullable(res, arguments, result_type, input_rows_count, &res_null_map);
}
/// Special case - one or both arguments are IPv4
if (isIPv4(arguments[0].type) || isIPv4(arguments[1].type))

View File

@ -1,36 +1,120 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include <Common/Exception.h>
#include <libdivide.h>
namespace DB
{
template <typename A, typename B>
struct ModuloOrNullImpl
: BinaryOperation<A, B, ModuloImpl<A, B>>
{
using ResultType = typename NumberTraits::ResultOfModulo<A, B>::Type;
using Op = ModuloImpl<A, B>;
using ResultType = typename Op::ResultType;
static const constexpr bool allow_fixed_string = false;
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply(A a, B b, NullMap::value_type * m = nullptr)
template <OpCase op_case>
static void NO_INLINE process(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t size, const NullMap * right_nullmap, NullMap * res_nullmap)
{
if constexpr (std::is_floating_point_v<ResultType>)
chassert(res_nullmap);
if constexpr (op_case == OpCase::RightConstant)
{
/// This computation is similar to `fmod` but the latter is not inlined and has 40 times worse performance.
return ResultType(a) - trunc(ResultType(a) / ResultType(b)) * ResultType(b);
if (right_nullmap && (*right_nullmap)[0])
return;
vectorConstant(a, *b, c, size, res_nullmap);
}
else
{
if (unlikely(divisionLeadsToFPE(a, b)))
for (size_t i = 0; i < size; ++i)
if ((*res_nullmap)[i])
c[i] = ResultType();
else
apply<op_case>(a, b, c, i, &((*res_nullmap)[i]));
}
}
static void NO_INLINE NO_SANITIZE_UNDEFINED vectorConstant(const A * __restrict src, B b, ResultType * __restrict dst, size_t size, NullMap * res_nullmap)
{
/// Modulo with too small divisor.
if (unlikely((std::is_signed_v<B> && b == -1) || b == 1))
{
for (size_t i = 0; i < size; ++i)
dst[i] = 0;
return;
}
/// Modulo with too large divisor.
if (unlikely(b > std::numeric_limits<A>::max()
|| (std::is_signed_v<A> && std::is_signed_v<B> && b < std::numeric_limits<A>::lowest())))
{
for (size_t i = 0; i < size; ++i)
dst[i] = static_cast<ResultType>(src[i]);
return;
}
/// Set result to NULL if divide by zero or too large divisor.
if (unlikely(static_cast<A>(b) == 0 || std::is_signed_v<B> && b == std::numeric_limits<B>::lowest()))
{
for (size_t i = 0; i < size; ++i)
(*res_nullmap)[i] = 1;
return;
}
/// Modulo of division by negative number is the same as the positive number.
if (b < 0)
b = -b;
/// Here we failed to make the SSE variant from libdivide give an advantage.
if (b & (b - 1))
{
libdivide::divider<A> divider(static_cast<A>(b));
for (size_t i = 0; i < size; ++i)
{
if (m)
*m = 1;
return Result();
/// NOTE: perhaps, the division semantics with the remainder of negative numbers is not preserved.
dst[i] = static_cast<ResultType>(src[i] - (src[i] / divider) * b);
}
}
else
{
// gcc libdivide doesn't work well for pow2 division
auto mask = b - 1;
for (size_t i = 0; i < size; ++i)
dst[i] = static_cast<ResultType>(src[i] & mask);
}
}
return ModuloImpl<A, B>::template apply<Result>(a, b);
static ResultType process(A a, B b, NullMap::value_type * m)
{
ResultType res;
try
{
res = Op::template apply<ResultType>(a, b);
}
catch (const std::exception&)
{
if (m)
*m = 1;
}
return res;
}
private:
template <OpCase op_case>
static void apply(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t i, NullMap::value_type * m)
{
try
{
if constexpr (op_case == OpCase::Vector)
c[i] = Op::template apply<ResultType>(a[i], b[i]);
else
c[i] = Op::template apply<ResultType>(*a, b[i]);
}
catch (const std::exception&)
{
*m = 1;
}
}
@ -39,6 +123,30 @@ struct ModuloOrNullImpl
#endif
};
namespace impl_
{
template <> struct BinaryOperationImpl<UInt64, UInt8, ModuloImpl<UInt64, UInt8>> : ModuloOrNullImpl<UInt64, UInt8> {};
template <> struct BinaryOperationImpl<UInt64, UInt16, ModuloImpl<UInt64, UInt16>> : ModuloOrNullImpl<UInt64, UInt16> {};
template <> struct BinaryOperationImpl<UInt64, UInt32, ModuloImpl<UInt64, UInt32>> : ModuloOrNullImpl<UInt64, UInt32> {};
template <> struct BinaryOperationImpl<UInt64, UInt64, ModuloImpl<UInt64, UInt64>> : ModuloOrNullImpl<UInt64, UInt64> {};
template <> struct BinaryOperationImpl<UInt32, UInt8, ModuloImpl<UInt32, UInt8>> : ModuloOrNullImpl<UInt32, UInt8> {};
template <> struct BinaryOperationImpl<UInt32, UInt16, ModuloImpl<UInt32, UInt16>> : ModuloOrNullImpl<UInt32, UInt16> {};
template <> struct BinaryOperationImpl<UInt32, UInt32, ModuloImpl<UInt32, UInt32>> : ModuloOrNullImpl<UInt32, UInt32> {};
template <> struct BinaryOperationImpl<UInt32, UInt64, ModuloImpl<UInt32, UInt64>> : ModuloOrNullImpl<UInt32, UInt64> {};
template <> struct BinaryOperationImpl<Int64, Int8, ModuloImpl<Int64, Int8>> : ModuloOrNullImpl<Int64, Int8> {};
template <> struct BinaryOperationImpl<Int64, Int16, ModuloImpl<Int64, Int16>> : ModuloOrNullImpl<Int64, Int16> {};
template <> struct BinaryOperationImpl<Int64, Int32, ModuloImpl<Int64, Int32>> : ModuloOrNullImpl<Int64, Int32> {};
template <> struct BinaryOperationImpl<Int64, Int64, ModuloImpl<Int64, Int64>> : ModuloOrNullImpl<Int64, Int64> {};
template <> struct BinaryOperationImpl<Int32, Int8, ModuloImpl<Int32, Int8>> : ModuloOrNullImpl<Int32, Int8> {};
template <> struct BinaryOperationImpl<Int32, Int16, ModuloImpl<Int32, Int16>> : ModuloOrNullImpl<Int32, Int16> {};
template <> struct BinaryOperationImpl<Int32, Int32, ModuloImpl<Int32, Int32>> : ModuloOrNullImpl<Int32, Int32> {};
template <> struct BinaryOperationImpl<Int32, Int64, ModuloImpl<Int32, Int64>> : ModuloOrNullImpl<Int32, Int64> {};
template <typename A, typename B> struct BinaryOperationImpl<A, B, ModuloImpl<A, B>> : ModuloOrNullImpl<A, B> {};
}
struct NameModuloOrNull { static constexpr auto name = "moduloOrNull"; };
using FunctionModuloOrNull = BinaryArithmeticOverloadResolver<ModuloOrNullImpl, NameModuloOrNull>;

View File

@ -1,7 +1,7 @@
\N
0
\N
\N
0
0
0
10
49