use std::{marker::PhantomData, sync::Arc};
use arrow::{array::Array, buffer::NullBuffer};
use crate::{mask::MaskData, TensorValue};
#[derive(Debug)]
pub struct TensorData<T, A> {
values: Arc<A>,
offset: usize,
len: usize,
_type: PhantomData<T>,
}
impl<T, A> Clone for TensorData<T, A>
where
T: TensorValue<Array = A>,
A: Array,
{
fn clone(&self) -> Self {
Self {
values: self.values.clone(),
offset: self.offset,
len: self.len,
_type: self._type,
}
}
}
impl<T, A> From<A> for TensorData<T, A>
where
T: TensorValue<Array = A>,
A: Array,
{
fn from(values: A) -> Self {
let len = values.len();
Self {
values: Arc::new(values),
offset: 0,
len,
_type: PhantomData,
}
}
}
impl<T, A> From<Arc<A>> for TensorData<T, A>
where
T: TensorValue<Array = A>,
A: Array,
{
fn from(values: Arc<A>) -> Self {
let len = values.len();
Self {
values,
offset: 0,
len,
_type: PhantomData,
}
}
}
impl<T, A> TensorData<T, A>
where
T: TensorValue<Array = A>,
A: Array + 'static,
{
pub fn new(values: Arc<T::Array>, offset: usize, len: usize) -> Self {
Self {
values,
offset,
len,
_type: PhantomData,
}
}
pub fn into_values(self) -> Arc<T::Array> {
self.shrink_to_fit().values
}
pub fn values(&self) -> Arc<T::Array> {
self.clone().shrink_to_fit().values
}
pub fn mask(&self) -> MaskData {
MaskData::new(self.values.nulls().cloned(), self.offset, self.len())
}
pub fn len(&self) -> usize {
self.len
}
#[allow(dead_code)]
pub fn value(&self, i: isize) -> T {
let i = i + self.offset as isize;
debug_assert!(i >= 0);
T::value(&self.values, i as usize)
}
pub unsafe fn value_unchecked(&self, i: isize) -> T {
let i = i + self.offset as isize;
debug_assert!(i >= 0);
T::value_unchecked(&self.values, i as usize)
}
pub fn slice_exact(&self, offset: isize, length: usize) -> Self {
debug_assert!(
self.offset as isize + offset >= 0,
"existing offset ({}) + new offset ({}) must be >= 0",
self.offset as isize,
offset,
);
let offset = (self.offset as isize + offset) as usize;
debug_assert!(length + offset <= self.values.len());
let values = Arc::new(T::slice(&self.values, offset, length));
Self::new(values, 0, length)
}
pub fn slice(&self, offset: isize, length: usize) -> Self {
debug_assert!(
self.offset as isize + offset >= 0,
"existing offset ({}) + new offset ({}) must be >= 0",
self.offset as isize,
offset,
);
let offset = (self.offset as isize + offset) as usize;
debug_assert!(
length + offset <= self.values.len(),
"length {} exceeds buffer length {}",
length + offset,
self.values.len()
);
Self::new(self.values.clone(), offset, length)
}
pub fn offset_exact(&self, offset: isize) -> Self {
self.slice_exact(offset, (self.len as isize - offset) as usize)
}
pub fn offset(&self, offset: isize) -> Self {
self.slice(offset, (self.len as isize - offset) as usize)
}
pub fn with_mask(self, mask: Option<MaskData>) -> Self {
let mask = if let Some(mask) = mask {
assert_eq!(self.len(), mask.len());
mask.shrink_to_fit().into_values()
} else {
None
};
let values = unsafe {
self.shrink_to_fit()
.values
.to_data()
.into_builder()
.nulls(mask)
.build_unchecked()
};
let values = T::from_array_data(values);
let len = values.len();
TensorData::new(values.into(), 0, len)
}
pub fn cast<O>(self) -> TensorData<O, A>
where
O: TensorValue<Array = A>,
{
TensorData {
values: self.values,
offset: self.offset,
len: self.len,
_type: PhantomData,
}
}
pub fn shrink_to_fit(self) -> Self {
if self.offset != 0 || self.len != self.values.len() {
self.slice_exact(0, self.len)
} else {
self
}
}
}
impl TensorData<bool, <bool as TensorValue>::Array> {
pub fn to_mask_data(&self) -> MaskData {
let values = NullBuffer::new(self.values.values().clone());
MaskData::new(values, self.offset, self.len())
}
}