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

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


The following commit(s) were added to refs/heads/main by this push:
     new 558c5fec9f perf(arrow-array): Reduce binary size 0.5%: do 
`PrimitiveArray` → `ArrayData` conversion once, not per type (#10893)
558c5fec9f is described below

commit 558c5fec9ffa2ac813cb1311ee2fc72ed3d16a97
Author: Andrew Lamb <[email protected]>
AuthorDate: Sat Aug 29 09:22:50 2026 -0400

    perf(arrow-array): Reduce binary size 0.5%: do `PrimitiveArray` → 
`ArrayData` conversion once, not per type (#10893)
    
    # Which issue does this PR close?
    
    - Part of the binary-size / LLVM IR reduction effort started in #10889.
    
    # Rationale for this change
    
    `From<PrimitiveArray<T>> for ArrayData` (reached via `Array::to_data` /
    `into_data`) is monomorphized for all ~32 primitive types in every crate
    that calls it
    
    # What changes are included in this PR?
    
    Move the `ArrayDataBuilder` construction into a private non-generic
    `primitive_to_array_data(data_type, len, values, nulls)` helper,
    compiled once in `arrow-array`.
    
    The same pattern applies to the byte/list array `From` impls (far fewer
    instantiations each); those can be follow-ups if this approach is
    agreeable.
    
    ## Measurements
    
    I measured the size of the `cast_kernels` binary with
    
    ```shell
    cargo bench --bench cast_kernels --no-run
    ```
    
    To see the actual number of bytes saved (60K / 0.45%):
    
    | before | after | delta |
    |---:|---:|---:|
    | 13,213,184 bytes | 13,153,152 bytes | **−60,032 bytes (−0.45%)** |
    
    I also measured the generated LLVM IR in a representative consumer crate
    with
    
    ```shell
    cargo llvm-lines --release -p arrow-row --lib
    ```
    
    | | before | after | delta |
    |---|---:|---:|---:|
    | `From<PrimitiveArray<T>> for ArrayData` IR in arrow-row | 4,992 lines
    / 32 copies | 1,952 lines / 32 thin shims | **−61%** |
    
    The other consumer crates (arrow-cast, arrow-ord, arrow-select, parquet,
    ...) have near-identical numbers, so the ~3,000-line saving repeats in
    each of them.
    
    # Are these changes tested?
    
    Covered by existing tests (`to_data`/`into_data` round-trips are
    exercised throughout the test suite).
    
    # Are there any user-facing changes?
    
    No. The helper is private and the produced `ArrayData` is identical.
---
 arrow-array/src/array/primitive_array.rs | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/arrow-array/src/array/primitive_array.rs 
b/arrow-array/src/array/primitive_array.rs
index c0d000e7b7..30d8f95f80 100644
--- a/arrow-array/src/array/primitive_array.rs
+++ b/arrow-array/src/array/primitive_array.rs
@@ -1207,12 +1207,29 @@ impl<T: ArrowPrimitiveType> PrimitiveArray<T> {
 
 impl<T: ArrowPrimitiveType> From<PrimitiveArray<T>> for ArrayData {
     fn from(array: PrimitiveArray<T>) -> Self {
-        let builder = ArrayDataBuilder::new(array.data_type)
-            .len(array.values.len())
-            .nulls(array.nulls)
-            .buffers(vec![array.values.into_inner()]);
-
-        unsafe { builder.build_unchecked() }
+        /// Converts the parts of a `PrimitiveArray` into [`ArrayData`].
+        /// Use an inner function to avoid code duplication over all
+        /// generic callsites as the body is the same.
+        ///
+        /// # Safety
+        /// The parts must come from a valid `PrimitiveArray`
+        unsafe fn inner(
+            data_type: DataType,
+            len: usize,
+            values: Buffer,
+            nulls: Option<NullBuffer>,
+        ) -> ArrayData {
+            let builder = ArrayDataBuilder::new(data_type)
+                .len(len)
+                .nulls(nulls)
+                .buffers(vec![values]);
+
+            // SAFETY: arguments are valid, per contract
+            unsafe { builder.build_unchecked() }
+        }
+        let len = array.values.len();
+        // SAFETY: the parts come from a valid PrimitiveArray
+        unsafe { inner(array.data_type, len, array.values.into_inner(), 
array.nulls) }
     }
 }
 

Reply via email to