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()
}
}
#[inline]
pub fn is_valid(&self, index: usize) -> bool {
if let Some(ref buf) = self.bitmap_builder {
buf.get_bit(index)
} else {
true
}
}
#[inline]
pub fn truncate(&mut self, len: usize) {
if let Some(buf) = self.bitmap_builder.as_mut() {
buf.truncate(len);
} else if len <= self.len {
self.len = len
}
}
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 append_buffer(&mut self, buffer: &NullBuffer) {
if buffer.null_count() > 0 {
self.materialize_if_needed();
}
if let Some(buf) = self.bitmap_builder.as_mut() {
buf.append_buffer(buffer.inner())
} else {
self.len += buffer.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())
}
pub fn allocated_size(&self) -> usize {
self.bitmap_builder
.as_ref()
.map(|b| b.capacity() / 8)
.unwrap_or(0)
}
}
impl NullBufferBuilder {
pub fn len(&self) -> usize {
self.bitmap_builder.as_ref().map_or(self.len, |b| b.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());
assert_eq!(64, builder.allocated_size());
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());
assert_eq!(64, builder.allocated_size());
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());
assert_eq!(0, builder.allocated_size());
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());
}
#[test]
fn test_null_buffer_builder_is_valid() {
let mut builder = NullBufferBuilder::new(0);
builder.append_n_non_nulls(6);
assert!(builder.is_valid(0));
builder.append_null();
assert!(!builder.is_valid(6));
builder.append_non_null();
assert!(builder.is_valid(7));
}
#[test]
fn test_null_buffer_builder_truncate() {
let mut builder = NullBufferBuilder::new(10);
builder.append_n_non_nulls(16);
assert_eq!(builder.as_slice(), None);
builder.truncate(20);
assert_eq!(builder.as_slice(), None);
assert_eq!(builder.len(), 16);
assert_eq!(builder.allocated_size(), 0);
builder.truncate(14);
assert_eq!(builder.as_slice(), None);
assert_eq!(builder.len(), 14);
builder.append_null();
builder.append_non_null();
assert_eq!(builder.as_slice().unwrap(), &[0xFF, 0b10111111]);
assert_eq!(builder.allocated_size(), 64);
}
#[test]
fn test_null_buffer_builder_truncate_never_materialized() {
let mut builder = NullBufferBuilder::new(0);
assert_eq!(builder.len(), 0);
builder.append_n_nulls(2); assert_eq!(builder.len(), 2);
builder.truncate(1);
assert_eq!(builder.len(), 1);
}
#[test]
fn test_append_buffers() {
let mut builder = NullBufferBuilder::new(0);
let buffer1 = NullBuffer::from(&[true, true]);
let buffer2 = NullBuffer::from(&[true, true, false]);
builder.append_buffer(&buffer1);
builder.append_buffer(&buffer2);
assert_eq!(builder.as_slice().unwrap(), &[0b01111_u8]);
}
#[test]
fn test_append_buffers_with_unaligned_length() {
let mut builder = NullBufferBuilder::new(0);
let buffer = NullBuffer::from(&[true, true, false, true, false]);
builder.append_buffer(&buffer);
assert_eq!(builder.as_slice().unwrap(), &[0b01011_u8]);
let buffer = NullBuffer::from(&[false, false, true, true, true, false, false]);
builder.append_buffer(&buffer);
assert_eq!(builder.as_slice().unwrap(), &[0b10001011_u8, 0b0011_u8]);
}
#[test]
fn test_append_empty_buffer() {
let mut builder = NullBufferBuilder::new(0);
let buffer = NullBuffer::from(&[true, true, false, true]);
builder.append_buffer(&buffer);
assert_eq!(builder.as_slice().unwrap(), &[0b1011_u8]);
let buffer = NullBuffer::from(&[]);
builder.append_buffer(&buffer);
assert_eq!(builder.as_slice().unwrap(), &[0b1011_u8]);
}
#[test]
fn test_should_not_materialize_when_appending_all_valid_buffers() {
let mut builder = NullBufferBuilder::new(0);
let buffer = NullBuffer::from(&[true; 10]);
builder.append_buffer(&buffer);
let buffer = NullBuffer::from(&[true; 2]);
builder.append_buffer(&buffer);
assert_eq!(builder.finish(), None);
}
}