@@ -41,12 +41,6 @@ pub trait KleeneBinaryOp {
4141 /// Apply the operation to two [`BitBuffer`]s.
4242 fn bit_op ( lhs : & BitBuffer , rhs : & BitBuffer ) -> BitBuffer ;
4343
44- /// Absorbing bits when one side is all-null.
45- ///
46- /// - AND: all-false, since `x AND null` is false or null.
47- /// - OR: all-true, since `x OR null` is true or null.
48- fn absorbing_bits_from_len ( len : usize ) -> BitBuffer ;
49-
5044 /// Returns a mask of positions with absorbing values.
5145 ///
5246 /// - AND: `FALSE` absorbs, so return `bits.not()` (false positions).
@@ -62,10 +56,6 @@ impl KleeneBinaryOp for KleeneAnd {
6256 lhs. bitand ( rhs)
6357 }
6458
65- fn absorbing_bits_from_len ( len : usize ) -> BitBuffer {
66- BitBuffer :: new_unset ( len) // All false.
67- }
68-
6959 fn absorb_bits ( bits : & BitBuffer ) -> BitBuffer {
7060 bits. not ( ) // `false` absorbs nulls.
7161 }
@@ -84,10 +74,6 @@ impl KleeneBinaryOp for KleeneOr {
8474 lhs. bitor ( rhs)
8575 }
8676
87- fn absorbing_bits_from_len ( len : usize ) -> BitBuffer {
88- BitBuffer :: new_set ( len) // All true.
89- }
90-
9177 fn absorb_bits ( bits : & BitBuffer ) -> BitBuffer {
9278 bits. clone ( ) // `true` absorbs nulls.
9379 }
@@ -181,16 +167,20 @@ fn kleene_vector_op<Op: KleeneBinaryOp>(lhs: &BoolVector, rhs: &BoolVector) -> B
181167
182168 // LHS is all valid, RHS is all null.
183169 ( Mask :: AllTrue ( _) , Mask :: AllFalse ( _) ) => {
184- // The result vector is valid where the LHS has an absorbing value.
185- let result_bits = Op :: absorbing_bits_from_len ( len) ;
170+ // The result vector is valid where the LHS has an absorbing value. Since only
171+ // absorbing values produce valid results, and absorbing values equal the result of the
172+ // operation, we can reuse the LHS bits directly.
173+ let result_bits = lhs. bits ( ) . clone ( ) ;
186174 let validity = Op :: absorb_bits ( lhs. bits ( ) ) ;
187175 BoolVector :: new ( result_bits, Mask :: from ( validity) )
188176 }
189177
190178 // LHS is all null, RHS is all valid.
191179 ( Mask :: AllFalse ( _) , Mask :: AllTrue ( _) ) => {
192- // The result vector is valid where the RHS has an absorbing value.
193- let result_bits = Op :: absorbing_bits_from_len ( len) ;
180+ // The result vector is valid where the RHS has an absorbing value. Since only
181+ // absorbing values produce valid results, and absorbing values equal the result of the
182+ // operation, we can reuse the RHS bits directly.
183+ let result_bits = rhs. bits ( ) . clone ( ) ;
194184 let validity = Op :: absorb_bits ( rhs. bits ( ) ) ;
195185 BoolVector :: new ( result_bits, Mask :: from ( validity) )
196186 }
@@ -213,52 +203,47 @@ fn kleene_vector_op<Op: KleeneBinaryOp>(lhs: &BoolVector, rhs: &BoolVector) -> B
213203
214204 // LHS is all null, RHS has specific validity.
215205 ( Mask :: AllFalse ( _) , Mask :: Values ( rhs_values) ) => {
216- // The result vector is valid where the RHS is valid AND has an absorbing value.
217- let result_bits = Op :: absorbing_bits_from_len ( len) ;
206+ // The result vector is valid where the RHS is valid AND has an absorbing value. Since
207+ // only absorbing values produce valid results, we can reuse the RHS bits directly.
208+ let result_bits = rhs. bits ( ) . clone ( ) ;
218209 let validity = rhs_values. bit_buffer ( ) . bitand ( & Op :: absorb_bits ( rhs. bits ( ) ) ) ;
219210 BoolVector :: new ( result_bits, Mask :: from ( validity) )
220211 }
221212
222213 // LHS has specific validity, RHS is all null.
223214 ( Mask :: Values ( lhs_values) , Mask :: AllFalse ( _) ) => {
224- // The result vector is valid where the LHS is valid AND has an absorbing value.
225- let result_bits = Op :: absorbing_bits_from_len ( len) ;
215+ // The result vector is valid where the LHS is valid AND has an absorbing value. Since
216+ // only absorbing values produce valid results, we can reuse the LHS bits directly.
217+ let result_bits = lhs. bits ( ) . clone ( ) ;
226218 let validity = lhs_values. bit_buffer ( ) . bitand ( & Op :: absorb_bits ( lhs. bits ( ) ) ) ;
227219 BoolVector :: new ( result_bits, Mask :: from ( validity) )
228220 }
229221
230222 // Both sides have specific validity.
231223 ( Mask :: Values ( lhs_values) , Mask :: Values ( rhs_values) ) => {
232- // The result is valid at position i when :
224+ // The result is valid at position `i` iff :
233225 // 1. Both lhs[i] and rhs[i] are valid (standard case), OR
234226 // 2. lhs[i] is null but rhs[i] is valid AND has an absorbing value, OR
235227 // 3. rhs[i] is null but lhs[i] is valid AND has an absorbing value.
236228 //
237229 // Absorbing values in Kleene logic:
238230 // - AND: false absorbs null (false AND null = false).
239231 // - OR: true absorbs null (true OR null = true).
232+ //
233+ // This simplifies to the gosition is valid iff:
234+ // - (lhs_valid OR rhs_absorbs) AND
235+ // - (rhs_valid OR lhs_absorbs).
236+ //
237+ // In other words, each side must either be valid or have an absorbing value that
238+ // "covers" the other side's null.
240239 let result_bits = Op :: bit_op ( lhs. bits ( ) , rhs. bits ( ) ) ;
241240
242- // Case 1: Both operands are valid at this position.
243- let both_valid = lhs_values. bit_buffer ( ) . bitand ( rhs_values. bit_buffer ( ) ) ;
244-
245- // Case 2: LHS is null, but RHS is valid with an absorbing value.
246- let lhs_null_rhs_absorbs = lhs_values
247- . bit_buffer ( )
248- . not ( )
249- . bitand ( rhs_values. bit_buffer ( ) )
250- . bitand ( & Op :: absorb_bits ( rhs. bits ( ) ) ) ;
251-
252- // Case 3: RHS is null, but LHS is valid with an absorbing value.
253- let rhs_null_lhs_absorbs = rhs_values
254- . bit_buffer ( )
255- . not ( )
256- . bitand ( lhs_values. bit_buffer ( ) )
257- . bitand ( & Op :: absorb_bits ( lhs. bits ( ) ) ) ;
258-
259- let validity = both_valid
260- . bitor ( & lhs_null_rhs_absorbs)
261- . bitor ( & rhs_null_lhs_absorbs) ;
241+ let lhs_valid_or_rhs_absorbs =
242+ lhs_values. bit_buffer ( ) . bitor ( & Op :: absorb_bits ( rhs. bits ( ) ) ) ;
243+ let rhs_valid_or_lhs_absorbs =
244+ rhs_values. bit_buffer ( ) . bitor ( & Op :: absorb_bits ( lhs. bits ( ) ) ) ;
245+ let validity = lhs_valid_or_rhs_absorbs. bitand ( & rhs_valid_or_lhs_absorbs) ;
246+
262247 BoolVector :: new ( result_bits, Mask :: from ( validity) )
263248 }
264249 }
0 commit comments