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;
 };

Reply via email to