Skip to main content

arrow_buffer/builder/
null.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::{BooleanBufferBuilder, MutableBuffer, NullBuffer};
19
20/// Builder for creating [`NullBuffer`]s (bitmaps indicating validity/nulls).
21///
22/// # See also
23/// * [`BooleanBufferBuilder`] for a lower-level bitmap builder.
24/// * [`Self::allocated_size`] for the current memory allocated by the builder.
25///
26/// # Performance
27///
28/// This builder only materializes the buffer when null values (`false`) are
29/// appended. If you only append non-null, (`true`) to the builder, no buffer is
30/// allocated and [`build`](#method.build) or [`finish`](#method.finish) return
31/// `None`.
32///
33/// This optimization is **very** important for the performance as it avoids
34/// allocating memory for the null buffer when there are no nulls.
35///
36/// # Example
37/// ```
38/// # use arrow_buffer::NullBufferBuilder;
39/// let mut builder = NullBufferBuilder::new(8);
40/// builder.append_n_non_nulls(8);
41/// // If no non null values are appended, the null buffer is not created
42/// let buffer = builder.finish();
43/// assert!(buffer.is_none());
44/// // however, if a null value is appended, the null buffer is created
45/// let mut builder = NullBufferBuilder::new(8);
46/// builder.append_n_non_nulls(7);
47/// builder.append_null();
48/// let buffer = builder.finish().unwrap();
49/// assert_eq!(buffer.len(), 8);
50/// assert_eq!(buffer.iter().collect::<Vec<_>>(), vec![true, true, true, true, true, true, true, false]);
51/// ```
52#[derive(Debug)]
53pub struct NullBufferBuilder {
54    /// The bitmap builder to store the null buffer:
55    /// * `Some` if any nulls have been appended ("materialized")
56    /// * `None` if no nulls have been appended.
57    bitmap_builder: Option<BooleanBufferBuilder>,
58    /// Length of the buffer before materializing.
59    ///
60    /// if `bitmap_buffer` buffer is `Some`, this value is not used.
61    len: usize,
62    /// Initial capacity of the `bitmap_builder`, when it is materialized.
63    capacity: usize,
64}
65
66impl NullBufferBuilder {
67    /// Creates a new empty builder.
68    ///
69    /// Note that this method does not allocate any memory, regardless of the
70    /// `capacity` parameter. If an allocation is required, `capacity` is the
71    /// size in bits (not bytes) that will be allocated at minimum.
72    pub fn new(capacity: usize) -> Self {
73        Self {
74            bitmap_builder: None,
75            len: 0,
76            capacity,
77        }
78    }
79
80    /// Creates a new builder with given length.
81    pub fn new_with_len(len: usize) -> Self {
82        Self {
83            bitmap_builder: None,
84            len,
85            capacity: len,
86        }
87    }
88
89    /// Creates a new builder from a `MutableBuffer`.
90    ///
91    /// # Panics
92    ///
93    /// Panics if `len > buffer.len() * 8`
94    pub fn new_from_buffer(buffer: MutableBuffer, len: usize) -> Self {
95        let capacity = buffer.len() * 8;
96        assert!(len <= capacity);
97
98        let bitmap_builder = Some(BooleanBufferBuilder::new_from_buffer(buffer, len));
99        Self {
100            bitmap_builder,
101            len,
102            capacity,
103        }
104    }
105
106    /// Appends `n` `true`s into the builder
107    /// to indicate that these `n` items are not nulls.
108    #[inline]
109    pub fn append_n_non_nulls(&mut self, n: usize) {
110        if let Some(buf) = self.bitmap_builder.as_mut() {
111            buf.append_n(n, true)
112        } else {
113            self.len += n;
114        }
115    }
116
117    /// Appends a `true` into the builder
118    /// to indicate that this item is not null.
119    #[inline]
120    pub fn append_non_null(&mut self) {
121        if let Some(buf) = self.bitmap_builder.as_mut() {
122            buf.append(true)
123        } else {
124            self.len += 1;
125        }
126    }
127
128    /// Appends `n` `false`s into the builder
129    /// to indicate that these `n` items are nulls.
130    #[inline]
131    pub fn append_n_nulls(&mut self, n: usize) {
132        self.materialize_if_needed().append_n(n, false);
133    }
134
135    /// Appends a `false` into the builder
136    /// to indicate that this item is null.
137    #[inline]
138    pub fn append_null(&mut self) {
139        self.materialize_if_needed().append(false);
140    }
141
142    /// Appends a boolean value into the builder.
143    #[inline]
144    pub fn append(&mut self, not_null: bool) {
145        if not_null {
146            self.append_non_null()
147        } else {
148            self.append_null()
149        }
150    }
151
152    /// Sets a bit in the builder at `index`
153    ///
154    /// # Panics
155    ///
156    /// Panics for the same reasons as [`BooleanBufferBuilder::set_bit`]
157    #[inline]
158    pub fn set_bit(&mut self, index: usize, v: bool) {
159        self.materialize_if_needed().set_bit(index, v);
160    }
161
162    /// Gets a bit in the buffer at `index`
163    ///
164    /// # Panics
165    ///
166    /// Panics for the same reasons as [`BooleanBufferBuilder::get_bit`], but only if
167    /// a bitmap has been materialized (i.e. a null was appended)
168    #[inline]
169    pub fn is_valid(&self, index: usize) -> bool {
170        if let Some(ref buf) = self.bitmap_builder {
171            buf.get_bit(index)
172        } else {
173            true
174        }
175    }
176
177    /// Truncates the builder to the given length
178    ///
179    /// If `len` is greater than the buffer's current length, this has no effect
180    #[inline]
181    pub fn truncate(&mut self, len: usize) {
182        if let Some(buf) = self.bitmap_builder.as_mut() {
183            buf.truncate(len);
184        } else if len <= self.len {
185            self.len = len
186        }
187    }
188
189    /// Appends a boolean slice into the builder
190    /// to indicate the validations of these items.
191    pub fn append_slice(&mut self, slice: &[bool]) {
192        // First check if not already materialized before checking if there are any nulls
193        if self.bitmap_builder.is_none() && slice.iter().any(|v| !v) {
194            self.materialize_if_needed();
195        }
196        if let Some(buf) = self.bitmap_builder.as_mut() {
197            buf.append_slice(slice)
198        } else {
199            self.len += slice.len();
200        }
201    }
202
203    /// Append [`NullBuffer`] to this [`NullBufferBuilder`]
204    ///
205    /// This is useful when you want to concatenate two null buffers.
206    pub fn append_buffer(&mut self, buffer: &NullBuffer) {
207        if buffer.null_count() > 0 {
208            self.materialize_if_needed();
209        }
210        if let Some(buf) = self.bitmap_builder.as_mut() {
211            buf.append_buffer(buffer.inner())
212        } else {
213            self.len += buffer.len();
214        }
215    }
216
217    /// Builds the [`NullBuffer`] and resets the builder.
218    ///
219    /// Returns `None` if the builder only contains `true`s. Use [`Self::build`]
220    /// when you don't need to reuse this builder.
221    pub fn finish(&mut self) -> Option<NullBuffer> {
222        self.len = 0;
223        Some(NullBuffer::new(self.bitmap_builder.take()?.build()))
224    }
225
226    /// Builds the [`NullBuffer`] without resetting the builder.
227    ///
228    /// This consumes the builder. Use [`Self::finish`] to reuse it.
229    pub fn build(self) -> Option<NullBuffer> {
230        self.bitmap_builder.map(NullBuffer::from)
231    }
232
233    /// Builds the [NullBuffer] without resetting the builder.
234    pub fn finish_cloned(&self) -> Option<NullBuffer> {
235        let buffer = self.bitmap_builder.as_ref()?.finish_cloned();
236        Some(NullBuffer::new(buffer))
237    }
238
239    /// Returns the inner bitmap builder as slice
240    pub fn as_slice(&self) -> Option<&[u8]> {
241        Some(self.bitmap_builder.as_ref()?.as_slice())
242    }
243
244    fn materialize_if_needed(&mut self) -> &mut BooleanBufferBuilder {
245        let (len, capacity) = (self.len, self.capacity);
246        self.bitmap_builder
247            .get_or_insert_with(|| Self::materialize(len, capacity))
248    }
249
250    #[cold]
251    fn materialize(len: usize, capacity: usize) -> BooleanBufferBuilder {
252        let mut b = BooleanBufferBuilder::new(len.max(capacity));
253        b.append_n(len, true);
254        b
255    }
256
257    /// Return a mutable reference to the inner bitmap slice.
258    pub fn as_slice_mut(&mut self) -> Option<&mut [u8]> {
259        self.bitmap_builder.as_mut().map(|b| b.as_slice_mut())
260    }
261
262    /// Return the allocated size of this builder, in bytes, useful for memory accounting.
263    pub fn allocated_size(&self) -> usize {
264        self.bitmap_builder
265            .as_ref()
266            .map(|b| b.capacity() / 8)
267            .unwrap_or(0)
268    }
269
270    /// Return the number of bits in the buffer.
271    pub fn len(&self) -> usize {
272        self.bitmap_builder.as_ref().map_or(self.len, |b| b.len())
273    }
274
275    /// Check if the builder is empty.
276    pub fn is_empty(&self) -> bool {
277        self.len() == 0
278    }
279}
280
281#[cfg(test)]
282mod tests {
283    use super::*;
284
285    #[test]
286    fn test_null_buffer_builder() {
287        let mut builder = NullBufferBuilder::new(0);
288        builder.append_null();
289        builder.append_non_null();
290        builder.append_n_nulls(2);
291        builder.append_n_non_nulls(2);
292        assert_eq!(6, builder.len());
293        assert_eq!(64, builder.allocated_size());
294
295        let buf = builder.finish().unwrap();
296        assert_eq!(&[0b110010_u8], buf.validity());
297    }
298
299    #[test]
300    fn test_null_buffer_builder_all_nulls() {
301        let mut builder = NullBufferBuilder::new(0);
302        builder.append_null();
303        builder.append_n_nulls(2);
304        builder.append_slice(&[false, false, false]);
305        assert_eq!(6, builder.len());
306        assert_eq!(64, builder.allocated_size());
307
308        let buf = builder.finish().unwrap();
309        assert_eq!(&[0b0_u8], buf.validity());
310    }
311
312    #[test]
313    fn test_null_buffer_builder_no_null() {
314        let mut builder = NullBufferBuilder::new(0);
315        builder.append_non_null();
316        builder.append_n_non_nulls(2);
317        builder.append_slice(&[true, true, true]);
318        assert_eq!(6, builder.len());
319        assert_eq!(0, builder.allocated_size());
320
321        let buf = builder.finish();
322        assert!(buf.is_none());
323    }
324
325    #[test]
326    fn test_null_buffer_builder_reset() {
327        let mut builder = NullBufferBuilder::new(0);
328        builder.append_slice(&[true, false, true]);
329        builder.finish();
330        assert!(builder.is_empty());
331
332        builder.append_slice(&[true, true, true]);
333        assert!(builder.finish().is_none());
334        assert!(builder.is_empty());
335
336        builder.append_slice(&[true, true, false, true]);
337
338        let buf = builder.finish().unwrap();
339        assert_eq!(&[0b1011_u8], buf.validity());
340    }
341
342    #[test]
343    fn test_null_buffer_builder_is_valid() {
344        let mut builder = NullBufferBuilder::new(0);
345        builder.append_n_non_nulls(6);
346        assert!(builder.is_valid(0));
347
348        builder.append_null();
349        assert!(!builder.is_valid(6));
350
351        builder.append_non_null();
352        assert!(builder.is_valid(7));
353    }
354
355    #[test]
356    fn test_null_buffer_builder_truncate() {
357        let mut builder = NullBufferBuilder::new(10);
358        builder.append_n_non_nulls(16);
359        assert_eq!(builder.as_slice(), None);
360        builder.truncate(20);
361        assert_eq!(builder.as_slice(), None);
362        assert_eq!(builder.len(), 16);
363        assert_eq!(builder.allocated_size(), 0);
364        builder.truncate(14);
365        assert_eq!(builder.as_slice(), None);
366        assert_eq!(builder.len(), 14);
367        builder.append_null();
368        builder.append_non_null();
369        assert_eq!(builder.as_slice().unwrap(), &[0xFF, 0b10111111]);
370        assert_eq!(builder.allocated_size(), 64);
371    }
372
373    #[test]
374    fn test_null_buffer_builder_truncate_never_materialized() {
375        let mut builder = NullBufferBuilder::new(0);
376        assert_eq!(builder.len(), 0);
377        builder.append_n_nulls(2); // doesn't materialize
378        assert_eq!(builder.len(), 2);
379        builder.truncate(1);
380        assert_eq!(builder.len(), 1);
381    }
382
383    #[test]
384    fn test_append_buffers() {
385        let mut builder = NullBufferBuilder::new(0);
386        let buffer1 = NullBuffer::from(&[true, true]);
387        let buffer2 = NullBuffer::from(&[true, true, false]);
388
389        builder.append_buffer(&buffer1);
390        builder.append_buffer(&buffer2);
391
392        assert_eq!(builder.as_slice().unwrap(), &[0b01111_u8]);
393    }
394
395    #[test]
396    fn test_append_buffers_with_unaligned_length() {
397        let mut builder = NullBufferBuilder::new(0);
398        let buffer = NullBuffer::from(&[true, true, false, true, false]);
399        builder.append_buffer(&buffer);
400        assert_eq!(builder.as_slice().unwrap(), &[0b01011_u8]);
401
402        let buffer = NullBuffer::from(&[false, false, true, true, true, false, false]);
403        builder.append_buffer(&buffer);
404        assert_eq!(builder.as_slice().unwrap(), &[0b10001011_u8, 0b0011_u8]);
405    }
406
407    #[test]
408    fn test_append_empty_buffer() {
409        let mut builder = NullBufferBuilder::new(0);
410        let buffer = NullBuffer::from(&[true, true, false, true]);
411        builder.append_buffer(&buffer);
412        assert_eq!(builder.as_slice().unwrap(), &[0b1011_u8]);
413
414        let buffer = NullBuffer::from(&[]);
415        builder.append_buffer(&buffer);
416
417        assert_eq!(builder.as_slice().unwrap(), &[0b1011_u8]);
418    }
419
420    #[test]
421    fn test_should_not_materialize_when_appending_all_valid_buffers() {
422        let mut builder = NullBufferBuilder::new(0);
423        let buffer = NullBuffer::from(&[true; 10]);
424        builder.append_buffer(&buffer);
425
426        let buffer = NullBuffer::from(&[true; 2]);
427        builder.append_buffer(&buffer);
428
429        assert_eq!(builder.finish(), None);
430    }
431}