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