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

github-merge-queue[bot] 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 0706d317a9 feat: specialize boolean interleave (#11501)
0706d317a9 is described below

commit 0706d317a94098cec4b631031efcdf16f51ed1f5
Author: dhruv tanwar <[email protected]>
AuthorDate: Sun Oct 11 20:57:05 2026 +0000

    feat: specialize boolean interleave (#11501)
    
    ## Summary
    
    - Add a specialized Boolean interleave implementation that copies
    selected Boolean values directly into a `BooleanBufferBuilder`.
    - Preserve null handling using the existing `Interleave` helper.
    - Add tests covering mixed Boolean values, nulls, sliced arrays, and
    comparison against the specialized implementation's fallback.
    - Add Boolean interleave benchmark cases with and without nulls.
    
    ## Testing
    
    - `cargo fmt --check`
    - `cargo test -p arrow-select interleave`
    - `cargo test -p arrow-select`
    - `cargo bench -p arrow --bench interleave_kernels --features test_utils
    --no-run`
    
    ## Benchmark results
    
    Preliminary benchmarks showed improvements over the fallback
    implementation across the tested selection sizes, with approximate
    speedups of 1.7x–4.1x. These measurements came from separate runs and
    should be treated as indicative rather than a controlled A/B comparison.
    
    Closes #11379
    
    ---------
    
    Co-authored-by: Jeffrey Vo <[email protected]>
---
 arrow-select/src/interleave.rs | 80 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/arrow-select/src/interleave.rs b/arrow-select/src/interleave.rs
index 74e29defe8..00abaf638e 100644
--- a/arrow-select/src/interleave.rs
+++ b/arrow-select/src/interleave.rs
@@ -101,6 +101,7 @@ pub fn interleave(
 
     downcast_primitive! {
         data_type => (primitive_helper, values, indices, data_type),
+        DataType::Boolean => interleave_boolean(values, indices),
         DataType::Utf8 => interleave_bytes::<Utf8Type>(values, indices),
         DataType::LargeUtf8 => interleave_bytes::<LargeUtf8Type>(values, 
indices),
         DataType::Binary => interleave_bytes::<BinaryType>(values, indices),
@@ -220,6 +221,23 @@ fn interleave_primitive<T: ArrowPrimitiveType>(
     Ok(Arc::new(array.with_data_type(data_type.clone())))
 }
 
+fn interleave_boolean(
+    values: &[&dyn Array],
+    indices: &[(usize, usize)],
+) -> Result<ArrayRef, ArrowError> {
+    let interleaved = Interleave::<'_, BooleanArray>::new(values, indices);
+    let arrays = &interleaved.arrays;
+
+    let mut values_builder = BooleanBufferBuilder::new(indices.len());
+
+    for &(array_idx, row_idx) in indices {
+        values_builder.append(arrays[array_idx].value(row_idx));
+    }
+
+    let array = BooleanArray::new(values_builder.build(), interleaved.nulls);
+    Ok(Arc::new(array))
+}
+
 fn interleave_bytes<T: ByteArrayType>(
     values: &[&dyn Array],
     indices: &[(usize, usize)],
@@ -994,6 +1012,68 @@ mod tests {
         assert_eq!(&v, &[Some(2), None, None, Some(4), Some(3)])
     }
 
+    #[test]
+    fn test_interleave_boolean() {
+        let a = BooleanArray::from(vec![Some(true), Some(false), None, 
Some(true)]);
+        let b = BooleanArray::from(vec![Some(false), Some(true), Some(true), 
None]);
+
+        let values = interleave(&[&a, &b], &[(0, 0), (1, 1), (0, 2), (1, 3), 
(1, 2)]).unwrap();
+
+        let result = values.as_boolean();
+
+        assert_eq!(
+            result.iter().collect::<Vec<_>>(),
+            vec![Some(true), Some(true), None, None, Some(true),]
+        );
+    }
+
+    #[test]
+    fn test_interleave_boolean_sliced() {
+        let original = BooleanArray::from(vec![
+            Some(false),
+            Some(true),
+            Some(false),
+            Some(true),
+            None,
+            Some(false),
+            Some(true),
+        ]);
+
+        let sliced_array = original.slice(1, 5);
+        let sliced = sliced_array
+            .as_any()
+            .downcast_ref::<BooleanArray>()
+            .unwrap();
+        let other = BooleanArray::from(vec![Some(false), Some(false), 
Some(true)]);
+
+        let values =
+            interleave(&[sliced, &other], &[(0, 0), (1, 2), (0, 3), (0, 4), 
(1, 0)]).unwrap();
+
+        let result = values.as_boolean();
+
+        assert_eq!(
+            result.iter().collect::<Vec<_>>(),
+            vec![Some(true), Some(true), None, Some(false), Some(false),]
+        );
+    }
+
+    #[test]
+    fn test_interleave_boolean_fallback_matches_specialized() {
+        let a = BooleanArray::from_iter(
+            (0..1024).map(|i| if i % 10 == 0 { None } else { Some(i % 2 == 0) 
}),
+        );
+        let b = BooleanArray::from_iter((0..1024).map(|i| Some(i % 3 == 0)));
+
+        let indices: Vec<_> = (0..1024).map(|i| (i % 2, (i * 37) % 
1024)).collect();
+
+        let values: [&dyn Array; 2] = [&a, &b];
+
+        let specialized = interleave_boolean(&values, &indices).unwrap();
+        let fallback = interleave_fallback(&values, &indices).unwrap();
+
+        assert_eq!(specialized.as_ref(), fallback.as_ref());
+    }
+
     #[test]
     fn test_primitive_empty() {
         let a = Int32Array::from_iter_values([1, 2, 3, 4]);

Reply via email to