@@ -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 ) ]
4850pub 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