From 536664625b54592ffdf851823ff4ee25e6daa4a0 Mon Sep 17 00:00:00 2001 From: Eduardo Ponce Date: Tue, 27 Apr 2021 14:19:34 -0400 Subject: [PATCH 1/6] add unary arithmetic support and Negate compute kernel --- cpp/src/arrow/compute/api_scalar.cc | 8 + cpp/src/arrow/compute/api_scalar.h | 11 + .../compute/kernels/scalar_arithmetic.cc | 118 ++++++++- .../compute/kernels/scalar_arithmetic_test.cc | 236 ++++++++++++++++++ cpp/src/arrow/util/int_util_internal.h | 28 +++ docs/source/cpp/compute.rst | 20 +- 6 files changed, 402 insertions(+), 19 deletions(-) diff --git a/cpp/src/arrow/compute/api_scalar.cc b/cpp/src/arrow/compute/api_scalar.cc index d169fd2ebde..c7c049af980 100644 --- a/cpp/src/arrow/compute/api_scalar.cc +++ b/cpp/src/arrow/compute/api_scalar.cc @@ -41,6 +41,14 @@ namespace compute { // ---------------------------------------------------------------------- // Arithmetic +#define SCALAR_ARITHMETIC_UNARY(NAME, REGISTRY_NAME, REGISTRY_CHECKED_NAME) \ + Result NAME(const Datum& arg, ArithmeticOptions options, ExecContext* ctx) { \ + auto func_name = (options.check_overflow) ? REGISTRY_CHECKED_NAME : REGISTRY_NAME; \ + return CallFunction(func_name, {arg}, ctx); \ + } + +SCALAR_ARITHMETIC_UNARY(Negate, "negate", "negate_checked") + #define SCALAR_ARITHMETIC_BINARY(NAME, REGISTRY_NAME, REGISTRY_CHECKED_NAME) \ Result NAME(const Datum& left, const Datum& right, ArithmeticOptions options, \ ExecContext* ctx) { \ diff --git a/cpp/src/arrow/compute/api_scalar.h b/cpp/src/arrow/compute/api_scalar.h index 53892ff6b3c..3e390df47e7 100644 --- a/cpp/src/arrow/compute/api_scalar.h +++ b/cpp/src/arrow/compute/api_scalar.h @@ -213,6 +213,17 @@ Result Divide(const Datum& left, const Datum& right, ArithmeticOptions options = ArithmeticOptions(), ExecContext* ctx = NULLPTR); +/// \brief Negate a value. Array values can be of arbitrary length. If argument +/// is null the result will be null. +/// +/// \param[in] arg the value negated +/// \param[in] options arithmetic options (overflow handling), optional +/// \param[in] ctx the function execution context, optional +/// \return the elementwise negation +ARROW_EXPORT +Result Negate(const Datum& arg, ArithmeticOptions options = ArithmeticOptions(), + ExecContext* ctx = NULLPTR); + /// \brief Raise the values of base array to the power of the exponent array values. /// Array values must be the same length. If either base or exponent is null the result /// will be null. diff --git a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc index 7b9b23e7ff8..f6f7555ab61 100644 --- a/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc +++ b/cpp/src/arrow/compute/kernels/scalar_arithmetic.cc @@ -18,6 +18,7 @@ #include #include "arrow/compute/kernels/common.h" +#include "arrow/type_traits.h" #include "arrow/util/int_util_internal.h" #include "arrow/util/macros.h" @@ -26,6 +27,7 @@ namespace arrow { using internal::AddWithOverflow; using internal::DivideWithOverflow; using internal::MultiplyWithOverflow; +using internal::NegateWithOverflow; using internal::SubtractWithOverflow; namespace compute { @@ -33,6 +35,8 @@ namespace internal { using applicator::ScalarBinaryEqualTypes; using applicator::ScalarBinaryNotNullEqualTypes; +using applicator::ScalarUnary; +using applicator::ScalarUnaryNotNull; namespace { @@ -246,6 +250,49 @@ struct DivideChecked { } }; +struct Negate { + template + static constexpr enable_if_floating_point Call(KernelContext*, Arg arg, Status*) { + return -arg; + } + + template + static constexpr enable_if_unsigned_integer Call(KernelContext*, Arg arg, Status*) { + return ~arg + 1; + } + + template + static constexpr enable_if_signed_integer Call(KernelContext*, Arg arg, Status* st) { + return arrow::internal::SafeSignedNegate(arg); + } +}; + +struct NegateChecked { + template + static enable_if_signed_integer Call(KernelContext*, Arg arg, Status* st) { + static_assert(std::is_same::value, ""); + T result = 0; + if (ARROW_PREDICT_FALSE(NegateWithOverflow(arg, &result))) { + *st = Status::Invalid("overflow"); + } + return result; + } + + template + static enable_if_unsigned_integer Call(KernelContext* ctx, Arg arg, Status* st) { + static_assert(std::is_same::value, ""); + DCHECK(false) << "This is included only for the purposes of instantiability from the " + "arithmetic kernel generator"; + return 0; + } + + template + static constexpr enable_if_floating_point Call(KernelContext*, Arg arg, Status* st) { + static_assert(std::is_same::value, ""); + return -arg; + } +}; + struct Power { ARROW_NOINLINE static uint64_t IntegerPower(uint64_t base, uint64_t exp) { @@ -310,7 +357,7 @@ struct PowerChecked { // Generate a kernel given an arithmetic functor template