#pragma once #include #include #include #include #include #include #include #include "config.h" /** FastOps is a fast vector math library from Mikhail Parakhin, https://www.linkedin.com/in/mikhail-parakhin/ * Enabled by default. */ #if USE_FASTOPS # include #endif namespace DB { namespace ErrorCodes { extern const int ILLEGAL_TYPE_OF_ARGUMENT; extern const int ILLEGAL_COLUMN; } template class FunctionMathUnary : public IFunction { public: static constexpr auto name = Impl::name; static FunctionPtr create(ContextPtr) { return std::make_shared(); } private: String getName() const override { return name; } size_t getNumberOfArguments() const override { return 1; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { const auto & argument = arguments.front(); if (!isNumber(argument)) throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Illegal type {} of argument of function {}", argument->getName(), getName()); /// Integers are converted to Float64. if (Impl::always_returns_float64 || !isFloat(argument)) return std::make_shared(); else return argument; } template static void executeInIterations(const T * src_data, ReturnType * dst_data, size_t size) { if constexpr (Impl::rows_per_iteration == 0) { /// Process all data as a whole and use FastOps implementation /// If the argument is integer, convert to Float64 beforehand if constexpr (!std::is_floating_point_v) { PODArray tmp_vec(size); for (size_t i = 0; i < size; ++i) tmp_vec[i] = static_cast(src_data[i]); Impl::execute(tmp_vec.data(), size, dst_data); } else { Impl::execute(src_data, size, dst_data); } } else { const size_t rows_remaining = size % Impl::rows_per_iteration; const size_t rows_size = size - rows_remaining; for (size_t i = 0; i < rows_size; i += Impl::rows_per_iteration) Impl::execute(&src_data[i], &dst_data[i]); if (rows_remaining != 0) { T src_remaining[Impl::rows_per_iteration]; memcpy(src_remaining, &src_data[rows_size], rows_remaining * sizeof(T)); memset(src_remaining + rows_remaining, 0, (Impl::rows_per_iteration - rows_remaining) * sizeof(T)); ReturnType dst_remaining[Impl::rows_per_iteration]; Impl::execute(src_remaining, dst_remaining); if constexpr (is_big_int_v || std::is_same_v) for (size_t i = 0; i < rows_remaining; ++i) dst_data[rows_size + i] = dst_remaining[i]; else memcpy(&dst_data[rows_size], dst_remaining, rows_remaining * sizeof(ReturnType)); } } } template static ColumnPtr execute(const ColumnVector * col) { const auto & src_data = col->getData(); const size_t size = src_data.size(); auto dst = ColumnVector::create(); auto & dst_data = dst->getData(); dst_data.resize(size); executeInIterations(src_data.data(), dst_data.data(), size); return dst; } template static ColumnPtr execute(const ColumnDecimal * col) { const auto & src_data = col->getData(); const size_t size = src_data.size(); UInt32 scale = col->getScale(); auto dst = ColumnVector::create(); auto & dst_data = dst->getData(); dst_data.resize(size); for (size_t i = 0; i < size; ++i) dst_data[i] = DecimalUtils::convertTo(src_data[i], scale); executeInIterations(dst_data.data(), dst_data.data(), size); return dst; } bool useDefaultImplementationForConstants() const override { return true; } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override { const ColumnWithTypeAndName & col = arguments[0]; ColumnPtr res; auto call = [&](const auto & types) -> bool { using Types = std::decay_t; using Type = typename Types::RightType; using ReturnType = std::conditional_t, Float64, Type>; using ColVecType = ColumnVectorOrDecimal; const auto col_vec = checkAndGetColumn(col.column.get()); return (res = execute(col_vec)) != nullptr; }; if (!callOnBasicType(col.type->getTypeId(), call)) throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}", col.column->getName(), getName()); return res; } }; template struct UnaryFunctionVectorized { static constexpr auto name = Name::name; static constexpr auto rows_per_iteration = 1; static constexpr bool always_returns_float64 = true; template static void execute(const T * __restrict src, Float64 * __restrict dst) { *dst = Function(static_cast(*src)); } }; }