You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by al...@apache.org on 2022/07/27 20:05:29 UTC

[arrow-rs] branch master updated: Use ArrayAccessor and FromIterator in Cast Kernels (#2169)

This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/master by this push:
     new 445283c83 Use ArrayAccessor and FromIterator in Cast Kernels (#2169)
445283c83 is described below

commit 445283c83b547744caf20a65ef0693327fdbed81
Author: Liang-Chi Hsieh <vi...@gmail.com>
AuthorDate: Wed Jul 27 13:05:23 2022 -0700

    Use ArrayAccessor and FromIterator in Cast Kernels (#2169)
    
    * Use ArrayAccessor
    
    * Add to_i128 and to_f64 to ArrowNumericType
    
    * Use AsPrimitive
---
 arrow/src/compute/kernels/cast.rs | 139 +++++++++++++++++++++++---------------
 1 file changed, 83 insertions(+), 56 deletions(-)

diff --git a/arrow/src/compute/kernels/cast.rs b/arrow/src/compute/kernels/cast.rs
index 781f199a6..25aa525b4 100644
--- a/arrow/src/compute/kernels/cast.rs
+++ b/arrow/src/compute/kernels/cast.rs
@@ -38,7 +38,6 @@
 use std::str;
 use std::sync::Arc;
 
-use crate::array::BasicDecimalArray;
 use crate::buffer::MutableBuffer;
 use crate::compute::divide_scalar;
 use crate::compute::kernels::arithmetic::{divide, multiply};
@@ -48,6 +47,7 @@ use crate::datatypes::*;
 use crate::error::{ArrowError, Result};
 use crate::{array::*, compute::take};
 use crate::{buffer::Buffer, util::serialization::lexical_to_string};
+use num::cast::AsPrimitive;
 use num::{NumCast, ToPrimitive};
 
 /// CastOptions provides a way to override the default cast behaviors
@@ -270,45 +270,60 @@ pub fn cast(array: &ArrayRef, to_type: &DataType) -> Result<ArrayRef> {
     cast_with_options(array, to_type, &DEFAULT_CAST_OPTIONS)
 }
 
-// cast the integer array to defined decimal data type array
-macro_rules! cast_integer_to_decimal {
-    ($ARRAY: expr, $ARRAY_TYPE: ident, $PRECISION : ident, $SCALE : ident) => {{
-        let array = $ARRAY.as_any().downcast_ref::<$ARRAY_TYPE>().unwrap();
-        let mul: i128 = 10_i128.pow(*$SCALE as u32);
-        let decimal_array = array
-            .iter()
-            .map(|v| {
-                v.map(|v| {
-                    let v = v as i128;
-                    // with_precision_and_scale validates the
-                    // value is within range for the output precision
-                    mul * v
-                })
-            })
-            .collect::<Decimal128Array>()
-            .with_precision_and_scale(*$PRECISION, *$SCALE)?;
-        Ok(Arc::new(decimal_array))
-    }};
+/// Cast the primitive array to defined decimal data type array
+fn cast_primitive_to_decimal<T: ArrayAccessor, F>(
+    array: T,
+    op: F,
+    precision: usize,
+    scale: usize,
+) -> Result<Arc<dyn Array>>
+where
+    F: Fn(T::Item) -> i128,
+{
+    #[allow(clippy::redundant_closure)]
+    let decimal_array = ArrayIter::new(array)
+        .map(|v| v.map(|v| op(v)))
+        .collect::<Decimal128Array>()
+        .with_precision_and_scale(precision, scale)?;
+
+    Ok(Arc::new(decimal_array))
 }
 
-// cast the floating-point array to defined decimal data type array
-macro_rules! cast_floating_point_to_decimal {
-    ($ARRAY: expr, $ARRAY_TYPE: ident, $PRECISION : ident, $SCALE : ident) => {{
-        let array = $ARRAY.as_any().downcast_ref::<$ARRAY_TYPE>().unwrap();
-        let mul = 10_f64.powi(*$SCALE as i32);
-        let decimal_array = array
-            .iter()
-            .map(|v| {
-                v.map(|v| {
-                    // with_precision_and_scale validates the
-                    // value is within range for the output precision
-                    ((v as f64) * mul) as i128
-                })
-            })
-            .collect::<Decimal128Array>()
-            .with_precision_and_scale(*$PRECISION, *$SCALE)?;
-        Ok(Arc::new(decimal_array))
-    }};
+fn cast_integer_to_decimal<T: ArrowNumericType>(
+    array: &PrimitiveArray<T>,
+    precision: usize,
+    scale: usize,
+) -> Result<Arc<dyn Array>>
+where
+    <T as ArrowPrimitiveType>::Native: AsPrimitive<i128>,
+{
+    let mul: i128 = 10_i128.pow(scale as u32);
+
+    // with_precision_and_scale validates the
+    // value is within range for the output precision
+    cast_primitive_to_decimal(array, |v| v.as_() * mul, precision, scale)
+}
+
+fn cast_floating_point_to_decimal<T: ArrowNumericType>(
+    array: &PrimitiveArray<T>,
+    precision: usize,
+    scale: usize,
+) -> Result<Arc<dyn Array>>
+where
+    <T as ArrowPrimitiveType>::Native: AsPrimitive<f64>,
+{
+    let mul = 10_f64.powi(scale as i32);
+
+    cast_primitive_to_decimal(
+        array,
+        |v| {
+            // with_precision_and_scale validates the
+            // value is within range for the output precision
+            (v.as_() * mul) as i128
+        },
+        precision,
+        scale,
+    )
 }
 
 // cast the decimal array to integer array
@@ -428,24 +443,36 @@ pub fn cast_with_options(
             // cast data to decimal
             match from_type {
                 // TODO now just support signed numeric to decimal, support decimal to numeric later
-                Int8 => {
-                    cast_integer_to_decimal!(array, Int8Array, precision, scale)
-                }
-                Int16 => {
-                    cast_integer_to_decimal!(array, Int16Array, precision, scale)
-                }
-                Int32 => {
-                    cast_integer_to_decimal!(array, Int32Array, precision, scale)
-                }
-                Int64 => {
-                    cast_integer_to_decimal!(array, Int64Array, precision, scale)
-                }
-                Float32 => {
-                    cast_floating_point_to_decimal!(array, Float32Array, precision, scale)
-                }
-                Float64 => {
-                    cast_floating_point_to_decimal!(array, Float64Array, precision, scale)
-                }
+                Int8 => cast_integer_to_decimal(
+                    as_primitive_array::<Int8Type>(array),
+                    *precision,
+                    *scale,
+                ),
+                Int16 => cast_integer_to_decimal(
+                    as_primitive_array::<Int16Type>(array),
+                    *precision,
+                    *scale,
+                ),
+                Int32 => cast_integer_to_decimal(
+                    as_primitive_array::<Int32Type>(array),
+                    *precision,
+                    *scale,
+                ),
+                Int64 => cast_integer_to_decimal(
+                    as_primitive_array::<Int64Type>(array),
+                    *precision,
+                    *scale,
+                ),
+                Float32 => cast_floating_point_to_decimal(
+                    as_primitive_array::<Float32Type>(array),
+                    *precision,
+                    *scale,
+                ),
+                Float64 => cast_floating_point_to_decimal(
+                    as_primitive_array::<Float64Type>(array),
+                    *precision,
+                    *scale,
+                ),
                 Null => Ok(new_null_array(to_type, array.len())),
                 _ => Err(ArrowError::CastError(format!(
                     "Casting from {:?} to {:?} not supported",