vortex_array/builders/
bool.rs1use std::any::Any;
5use std::mem;
6
7use vortex_buffer::BitBufferMut;
8use vortex_error::VortexExpect;
9use vortex_error::VortexResult;
10use vortex_error::vortex_ensure;
11use vortex_mask::Mask;
12
13use crate::ArrayRef;
14use crate::IntoArray;
15use crate::LEGACY_SESSION;
16use crate::VortexSessionExecute;
17use crate::arrays::BoolArray;
18use crate::arrays::bool::BoolArrayExt;
19use crate::builders::ArrayBuilder;
20use crate::builders::DEFAULT_BUILDER_CAPACITY;
21use crate::builders::LazyBitBufferBuilder;
22use crate::canonical::Canonical;
23use crate::canonical::ToCanonical;
24use crate::dtype::DType;
25use crate::dtype::Nullability;
26use crate::scalar::Scalar;
27
28pub struct BoolBuilder {
29 dtype: DType,
30 inner: BitBufferMut,
31 nulls: LazyBitBufferBuilder,
32}
33
34impl BoolBuilder {
35 pub fn new(nullability: Nullability) -> Self {
36 Self::with_capacity(nullability, DEFAULT_BUILDER_CAPACITY)
37 }
38
39 pub fn with_capacity(nullability: Nullability, capacity: usize) -> Self {
40 Self {
41 inner: BitBufferMut::with_capacity(capacity),
42 nulls: LazyBitBufferBuilder::new(capacity),
43 dtype: DType::Bool(nullability),
44 }
45 }
46
47 pub fn append_value(&mut self, value: bool) {
49 self.append_values(value, 1)
50 }
51
52 pub fn append_values(&mut self, value: bool, n: usize) {
56 self.inner.append_n(value, n);
57 self.nulls.append_n_non_nulls(n)
58 }
59
60 pub fn finish_into_bool(&mut self) -> BoolArray {
62 assert_eq!(
63 self.nulls.len(),
64 self.inner.len(),
65 "Null count and value count should match when calling BoolBuilder::finish."
66 );
67
68 BoolArray::new(
69 mem::take(&mut self.inner).freeze(),
70 self.nulls.finish_with_nullability(self.dtype.nullability()),
71 )
72 }
73}
74
75impl ArrayBuilder for BoolBuilder {
76 fn as_any(&self) -> &dyn Any {
77 self
78 }
79
80 fn as_any_mut(&mut self) -> &mut dyn Any {
81 self
82 }
83
84 fn dtype(&self) -> &DType {
85 &self.dtype
86 }
87
88 fn len(&self) -> usize {
89 self.inner.len()
90 }
91
92 fn append_zeros(&mut self, n: usize) {
93 self.append_values(false, n)
94 }
95
96 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
97 self.inner.append_n(false, n);
98 self.nulls.append_n_nulls(n)
99 }
100
101 fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
102 vortex_ensure!(
103 scalar.dtype() == self.dtype(),
104 "BoolBuilder expected scalar with dtype {}, got {}",
105 self.dtype(),
106 scalar.dtype()
107 );
108
109 match scalar.as_bool().value() {
110 Some(value) => self.append_value(value),
111 None => self.append_null(),
112 }
113
114 Ok(())
115 }
116
117 unsafe fn extend_from_array_unchecked(&mut self, array: &ArrayRef) {
118 let bool_array = array.to_bool();
119
120 self.inner.append_buffer(&bool_array.to_bit_buffer());
121 self.nulls.append_validity_mask(
122 bool_array
123 .as_ref()
124 .validity()
125 .vortex_expect("validity_mask")
126 .to_mask(
127 bool_array.as_ref().len(),
128 &mut LEGACY_SESSION.create_execution_ctx(),
129 )
130 .vortex_expect("Failed to compute validity mask"),
131 );
132 }
133
134 fn reserve_exact(&mut self, additional: usize) {
135 self.inner.reserve(additional);
136 self.nulls.reserve_exact(additional);
137 }
138
139 unsafe fn set_validity_unchecked(&mut self, validity: Mask) {
140 self.nulls = LazyBitBufferBuilder::new(validity.len());
141 self.nulls.append_validity_mask(validity);
142 }
143
144 fn finish(&mut self) -> ArrayRef {
145 self.finish_into_bool().into_array()
146 }
147
148 fn finish_into_canonical(&mut self) -> Canonical {
149 Canonical::Bool(self.finish_into_bool())
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use rand::RngExt;
156 use rand::SeedableRng;
157 use rand::prelude::StdRng;
158 use vortex_error::VortexResult;
159
160 use crate::ArrayRef;
161 use crate::IntoArray;
162 use crate::LEGACY_SESSION;
163 use crate::VortexSessionExecute;
164 use crate::arrays::ChunkedArray;
165 use crate::arrays::bool::BoolArrayExt;
166 use crate::assert_arrays_eq;
167 use crate::builders::ArrayBuilder;
168 use crate::builders::BoolBuilder;
169 use crate::builders::bool::BoolArray;
170 use crate::builders::builder_with_capacity;
171 use crate::canonical::ToCanonical;
172 use crate::dtype::DType;
173 use crate::dtype::Nullability;
174 use crate::scalar::Scalar;
175
176 fn make_opt_bool_chunks(len: usize, chunk_count: usize) -> ArrayRef {
177 let mut rng = StdRng::seed_from_u64(0);
178
179 (0..chunk_count)
180 .map(|_| {
181 BoolArray::from_iter((0..len).map(|_| match rng.random_range::<u8, _>(0..=2) {
182 0 => Some(false),
183 1 => Some(true),
184 2 => None,
185 _ => unreachable!(),
186 }))
187 .into_array()
188 })
189 .collect::<ChunkedArray>()
190 .into_array()
191 }
192
193 #[test]
194 fn tests() -> VortexResult<()> {
195 let len = 1000;
196 let chunk_count = 10;
197 let chunk = make_opt_bool_chunks(len, chunk_count);
198
199 let mut ctx = LEGACY_SESSION.create_execution_ctx();
200 let mut builder = builder_with_capacity(chunk.dtype(), len * chunk_count);
201 chunk
202 .clone()
203 .append_to_builder(builder.as_mut(), &mut ctx)?;
204
205 let canon_into = builder.finish().to_bool();
206 let into_canon = chunk.to_bool();
207
208 assert!(
209 canon_into
210 .validity()?
211 .mask_eq(&into_canon.validity()?, &mut ctx)?
212 );
213 assert_eq!(canon_into.to_bit_buffer(), into_canon.to_bit_buffer());
214 Ok(())
215 }
216
217 #[test]
218 fn test_append_scalar() {
219 let mut builder = BoolBuilder::with_capacity(Nullability::Nullable, 10);
220
221 let true_scalar = Scalar::bool(true, Nullability::Nullable);
223 builder.append_scalar(&true_scalar).unwrap();
224
225 let false_scalar = Scalar::bool(false, Nullability::Nullable);
227 builder.append_scalar(&false_scalar).unwrap();
228
229 let null_scalar = Scalar::null(DType::Bool(Nullability::Nullable));
231 builder.append_scalar(&null_scalar).unwrap();
232
233 let array = builder.finish_into_bool();
234 let expected = BoolArray::from_iter([Some(true), Some(false), None]);
235 assert_arrays_eq!(&array, &expected);
236
237 let mut builder = BoolBuilder::with_capacity(Nullability::NonNullable, 10);
239 let wrong_scalar = Scalar::from(42i32);
240 assert!(builder.append_scalar(&wrong_scalar).is_err());
241 }
242}