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