vortex_array/builders/
bool.rs1use std::any::Any;
5
6use arrow_buffer::BooleanBufferBuilder;
7use vortex_dtype::{DType, Nullability};
8use vortex_error::{VortexResult, vortex_ensure};
9use vortex_mask::Mask;
10use vortex_scalar::{BoolScalar, Scalar};
11
12use crate::arrays::BoolArray;
13use crate::builders::{ArrayBuilder, DEFAULT_BUILDER_CAPACITY, LazyNullBufferBuilder};
14use crate::canonical::{Canonical, ToCanonical};
15use crate::{Array, ArrayRef, IntoArray};
16
17pub struct BoolBuilder {
18 dtype: DType,
19 inner: BooleanBufferBuilder,
20 nulls: LazyNullBufferBuilder,
21}
22
23impl BoolBuilder {
24 pub fn new(nullability: Nullability) -> Self {
25 Self::with_capacity(nullability, DEFAULT_BUILDER_CAPACITY)
26 }
27
28 pub fn with_capacity(nullability: Nullability, capacity: usize) -> Self {
29 Self {
30 inner: BooleanBufferBuilder::new(capacity),
31 nulls: LazyNullBufferBuilder::new(capacity),
32 dtype: DType::Bool(nullability),
33 }
34 }
35
36 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) {
45 self.inner.append_n(n, value);
46 self.nulls.append_n_non_nulls(n)
47 }
48
49 pub fn finish_into_bool(&mut self) -> BoolArray {
51 assert_eq!(
52 self.nulls.len(),
53 self.inner.len(),
54 "Null count and value count should match when calling BoolBuilder::finish."
55 );
56
57 BoolArray::from_bool_buffer(
58 self.inner.finish(),
59 self.nulls.finish_with_nullability(self.dtype.nullability()),
60 )
61 }
62}
63
64impl ArrayBuilder for BoolBuilder {
65 fn as_any(&self) -> &dyn Any {
66 self
67 }
68
69 fn as_any_mut(&mut self) -> &mut dyn Any {
70 self
71 }
72
73 fn dtype(&self) -> &DType {
74 &self.dtype
75 }
76
77 fn len(&self) -> usize {
78 self.inner.len()
79 }
80
81 fn append_zeros(&mut self, n: usize) {
82 self.append_values(false, n)
83 }
84
85 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
86 self.inner.append_n(n, false);
87 self.nulls.append_n_nulls(n)
88 }
89
90 fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
91 vortex_ensure!(
92 scalar.dtype() == self.dtype(),
93 "BoolBuilder expected scalar with dtype {:?}, got {:?}",
94 self.dtype(),
95 scalar.dtype()
96 );
97
98 let bool_scalar = BoolScalar::try_from(scalar)?;
99 match bool_scalar.value() {
100 Some(value) => self.append_value(value),
101 None => self.append_null(),
102 }
103
104 Ok(())
105 }
106
107 unsafe fn extend_from_array_unchecked(&mut self, array: &dyn Array) {
108 let bool_array = array.to_bool();
109
110 self.inner.append_buffer(bool_array.boolean_buffer());
111 self.nulls.append_validity_mask(bool_array.validity_mask());
112 }
113
114 fn reserve_exact(&mut self, additional: usize) {
115 self.inner.reserve(additional);
116 self.nulls.reserve_exact(additional);
117 }
118
119 unsafe fn set_validity_unchecked(&mut self, validity: Mask) {
120 self.nulls = LazyNullBufferBuilder::new(validity.len());
121 self.nulls.append_validity_mask(validity);
122 }
123
124 fn finish(&mut self) -> ArrayRef {
125 self.finish_into_bool().into_array()
126 }
127
128 fn finish_into_canonical(&mut self) -> Canonical {
129 Canonical::Bool(self.finish_into_bool())
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use rand::prelude::StdRng;
136 use rand::{Rng, SeedableRng};
137 use vortex_dtype::{DType, Nullability};
138 use vortex_scalar::Scalar;
139
140 use crate::array::Array;
141 use crate::arrays::{BoolArray, ChunkedArray};
142 use crate::builders::{ArrayBuilder, BoolBuilder, builder_with_capacity};
143 use crate::canonical::ToCanonical;
144 use crate::vtable::ValidityHelper;
145 use crate::{ArrayRef, IntoArray};
146
147 fn make_opt_bool_chunks(len: usize, chunk_count: usize) -> ArrayRef {
148 let mut rng = StdRng::seed_from_u64(0);
149
150 (0..chunk_count)
151 .map(|_| {
152 BoolArray::from_iter((0..len).map(|_| match rng.random_range::<u8, _>(0..=2) {
153 0 => Some(false),
154 1 => Some(true),
155 2 => None,
156 _ => unreachable!(),
157 }))
158 .into_array()
159 })
160 .collect::<ChunkedArray>()
161 .into_array()
162 }
163
164 #[test]
165 fn tests() {
166 let len = 1000;
167 let chunk_count = 10;
168 let chunk = make_opt_bool_chunks(len, chunk_count);
169
170 let mut builder = builder_with_capacity(chunk.dtype(), len * chunk_count);
171 chunk.clone().append_to_builder(builder.as_mut());
172
173 let canon_into = builder.finish().to_bool();
174 let into_canon = chunk.to_bool();
175
176 assert_eq!(canon_into.validity(), into_canon.validity());
177 assert_eq!(canon_into.boolean_buffer(), into_canon.boolean_buffer());
178 }
179
180 #[test]
181 fn test_append_scalar() {
182 let mut builder = BoolBuilder::with_capacity(Nullability::Nullable, 10);
183
184 let true_scalar = Scalar::bool(true, Nullability::Nullable);
186 builder.append_scalar(&true_scalar).unwrap();
187
188 let false_scalar = Scalar::bool(false, Nullability::Nullable);
190 builder.append_scalar(&false_scalar).unwrap();
191
192 let null_scalar = Scalar::null(DType::Bool(Nullability::Nullable));
194 builder.append_scalar(&null_scalar).unwrap();
195
196 let array = builder.finish_into_bool();
197 assert_eq!(array.len(), 3);
198
199 assert!(array.boolean_buffer().value(0));
201 assert!(!array.boolean_buffer().value(1));
202 assert!(array.validity().is_valid(0));
206 assert!(array.validity().is_valid(1));
207 assert!(!array.validity().is_valid(2));
208
209 let mut builder = BoolBuilder::with_capacity(Nullability::NonNullable, 10);
211 let wrong_scalar = Scalar::from(42i32);
212 assert!(builder.append_scalar(&wrong_scalar).is_err());
213 }
214}