use std::fmt;
use std::rc::Rc;
use crate::error::RuntimeError;
use crate::tensor::Tensor;
#[derive(Debug, Clone)]
pub struct AlignedPool {
storage: Vec<u8>,
aligned_offset: usize,
capacity: usize,
len: usize,
}
impl AlignedPool {
pub fn new(capacity_bytes: usize) -> Self {
let alloc_size = capacity_bytes + 15;
let storage = vec![0u8; alloc_size];
let base_ptr = storage.as_ptr() as usize;
let aligned_offset = (16 - (base_ptr % 16)) % 16;
AlignedPool {
storage,
aligned_offset,
capacity: capacity_bytes,
len: 0,
}
}
pub fn as_ptr(&self) -> *const u8 {
unsafe { self.storage.as_ptr().add(self.aligned_offset) }
}
pub fn as_mut_ptr(&mut self) -> *mut u8 {
unsafe { self.storage.as_mut_ptr().add(self.aligned_offset) }
}
pub fn as_bytes(&self) -> &[u8] {
&self.storage[self.aligned_offset..self.aligned_offset + self.len]
}
pub fn is_aligned_16(ptr: *const u8) -> bool {
(ptr as usize) % 16 == 0
}
pub fn copy_from(&mut self, data: &[u8]) -> Result<(), RuntimeError> {
if data.len() > self.capacity {
return Err(RuntimeError::InvalidOperation(
format!(
"AlignedPool: data length {} exceeds capacity {}",
data.len(),
self.capacity
),
));
}
let dest = &mut self.storage[self.aligned_offset..self.aligned_offset + data.len()];
dest.copy_from_slice(data);
self.len = data.len();
Ok(())
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn check_alignment(&self) -> bool {
Self::is_aligned_16(self.as_ptr())
}
}
impl fmt::Display for AlignedPool {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"AlignedPool(len={}, capacity={}, aligned={})",
self.len, self.capacity, self.check_alignment()
)
}
}
#[derive(Debug, Clone)]
pub struct AlignedByteSlice {
pool: Option<AlignedPool>,
original: Rc<Vec<u8>>,
was_copied: bool,
}
impl AlignedByteSlice {
pub fn from_bytes(data: Rc<Vec<u8>>) -> Self {
let ptr = data.as_ptr();
if AlignedPool::is_aligned_16(ptr) {
AlignedByteSlice {
pool: None,
original: data,
was_copied: false,
}
} else {
let mut pool = AlignedPool::new(data.len());
pool.copy_from(&data).unwrap();
AlignedByteSlice {
pool: Some(pool),
original: data,
was_copied: true,
}
}
}
pub fn as_bytes(&self) -> &[u8] {
match &self.pool {
Some(pool) => pool.as_bytes(),
None => &self.original,
}
}
pub fn was_realigned(&self) -> bool {
self.was_copied
}
pub fn len(&self) -> usize {
self.original.len()
}
pub fn is_empty(&self) -> bool {
self.original.is_empty()
}
pub fn as_tensor(&self, shape: &[usize], dtype: &str) -> Result<Tensor, RuntimeError> {
Tensor::from_bytes(self.as_bytes(), shape, dtype)
}
}
impl fmt::Display for AlignedByteSlice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"AlignedByteSlice(len={}, realigned={})",
self.len(),
self.was_copied
)
}
}