@@ -23,7 +23,6 @@ use std::hash::Hash;
2323use std:: { any:: Any , sync:: Arc } ;
2424
2525use arrow:: array:: * ;
26- use arrow:: buffer:: BooleanBuffer ;
2726use arrow:: compute:: kernels:: boolean:: { and_kleene, or_kleene} ;
2827use arrow:: compute:: kernels:: concat_elements:: concat_elements_utf8;
2928use arrow:: compute:: { SlicesIterator , cast, filter_record_batch} ;
@@ -173,11 +172,12 @@ enum BoolOp {
173172 Or ,
174173}
175174
176- /// Try in-place bitwise AND/OR on boolean arrays when neither side has nulls
177- /// and both have zero offset. Tries left first, then right.
178- /// Falls back to the standard kleene kernel otherwise.
179- fn boolean_op_inplace ( left : ArrayRef , right : ArrayRef , op : BoolOp ) -> Result < ArrayRef > {
180- // Only optimize the non-null, zero-offset case
175+ /// Try in-place bitwise AND/OR on boolean arrays when neither side has nulls.
176+ /// Uses `BooleanBuffer`'s `BitAndAssign`/`BitOrAssign` which internally attempts
177+ /// `Buffer::into_mutable()` for in-place mutation, falling back to allocation if shared.
178+ /// Falls back to standard kleene kernel when nulls are present.
179+ fn boolean_op_inplace ( left : ArrayRef , right : & ArrayRef , op : BoolOp ) -> Result < ArrayRef > {
180+ // Only optimize the non-null case; kleene logic is needed when nulls are present
181181 if left. null_count ( ) != 0 || right. null_count ( ) != 0 || left. len ( ) != right. len ( ) {
182182 let kleene_fn = match op {
183183 BoolOp :: And => and_kleene,
@@ -191,78 +191,18 @@ fn boolean_op_inplace(left: ArrayRef, right: ArrayRef, op: BoolOp) -> Result<Arr
191191 let right_bool = as_boolean_array ( & right)
192192 . expect ( "boolean_op_inplace failed to downcast right array" ) ;
193193
194- if left_bool. offset ( ) != 0 || right_bool. offset ( ) != 0 {
195- let kleene_fn = match op {
196- BoolOp :: And => and_kleene,
197- BoolOp :: Or => or_kleene,
198- } ;
199- return Ok ( boolean_op ( & left, & right, kleene_fn) ?) ;
200- }
201-
202- let len = left_bool. len ( ) ;
203- let byte_len = len. div_ceil ( 8 ) ;
204-
205- // Try left first
206- let other_bytes = right_bool. values ( ) . inner ( ) . as_slice ( ) ;
207- let left_clone = left_bool. clone ( ) ;
194+ let right_values = right_bool. values ( ) ;
195+ // Clone left BooleanBuffer (cheap Arc clone), then drop ArrayRef to
196+ // reduce refcount so BitAndAssign/BitOrAssign can mutate in-place.
197+ let mut left_values = left_bool. values ( ) . clone ( ) ;
208198 drop ( left) ;
209- let ( left_values, _nulls) = left_clone. into_parts ( ) ;
210- match left_values. into_inner ( ) . into_mutable ( ) {
211- Ok ( mut mutable) => {
212- apply_bool_assign ( mutable. as_slice_mut ( ) , other_bytes, byte_len, op) ;
213- Ok ( Arc :: new ( BooleanArray :: new (
214- BooleanBuffer :: new ( mutable. into ( ) , 0 , len) ,
215- None ,
216- ) ) )
217- }
218- Err ( left_buf) => {
219- // Left buffer shared — try right
220- let left_bytes = left_buf. as_slice ( ) ;
221- let right_clone = right_bool. clone ( ) ;
222- drop ( right) ;
223- let ( right_values, _nulls) = right_clone. into_parts ( ) ;
224- match right_values. into_inner ( ) . into_mutable ( ) {
225- Ok ( mut mutable) => {
226- // AND/OR are commutative, so we can swap operands
227- apply_bool_assign ( mutable. as_slice_mut ( ) , left_bytes, byte_len, op) ;
228- Ok ( Arc :: new ( BooleanArray :: new (
229- BooleanBuffer :: new ( mutable. into ( ) , 0 , len) ,
230- None ,
231- ) ) )
232- }
233- Err ( right_buf) => {
234- // Both shared — fall back
235- let left_arr =
236- BooleanArray :: new ( BooleanBuffer :: new ( left_buf, 0 , len) , None ) ;
237- let right_arr =
238- BooleanArray :: new ( BooleanBuffer :: new ( right_buf, 0 , len) , None ) ;
239- let kleene_fn = match op {
240- BoolOp :: And => and_kleene,
241- BoolOp :: Or => or_kleene,
242- } ;
243- Ok ( boolean_op ( & left_arr, & right_arr, kleene_fn) ?)
244- }
245- }
246- }
247- }
248- }
249199
250- #[ inline]
251- fn apply_bool_assign ( dst : & mut [ u8 ] , src : & [ u8 ] , byte_len : usize , op : BoolOp ) {
252200 match op {
253- BoolOp :: And => {
254- dst[ ..byte_len]
255- . iter_mut ( )
256- . zip ( & src[ ..byte_len] )
257- . for_each ( |( d, s) | * d &= s) ;
258- }
259- BoolOp :: Or => {
260- dst[ ..byte_len]
261- . iter_mut ( )
262- . zip ( & src[ ..byte_len] )
263- . for_each ( |( d, s) | * d |= s) ;
264- }
201+ BoolOp :: And => left_values &= right_values,
202+ BoolOp :: Or => left_values |= right_values,
265203 }
204+
205+ Ok ( Arc :: new ( BooleanArray :: new ( left_values, None ) ) )
266206}
267207
268208/// Returns true if both operands are Date types (Date32 or Date64)
@@ -793,7 +733,7 @@ impl BinaryExpr {
793733 | NotLikeMatch | NotILikeMatch => unreachable ! ( ) ,
794734 And => {
795735 if left_data_type == & DataType :: Boolean {
796- boolean_op_inplace ( left, right, BoolOp :: And )
736+ boolean_op_inplace ( left, & right, BoolOp :: And )
797737 } else {
798738 internal_err ! (
799739 "Cannot evaluate binary expression {:?} with types {:?} and {:?}" ,
@@ -805,7 +745,7 @@ impl BinaryExpr {
805745 }
806746 Or => {
807747 if left_data_type == & DataType :: Boolean {
808- boolean_op_inplace ( left, right, BoolOp :: Or )
748+ boolean_op_inplace ( left, & right, BoolOp :: Or )
809749 } else {
810750 internal_err ! (
811751 "Cannot evaluate binary expression {:?} with types {:?} and {:?}" ,
0 commit comments