use crate::{BooleanBufferBuilder, MutableBuffer, NullBuffer};
#[derive(Debug)]
pub struct NullBufferBuilder {
bitmap_builder: Option<BooleanBufferBuilder>,
len: usize,
capacity: usize,
}
impl NullBufferBuilder {
pub fn new(capacity: usize) -> Self {
Self {
bitmap_builder: None,
len: 0,
capacity,
}
}
pub fn new_with_len(len: usize) -> Self {
Self {
bitmap_builder: None,
len,
capacity: len,
}
}
pub fn new_from_buffer(buffer: MutableBuffer, len: usize) -> Self {
let capacity = buffer.len() * 8;
assert!(len < capacity);
let bitmap_builder = Some(BooleanBufferBuilder::new_from_buffer(buffer, len));
Self {
bitmap_builder,
len,
capacity,
}
}
#[inline]
pub fn append_n_non_nulls(&mut self, n: usize) {
if let Some(buf) = self.bitmap_builder.as_mut() {
buf.append_n(n, true)
} else {
self.len += n;
}
}
#[inline]
pub fn append_non_null(&mut self) {
if let Some(buf) = self.bitmap_builder.as_mut() {
buf.append(true)
} else {
self.len += 1;
}
}
#[inline]
pub fn append_n_nulls(&mut self, n: usize) {
self.materialize_if_needed();
self.bitmap_builder.as_mut().unwrap().append_n(n, false);
}
#[inline]
pub fn append_null(&mut self) {
self.materialize_if_needed();
self.bitmap_builder.as_mut().unwrap().append(false);
}
#[inline]
pub fn append(&mut self, not_null: bool) {
if not_null {
self.append_non_null()
} else {
self.append_null()
}
}
pub fn append_slice(&mut self, slice: &[bool]) {
if slice.iter().any(|v| !v) {
self.materialize_if_needed()
}
if let Some(buf) = self.bitmap_builder.as_mut() {
buf.append_slice(slice)
} else {
self.len += slice.len();
}
}
pub fn finish(&mut self) -> Option<NullBuffer> {
self.len = 0;
Some(NullBuffer::new(self.bitmap_builder.take()?.finish()))
}
pub fn finish_cloned(&self) -> Option<NullBuffer> {
let buffer = self.bitmap_builder.as_ref()?.finish_cloned();
Some(NullBuffer::new(buffer))
}
pub fn as_slice(&self) -> Option<&[u8]> {
Some(self.bitmap_builder.as_ref()?.as_slice())
}
fn materialize_if_needed(&mut self) {
if self.bitmap_builder.is_none() {
self.materialize()
}
}
#[cold]
fn materialize(&mut self) {
if self.bitmap_builder.is_none() {
let mut b = BooleanBufferBuilder::new(self.len.max(self.capacity));
b.append_n(self.len, true);
self.bitmap_builder = Some(b);
}
}
pub fn as_slice_mut(&mut self) -> Option<&mut [u8]> {
self.bitmap_builder.as_mut().map(|b| b.as_slice_mut())
}
}
impl NullBufferBuilder {
pub fn len(&self) -> usize {
if let Some(b) = &self.bitmap_builder {
b.len()
} else {
self.len
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_null_buffer_builder() {
let mut builder = NullBufferBuilder::new(0);
builder.append_null();
builder.append_non_null();
builder.append_n_nulls(2);
builder.append_n_non_nulls(2);
assert_eq!(6, builder.len());
let buf = builder.finish().unwrap();
assert_eq!(&[0b110010_u8], buf.validity());
}
#[test]
fn test_null_buffer_builder_all_nulls() {
let mut builder = NullBufferBuilder::new(0);
builder.append_null();
builder.append_n_nulls(2);
builder.append_slice(&[false, false, false]);
assert_eq!(6, builder.len());
let buf = builder.finish().unwrap();
assert_eq!(&[0b0_u8], buf.validity());
}
#[test]
fn test_null_buffer_builder_no_null() {
let mut builder = NullBufferBuilder::new(0);
builder.append_non_null();
builder.append_n_non_nulls(2);
builder.append_slice(&[true, true, true]);
assert_eq!(6, builder.len());
let buf = builder.finish();
assert!(buf.is_none());
}
#[test]
fn test_null_buffer_builder_reset() {
let mut builder = NullBufferBuilder::new(0);
builder.append_slice(&[true, false, true]);
builder.finish();
assert!(builder.is_empty());
builder.append_slice(&[true, true, true]);
assert!(builder.finish().is_none());
assert!(builder.is_empty());
builder.append_slice(&[true, true, false, true]);
let buf = builder.finish().unwrap();
assert_eq!(&[0b1011_u8], buf.validity());
}
}