Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions cpp/src/arrow/compute/api_scalar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ SCALAR_ARITHMETIC_BINARY(Multiply, "multiply", "multiply_checked")
SCALAR_ARITHMETIC_BINARY(Divide, "divide", "divide_checked")
SCALAR_ARITHMETIC_BINARY(Power, "power", "power_checked")

Result<Datum> ElementWiseMax(const std::vector<Datum>& args,
ElementWiseAggregateOptions options, ExecContext* ctx) {
return CallFunction("element_wise_max", args, &options, ctx);
}

Result<Datum> ElementWiseMin(const std::vector<Datum>& args,
ElementWiseAggregateOptions options, ExecContext* ctx) {
return CallFunction("element_wise_min", args, &options, ctx);
}

// ----------------------------------------------------------------------
// Set-related operations

Expand Down
29 changes: 29 additions & 0 deletions cpp/src/arrow/compute/api_scalar.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ struct ArithmeticOptions : public FunctionOptions {
bool check_overflow;
};

struct ARROW_EXPORT ElementWiseAggregateOptions : public FunctionOptions {
ElementWiseAggregateOptions() : skip_nulls(true) {}
bool skip_nulls;
};

struct ARROW_EXPORT MatchSubstringOptions : public FunctionOptions {
explicit MatchSubstringOptions(std::string pattern, bool ignore_case = false)
: pattern(std::move(pattern)), ignore_case(ignore_case) {}
Expand Down Expand Up @@ -253,6 +258,30 @@ Result<Datum> Power(const Datum& left, const Datum& right,
ArithmeticOptions options = ArithmeticOptions(),
ExecContext* ctx = NULLPTR);

/// \brief Find the element-wise maximum of any number of arrays or scalars.
/// Array values must be the same length.
///
/// \param[in] args arrays or scalars to operate on.
/// \param[in] options options for handling nulls, optional
/// \param[in] ctx the function execution context, optional
/// \return the element-wise maximum
ARROW_EXPORT
Result<Datum> ElementWiseMax(const std::vector<Datum>& args,
ElementWiseAggregateOptions options = {},
ExecContext* ctx = NULLPTR);

/// \brief Find the element-wise minimum of any number of arrays or scalars.
/// Array values must be the same length.
///
/// \param[in] args arrays or scalars to operate on.
/// \param[in] options options for handling nulls, optional
/// \param[in] ctx the function execution context, optional
/// \return the element-wise minimum
ARROW_EXPORT
Result<Datum> ElementWiseMin(const std::vector<Datum>& args,
ElementWiseAggregateOptions options = {},
ExecContext* ctx = NULLPTR);

/// \brief Compare a numeric array with a scalar.
///
/// \param[in] left datum to compare, must be an Array
Expand Down
43 changes: 41 additions & 2 deletions cpp/src/arrow/compute/kernels/codegen_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,12 @@ struct BoxScalar;
template <typename Type>
struct BoxScalar<Type, enable_if_has_c_type<Type>> {
using T = typename GetOutputType<Type>::T;
using ScalarType = typename TypeTraits<Type>::ScalarType;
static void Box(T val, Scalar* out) { checked_cast<ScalarType*>(out)->value = val; }
static void Box(T val, Scalar* out) {
// Enables BoxScalar<Int64Type> to work on a (for example) Time64Scalar
T* mutable_data = reinterpret_cast<T*>(
checked_cast<::arrow::internal::PrimitiveScalarBase*>(out)->mutable_data());
*mutable_data = val;
}
};

template <typename Type>
Expand Down Expand Up @@ -1093,6 +1097,41 @@ ArrayKernelExec GeneratePhysicalInteger(detail::GetTypeId get_id) {
}
}

template <template <typename... Args> class Generator, typename... Args>
ArrayKernelExec GeneratePhysicalNumeric(detail::GetTypeId get_id) {
switch (get_id.id) {
case Type::INT8:
return Generator<Int8Type, Args...>::Exec;
case Type::INT16:
return Generator<Int16Type, Args...>::Exec;
case Type::INT32:
case Type::DATE32:
case Type::TIME32:
return Generator<Int32Type, Args...>::Exec;
case Type::INT64:
case Type::DATE64:
case Type::TIMESTAMP:
case Type::TIME64:
case Type::DURATION:
return Generator<Int64Type, Args...>::Exec;
case Type::UINT8:
return Generator<UInt8Type, Args...>::Exec;
case Type::UINT16:
return Generator<UInt16Type, Args...>::Exec;
case Type::UINT32:
return Generator<UInt32Type, Args...>::Exec;
case Type::UINT64:
return Generator<UInt64Type, Args...>::Exec;
case Type::FLOAT:
return Generator<FloatType, Args...>::Exec;
case Type::DOUBLE:
return Generator<DoubleType, Args...>::Exec;
default:
DCHECK(false);
return ExecFail;
}
}

// Generate a kernel given a templated functor for integer types
//
// See "Numeric" above for description of the generator functor
Expand Down
56 changes: 28 additions & 28 deletions cpp/src/arrow/compute/kernels/scalar_boolean.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ inline Bitmap GetBitmap(const ArrayData& arr, int index) {
return Bitmap{arr.buffers[index], arr.offset, arr.length};
}

struct Invert {
struct InvertOp {
static Status Call(KernelContext* ctx, const Scalar& in, Scalar* out) {
*checked_cast<BooleanScalar*>(out) = InvertScalar(in);
return Status::OK();
Expand All @@ -115,8 +115,8 @@ struct Commutative {
}
};

struct And : Commutative<And> {
using Commutative<And>::Call;
struct AndOp : Commutative<AndOp> {
using Commutative<AndOp>::Call;

static Status Call(KernelContext* ctx, const Scalar& left, const Scalar& right,
Scalar* out) {
Expand Down Expand Up @@ -147,8 +147,8 @@ struct And : Commutative<And> {
}
};

struct KleeneAnd : Commutative<KleeneAnd> {
using Commutative<KleeneAnd>::Call;
struct KleeneAndOp : Commutative<KleeneAndOp> {
using Commutative<KleeneAndOp>::Call;

static Status Call(KernelContext* ctx, const Scalar& left, const Scalar& right,
Scalar* out) {
Expand Down Expand Up @@ -205,7 +205,7 @@ struct KleeneAnd : Commutative<KleeneAnd> {
if (left.GetNullCount() == 0 && right.GetNullCount() == 0) {
out->null_count = 0;
out->buffers[0] = nullptr;
return And::Call(ctx, left, right, out);
return AndOp::Call(ctx, left, right, out);
}
auto compute_word = [](uint64_t left_true, uint64_t left_false, uint64_t right_true,
uint64_t right_false, uint64_t* out_valid,
Expand All @@ -218,8 +218,8 @@ struct KleeneAnd : Commutative<KleeneAnd> {
}
};

struct Or : Commutative<Or> {
using Commutative<Or>::Call;
struct OrOp : Commutative<OrOp> {
using Commutative<OrOp>::Call;

static Status Call(KernelContext* ctx, const Scalar& left, const Scalar& right,
Scalar* out) {
Expand Down Expand Up @@ -250,8 +250,8 @@ struct Or : Commutative<Or> {
}
};

struct KleeneOr : Commutative<KleeneOr> {
using Commutative<KleeneOr>::Call;
struct KleeneOrOp : Commutative<KleeneOrOp> {
using Commutative<KleeneOrOp>::Call;

static Status Call(KernelContext* ctx, const Scalar& left, const Scalar& right,
Scalar* out) {
Expand Down Expand Up @@ -308,7 +308,7 @@ struct KleeneOr : Commutative<KleeneOr> {
if (left.GetNullCount() == 0 && right.GetNullCount() == 0) {
out->null_count = 0;
out->buffers[0] = nullptr;
return Or::Call(ctx, left, right, out);
return OrOp::Call(ctx, left, right, out);
}

static auto compute_word = [](uint64_t left_true, uint64_t left_false,
Expand All @@ -323,8 +323,8 @@ struct KleeneOr : Commutative<KleeneOr> {
}
};

struct Xor : Commutative<Xor> {
using Commutative<Xor>::Call;
struct XorOp : Commutative<XorOp> {
using Commutative<XorOp>::Call;

static Status Call(KernelContext* ctx, const Scalar& left, const Scalar& right,
Scalar* out) {
Expand Down Expand Up @@ -355,10 +355,10 @@ struct Xor : Commutative<Xor> {
}
};

struct AndNot {
struct AndNotOp {
static Status Call(KernelContext* ctx, const Scalar& left, const Scalar& right,
Scalar* out) {
return And::Call(ctx, left, InvertScalar(right), out);
return AndOp::Call(ctx, left, InvertScalar(right), out);
}

static Status Call(KernelContext* ctx, const Scalar& left, const ArrayData& right,
Expand All @@ -373,7 +373,7 @@ struct AndNot {

static Status Call(KernelContext* ctx, const ArrayData& left, const Scalar& right,
ArrayData* out) {
return And::Call(ctx, left, InvertScalar(right), out);
return AndOp::Call(ctx, left, InvertScalar(right), out);
}

static Status Call(KernelContext* ctx, const ArrayData& left, const ArrayData& right,
Expand All @@ -385,10 +385,10 @@ struct AndNot {
}
};

struct KleeneAndNot {
struct KleeneAndNotOp {
static Status Call(KernelContext* ctx, const Scalar& left, const Scalar& right,
Scalar* out) {
return KleeneAnd::Call(ctx, left, InvertScalar(right), out);
return KleeneAndOp::Call(ctx, left, InvertScalar(right), out);
}

static Status Call(KernelContext* ctx, const Scalar& left, const ArrayData& right,
Expand Down Expand Up @@ -430,15 +430,15 @@ struct KleeneAndNot {

static Status Call(KernelContext* ctx, const ArrayData& left, const Scalar& right,
ArrayData* out) {
return KleeneAnd::Call(ctx, left, InvertScalar(right), out);
return KleeneAndOp::Call(ctx, left, InvertScalar(right), out);
}

static Status Call(KernelContext* ctx, const ArrayData& left, const ArrayData& right,
ArrayData* out) {
if (left.GetNullCount() == 0 && right.GetNullCount() == 0) {
out->null_count = 0;
out->buffers[0] = nullptr;
return AndNot::Call(ctx, left, right, out);
return AndNotOp::Call(ctx, left, right, out);
}

static auto compute_word = [](uint64_t left_true, uint64_t left_false,
Expand Down Expand Up @@ -543,20 +543,20 @@ namespace internal {

void RegisterScalarBoolean(FunctionRegistry* registry) {
// These functions can write into sliced output bitmaps
MakeFunction("invert", 1, applicator::SimpleUnary<Invert>, &invert_doc, registry);
MakeFunction("and", 2, applicator::SimpleBinary<And>, &and_doc, registry);
MakeFunction("and_not", 2, applicator::SimpleBinary<AndNot>, &and_not_doc, registry);
MakeFunction("or", 2, applicator::SimpleBinary<Or>, &or_doc, registry);
MakeFunction("xor", 2, applicator::SimpleBinary<Xor>, &xor_doc, registry);
MakeFunction("invert", 1, applicator::SimpleUnary<InvertOp>, &invert_doc, registry);
MakeFunction("and", 2, applicator::SimpleBinary<AndOp>, &and_doc, registry);
MakeFunction("and_not", 2, applicator::SimpleBinary<AndNotOp>, &and_not_doc, registry);
MakeFunction("or", 2, applicator::SimpleBinary<OrOp>, &or_doc, registry);
MakeFunction("xor", 2, applicator::SimpleBinary<XorOp>, &xor_doc, registry);

// The Kleene logic kernels cannot write into sliced output bitmaps
MakeFunction("and_kleene", 2, applicator::SimpleBinary<KleeneAnd>, &and_kleene_doc,
MakeFunction("and_kleene", 2, applicator::SimpleBinary<KleeneAndOp>, &and_kleene_doc,
registry,
/*can_write_into_slices=*/false, NullHandling::COMPUTED_PREALLOCATE);
MakeFunction("and_not_kleene", 2, applicator::SimpleBinary<KleeneAndNot>,
MakeFunction("and_not_kleene", 2, applicator::SimpleBinary<KleeneAndNotOp>,
&and_not_kleene_doc, registry,
/*can_write_into_slices=*/false, NullHandling::COMPUTED_PREALLOCATE);
MakeFunction("or_kleene", 2, applicator::SimpleBinary<KleeneOr>, &or_kleene_doc,
MakeFunction("or_kleene", 2, applicator::SimpleBinary<KleeneOrOp>, &or_kleene_doc,
registry,
/*can_write_into_slices=*/false, NullHandling::COMPUTED_PREALLOCATE);
}
Expand Down
Loading