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