use crate::column::Column;
use crate::error::{CudfError, Result};
use crate::types::checked_i32;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MaskState {
Unallocated = 0,
Uninitialized = 1,
AllValid = 2,
AllNull = 3,
}
pub fn bitmask_allocation_size(num_bits: usize) -> Result<usize> {
Ok(cudf_cxx::null_mask::ffi::bitmask_allocation_size(checked_i32(num_bits)?) as usize)
}
pub fn null_mask_to_host(col: &Column) -> Result<Vec<u8>> {
let num_bytes = bitmask_allocation_size(col.len())?;
if num_bytes == 0 {
return Ok(Vec::new());
}
let mut buf = vec![0u8; num_bytes];
cudf_cxx::null_mask::ffi::copy_null_mask_to_host(&col.inner, &mut buf)
.map_err(CudfError::from_cxx)?;
Ok(buf)
}
pub fn null_count(col: &Column) -> usize {
cudf_cxx::null_mask::ffi::null_count_column(&col.inner) as usize
}
impl Column {
pub fn with_null_mask(&self, mask: &[u8], null_count: usize) -> Result<Column> {
let raw = cudf_cxx::null_mask::ffi::set_null_mask_from_host(
&self.inner,
mask,
checked_i32(null_count)?,
)
.map_err(CudfError::from_cxx)?;
Ok(Column { inner: raw })
}
pub fn set_null_mask_range(&self, begin: usize, end: usize, valid: bool) -> Result<Column> {
let raw = cudf_cxx::null_mask::ffi::set_null_mask_range(
&self.inner,
checked_i32(begin)?,
checked_i32(end)?,
valid,
)
.map_err(CudfError::from_cxx)?;
Ok(Column { inner: raw })
}
pub fn index_of_first_valid(&self) -> Result<Option<usize>> {
let idx = cudf_cxx::null_mask::ffi::index_of_first_set_bit(&self.inner)
.map_err(CudfError::from_cxx)?;
Ok(if idx < 0 { None } else { Some(idx as usize) })
}
}
pub fn copy_bitmask(col: &Column) -> Vec<u8> {
cudf_cxx::null_mask::ffi::copy_bitmask_to_host(&col.inner)
}
pub struct BitmaskResult {
pub mask: Vec<u8>,
pub null_count: usize,
}
pub fn bitmask_and(columns: &[&Column]) -> Result<BitmaskResult> {
if columns.is_empty() {
return Err(CudfError::InvalidArgument(
"bitmask_and requires at least one column".to_string(),
));
}
let mut builder = cudf_cxx::null_mask::ffi::bitmask_builder_new();
for col in columns {
builder.pin_mut().add_column(&col.inner);
}
let result = cudf_cxx::null_mask::ffi::bitmask_and(&builder).map_err(CudfError::from_cxx)?;
Ok(BitmaskResult {
mask: result.get_mask(),
null_count: result.get_null_count() as usize,
})
}
pub fn state_null_count(state: MaskState, size: usize) -> Result<usize> {
let count = cudf_cxx::null_mask::ffi::state_null_count(state as i32, checked_i32(size)?)
.map_err(CudfError::from_cxx)?;
Ok(count as usize)
}
pub fn num_bitmask_words(num_bits: usize) -> Result<usize> {
Ok(cudf_cxx::null_mask::ffi::num_bitmask_words(checked_i32(num_bits)?) as usize)
}
pub fn bitmask_or(columns: &[&Column]) -> Result<BitmaskResult> {
if columns.is_empty() {
return Err(CudfError::InvalidArgument(
"bitmask_or requires at least one column".to_string(),
));
}
let mut builder = cudf_cxx::null_mask::ffi::bitmask_builder_new();
for col in columns {
builder.pin_mut().add_column(&col.inner);
}
let result = cudf_cxx::null_mask::ffi::bitmask_or(&builder).map_err(CudfError::from_cxx)?;
Ok(BitmaskResult {
mask: result.get_mask(),
null_count: result.get_null_count() as usize,
})
}