Skip to content

Commit 6aaff7e

Browse files
Chen-Yuan-LaiIan LaiCheng-Yuan-Laialamb
authored
Add is_valid and truncate methods to NullBufferBuilder (#7013)
* feat: add required methods to NullBufferBuilder * modify realated unit tests * remove blank * fix typo & naming * add more assert in unit tests * remove the change for sync self.capacity in apped/truncate/new_from_buffer calls * remove ';' * refactor NullBufferBuilder methods to use references for bitmap_builder * Add another test for truncate * Update arrow-buffer/src/builder/null.rs * Remove capacity and use allocated_size instead * fix truncate --------- Co-authored-by: Ian Lai <Ian.Lai@senao.com> Co-authored-by: Cheng-Yuan-Lai <a186235@g,ail.com> Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
1 parent a28f4ef commit 6aaff7e

File tree

1 file changed

+75
-2
lines changed

1 file changed

+75
-2
lines changed

arrow-buffer/src/builder/null.rs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ use crate::{BooleanBufferBuilder, MutableBuffer, NullBuffer};
2828
/// This optimization is **very** important for the performance as it avoids
2929
/// allocating memory for the null buffer when there are no nulls.
3030
///
31+
/// See [`Self::allocated_size`] to get the current memory allocated by the builder.
32+
///
3133
/// # Example
3234
/// ```
3335
/// # use arrow_buffer::NullBufferBuilder;
@@ -46,9 +48,15 @@ use crate::{BooleanBufferBuilder, MutableBuffer, NullBuffer};
4648
/// ```
4749
#[derive(Debug)]
4850
pub struct NullBufferBuilder {
51+
/// The bitmap builder to store the null buffer:
52+
/// * `Some` if any nulls have been appended ("materialized")
53+
/// * `None` if no nulls have been appended.
4954
bitmap_builder: Option<BooleanBufferBuilder>,
50-
/// Store the length of the buffer before materializing.
55+
/// Length of the buffer before materializing.
56+
///
57+
/// if `bitmap_buffer` buffer is `Some`, this value is not used.
5158
len: usize,
59+
/// Initial capacity of the `bitmap_builder`, when it is materialized.
5260
capacity: usize,
5361
}
5462

@@ -78,7 +86,6 @@ impl NullBufferBuilder {
7886
/// Creates a new builder from a `MutableBuffer`.
7987
pub fn new_from_buffer(buffer: MutableBuffer, len: usize) -> Self {
8088
let capacity = buffer.len() * 8;
81-
8289
assert!(len <= capacity);
8390

8491
let bitmap_builder = Some(BooleanBufferBuilder::new_from_buffer(buffer, len));
@@ -137,6 +144,28 @@ impl NullBufferBuilder {
137144
}
138145
}
139146

147+
/// Gets a bit in the buffer at `index`
148+
#[inline]
149+
pub fn is_valid(&self, index: usize) -> bool {
150+
if let Some(ref buf) = self.bitmap_builder {
151+
buf.get_bit(index)
152+
} else {
153+
true
154+
}
155+
}
156+
157+
/// Truncates the builder to the given length
158+
///
159+
/// If `len` is greater than the buffer's current length, this has no effect
160+
#[inline]
161+
pub fn truncate(&mut self, len: usize) {
162+
if let Some(buf) = self.bitmap_builder.as_mut() {
163+
buf.truncate(len);
164+
} else if len <= self.len {
165+
self.len = len
166+
}
167+
}
168+
140169
/// Appends a boolean slice into the builder
141170
/// to indicate the validations of these items.
142171
pub fn append_slice(&mut self, slice: &[bool]) {
@@ -221,6 +250,7 @@ mod tests {
221250
builder.append_n_nulls(2);
222251
builder.append_n_non_nulls(2);
223252
assert_eq!(6, builder.len());
253+
assert_eq!(512, builder.allocated_size());
224254

225255
let buf = builder.finish().unwrap();
226256
assert_eq!(&[0b110010_u8], buf.validity());
@@ -233,6 +263,7 @@ mod tests {
233263
builder.append_n_nulls(2);
234264
builder.append_slice(&[false, false, false]);
235265
assert_eq!(6, builder.len());
266+
assert_eq!(512, builder.allocated_size());
236267

237268
let buf = builder.finish().unwrap();
238269
assert_eq!(&[0b0_u8], buf.validity());
@@ -245,6 +276,7 @@ mod tests {
245276
builder.append_n_non_nulls(2);
246277
builder.append_slice(&[true, true, true]);
247278
assert_eq!(6, builder.len());
279+
assert_eq!(0, builder.allocated_size());
248280

249281
let buf = builder.finish();
250282
assert!(buf.is_none());
@@ -266,4 +298,45 @@ mod tests {
266298
let buf = builder.finish().unwrap();
267299
assert_eq!(&[0b1011_u8], buf.validity());
268300
}
301+
302+
#[test]
303+
fn test_null_buffer_builder_is_valid() {
304+
let mut builder = NullBufferBuilder::new(0);
305+
builder.append_n_non_nulls(6);
306+
assert!(builder.is_valid(0));
307+
308+
builder.append_null();
309+
assert!(!builder.is_valid(6));
310+
311+
builder.append_non_null();
312+
assert!(builder.is_valid(7));
313+
}
314+
315+
#[test]
316+
fn test_null_buffer_builder_truncate() {
317+
let mut builder = NullBufferBuilder::new(10);
318+
builder.append_n_non_nulls(16);
319+
assert_eq!(builder.as_slice(), None);
320+
builder.truncate(20);
321+
assert_eq!(builder.as_slice(), None);
322+
assert_eq!(builder.len(), 16);
323+
assert_eq!(builder.allocated_size(), 0);
324+
builder.truncate(14);
325+
assert_eq!(builder.as_slice(), None);
326+
assert_eq!(builder.len(), 14);
327+
builder.append_null();
328+
builder.append_non_null();
329+
assert_eq!(builder.as_slice().unwrap(), &[0xFF, 0b10111111]);
330+
assert_eq!(builder.allocated_size(), 512);
331+
}
332+
333+
#[test]
334+
fn test_null_buffer_builder_truncate_never_materialized() {
335+
let mut builder = NullBufferBuilder::new(0);
336+
assert_eq!(builder.len(), 0);
337+
builder.append_n_nulls(2); // doesn't materialize
338+
assert_eq!(builder.len(), 2);
339+
builder.truncate(1);
340+
assert_eq!(builder.len(), 1);
341+
}
269342
}

0 commit comments

Comments
 (0)