mod npy;
mod reader;
use std::{
marker::PhantomData,
mem::size_of,
ops::{Index, IndexMut},
ptr::null_mut,
rc::Rc,
slice::SliceIndex,
};
pub use npy::{Field, NpyDTyped, NpyHeader, read_npy_file, read_npz_file, write_npy};
pub use reader::{Cache, DataPreprocess, DataSource, FeedLatencyAdjustment, Reader, ReaderBuilder};
use crate::utils::{AlignedArray, CACHE_LINE_SIZE};
pub unsafe trait POD: Sized {}
#[derive(Clone, Debug)]
pub struct Data<D>
where
D: POD + Clone,
{
ptr: Rc<DataPtr>,
offset: usize,
_d_marker: PhantomData<D>,
}
impl<D> Data<D>
where
D: POD + Clone,
{
#[inline(always)]
pub fn len(&self) -> usize {
let size = size_of::<D>();
(self.ptr.len() - self.offset) / size
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.ptr.len() == 0
}
pub fn empty() -> Self {
Self {
ptr: Default::default(),
offset: 0,
_d_marker: PhantomData,
}
}
pub fn from_data(data: &[D]) -> Self {
let byte_len = size_of_val(data);
let bytes = unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, byte_len) };
let dest_data_ptr = DataPtr::new(byte_len);
unsafe {
let dest_data = dest_data_ptr.ptr.as_mut().unwrap();
dest_data.copy_from_slice(bytes);
Self::from_data_ptr(dest_data_ptr, 0)
}
}
pub unsafe fn from_data_ptr(ptr: DataPtr, offset: usize) -> Self {
Self {
ptr: Rc::new(ptr),
offset,
_d_marker: PhantomData,
}
}
#[inline(always)]
pub unsafe fn get_unchecked(&self, index: usize) -> &D {
let size = size_of::<D>();
let i = self.offset + index * size;
unsafe { &*(self.ptr.at(i) as *const D) }
}
pub fn data_eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.ptr, &other.ptr)
}
}
impl<D> Index<usize> for Data<D>
where
D: POD + Clone,
{
type Output = D;
#[inline(always)]
fn index(&self, index: usize) -> &Self::Output {
let size = size_of::<D>();
let i = self.offset + index * size;
if i + size > self.ptr.len() {
panic!("Out of the size.");
}
unsafe { &*(self.ptr.at(i) as *const D) }
}
}
impl<D> IndexMut<usize> for Data<D>
where
D: POD + Clone,
{
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let size = size_of::<D>();
let i = self.offset + index * size;
if i + size > self.ptr.len() {
panic!("Out of the size.");
}
unsafe { &mut *(self.ptr.at(i) as *mut D) }
}
}
#[derive(Debug)]
pub struct DataPtr {
ptr: *mut [u8],
managed: bool,
}
impl DataPtr {
pub fn new(size: usize) -> Self {
let arr = AlignedArray::<u8, CACHE_LINE_SIZE>::new(size);
Self {
ptr: arr.into_raw(),
managed: true,
}
}
pub unsafe fn from_ptr(ptr: *mut [u8]) -> Self {
Self {
ptr,
managed: false,
}
}
#[allow(clippy::len_without_is_empty)]
#[inline]
pub fn len(&self) -> usize {
self.ptr.len()
}
#[inline]
pub unsafe fn at(&self, index: usize) -> *const u8 {
let ptr = self.ptr as *const u8;
unsafe { ptr.add(index) }
}
}
impl Default for DataPtr {
fn default() -> Self {
Self {
ptr: null_mut::<[u8; 0]>() as *mut [u8],
managed: false,
}
}
}
impl<Idx> Index<Idx> for DataPtr
where
Idx: SliceIndex<[u8]>,
{
type Output = Idx::Output;
#[inline]
fn index(&self, index: Idx) -> &Self::Output {
let arr = unsafe { &*self.ptr };
&arr[index]
}
}
impl<Idx> IndexMut<Idx> for DataPtr
where
Idx: SliceIndex<[u8]>,
{
#[inline]
fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
let arr = unsafe { &mut *self.ptr };
&mut arr[index]
}
}
impl Drop for DataPtr {
fn drop(&mut self) {
if self.managed {
let _ = unsafe { AlignedArray::<u8, CACHE_LINE_SIZE>::from_raw(self.ptr) };
}
}
}