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

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-11501-36122935e488001fae53344ed17ee39f0a5970c9
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git

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