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