1use std::fmt::Display;
5use std::fmt::Formatter;
6
7use smallvec::smallvec;
8use vortex_buffer::BitBuffer;
9use vortex_buffer::BitBufferMeta;
10use vortex_buffer::BitBufferMut;
11use vortex_buffer::BitBufferView;
12use vortex_error::VortexExpect;
13use vortex_error::VortexResult;
14use vortex_error::vortex_ensure;
15use vortex_error::vortex_ensure_eq;
16use vortex_mask::Mask;
17
18use crate::ArrayRef;
19use crate::ArraySlots;
20use crate::ExecutionCtx;
21use crate::IntoArray;
22use crate::array::Array;
23use crate::array::ArrayParts;
24use crate::array::TypedArrayRef;
25use crate::array::child_to_validity;
26use crate::array::validity_to_child;
27use crate::array_slots;
28use crate::arrays::Bool;
29use crate::arrays::BoolArray;
30use crate::buffer::BufferHandle;
31use crate::dtype::DType;
32use crate::validity::Validity;
33
34#[array_slots(Bool)]
35pub struct BoolSlots {
36 #[slot(0)]
38 pub validity: Option<ArrayRef>,
39}
40
41#[derive(Clone, Debug)]
75pub struct BoolData {
76 pub(super) bits: BufferHandle,
77 pub(super) meta: BitBufferMeta,
78}
79
80impl Display for BoolData {
81 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
82 write!(f, "offset: {}", self.meta.offset())
83 }
84}
85
86pub struct BoolDataParts {
87 pub bits: BufferHandle,
88 pub meta: BitBufferMeta,
89}
90
91pub trait BoolArrayExt: TypedArrayRef<Bool> {
92 fn nullability(&self) -> crate::dtype::Nullability {
93 match self.as_ref().dtype() {
94 DType::Bool(nullability) => *nullability,
95 _ => unreachable!("BoolArrayExt requires a bool dtype"),
96 }
97 }
98
99 fn validity(&self) -> Validity {
100 child_to_validity(
101 self.as_ref().slots()[BoolSlots::VALIDITY].as_ref(),
102 self.nullability(),
103 )
104 }
105
106 fn to_bit_buffer(&self) -> BitBuffer {
107 let buffer = self.bits.as_host().clone();
108 BitBuffer::new_with_offset(buffer, self.meta.len(), self.meta.offset())
109 }
110
111 fn bit_buffer_view(&self) -> BitBufferView<'_> {
113 BitBufferView::from_meta(self.bits.as_host().as_slice(), self.meta)
114 }
115
116 fn maybe_execute_mask(&self, ctx: &mut ExecutionCtx) -> VortexResult<Option<Mask>> {
117 let all_valid = match &BoolArrayExt::validity(self) {
118 Validity::NonNullable | Validity::AllValid => true,
119 Validity::AllInvalid => false,
120 Validity::Array(a) => a.statistics().compute_min::<bool>(ctx).unwrap_or(false),
121 };
122 Ok(all_valid.then(|| Mask::from_buffer(self.to_bit_buffer())))
123 }
124
125 fn execute_mask(&self, ctx: &mut ExecutionCtx) -> Mask {
126 self.maybe_execute_mask(ctx)
127 .vortex_expect("failed to check validity")
128 .vortex_expect("cannot convert nullable boolean array to mask")
129 }
130
131 fn to_mask_fill_null_false(&self, ctx: &mut ExecutionCtx) -> Mask {
132 let validity_mask = BoolArrayExt::validity(self)
133 .execute_mask(self.as_ref().len(), ctx)
134 .vortex_expect("Failed to compute validity mask");
135 let buffer = match validity_mask {
136 Mask::AllTrue(_) => self.to_bit_buffer(),
137 Mask::AllFalse(_) => return Mask::new_false(self.as_ref().len()),
138 Mask::Values(validity) => validity.bit_buffer() & self.to_bit_buffer(),
139 };
140 Mask::from_buffer(buffer)
141 }
142}
143impl<T: TypedArrayRef<Bool>> BoolArrayExt for T {}
144
145impl BoolData {
147 #[inline]
149 pub fn into_parts(self, len: usize) -> BoolDataParts {
150 BoolDataParts {
151 bits: self.bits,
152 meta: BitBufferMeta::new(self.meta.offset(), len),
153 }
154 }
155
156 pub(crate) fn make_slots(validity: &Validity, len: usize) -> ArraySlots {
157 smallvec![validity_to_child(validity, len)]
158 }
159}
160
161impl Array<Bool> {
163 pub fn new(bits: BitBuffer, validity: Validity) -> Self {
169 Self::try_new(bits, validity).vortex_expect("Failed to create BoolArray")
170 }
171
172 pub fn new_handle(handle: BufferHandle, offset: usize, len: usize, validity: Validity) -> Self {
178 Self::try_new_from_handle(handle, offset, len, validity)
179 .vortex_expect("Failed to create BoolArray from BufferHandle")
180 }
181
182 pub fn try_new(bits: BitBuffer, validity: Validity) -> VortexResult<Self> {
188 let dtype = DType::Bool(validity.nullability());
189 let len = bits.len();
190 let slots = BoolData::make_slots(&validity, len);
191 let data = BoolData::try_new(bits, validity)?;
192 Ok(unsafe { Array::from_parts_unchecked(ArrayParts::new(Bool, dtype, len, data, slots)) })
193 }
194
195 pub fn try_new_from_handle(
198 bits: BufferHandle,
199 offset: usize,
200 len: usize,
201 validity: Validity,
202 ) -> VortexResult<Self> {
203 let dtype = DType::Bool(validity.nullability());
204 let slots = BoolData::make_slots(&validity, len);
205 let data = BoolData::try_new_from_handle(bits, offset, len, validity)?;
206 Ok(unsafe { Array::from_parts_unchecked(ArrayParts::new(Bool, dtype, len, data, slots)) })
207 }
208
209 pub unsafe fn new_unchecked(bits: BitBuffer, validity: Validity) -> Self {
215 let dtype = DType::Bool(validity.nullability());
216 let len = bits.len();
217 let slots = BoolData::make_slots(&validity, len);
218 let data = unsafe { BoolData::new_unchecked(bits, validity) };
220 unsafe { Array::from_parts_unchecked(ArrayParts::new(Bool, dtype, len, data, slots)) }
221 }
222
223 pub fn validate(bits: &BitBuffer, validity: &Validity) -> VortexResult<()> {
225 BoolData::validate(bits, validity)
226 }
227
228 pub fn from_indices<I: IntoIterator<Item = usize>>(
232 length: usize,
233 indices: I,
234 validity: Validity,
235 ) -> Self {
236 let mut buffer = BitBufferMut::new_unset(length);
237 indices.into_iter().for_each(|idx| buffer.set(idx));
238 Self::new(buffer.freeze(), validity)
239 }
240
241 pub fn into_bit_buffer(self) -> BitBuffer {
243 let len = self.len();
244 let data = self.into_data();
245 let buffer = data.bits.unwrap_host();
246 BitBuffer::new_with_offset(buffer, len, data.meta.offset())
247 }
248}
249
250impl BoolData {
252 pub(super) fn try_new(bits: BitBuffer, validity: Validity) -> VortexResult<Self> {
253 let bits = bits.shrink_offset();
254 Self::validate(&bits, &validity)?;
255
256 let (offset, len, buffer) = bits.into_inner();
257
258 Ok(Self {
259 bits: BufferHandle::new_host(buffer),
260 meta: BitBufferMeta::new(offset, len),
261 })
262 }
263
264 pub(super) fn try_new_from_handle(
265 bits: BufferHandle,
266 offset: usize,
267 len: usize,
268 validity: Validity,
269 ) -> VortexResult<Self> {
270 vortex_ensure!(offset < 8, "BitBuffer offset must be <8, got {}", offset);
271 if let Some(validity_len) = validity.maybe_len() {
272 vortex_ensure_eq!(
273 validity_len,
274 len,
275 "BoolArray validity length does not match array length",
276 );
277 }
278
279 vortex_ensure!(
280 bits.len() * 8 >= (len + offset),
281 "provided BufferHandle with offset {offset} len {len} had size {} bits",
282 bits.len() * 8,
283 );
284
285 Ok(Self {
286 bits,
287 meta: BitBufferMeta::new(offset, len),
288 })
289 }
290
291 pub(super) unsafe fn new_unchecked(bits: BitBuffer, validity: Validity) -> Self {
292 if cfg!(debug_assertions) {
293 Self::try_new(bits, validity).vortex_expect("Failed to create BoolData")
294 } else {
295 let (offset, len, buffer) = bits.into_inner();
296
297 Self {
298 bits: BufferHandle::new_host(buffer),
299 meta: BitBufferMeta::new(offset, len),
300 }
301 }
302 }
303
304 pub(super) fn validate(bits: &BitBuffer, validity: &Validity) -> VortexResult<()> {
305 vortex_ensure!(
306 bits.offset() < 8,
307 "BitBuffer offset must be <8, got {}",
308 bits.offset()
309 );
310
311 if let Some(validity_len) = validity.maybe_len() {
312 vortex_ensure_eq!(
313 validity_len,
314 bits.len(),
315 "BoolArray validity length does not match array length",
316 );
317 }
318
319 Ok(())
320 }
321}
322
323impl From<BitBuffer> for BoolArray {
324 fn from(value: BitBuffer) -> Self {
325 BoolArray::new(value, Validity::NonNullable)
326 }
327}
328
329impl FromIterator<bool> for BoolArray {
330 fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
331 BoolArray::from(BitBuffer::from_iter(iter))
332 }
333}
334
335impl FromIterator<Option<bool>> for BoolArray {
336 fn from_iter<I: IntoIterator<Item = Option<bool>>>(iter: I) -> Self {
337 let iter = iter.into_iter();
338 let capacity = iter.size_hint().0;
339 let mut bits = BitBufferMut::with_capacity(capacity);
340 let mut validity = BitBufferMut::with_capacity(capacity);
341 for value in iter {
342 bits.append(value.unwrap_or_default());
343 validity.append(value.is_some());
344 }
345
346 BoolArray::new(bits.freeze(), Validity::from(validity.freeze()))
347 }
348}
349
350impl IntoArray for BitBuffer {
351 fn into_array(self) -> ArrayRef {
352 BoolArray::new(self, Validity::NonNullable).into_array()
353 }
354}
355
356impl IntoArray for BitBufferMut {
357 fn into_array(self) -> ArrayRef {
358 self.freeze().into_array()
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use std::iter::once;
365 use std::iter::repeat_n;
366
367 use vortex_buffer::Alignment;
368 use vortex_buffer::BitBuffer;
369 use vortex_buffer::BitBufferMut;
370 use vortex_buffer::ByteBuffer;
371 use vortex_buffer::buffer;
372 use vortex_error::VortexResult;
373
374 use crate::IntoArray;
375 use crate::VortexSessionExecute;
376 use crate::array_session;
377 use crate::arrays::BoolArray;
378 use crate::arrays::PrimitiveArray;
379 use crate::arrays::bool::BoolArrayExt;
380 use crate::assert_arrays_eq;
381 use crate::buffer::BufferHandle;
382 use crate::patches::Patches;
383 use crate::validity::Validity;
384
385 #[test]
386 fn bool_array() {
387 let mut ctx = array_session().create_execution_ctx();
388
389 let arr = BoolArray::from_iter([true, false, true]);
390 let scalar = bool::try_from(&arr.execute_scalar(0, &mut ctx).unwrap()).unwrap();
391 assert!(scalar);
392 }
393
394 #[test]
395 fn test_all_some_iter() {
396 let mut ctx = array_session().create_execution_ctx();
397
398 let arr = BoolArray::from_iter([Some(true), Some(false)]);
399
400 assert!(matches!(arr.validity(), Ok(Validity::AllValid)));
401
402 let scalar = bool::try_from(&arr.execute_scalar(0, &mut ctx).unwrap()).unwrap();
403 assert!(scalar);
404 let scalar = bool::try_from(&arr.execute_scalar(1, &mut ctx).unwrap()).unwrap();
405 assert!(!scalar);
406 }
407
408 #[test]
409 fn test_bool_from_iter() {
410 let mut ctx = array_session().create_execution_ctx();
411 let arr = BoolArray::from_iter([Some(true), Some(true), None, Some(false), None]);
412
413 let scalar = bool::try_from(&arr.execute_scalar(0, &mut ctx).unwrap()).unwrap();
414 assert!(scalar);
415
416 let scalar = bool::try_from(&arr.execute_scalar(1, &mut ctx).unwrap()).unwrap();
417 assert!(scalar);
418
419 let scalar = arr.execute_scalar(2, &mut ctx).unwrap();
420 assert!(scalar.is_null());
421
422 let scalar = bool::try_from(&arr.execute_scalar(3, &mut ctx).unwrap()).unwrap();
423 assert!(!scalar);
424
425 let scalar = arr.execute_scalar(4, &mut ctx).unwrap();
426 assert!(scalar.is_null());
427 }
428
429 #[test]
430 fn patch_sliced_bools() {
431 let mut ctx = array_session().create_execution_ctx();
432 let arr = BoolArray::from(BitBuffer::new_set(12));
433 let sliced = arr.slice(4..12).unwrap();
434 assert_arrays_eq!(sliced, BoolArray::from_iter([true; 8]), &mut ctx);
435
436 let arr = {
437 let mut builder = BitBufferMut::new_unset(12);
438 (1..12).for_each(|i| builder.set(i));
439 BoolArray::from(builder.freeze())
440 };
441 let sliced = arr.slice(4..12).unwrap();
442 let expected_slice: Vec<bool> = (4..12).map(|i| (1..12).contains(&i)).collect();
443 assert_arrays_eq!(
444 sliced,
445 BoolArray::from_iter(expected_slice.clone()),
446 &mut ctx
447 );
448
449 let patches = Patches::new(
451 arr.len(),
452 0,
453 buffer![4u32].into_array(),
454 BoolArray::from(BitBuffer::new_unset(1)).into_array(),
455 None,
456 )
457 .unwrap();
458 let arr = arr.patch(&patches, &mut ctx).unwrap();
459 let expected_patched: Vec<bool> = (0..12).map(|i| (1..12).contains(&i) && i != 4).collect();
461 assert_arrays_eq!(arr, BoolArray::from_iter(expected_patched), &mut ctx);
462
463 assert_arrays_eq!(sliced, BoolArray::from_iter(expected_slice), &mut ctx);
465 }
466
467 #[test]
468 fn slice_array_in_middle() {
469 let mut ctx = array_session().create_execution_ctx();
470 let arr = BoolArray::from(BitBuffer::new_set(16));
471 let sliced = arr.slice(4..12).unwrap();
472 assert_arrays_eq!(sliced, BoolArray::from_iter([true; 8]), &mut ctx);
473 }
474
475 #[test]
476 fn slice_aligned_host_handle_at_unaligned_byte() -> VortexResult<()> {
477 let bits: ByteBuffer = buffer![0b1010_1100_u8, 0b0110_1001, 0];
478 let bits = bits.aligned(Alignment::of::<u64>());
479 let array =
480 BoolArray::new_handle(BufferHandle::new_host(bits), 0, 16, Validity::NonNullable)
481 .into_array();
482
483 let sliced = array.slice(9..15)?;
484
485 let mut ctx = array_session().create_execution_ctx();
486 assert_arrays_eq!(
487 sliced,
488 BoolArray::from_iter([false, false, true, false, true, true]),
489 &mut ctx
490 );
491 Ok(())
492 }
493
494 #[test]
495 fn patch_bools_owned() {
496 let mut ctx = array_session().create_execution_ctx();
497 let arr = BoolArray::from(BitBuffer::new_set(16));
498 let buf_ptr = arr.to_bit_buffer().inner().as_ptr();
499
500 let patches = Patches::new(
501 arr.len(),
502 0,
503 PrimitiveArray::new(buffer![0u32], Validity::NonNullable).into_array(),
504 BoolArray::from(BitBuffer::new_unset(1)).into_array(),
505 None,
506 )
507 .unwrap();
508 let arr = arr.patch(&patches, &mut ctx).unwrap();
509 assert_eq!(arr.to_bit_buffer().inner().as_ptr(), buf_ptr);
511
512 let expected: BoolArray = once(false).chain(repeat_n(true, 15)).collect();
514 assert_arrays_eq!(arr, expected, &mut ctx);
515 }
516
517 #[test]
518 fn patch_sliced_bools_offset() {
519 let mut ctx = array_session().create_execution_ctx();
520 let arr = BoolArray::from(BitBuffer::new_set(15));
521 let sliced = arr.slice(4..15).unwrap();
522 assert_arrays_eq!(sliced, BoolArray::from_iter([true; 11]), &mut ctx);
523 }
524}