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