use std::any::Any;
use std::sync::Arc;
use crate::array::ArrayBuilder;
use crate::array::ArrayData;
use crate::array::ArrayRef;
use crate::array::BooleanArray;
use crate::datatypes::DataType;
use crate::error::ArrowError;
use crate::error::Result;
use super::BooleanBufferBuilder;
#[derive(Debug)]
pub struct BooleanBuilder {
values_builder: BooleanBufferBuilder,
bitmap_builder: Option<BooleanBufferBuilder>,
}
impl BooleanBuilder {
pub fn new(capacity: usize) -> Self {
Self {
values_builder: BooleanBufferBuilder::new(capacity),
bitmap_builder: None,
}
}
pub fn capacity(&self) -> usize {
self.values_builder.capacity()
}
#[inline]
pub fn append_value(&mut self, v: bool) {
self.values_builder.append(v);
if let Some(b) = self.bitmap_builder.as_mut() {
b.append(true)
}
}
#[inline]
pub fn append_null(&mut self) {
self.materialize_bitmap_builder();
self.bitmap_builder.as_mut().unwrap().append(false);
self.values_builder.advance(1);
}
#[inline]
pub fn append_option(&mut self, v: Option<bool>) {
match v {
None => self.append_null(),
Some(v) => self.append_value(v),
};
}
#[inline]
pub fn append_slice(&mut self, v: &[bool]) {
if let Some(b) = self.bitmap_builder.as_mut() {
b.append_n(v.len(), true)
}
self.values_builder.append_slice(v);
}
#[inline]
pub fn append_values(&mut self, values: &[bool], is_valid: &[bool]) -> Result<()> {
if values.len() != is_valid.len() {
Err(ArrowError::InvalidArgumentError(
"Value and validity lengths must be equal".to_string(),
))
} else {
is_valid
.iter()
.any(|v| !*v)
.then(|| self.materialize_bitmap_builder());
if let Some(b) = self.bitmap_builder.as_mut() {
b.append_slice(is_valid)
}
self.values_builder.append_slice(values);
Ok(())
}
}
pub fn finish(&mut self) -> BooleanArray {
let len = self.len();
let null_bit_buffer = self.bitmap_builder.as_mut().map(|b| b.finish());
let builder = ArrayData::builder(DataType::Boolean)
.len(len)
.add_buffer(self.values_builder.finish())
.null_bit_buffer(null_bit_buffer);
let array_data = unsafe { builder.build_unchecked() };
BooleanArray::from(array_data)
}
fn materialize_bitmap_builder(&mut self) {
if self.bitmap_builder.is_none() {
let mut b = BooleanBufferBuilder::new(0);
b.reserve(self.values_builder.capacity());
b.append_n(self.values_builder.len(), true);
self.bitmap_builder = Some(b);
}
}
}
impl ArrayBuilder for BooleanBuilder {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn into_box_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn len(&self) -> usize {
self.values_builder.len()
}
fn is_empty(&self) -> bool {
self.values_builder.is_empty()
}
fn finish(&mut self) -> ArrayRef {
Arc::new(self.finish())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{array::Array, buffer::Buffer};
#[test]
fn test_boolean_array_builder() {
let buf = Buffer::from([72_u8, 2_u8]);
let mut builder = BooleanArray::builder(10);
for i in 0..10 {
if i == 3 || i == 6 || i == 9 {
builder.append_value(true);
} else {
builder.append_value(false);
}
}
let arr = builder.finish();
assert_eq!(&buf, arr.values());
assert_eq!(10, arr.len());
assert_eq!(0, arr.offset());
assert_eq!(0, arr.null_count());
for i in 0..10 {
assert!(!arr.is_null(i));
assert!(arr.is_valid(i));
assert_eq!(i == 3 || i == 6 || i == 9, arr.value(i), "failed at {}", i)
}
}
#[test]
fn test_boolean_array_builder_append_slice() {
let arr1 =
BooleanArray::from(vec![Some(true), Some(false), None, None, Some(false)]);
let mut builder = BooleanArray::builder(0);
builder.append_slice(&[true, false]);
builder.append_null();
builder.append_null();
builder.append_value(false);
let arr2 = builder.finish();
assert_eq!(arr1, arr2);
}
#[test]
fn test_boolean_array_builder_append_slice_large() {
let arr1 = BooleanArray::from(vec![true; 513]);
let mut builder = BooleanArray::builder(512);
builder.append_slice(&[true; 513]);
let arr2 = builder.finish();
assert_eq!(arr1, arr2);
}
#[test]
fn test_boolean_array_builder_no_null() {
let mut builder = BooleanArray::builder(0);
builder.append_option(Some(true));
builder.append_value(false);
builder.append_slice(&[true, false, true]);
builder
.append_values(&[false, false, true], &[true, true, true])
.unwrap();
let array = builder.finish();
assert_eq!(0, array.null_count());
assert!(array.data().null_buffer().is_none());
}
}