use std::sync::Arc;
use antecedent_core::VariableId;
use antecedent_kernels::{BitMaskView, F64VectorView};
use crate::buffer::F64Buffer;
use crate::categorical::CategoricalColumn;
use crate::error::DataError;
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ValidityBitmap {
bytes: Arc<[u8]>,
len: usize,
}
impl ValidityBitmap {
#[must_use]
pub fn all_valid(len: usize) -> Self {
let n = len.div_ceil(8);
Self { bytes: Arc::from(vec![0xFFu8; n].into_boxed_slice()), len }
}
pub fn from_bytes(bytes: impl Into<Arc<[u8]>>, len: usize) -> Result<Self, DataError> {
let bytes = bytes.into();
if bytes.len() < len.div_ceil(8) {
return Err(DataError::InvalidValidity { message: "validity buffer too short" });
}
Ok(Self { bytes, len })
}
#[must_use]
pub const fn len(&self) -> usize {
self.len
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
pub fn as_mask_view(&self) -> Result<BitMaskView<'_>, DataError> {
BitMaskView::new(&self.bytes, self.len)
.map_err(|_| DataError::InvalidValidity { message: "mask view rejected buffer" })
}
#[must_use]
pub fn is_valid(&self, i: usize) -> bool {
self.as_mask_view().is_ok_and(|m| m.get(i))
}
#[must_use]
pub fn is_all_valid(&self) -> bool {
self.as_mask_view().is_ok_and(|m| (0..self.len).all(|i| m.get(i)))
}
pub fn gather(&self, row_map: &[u32]) -> Result<Self, DataError> {
let mask = self.as_mask_view()?;
let n = row_map.len();
let mut bytes = vec![0u8; n.div_ceil(8)];
for (i, &r) in row_map.iter().enumerate() {
let r = r as usize;
if r >= self.len {
return Err(DataError::InvalidValidity { message: "row map exceeds bitmap" });
}
if mask.get(r) {
bytes[i / 8] |= 1 << (i % 8);
}
}
Self::from_bytes(bytes, n)
}
pub fn gather_rows(&self, row_map: &[usize]) -> Result<Self, DataError> {
let mask = self.as_mask_view()?;
let n = row_map.len();
let mut bytes = vec![0u8; n.div_ceil(8)];
for (i, &r) in row_map.iter().enumerate() {
if r >= self.len {
return Err(DataError::InvalidValidity { message: "row map exceeds bitmap" });
}
if mask.get(r) {
bytes[i / 8] |= 1 << (i % 8);
}
}
Self::from_bytes(bytes, n)
}
pub fn compact(&self, keep: &[bool]) -> Result<Self, DataError> {
if keep.len() != self.len {
return Err(DataError::LengthMismatch {
expected: self.len,
actual: keep.len(),
context: "validity compact keep",
});
}
let n_new = keep.iter().filter(|&&k| k).count();
let mut bytes = vec![0u8; n_new.div_ceil(8)];
let mut j = 0usize;
for (i, &k) in keep.iter().enumerate() {
if k {
if self.is_valid(i) {
bytes[j / 8] |= 1 << (j % 8);
}
j += 1;
}
}
Self::from_bytes(bytes, n_new)
}
pub fn concat(parts: &[&Self]) -> Result<Self, DataError> {
let n: usize = parts.iter().map(|p| p.len).sum();
let mut bytes = vec![0u8; n.div_ceil(8)];
let mut offset = 0usize;
for part in parts {
for i in 0..part.len {
if part.is_valid(i) {
let j = offset + i;
bytes[j / 8] |= 1 << (j % 8);
}
}
offset += part.len;
}
Self::from_bytes(bytes, n)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Float64Column {
pub id: VariableId,
pub values: F64Buffer,
pub validity: ValidityBitmap,
}
impl Float64Column {
pub fn new(
id: VariableId,
values: impl Into<F64Buffer>,
validity: ValidityBitmap,
) -> Result<Self, DataError> {
let values = values.into();
if validity.len() != values.len() {
return Err(DataError::LengthMismatch {
expected: values.len(),
actual: validity.len(),
context: "float64 validity",
});
}
Ok(Self { id, values, validity })
}
#[must_use]
pub fn len(&self) -> usize {
self.values.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
#[must_use]
pub fn as_f64_view(&self) -> F64VectorView<'_> {
F64VectorView::contiguous(self.values.as_slice())
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Int64Column {
pub id: VariableId,
pub values: Arc<[i64]>,
pub validity: ValidityBitmap,
}
impl Int64Column {
pub fn new(
id: VariableId,
values: impl Into<Arc<[i64]>>,
validity: ValidityBitmap,
) -> Result<Self, DataError> {
let values = values.into();
if validity.len() != values.len() {
return Err(DataError::LengthMismatch {
expected: values.len(),
actual: validity.len(),
context: "int64 validity",
});
}
Ok(Self { id, values, validity })
}
#[must_use]
pub fn len(&self) -> usize {
self.values.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BooleanColumn {
pub id: VariableId,
pub values: Arc<[u8]>,
pub validity: ValidityBitmap,
}
impl BooleanColumn {
pub fn new(
id: VariableId,
values: impl Into<Arc<[u8]>>,
validity: ValidityBitmap,
) -> Result<Self, DataError> {
let values = values.into();
if validity.len() != values.len() {
return Err(DataError::LengthMismatch {
expected: values.len(),
actual: validity.len(),
context: "bool validity",
});
}
Ok(Self { id, values, validity })
}
#[must_use]
pub fn len(&self) -> usize {
self.values.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TimestampColumn {
pub id: VariableId,
pub values_ns: Arc<[i64]>,
pub validity: ValidityBitmap,
}
impl TimestampColumn {
pub fn new(
id: VariableId,
values_ns: impl Into<Arc<[i64]>>,
validity: ValidityBitmap,
) -> Result<Self, DataError> {
let values_ns = values_ns.into();
if validity.len() != values_ns.len() {
return Err(DataError::LengthMismatch {
expected: values_ns.len(),
actual: validity.len(),
context: "timestamp validity",
});
}
Ok(Self { id, values_ns, validity })
}
#[must_use]
pub fn len(&self) -> usize {
self.values_ns.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.values_ns.is_empty()
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct FixedVectorColumn {
pub id: VariableId,
pub dim: usize,
pub values: Arc<[f64]>,
pub validity: ValidityBitmap,
}
impl FixedVectorColumn {
pub fn new(
id: VariableId,
dim: usize,
values: impl Into<Arc<[f64]>>,
validity: ValidityBitmap,
) -> Result<Self, DataError> {
if dim == 0 {
return Err(DataError::InvalidValidity { message: "fixed vector dim must be > 0" });
}
let values = values.into();
let expected = validity
.len()
.checked_mul(dim)
.ok_or(DataError::InvalidValidity { message: "fixed vector shape overflow" })?;
if values.len() != expected {
return Err(DataError::LengthMismatch {
expected,
actual: values.len(),
context: "fixed vector values",
});
}
Ok(Self { id, dim, values, validity })
}
#[must_use]
pub fn len(&self) -> usize {
self.validity.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[derive(Clone, Copy, Debug)]
pub enum ColumnView<'a> {
Float64(&'a Float64Column),
Int64(&'a Int64Column),
Boolean(&'a BooleanColumn),
Categorical(&'a CategoricalColumn),
Timestamp(&'a TimestampColumn),
FixedVector(&'a FixedVectorColumn),
}
impl<'a> ColumnView<'a> {
#[must_use]
pub fn id(self) -> VariableId {
match self {
Self::Float64(c) => c.id,
Self::Int64(c) => c.id,
Self::Boolean(c) => c.id,
Self::Categorical(c) => c.id,
Self::Timestamp(c) => c.id,
Self::FixedVector(c) => c.id,
}
}
#[must_use]
pub fn len(self) -> usize {
match self {
Self::Float64(c) => c.len(),
Self::Int64(c) => c.len(),
Self::Boolean(c) => c.len(),
Self::Categorical(c) => c.len(),
Self::Timestamp(c) => c.len(),
Self::FixedVector(c) => c.len(),
}
}
#[must_use]
pub fn is_empty(self) -> bool {
self.len() == 0
}
#[must_use]
pub fn validity(self) -> &'a ValidityBitmap {
match self {
Self::Float64(c) => &c.validity,
Self::Int64(c) => &c.validity,
Self::Boolean(c) => &c.validity,
Self::Categorical(c) => &c.validity,
Self::Timestamp(c) => &c.validity,
Self::FixedVector(c) => &c.validity,
}
}
}
#[derive(Clone, Debug)]
pub enum OwnedColumn {
Float64(Float64Column),
Int64(Int64Column),
Boolean(BooleanColumn),
Categorical(CategoricalColumn),
Timestamp(TimestampColumn),
FixedVector(FixedVectorColumn),
}
impl OwnedColumn {
#[must_use]
pub fn id(&self) -> VariableId {
match self {
Self::Float64(c) => c.id,
Self::Int64(c) => c.id,
Self::Boolean(c) => c.id,
Self::Categorical(c) => c.id,
Self::Timestamp(c) => c.id,
Self::FixedVector(c) => c.id,
}
}
#[must_use]
pub fn with_id(&self, id: VariableId) -> Self {
match self {
Self::Float64(c) => Self::Float64(Float64Column {
id,
values: c.values.clone(),
validity: c.validity.clone(),
}),
Self::Int64(c) => Self::Int64(Int64Column {
id,
values: Arc::clone(&c.values),
validity: c.validity.clone(),
}),
Self::Boolean(c) => Self::Boolean(BooleanColumn {
id,
values: Arc::clone(&c.values),
validity: c.validity.clone(),
}),
Self::Categorical(c) => Self::Categorical(CategoricalColumn {
id,
codes: Arc::clone(&c.codes),
validity: c.validity.clone(),
domain: Arc::clone(&c.domain),
}),
Self::Timestamp(c) => Self::Timestamp(TimestampColumn {
id,
values_ns: Arc::clone(&c.values_ns),
validity: c.validity.clone(),
}),
Self::FixedVector(c) => Self::FixedVector(FixedVectorColumn {
id,
values: Arc::clone(&c.values),
dim: c.dim,
validity: c.validity.clone(),
}),
}
}
#[must_use]
pub fn len(&self) -> usize {
match self {
Self::Float64(c) => c.len(),
Self::Int64(c) => c.len(),
Self::Boolean(c) => c.len(),
Self::Categorical(c) => c.len(),
Self::Timestamp(c) => c.len(),
Self::FixedVector(c) => c.len(),
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[must_use]
pub fn as_view(&self) -> ColumnView<'_> {
match self {
Self::Float64(c) => ColumnView::Float64(c),
Self::Int64(c) => ColumnView::Int64(c),
Self::Boolean(c) => ColumnView::Boolean(c),
Self::Categorical(c) => ColumnView::Categorical(c),
Self::Timestamp(c) => ColumnView::Timestamp(c),
Self::FixedVector(c) => ColumnView::FixedVector(c),
}
}
}