vortex_array/builders/
bool.rs1use std::any::Any;
5
6use arrow_buffer::BooleanBufferBuilder;
7use vortex_dtype::{DType, Nullability};
8use vortex_error::{VortexResult, vortex_bail};
9use vortex_mask::Mask;
10
11use crate::arrays::BoolArray;
12use crate::builders::ArrayBuilder;
13use crate::builders::lazy_validity_builder::LazyNullBufferBuilder;
14use crate::{Array, ArrayRef, Canonical, IntoArray};
15
16pub struct BoolBuilder {
17 inner: BooleanBufferBuilder,
18 nulls: LazyNullBufferBuilder,
19 nullability: Nullability,
20 dtype: DType,
21}
22
23impl BoolBuilder {
24 pub fn new(nullability: Nullability) -> Self {
25 Self::with_capacity(nullability, 1024) }
27
28 pub fn with_capacity(nullability: Nullability, capacity: usize) -> Self {
29 Self {
30 inner: BooleanBufferBuilder::new(capacity),
31 nulls: LazyNullBufferBuilder::new(capacity),
32 nullability,
33 dtype: DType::Bool(nullability),
34 }
35 }
36
37 pub fn append_value(&mut self, value: bool) {
38 self.append_values(value, 1)
39 }
40
41 pub fn append_values(&mut self, value: bool, n: usize) {
42 self.inner.append_n(n, value);
43 self.nulls.append_n_non_nulls(n)
44 }
45
46 pub fn append_option(&mut self, value: Option<bool>) {
47 match value {
48 Some(value) => self.append_value(value),
49 None => self.append_null(),
50 }
51 }
52}
53
54impl ArrayBuilder for BoolBuilder {
55 fn as_any(&self) -> &dyn Any {
56 self
57 }
58
59 fn as_any_mut(&mut self) -> &mut dyn Any {
60 self
61 }
62
63 fn dtype(&self) -> &DType {
64 &self.dtype
65 }
66
67 fn len(&self) -> usize {
68 self.inner.len()
69 }
70
71 fn append_zeros(&mut self, n: usize) {
72 self.append_values(false, n)
73 }
74
75 fn append_nulls(&mut self, n: usize) {
76 self.inner.append_n(n, false);
77 self.nulls.append_n_nulls(n)
78 }
79
80 fn extend_from_array(&mut self, array: &dyn Array) -> VortexResult<()> {
81 let array = array.to_canonical()?;
82 let Canonical::Bool(array) = array else {
83 vortex_bail!("Expected Canonical::Bool, found {:?}", array);
84 };
85
86 self.inner.append_buffer(array.boolean_buffer());
87 self.nulls.append_validity_mask(array.validity_mask());
88
89 Ok(())
90 }
91
92 fn ensure_capacity(&mut self, capacity: usize) {
93 if capacity > self.inner.capacity() {
94 self.nulls.ensure_capacity(capacity);
95 self.inner.reserve(capacity - self.inner.capacity());
96 }
97 }
98
99 fn set_validity(&mut self, validity: Mask) {
100 self.nulls = LazyNullBufferBuilder::new(validity.len());
101 self.nulls.append_validity_mask(validity);
102 }
103
104 fn finish(&mut self) -> ArrayRef {
105 assert_eq!(
106 self.nulls.len(),
107 self.inner.len(),
108 "Null count and value count should match when calling BoolBuilder::finish."
109 );
110
111 BoolArray::new(
112 self.inner.finish(),
113 self.nulls.finish_with_nullability(self.nullability),
114 )
115 .into_array()
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use rand::prelude::StdRng;
122 use rand::{Rng, SeedableRng};
123
124 use crate::array::Array;
125 use crate::arrays::{BoolArray, ChunkedArray};
126 use crate::builders::builder_with_capacity;
127 use crate::canonical::ToCanonical;
128 use crate::vtable::ValidityHelper;
129 use crate::{ArrayRef, IntoArray};
130 fn make_opt_bool_chunks(len: usize, chunk_count: usize) -> ArrayRef {
131 let mut rng = StdRng::seed_from_u64(0);
132
133 (0..chunk_count)
134 .map(|_| {
135 BoolArray::from_iter((0..len).map(|_| match rng.random_range::<u8, _>(0..=2) {
136 0 => Some(false),
137 1 => Some(true),
138 2 => None,
139 _ => unreachable!(),
140 }))
141 .into_array()
142 })
143 .collect::<ChunkedArray>()
144 .into_array()
145 }
146
147 #[test]
148 fn tests() {
149 let len = 1000;
150 let chunk_count = 10;
151 let chunk = make_opt_bool_chunks(len, chunk_count);
152
153 let mut builder = builder_with_capacity(chunk.dtype(), len * chunk_count);
154 chunk.clone().append_to_builder(builder.as_mut()).unwrap();
155 let canon_into = builder
156 .finish()
157 .to_canonical()
158 .unwrap()
159 .into_bool()
160 .unwrap();
161
162 let into_canon = chunk.to_bool().unwrap();
163
164 assert_eq!(canon_into.validity(), into_canon.validity());
165 assert_eq!(canon_into.boolean_buffer(), into_canon.boolean_buffer());
166 }
167}