use std::{
marker::PhantomData,
mem::ManuallyDrop,
ptr,
ops::{
Deref,
DerefMut
},
borrow::Cow,
fmt,
cmp
};
pub trait Meta: Copy {
const MAX_LENGTH: usize;
fn new(len: usize, capacity: Option<usize>) -> Self;
fn len(&self) -> usize;
fn capacity(&self) -> Option<usize>;
fn set_len(&mut self, len: usize);
fn set_capacity(&mut self, capacity: Option<usize>);
}
union Data<T, const N: usize> {
stack: ManuallyDrop<[T; N]>,
ptr: *mut T
}
impl<T, const N: usize> Data<T, N> {
#[inline]
unsafe fn drop_with<M: Meta>(&mut self, meta: M) {
match meta.capacity() {
Some(capacity) => {
let len = meta.len();
if capacity <= N {
ptr::drop_in_place(&mut (*self.stack)[0..len]);
} else {
Vec::from_raw_parts(self.ptr, len, capacity);
}
},
None => ()
}
}
}
pub struct CalfVec<'a, M: Meta, T, const N: usize> {
meta: M,
data: Data<T, N>,
lifetime: PhantomData<&'a T>
}
impl<'a, M: Meta, T, const N: usize> Drop for CalfVec<'a, M, T, N> {
fn drop(&mut self) {
unsafe {
self.data.drop_with(self.meta)
}
}
}
impl<'a, M: Meta, T, const N: usize> CalfVec<'a, M, T, N> {
#[inline]
pub fn borrowed<B: AsRef<[T]> + ?Sized>(borrowed: &'a B) -> CalfVec<'a, M, T, N> {
let slice = borrowed.as_ref();
CalfVec {
meta: M::new(slice.len(), None),
data: Data { ptr: slice.as_ptr() as *mut T },
lifetime: PhantomData
}
}
#[inline]
pub fn owned<O: Into<Vec<T>>>(owned: O) -> CalfVec<'a, M, T, N> {
let vec = owned.into();
let (ptr, len, capacity) = vec.into_raw_parts();
if capacity <= N {
unsafe {
let mut data = Data { ptr: ptr::null_mut() };
std::ptr::copy_nonoverlapping(ptr, (*data.stack).as_mut_ptr(), len);
Vec::from_raw_parts(ptr, 0, capacity);
CalfVec {
meta: M::new(len, Some(N)),
data,
lifetime: PhantomData
}
}
} else {
CalfVec {
meta: M::new(len, Some(capacity)),
data: Data { ptr },
lifetime: PhantomData
}
}
}
#[inline]
pub fn try_into_slice(self) -> Result<&'a [T], Self> {
match self.capacity() {
Some(_) => Err(self),
None => unsafe {
Ok(std::slice::from_raw_parts(self.as_ptr(), self.len()))
}
}
}
#[inline]
pub fn try_into_vec(self) -> Result<Vec<T>, Self> {
match self.capacity() {
Some(capacity) if capacity > N => unsafe {
let ptr = self.data.ptr;
let len = self.len();
std::mem::forget(self); Ok(Vec::from_raw_parts(ptr, len, capacity))
},
_ => Err(self)
}
}
#[inline]
pub fn into_vec(mut self) -> Vec<T> where T: Clone {
unsafe {
let capacity = self.own();
let len = self.len();
let vec = if capacity <= N {
let src = (*self.data.stack).as_mut_ptr();
let mut vec = Vec::with_capacity(len);
std::ptr::copy_nonoverlapping(src, vec.as_mut_ptr(), len);
vec
} else {
let ptr = self.data.ptr;
Vec::from_raw_parts(ptr, len, capacity)
};
std::mem::forget(self); vec
}
}
#[inline]
pub fn as_ptr(&self) -> *const T {
unsafe {
match self.capacity() {
Some(capacity) => {
if capacity <= N {
(*self.data.stack).as_ptr()
} else {
self.data.ptr
}
},
None => self.data.ptr
}
}
}
#[inline]
pub fn as_slice(&self) -> &[T] {
unsafe {
std::slice::from_raw_parts(self.as_ptr(), self.len())
}
}
#[inline]
pub fn is_owned(&self) -> bool {
self.meta.capacity().is_some()
}
#[inline]
pub fn is_borrowed(&self) -> bool {
self.meta.capacity().is_none()
}
#[inline]
pub fn len(&self) -> usize {
self.meta.len()
}
#[inline]
pub fn capacity(&self) -> Option<usize> {
self.meta.capacity()
}
}
impl<'a, M: Meta, T, const N: usize> CalfVec<'a, M, T, N> where T: Clone {
#[inline]
pub fn own(&mut self) -> usize {
match self.capacity() {
Some(capacity) => capacity,
None => unsafe { let len = self.len();
let slice = std::slice::from_raw_parts(self.data.ptr, len);
let capacity = if len <= N {
&mut (*self.data.stack)[0..len].clone_from_slice(slice);
N
} else {
let (ptr, _, capacity) = self.as_slice().to_vec().into_raw_parts();
self.data.ptr = ptr;
capacity
};
self.meta.set_capacity(Some(capacity));
capacity
}
}
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
let capacity = self.own();
unsafe {
if capacity <= N {
(*self.data.stack).as_mut_ptr()
} else {
self.data.ptr
}
}
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
self.own();
unsafe {
std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.len())
}
}
#[inline]
pub fn truncate(&mut self, len: usize) {
self.own();
unsafe {
if len > self.len() {
return;
}
let remaining_len = self.len() - len;
let s = ptr::slice_from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len);
self.meta.set_len(len);
ptr::drop_in_place(s);
}
}
pub fn reserve(&mut self, additional: usize) {
let capacity = self.own();
unsafe {
let mut vec = if capacity <= N {
self.spill()
} else {
Vec::from_raw_parts(self.data.ptr, self.len(), capacity)
};
vec.reserve(additional);
let (ptr, _, capacity) = vec.into_raw_parts();
self.data.ptr = ptr;
self.meta.set_capacity(Some(capacity));
}
}
pub fn reserve_exact(&mut self, additional: usize) {
let capacity = self.own();
unsafe {
let mut vec = if capacity <= N {
self.spill()
} else {
Vec::from_raw_parts(self.data.ptr, self.len(), capacity)
};
vec.reserve_exact(additional);
let (ptr, _, capacity) = vec.into_raw_parts();
self.data.ptr = ptr;
self.meta.set_capacity(Some(capacity));
}
}
#[inline]
unsafe fn spill(&mut self) -> Vec<T> {
let mut data = Data {
ptr: ptr::null_mut()
};
std::mem::swap(&mut data, &mut self.data);
let boxed_slice: Box<[T]> = Box::new(ManuallyDrop::into_inner(data.stack));
let mut vec = boxed_slice.into_vec();
self.data.ptr = vec.as_mut_ptr();
vec
}
pub fn shrink_to(&mut self, min_capacity: usize) {
match self.capacity() {
Some(capacity) => unsafe {
assert!(capacity < min_capacity);
let len = self.len();
let new_capacity = cmp::max(len, min_capacity);
if new_capacity != capacity {
if new_capacity <= N {
if capacity > N {
let ptr = self.data.ptr;
ptr::copy_nonoverlapping(ptr, (*self.data.stack).as_mut_ptr(), len);
Vec::from_raw_parts(ptr, 0, capacity); self.meta.set_capacity(Some(N));
}
} else {
let mut vec = Vec::from_raw_parts(self.data.ptr, len, capacity);
vec.shrink_to(new_capacity);
let (ptr, _, actual_new_capacity) = vec.into_raw_parts();
self.data.ptr = ptr;
self.meta.set_capacity(Some(actual_new_capacity));
}
}
},
None => ()
}
}
#[inline]
pub fn shrink_to_fit(&mut self) {
self.shrink_to(self.len());
}
pub fn insert(&mut self, index: usize, element: T) {
let len = self.len();
if index > len {
panic!("insertion index (is {}) should be <= len (which is {})", index, len);
}
let capacity = self.own();
if len == capacity {
self.reserve(1);
}
unsafe {
{
let p = self.as_mut_ptr().add(index);
ptr::copy(p, p.offset(1), len - index);
ptr::write(p, element);
}
self.meta.set_len(len + 1);
}
}
pub fn remove(&mut self, index: usize) -> T {
let len = self.len();
if index >= len {
panic!("removal index (is {}) should be < len (is {})", index, len);
}
self.own();
unsafe {
let ret;
{
let ptr = self.as_mut_ptr().add(index);
ret = ptr::read(ptr);
ptr::copy(ptr.offset(1), ptr, len - index - 1);
}
self.meta.set_len(len - 1);
ret
}
}
#[inline]
pub fn append(&mut self, other: &mut Vec<T>) {
unsafe {
self.append_elements(other.as_slice() as _);
other.set_len(0);
}
}
#[inline]
unsafe fn append_elements(&mut self, other: *const [T]) {
let count = (*other).len();
self.reserve(count);
let len = self.len();
ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count);
self.meta.set_len(len + count);
}
#[inline]
pub fn extend_from_slice(&mut self, other: &[T]) {
self.extend(other.iter().cloned())
}
#[inline]
pub fn clear(&mut self) {
self.truncate(0)
}
#[inline]
pub fn push(&mut self, value: T) {
let capacity = self.own();
unsafe {
if self.len() == capacity {
self.reserve(1);
}
let end = self.as_mut_ptr().add(self.len());
ptr::write(end, value);
self.meta.set_len(self.len()+1);
}
}
#[inline]
pub fn pop(&mut self) -> Option<T> {
if self.len() == 0 {
None
} else {
self.own();
unsafe {
self.meta.set_len(self.len()-1);
Some(ptr::read(self.as_ptr().add(self.len())))
}
}
}
pub fn dedup_by<F>(&mut self, same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool {
self.own();
let len = {
let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket);
dedup.len()
};
self.truncate(len);
}
#[inline]
pub fn dedup_by_key<F, K>(&mut self, mut key: F) where F: FnMut(&mut T) -> K, K: PartialEq {
self.dedup_by(|a, b| key(a) == key(b))
}
#[inline]
pub fn dedup(&mut self) where T: PartialEq {
self.dedup_by(|a, b| a == b)
}
}
unsafe impl<'a, M: Meta + Send, T: Sync, const N: usize> Send for CalfVec<'a, M, T, N> {}
unsafe impl<'a, M: Meta + Sync, T: Sync, const N: usize> Sync for CalfVec<'a, M, T, N> {}
impl<'a, M: Meta, T, const N: usize> Deref for CalfVec<'a, M, T, N> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
self.as_slice()
}
}
impl<'a, M: Meta, T, const N: usize> DerefMut for CalfVec<'a, M, T, N> where T: Clone {
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<'v, 'a, M: Meta, T, const N: usize> IntoIterator for &'v CalfVec<'a, M, T, N> {
type Item = &'v T;
type IntoIter = std::slice::Iter<'v, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().into_iter()
}
}
impl<'v, 'a, M: Meta, T, const N: usize> IntoIterator for &'v mut CalfVec<'a, M, T, N> where T: Clone {
type Item = &'v mut T;
type IntoIter = std::slice::IterMut<'v, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().into_iter()
}
}
pub union IntoIterData<T, const N: usize> {
stack: ManuallyDrop<[T; N]>,
vec: ManuallyDrop<std::vec::IntoIter<T>>
}
pub struct IntoIter<M: Meta, T, const N: usize> {
meta: M,
offset: usize,
data: IntoIterData<T, N>
}
impl<M: Meta, T, const N: usize> Iterator for IntoIter<M, T, N> {
type Item = T;
fn next(&mut self) -> Option<T> {
unsafe {
let capacity = self.meta.capacity().unwrap();
let item = if capacity <= N {
let i = self.offset;
if i < self.meta.len() {
self.offset += 1;
Some(ptr::read(self.data.stack.as_ptr().add(i)))
} else {
None
}
} else {
(*self.data.vec).next()
};
item
}
}
}
impl<M: Meta, T, const N: usize> Drop for IntoIter<M, T, N> {
fn drop(&mut self) {
unsafe {
let capacity = self.meta.capacity().unwrap();
if capacity <= N {
ptr::drop_in_place(&mut (*self.data.stack)[self.offset..self.meta.len()]); } else {
ManuallyDrop::drop(&mut self.data.vec)
}
}
}
}
impl<'a, M: Meta, T, const N: usize> IntoIterator for CalfVec<'a, M, T, N> where T: Clone {
type Item = T;
type IntoIter = IntoIter<M, T, N>;
fn into_iter(mut self) -> Self::IntoIter {
unsafe {
let capacity = self.own();
let meta = self.meta;
let mut data = Data {
ptr: ptr::null_mut()
};
std::mem::swap(&mut data, &mut self.data);
std::mem::forget(self);
let into_iter_data = if capacity <= N {
IntoIterData {
stack: data.stack
}
} else {
let vec = Vec::from_raw_parts(data.ptr, meta.len(), capacity);
IntoIterData {
vec: ManuallyDrop::new(vec.into_iter())
}
};
IntoIter {
meta,
offset: 0,
data: into_iter_data
}
}
}
}
impl<'a, M: Meta, T, const N: usize> Extend<T> for CalfVec<'a, M, T, N> where T: Clone {
#[inline]
fn extend<I: IntoIterator<Item = T>>(&mut self, iterator: I) {
let mut iterator = iterator.into_iter();
while let Some(element) = iterator.next() {
let len = self.len();
if len == self.own() {
let (lower, _) = iterator.size_hint();
self.reserve(lower.saturating_add(1));
}
unsafe {
ptr::write(self.as_mut_ptr().add(len), element);
self.meta.set_len(len + 1);
}
}
}
}
impl<'a, M: Meta, T: fmt::Debug, const N: usize> fmt::Debug for CalfVec<'a, M, T, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<'a, M: Meta, T, const N: usize> AsRef<CalfVec<'a, M, T, N>> for CalfVec<'a, M, T, N> {
fn as_ref(&self) -> &CalfVec<'a, M, T, N> {
self
}
}
impl<'a, M: Meta, T, const N: usize> AsMut<CalfVec<'a, M, T, N>> for CalfVec<'a, M, T, N> {
fn as_mut(&mut self) -> &mut CalfVec<'a, M, T, N> {
self
}
}
impl<'a, M: Meta, T, const N: usize> AsRef<[T]> for CalfVec<'a, M, T, N> {
fn as_ref(&self) -> &[T] {
self
}
}
impl<'a, M: Meta, T, const N: usize> AsMut<[T]> for CalfVec<'a, M, T, N> where T: Clone {
fn as_mut(&mut self) -> &mut [T] {
self
}
}
impl<'a, M: Meta, T, const N: usize> From<Vec<T>> for CalfVec<'a, M, T, N> {
fn from(v: Vec<T>) -> CalfVec<'a, M, T, N> {
CalfVec::owned(v)
}
}
impl<'a, M: Meta, T, const N: usize> From<&'a [T]> for CalfVec<'a, M, T, N> {
fn from(s: &'a [T]) -> CalfVec<'a, M, T, N> {
CalfVec::borrowed(s)
}
}
macro_rules! impl_slice_eq1 {
([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => {
impl<$($vars)*> PartialEq<$rhs> for $lhs where A: PartialEq<B>, $($ty: $bound)? {
#[inline]
fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
#[inline]
fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] }
}
}
}
impl_slice_eq1! { ['a, 'b, A, B, O: Meta, P: Meta, const N: usize, const M: usize] CalfVec<'a, O, A, N>, CalfVec<'b, P, B, M> }
impl_slice_eq1! { ['a, A, B, M: Meta, const N: usize] CalfVec<'a, M, A, N>, Vec<B> }
impl_slice_eq1! { ['b, A, B, M: Meta, const N: usize] Vec<A>, CalfVec<'b, M, B, N> }
impl_slice_eq1! { ['a, A, B, M: Meta, const N: usize] CalfVec<'a, M, A, N>, &[B] }
impl_slice_eq1! { ['a, A, B, M: Meta, const N: usize] CalfVec<'a, M, A, N>, &mut [B] }
impl_slice_eq1! { ['b, A, B, M: Meta, const N: usize] &[A], CalfVec<'b, M, B, N> }
impl_slice_eq1! { ['b, A, B, M: Meta, const N: usize] &mut [A], CalfVec<'b, M, B, N> }
impl_slice_eq1! { ['a, A, B, M: Meta, const N: usize] CalfVec<'a, M, A, N>, Cow<'_, [B]> where B: Clone }
impl_slice_eq1! { ['b, A, B, M: Meta, const N: usize] Cow<'_, [A]>, CalfVec<'b, M, B, N> where A: Clone }
impl_slice_eq1! { ['a, A, B, M: Meta, const N: usize, const O: usize] CalfVec<'a, M, A, N>, [B; O] }
impl_slice_eq1! { ['a, A, B, M: Meta, const N: usize, const O: usize] CalfVec<'a, M, A, N>, &[B; O] }
impl_slice_eq1! { ['b, A, B, M: Meta, const N: usize, const O: usize] [A; O], CalfVec<'b, M, B, N> }
impl_slice_eq1! { ['b, A, B, M: Meta, const N: usize, const O: usize] &[A; O], CalfVec<'b, M, B, N> }