This is an automated email from the ASF dual-hosted git repository.
wesm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/master by this push:
new d64891c ARROW-9254: [C++] Split out CastNumberToNumberUnsafe function
from scalar_cast_numeric, add data()/mutable_data() functions for accessing
primitive scalar data opaquely
d64891c is described below
commit d64891c6ace09651b703aaee3c7a5eb004124106
Author: Wes McKinney <[email protected]>
AuthorDate: Sun Jun 28 17:24:08 2020 -0500
ARROW-9254: [C++] Split out CastNumberToNumberUnsafe function from
scalar_cast_numeric, add data()/mutable_data() functions for accessing
primitive scalar data opaquely
This is some preparatory work for ARROW-9196. I also addressed some prior
uncleanliness related to unboxing temporal scalars based on C types. By adding
these `data()` and `mutable_data()` functions we can obtain a pointer e.g. to
the `int64_t` stored in the scalar. Previously I was resorting to some slightly
hacky inheritance tricks -- this seems better.
Closes #7561 from wesm/ARROW-9254
Authored-by: Wes McKinney <[email protected]>
Signed-off-by: Wes McKinney <[email protected]>
---
cpp/src/arrow/compute/kernels/codegen_internal.h | 7 +-
.../arrow/compute/kernels/scalar_cast_internal.cc | 124 ++++++++++++++++++++
.../arrow/compute/kernels/scalar_cast_internal.h | 4 +
.../arrow/compute/kernels/scalar_cast_numeric.cc | 130 +--------------------
cpp/src/arrow/scalar.h | 26 +++--
5 files changed, 152 insertions(+), 139 deletions(-)
diff --git a/cpp/src/arrow/compute/kernels/codegen_internal.h
b/cpp/src/arrow/compute/kernels/codegen_internal.h
index 796d96b..a33544e 100644
--- a/cpp/src/arrow/compute/kernels/codegen_internal.h
+++ b/cpp/src/arrow/compute/kernels/codegen_internal.h
@@ -169,9 +169,10 @@ struct UnboxScalar;
template <typename Type>
struct UnboxScalar<Type, enable_if_has_c_type<Type>> {
- using ScalarType = ::arrow::internal::PrimitiveScalar<typename
Type::PhysicalType>;
- static typename Type::c_type Unbox(const Scalar& val) {
- return checked_cast<const ScalarType&>(val).value;
+ using T = typename Type::c_type;
+ static T Unbox(const Scalar& val) {
+ return *reinterpret_cast<const T*>(
+ checked_cast<const
::arrow::internal::PrimitiveScalarBase&>(val).data());
}
};
diff --git a/cpp/src/arrow/compute/kernels/scalar_cast_internal.cc
b/cpp/src/arrow/compute/kernels/scalar_cast_internal.cc
index bdb27ac..cd33de6 100644
--- a/cpp/src/arrow/compute/kernels/scalar_cast_internal.cc
+++ b/cpp/src/arrow/compute/kernels/scalar_cast_internal.cc
@@ -21,9 +21,133 @@
#include "arrow/extension_type.h"
namespace arrow {
+
+using internal::PrimitiveScalarBase;
+
namespace compute {
namespace internal {
+// ----------------------------------------------------------------------
+
+template <typename OutT, typename InT>
+ARROW_DISABLE_UBSAN("float-cast-overflow")
+void DoStaticCast(const void* in_data, int64_t in_offset, int64_t length,
+ int64_t out_offset, void* out_data) {
+ auto in = reinterpret_cast<const InT*>(in_data) + in_offset;
+ auto out = reinterpret_cast<OutT*>(out_data) + out_offset;
+ for (int64_t i = 0; i < length; ++i) {
+ *out++ = static_cast<OutT>(*in++);
+ }
+}
+
+using StaticCastFunc = std::function<void(const void*, int64_t, int64_t,
int64_t, void*)>;
+
+template <typename OutType, typename InType, typename Enable = void>
+struct CastPrimitive {
+ static void Exec(const Datum& input, Datum* out) {
+ using OutT = typename OutType::c_type;
+ using InT = typename InType::c_type;
+
+ StaticCastFunc caster = DoStaticCast<OutT, InT>;
+ if (input.kind() == Datum::ARRAY) {
+ const ArrayData& arr = *input.array();
+ ArrayData* out_arr = out->mutable_array();
+ caster(arr.buffers[1]->data(), arr.offset, arr.length, out_arr->offset,
+ out_arr->buffers[1]->mutable_data());
+ } else {
+ // Scalar path. Use the caster with length 1 to place the casted value
into
+ // the output
+ const auto& in_scalar = input.scalar_as<PrimitiveScalarBase>();
+ auto out_scalar =
checked_cast<PrimitiveScalarBase*>(out->scalar().get());
+ caster(in_scalar.data(), /*in_offset=*/0, /*length=*/1, /*out_offset=*/0,
+ out_scalar->mutable_data());
+ }
+ }
+};
+
+template <typename OutType, typename InType>
+struct CastPrimitive<OutType, InType, enable_if_t<std::is_same<OutType,
InType>::value>> {
+ // memcpy output
+ static void Exec(const Datum& input, Datum* out) {
+ using T = typename InType::c_type;
+
+ if (input.kind() == Datum::ARRAY) {
+ const ArrayData& arr = *input.array();
+ ArrayData* out_arr = out->mutable_array();
+ std::memcpy(
+ reinterpret_cast<T*>(out_arr->buffers[1]->mutable_data()) +
out_arr->offset,
+ reinterpret_cast<const T*>(arr.buffers[1]->data()) + arr.offset,
+ arr.length * sizeof(T));
+ } else {
+ // Scalar path. Use the caster with length 1 to place the casted value
into
+ // the output
+ const auto& in_scalar = input.scalar_as<PrimitiveScalarBase>();
+ auto out_scalar =
checked_cast<PrimitiveScalarBase*>(out->scalar().get());
+ *reinterpret_cast<T*>(out_scalar->mutable_data()) =
+ *reinterpret_cast<const T*>(in_scalar.data());
+ }
+ }
+};
+
+template <typename InType>
+void CastNumberImpl(Type::type out_type, const Datum& input, Datum* out) {
+ switch (out_type) {
+ case Type::INT8:
+ return CastPrimitive<Int8Type, InType>::Exec(input, out);
+ case Type::INT16:
+ return CastPrimitive<Int16Type, InType>::Exec(input, out);
+ case Type::INT32:
+ return CastPrimitive<Int32Type, InType>::Exec(input, out);
+ case Type::INT64:
+ return CastPrimitive<Int64Type, InType>::Exec(input, out);
+ case Type::UINT8:
+ return CastPrimitive<UInt8Type, InType>::Exec(input, out);
+ case Type::UINT16:
+ return CastPrimitive<UInt16Type, InType>::Exec(input, out);
+ case Type::UINT32:
+ return CastPrimitive<UInt32Type, InType>::Exec(input, out);
+ case Type::UINT64:
+ return CastPrimitive<UInt64Type, InType>::Exec(input, out);
+ case Type::FLOAT:
+ return CastPrimitive<FloatType, InType>::Exec(input, out);
+ case Type::DOUBLE:
+ return CastPrimitive<DoubleType, InType>::Exec(input, out);
+ default:
+ break;
+ }
+}
+
+void CastNumberToNumberUnsafe(Type::type in_type, Type::type out_type, const
Datum& input,
+ Datum* out) {
+ switch (in_type) {
+ case Type::INT8:
+ return CastNumberImpl<Int8Type>(out_type, input, out);
+ case Type::INT16:
+ return CastNumberImpl<Int16Type>(out_type, input, out);
+ case Type::INT32:
+ return CastNumberImpl<Int32Type>(out_type, input, out);
+ case Type::INT64:
+ return CastNumberImpl<Int64Type>(out_type, input, out);
+ case Type::UINT8:
+ return CastNumberImpl<UInt8Type>(out_type, input, out);
+ case Type::UINT16:
+ return CastNumberImpl<UInt16Type>(out_type, input, out);
+ case Type::UINT32:
+ return CastNumberImpl<UInt32Type>(out_type, input, out);
+ case Type::UINT64:
+ return CastNumberImpl<UInt64Type>(out_type, input, out);
+ case Type::FLOAT:
+ return CastNumberImpl<FloatType>(out_type, input, out);
+ case Type::DOUBLE:
+ return CastNumberImpl<DoubleType>(out_type, input, out);
+ default:
+ DCHECK(false);
+ break;
+ }
+}
+
+// ----------------------------------------------------------------------
+
void UnpackDictionary(KernelContext* ctx, const ExecBatch& batch, Datum* out) {
DictionaryArray dict_arr(batch[0].array());
const CastOptions& options = checked_cast<const
CastState&>(*ctx->state()).options;
diff --git a/cpp/src/arrow/compute/kernels/scalar_cast_internal.h
b/cpp/src/arrow/compute/kernels/scalar_cast_internal.h
index a247646..59cff56 100644
--- a/cpp/src/arrow/compute/kernels/scalar_cast_internal.h
+++ b/cpp/src/arrow/compute/kernels/scalar_cast_internal.h
@@ -42,6 +42,10 @@ struct CastFunctor<
void CastFromExtension(KernelContext* ctx, const ExecBatch& batch, Datum* out);
+// Utility for numeric casts
+void CastNumberToNumberUnsafe(Type::type in_type, Type::type out_type, const
Datum& input,
+ Datum* out);
+
// ----------------------------------------------------------------------
// Dictionary to other things
diff --git a/cpp/src/arrow/compute/kernels/scalar_cast_numeric.cc
b/cpp/src/arrow/compute/kernels/scalar_cast_numeric.cc
index 7207fd2..f93bb35 100644
--- a/cpp/src/arrow/compute/kernels/scalar_cast_numeric.cc
+++ b/cpp/src/arrow/compute/kernels/scalar_cast_numeric.cc
@@ -34,134 +34,16 @@ using internal::ParseValue;
namespace compute {
namespace internal {
-template <typename OutT, typename InT>
-ARROW_DISABLE_UBSAN("float-cast-overflow")
-void DoStaticCast(const void* in_data, int64_t in_offset, int64_t length,
- int64_t out_offset, void* out_data) {
- auto in = reinterpret_cast<const InT*>(in_data) + in_offset;
- auto out = reinterpret_cast<OutT*>(out_data) + out_offset;
- for (int64_t i = 0; i < length; ++i) {
- *out++ = static_cast<OutT>(*in++);
- }
-}
-
-using StaticCastFunc = std::function<void(const void*, int64_t, int64_t,
int64_t, void*)>;
-
-template <typename OutType, typename InType, typename Enable = void>
-struct CastPrimitive {
- static void Exec(const ExecBatch& batch, Datum* out) {
- using OutT = typename OutType::c_type;
- using InT = typename InType::c_type;
- using OutScalar = typename TypeTraits<OutType>::ScalarType;
- using InScalar = typename TypeTraits<InType>::ScalarType;
-
- StaticCastFunc caster = DoStaticCast<OutT, InT>;
- if (batch[0].kind() == Datum::ARRAY) {
- const ArrayData& arr = *batch[0].array();
- ArrayData* out_arr = out->mutable_array();
- caster(arr.buffers[1]->data(), arr.offset, arr.length, out_arr->offset,
- out_arr->buffers[1]->mutable_data());
- } else {
- // Scalar path. Use the caster with length 1 to place the casted value
into
- // the output
- const auto& in_scalar = batch[0].scalar_as<InScalar>();
- auto out_scalar = checked_cast<OutScalar*>(out->scalar().get());
- caster(&in_scalar.value, /*in_offset=*/0, /*length=*/1, /*out_offset=*/0,
- &out_scalar->value);
- }
- }
-};
-
-template <typename OutType, typename InType>
-struct CastPrimitive<OutType, InType, enable_if_t<std::is_same<OutType,
InType>::value>> {
- // memcpy output
- static void Exec(const ExecBatch& batch, Datum* out) {
- using T = typename InType::c_type;
- using OutScalar = typename TypeTraits<OutType>::ScalarType;
- using InScalar = typename TypeTraits<InType>::ScalarType;
-
- if (batch[0].kind() == Datum::ARRAY) {
- const ArrayData& arr = *batch[0].array();
- ArrayData* out_arr = out->mutable_array();
- std::memcpy(
- reinterpret_cast<T*>(out_arr->buffers[1]->mutable_data()) +
out_arr->offset,
- reinterpret_cast<const T*>(arr.buffers[1]->data()) + arr.offset,
- arr.length * sizeof(T));
- } else {
- // Scalar path. Use the caster with length 1 to place the casted value
into
- // the output
- const auto& in_scalar = batch[0].scalar_as<InScalar>();
- checked_cast<OutScalar*>(out->scalar().get())->value = in_scalar.value;
- }
- }
-};
-
-template <typename InType>
-void CastNumberImpl(const ExecBatch& batch, Datum* out) {
- switch (out->type()->id()) {
- case Type::INT8:
- return CastPrimitive<Int8Type, InType>::Exec(batch, out);
- case Type::INT16:
- return CastPrimitive<Int16Type, InType>::Exec(batch, out);
- case Type::INT32:
- return CastPrimitive<Int32Type, InType>::Exec(batch, out);
- case Type::INT64:
- return CastPrimitive<Int64Type, InType>::Exec(batch, out);
- case Type::UINT8:
- return CastPrimitive<UInt8Type, InType>::Exec(batch, out);
- case Type::UINT16:
- return CastPrimitive<UInt16Type, InType>::Exec(batch, out);
- case Type::UINT32:
- return CastPrimitive<UInt32Type, InType>::Exec(batch, out);
- case Type::UINT64:
- return CastPrimitive<UInt64Type, InType>::Exec(batch, out);
- case Type::FLOAT:
- return CastPrimitive<FloatType, InType>::Exec(batch, out);
- case Type::DOUBLE:
- return CastPrimitive<DoubleType, InType>::Exec(batch, out);
- default:
- break;
- }
-}
-
-void CastNumberToNumberUnsafe(const ExecBatch& batch, Datum* out) {
- switch (batch[0].type()->id()) {
- case Type::INT8:
- return CastNumberImpl<Int8Type>(batch, out);
- case Type::INT16:
- return CastNumberImpl<Int16Type>(batch, out);
- case Type::INT32:
- return CastNumberImpl<Int32Type>(batch, out);
- case Type::INT64:
- return CastNumberImpl<Int64Type>(batch, out);
- case Type::UINT8:
- return CastNumberImpl<UInt8Type>(batch, out);
- case Type::UINT16:
- return CastNumberImpl<UInt16Type>(batch, out);
- case Type::UINT32:
- return CastNumberImpl<UInt32Type>(batch, out);
- case Type::UINT64:
- return CastNumberImpl<UInt64Type>(batch, out);
- case Type::FLOAT:
- return CastNumberImpl<FloatType>(batch, out);
- case Type::DOUBLE:
- return CastNumberImpl<DoubleType>(batch, out);
- default:
- DCHECK(false);
- break;
- }
-}
-
void CastIntegerToInteger(KernelContext* ctx, const ExecBatch& batch, Datum*
out) {
const auto& options = checked_cast<const CastState*>(ctx->state())->options;
if (!options.allow_int_overflow) {
KERNEL_RETURN_IF_ERROR(ctx, IntegersCanFit(batch[0], *out->type()));
}
- CastNumberToNumberUnsafe(batch, out);
+ CastNumberToNumberUnsafe(batch[0].type()->id(), out->type()->id(), batch[0],
out);
}
void CastFloatingToFloating(KernelContext*, const ExecBatch& batch, Datum*
out) {
- CastNumberToNumberUnsafe(batch, out);
+ CastNumberToNumberUnsafe(batch[0].type()->id(), out->type()->id(), batch[0],
out);
}
// ----------------------------------------------------------------------
@@ -291,7 +173,7 @@ Status CheckFloatToIntTruncation(const Datum& input, const
Datum& output) {
void CastFloatingToInteger(KernelContext* ctx, const ExecBatch& batch, Datum*
out) {
const auto& options = checked_cast<const CastState*>(ctx->state())->options;
- CastNumberToNumberUnsafe(batch, out);
+ CastNumberToNumberUnsafe(batch[0].type()->id(), out->type()->id(), batch[0],
out);
if (!options.allow_float_truncate) {
KERNEL_RETURN_IF_ERROR(ctx, CheckFloatToIntTruncation(batch[0], *out));
}
@@ -369,11 +251,11 @@ Status CheckForIntegerToFloatingTruncation(const Datum&
input, Type::type out_ty
void CastIntegerToFloating(KernelContext* ctx, const ExecBatch& batch, Datum*
out) {
const auto& options = checked_cast<const CastState*>(ctx->state())->options;
+ Type::type out_type = out->type()->id();
if (!options.allow_float_truncate) {
- KERNEL_RETURN_IF_ERROR(
- ctx, CheckForIntegerToFloatingTruncation(batch[0], out->type()->id()));
+ KERNEL_RETURN_IF_ERROR(ctx, CheckForIntegerToFloatingTruncation(batch[0],
out_type));
}
- CastNumberToNumberUnsafe(batch, out);
+ CastNumberToNumberUnsafe(batch[0].type()->id(), out_type, batch[0], out);
}
// ----------------------------------------------------------------------
diff --git a/cpp/src/arrow/scalar.h b/cpp/src/arrow/scalar.h
index b9dc792..48a604c 100644
--- a/cpp/src/arrow/scalar.h
+++ b/cpp/src/arrow/scalar.h
@@ -92,20 +92,29 @@ struct ARROW_EXPORT NullScalar : public Scalar {
namespace internal {
-template <typename T, typename CType = typename T::c_type>
-struct ARROW_EXPORT PrimitiveScalar : public Scalar {
+struct ARROW_EXPORT PrimitiveScalarBase : public Scalar {
using Scalar::Scalar;
+ virtual void* mutable_data() = 0;
+ virtual const void* data() const = 0;
+};
+
+template <typename T, typename CType = typename T::c_type>
+struct ARROW_EXPORT PrimitiveScalar : public PrimitiveScalarBase {
+ using PrimitiveScalarBase::PrimitiveScalarBase;
using TypeClass = T;
using ValueType = CType;
// Non-null constructor.
PrimitiveScalar(ValueType value, std::shared_ptr<DataType> type)
- : Scalar(std::move(type), true), value(value) {}
+ : PrimitiveScalarBase(std::move(type), true), value(value) {}
explicit PrimitiveScalar(std::shared_ptr<DataType> type)
- : Scalar(std::move(type), false) {}
+ : PrimitiveScalarBase(std::move(type), false) {}
ValueType value{};
+
+ void* mutable_data() override { return &value; }
+ const void* data() const override { return &value; }
};
} // namespace internal
@@ -245,15 +254,8 @@ struct ARROW_EXPORT FixedSizeBinaryScalar : public
BinaryScalar {
explicit FixedSizeBinaryScalar(std::shared_ptr<DataType> type) :
BinaryScalar(type) {}
};
-template <typename T, typename PhysicalType = typename T::PhysicalType,
- typename Enable = void>
-struct ARROW_EXPORT TemporalScalar : internal::PrimitiveScalar<PhysicalType> {
- using internal::PrimitiveScalar<PhysicalType>::PrimitiveScalar;
- using TypeClass = T;
-};
-
template <typename T>
-struct ARROW_EXPORT TemporalScalar<T, void, void> :
internal::PrimitiveScalar<T> {
+struct ARROW_EXPORT TemporalScalar : internal::PrimitiveScalar<T> {
using internal::PrimitiveScalar<T>::PrimitiveScalar;
using TypeClass = T;
};