use std::ops::Deref;
use either::Either;
use num_traits::Zero;
use super::IntoIter;
use crate::array::{ArrayAccessor, Splitable};
use crate::storage::SharedStorage;
#[derive(Clone)]
pub struct Buffer<T> {
storage: SharedStorage<T>,
ptr: *const T,
length: usize,
}
unsafe impl<T: Send + Sync> Sync for Buffer<T> {}
unsafe impl<T: Send + Sync> Send for Buffer<T> {}
impl<T: PartialEq> PartialEq for Buffer<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.deref() == other.deref()
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for Buffer<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&**self, f)
}
}
impl<T> Default for Buffer<T> {
#[inline]
fn default() -> Self {
Vec::new().into()
}
}
impl<T> Buffer<T> {
#[inline]
pub fn new() -> Self {
Self::default()
}
pub(crate) fn from_storage(storage: SharedStorage<T>) -> Self {
let ptr = storage.as_ptr();
let length = storage.len();
Buffer {
storage,
ptr,
length,
}
}
#[inline]
pub fn len(&self) -> usize {
self.length
}
#[inline]
pub fn is_empty(&self) -> bool {
self.length == 0
}
pub fn is_sliced(&self) -> bool {
self.storage.len() != self.length
}
#[inline]
pub fn as_slice(&self) -> &[T] {
debug_assert!(self.offset() + self.length <= self.storage.len());
unsafe { std::slice::from_raw_parts(self.ptr, self.length) }
}
#[inline]
pub(super) unsafe fn get_unchecked(&self, index: usize) -> &T {
debug_assert!(index < self.length);
unsafe { &*self.ptr.add(index) }
}
#[inline]
pub fn sliced(self, offset: usize, length: usize) -> Self {
assert!(
offset + length <= self.len(),
"the offset of the new Buffer cannot exceed the existing length"
);
unsafe { self.sliced_unchecked(offset, length) }
}
#[inline]
pub fn slice(&mut self, offset: usize, length: usize) {
assert!(
offset + length <= self.len(),
"the offset of the new Buffer cannot exceed the existing length"
);
unsafe { self.slice_unchecked(offset, length) }
}
#[inline]
#[must_use]
pub unsafe fn sliced_unchecked(mut self, offset: usize, length: usize) -> Self {
self.slice_unchecked(offset, length);
self
}
#[inline]
pub unsafe fn slice_unchecked(&mut self, offset: usize, length: usize) {
self.ptr = self.ptr.add(offset);
self.length = length;
}
#[inline]
pub(crate) fn storage_ptr(&self) -> *const T {
self.storage.as_ptr()
}
#[inline]
pub fn offset(&self) -> usize {
unsafe {
let ret = self.ptr.offset_from(self.storage.as_ptr()) as usize;
debug_assert!(ret <= self.storage.len());
ret
}
}
#[inline]
pub unsafe fn set_len(&mut self, len: usize) {
self.length = len;
}
#[inline]
pub fn into_mut(mut self) -> Either<Self, Vec<T>> {
if self.is_sliced() {
return Either::Left(self);
}
match self.storage.try_into_vec() {
Ok(v) => Either::Right(v),
Err(slf) => {
self.storage = slf;
Either::Left(self)
},
}
}
#[inline]
pub fn get_mut_slice(&mut self) -> Option<&mut [T]> {
let offset = self.offset();
let slice = self.storage.try_as_mut_slice()?;
Some(unsafe { slice.get_unchecked_mut(offset..offset + self.length) })
}
pub fn storage_refcount(&self) -> u64 {
self.storage.refcount()
}
}
impl<T: Clone> Buffer<T> {
pub fn make_mut(self) -> Vec<T> {
match self.into_mut() {
Either::Right(v) => v,
Either::Left(same) => same.as_slice().to_vec(),
}
}
}
impl<T: Zero + Copy> Buffer<T> {
pub fn zeroed(len: usize) -> Self {
vec![T::zero(); len].into()
}
}
impl<T> From<Vec<T>> for Buffer<T> {
#[inline]
fn from(v: Vec<T>) -> Self {
Self::from_storage(SharedStorage::from_vec(v))
}
}
impl<T> std::ops::Deref for Buffer<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> FromIterator<T> for Buffer<T> {
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Vec::from_iter(iter).into()
}
}
impl<T: Copy> IntoIterator for Buffer<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
IntoIter::new(self)
}
}
unsafe impl<'a, T: 'a> ArrayAccessor<'a> for Buffer<T> {
type Item = &'a T;
unsafe fn value_unchecked(&'a self, index: usize) -> Self::Item {
unsafe { &*self.ptr.add(index) }
}
fn len(&self) -> usize {
Buffer::len(self)
}
}
impl<T> Splitable for Buffer<T> {
#[inline(always)]
fn check_bound(&self, offset: usize) -> bool {
offset <= self.len()
}
unsafe fn _split_at_unchecked(&self, offset: usize) -> (Self, Self) {
let storage = &self.storage;
(
Self {
storage: storage.clone(),
ptr: self.ptr,
length: offset,
},
Self {
storage: storage.clone(),
ptr: self.ptr.wrapping_add(offset),
length: self.length - offset,
},
)
}
}