use core::{
iter::FusedIterator,
mem::MaybeUninit,
ops::{Index, IndexMut},
};
use crate::{
IndexScalarType, IndexType,
array::TypedArray,
enumerate::UncheckedTypedEnumerate,
range::{TypedRange, TypedRangeIterExt},
slice::TypedSlice,
utils::resolve_range_bounds,
};
#[cold]
fn panic_insufficient_capacity() -> ! {
panic!("insufficient capacity")
}
pub struct TypedArrayVec<I: IndexType, T, const N: usize> {
storage: TypedArray<I, MaybeUninit<T>, N>,
len: I,
}
impl<I: IndexType, T, const N: usize> TypedArrayVec<I, T, N> {
const _ASSERT_CAPACITY_IN_INDEX_BOUNDS: () = if N > I::MAX_RAW_INDEX {
panic!("capacity is not in bounds of the index type");
};
#[inline]
pub const fn new() -> Self {
const { Self::_ASSERT_CAPACITY_IN_INDEX_BOUNDS };
Self {
storage: TypedArray::from_array([const { MaybeUninit::uninit() }; N]),
len: I::ZERO,
}
}
#[inline]
pub const fn len(&self) -> I {
self.len
}
#[inline]
pub fn len_usize(&self) -> usize {
self.len.to_raw_index()
}
#[inline]
pub fn indices(&self) -> TypedRange<I> {
(I::ZERO..self.len()).iter()
}
#[inline]
pub fn iter_enumerated(&self) -> UncheckedTypedEnumerate<I, core::slice::Iter<'_, T>> {
unsafe { UncheckedTypedEnumerate::new(self.as_slice().iter()) }
}
#[inline]
pub fn iter_mut_enumerated(
&mut self,
) -> UncheckedTypedEnumerate<I, core::slice::IterMut<'_, T>> {
unsafe { UncheckedTypedEnumerate::new(self.as_mut_slice().iter_mut()) }
}
#[inline]
pub fn into_iter_enumerated(self) -> UncheckedTypedEnumerate<I, IntoIter<I, T, N>> {
unsafe { UncheckedTypedEnumerate::new(self.into_iter()) }
}
#[inline]
pub fn capacity(&self) -> I {
unsafe { I::from_raw_index_unchecked(N) }
}
#[inline]
pub fn remaining_capacity(&self) -> I {
let diff = unsafe { self.capacity().unchecked_sub_index(self.len()) };
unsafe { I::from_scalar_unchecked(diff) }
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == I::ZERO
}
#[inline]
pub fn is_full(&self) -> bool {
self.len == self.capacity()
}
#[inline]
pub fn as_slice(&self) -> &TypedSlice<I, T> {
unsafe { TypedSlice::from_raw_parts(self.storage.as_ptr().cast(), self.len) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut TypedSlice<I, T> {
unsafe { TypedSlice::from_raw_parts_mut(self.storage.as_mut_ptr().cast(), self.len) }
}
#[inline]
pub fn cast_index_type<I2: IndexType>(
self,
) -> Result<TypedArrayVec<I2, T, N>, I2::IndexTooBigError> {
let len = self.len;
let storage = unsafe { core::ptr::read(&self.storage) };
let casted_storage = storage.cast_index_type()?;
let result = TypedArrayVec {
storage: casted_storage,
len: unsafe { I2::from_raw_index_unchecked(len.to_raw_index()) },
};
core::mem::forget(self);
Ok(result)
}
#[inline]
pub fn push(&mut self, element: T) -> I {
self.try_push(element)
.unwrap_or_else(|_| panic_insufficient_capacity())
}
#[inline]
pub fn try_push(&mut self, element: T) -> Result<I, CapacityError<T>> {
if self.is_full() {
return Err(CapacityError::new(element));
}
let idx = self.len;
unsafe {
self.storage.get_unchecked_mut(self.len).write(element);
self.len = self.len.unchecked_add_scalar(I::Scalar::ONE);
}
Ok(idx)
}
#[inline]
pub fn extend_from_slice(&mut self, other: &TypedSlice<I, T>)
where
T: Clone,
{
self.try_extend_from_slice(other)
.unwrap_or_else(|_| panic_insufficient_capacity())
}
#[inline]
pub fn try_extend_from_slice(
&mut self,
other: &TypedSlice<I, T>,
) -> Result<(), CapacityError<()>>
where
T: Clone,
{
let new_len = self
.len()
.checked_add_scalar(other.len().to_scalar())
.map_err(|_| CapacityError::new(()))?;
if new_len > self.capacity() {
return Err(CapacityError::new(()));
}
for item in other.as_slice() {
unsafe {
self.storage.get_unchecked_mut(self.len).write(item.clone());
self.len = self.len.unchecked_add_scalar(I::Scalar::ONE);
}
}
Ok(())
}
#[inline]
pub fn pop(&mut self) -> Option<T> {
let new_len = self.len.checked_sub_scalar(I::Scalar::ONE)?;
self.len = new_len;
unsafe { Some(self.storage.get_unchecked(new_len).assume_init_read()) }
}
#[inline]
pub fn clear(&mut self) {
self.truncate(I::ZERO);
}
#[inline]
pub fn truncate(&mut self, len: I) {
if len >= self.len {
return;
}
let old_len = core::mem::replace(&mut self.len, len);
unsafe {
let tail_len = old_len.unchecked_sub_index(len);
let tail = core::slice::from_raw_parts_mut(
self.storage
.as_mut_ptr()
.add(len.to_raw_index())
.cast::<T>(),
tail_len.to_usize(),
);
core::ptr::drop_in_place(tail);
}
}
#[inline]
pub fn insert(&mut self, index: I, element: T) {
self.try_insert(index, element)
.unwrap_or_else(|_| panic_insufficient_capacity())
}
#[inline]
pub fn try_insert(&mut self, index: I, element: T) -> Result<(), CapacityError<T>> {
let old_len = self.len;
assert!(index <= old_len, "index out of bounds");
if self.is_full() {
return Err(CapacityError::new(element));
}
unsafe {
let p = self.storage.as_mut_ptr().add(index.to_raw_index());
core::ptr::copy(p, p.add(1), old_len.unchecked_sub_index(index).to_usize());
core::ptr::write(p, MaybeUninit::new(element));
self.len = self.len.unchecked_add_scalar(I::Scalar::ONE);
}
Ok(())
}
#[inline]
pub fn remove(&mut self, index: I) -> T {
let old_len = self.len;
assert!(index < old_len, "index out of bounds");
unsafe {
let new_len = old_len.unchecked_sub_scalar(I::Scalar::ONE);
let p = self.storage.as_mut_ptr().add(index.to_raw_index());
let result = p.read().assume_init();
core::ptr::copy(p.add(1), p, new_len.unchecked_sub_index(index).to_usize());
self.len = new_len;
result
}
}
#[inline]
pub fn swap_remove(&mut self, index: I) -> T {
let old_len = self.len;
assert!(index < old_len, "index out of bounds");
unsafe {
let last_idx = old_len.unchecked_sub_scalar(I::Scalar::ONE);
self.len = last_idx;
let last = self.storage.get_unchecked(last_idx).assume_init_read();
if index < last_idx {
core::mem::replace(
&mut *self.storage.get_unchecked_mut(index).as_mut_ptr(),
last,
)
} else {
last
}
}
}
#[inline]
pub fn as_ptr(&self) -> *const T {
self.storage.as_ptr().cast()
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
self.storage.as_mut_ptr().cast()
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&T) -> bool,
{
let old_len = self.len();
if old_len == I::ZERO {
return;
}
struct PanicGuard<'a, I: IndexType, T, const N: usize> {
v: &'a mut TypedArrayVec<I, T, N>,
read: I,
write: I,
original_len: I,
}
impl<'a, I: IndexType, T, const N: usize> Drop for PanicGuard<'a, I, T, N> {
#[cold]
fn drop(&mut self) {
let remaining = unsafe { self.original_len.unchecked_sub_index(self.read) };
let storage_ptr = self.v.storage.as_mut_ptr();
unsafe {
core::ptr::copy(
storage_ptr.add(self.read.to_raw_index()),
storage_ptr.add(self.write.to_raw_index()),
remaining.to_usize(),
);
}
unsafe {
self.v.set_len(self.write.unchecked_add_scalar(remaining));
}
}
}
let mut read = I::ZERO;
loop {
let cur = unsafe { self.get_unchecked_mut(read) };
if !f(cur) {
break;
}
read = unsafe { read.unchecked_add_scalar(I::Scalar::ONE) };
if read == old_len {
return;
}
}
let mut g = PanicGuard {
v: self,
read: unsafe { read.unchecked_add_scalar(I::Scalar::ONE) },
write: read,
original_len: old_len,
};
unsafe { core::ptr::drop_in_place(&mut *g.v.as_mut_ptr().add(read.to_raw_index())) };
while g.read < g.original_len {
let storage_ptr = g.v.storage.as_mut_ptr();
let cur_ptr = unsafe { storage_ptr.add(g.read.to_raw_index()) };
if !f(unsafe { (&mut *cur_ptr).assume_init_mut() }) {
g.read = unsafe { g.read.unchecked_add_scalar(I::Scalar::ONE) };
unsafe { core::ptr::drop_in_place(cur_ptr) };
} else {
unsafe {
let hole = storage_ptr.add(g.write.to_raw_index());
core::ptr::copy_nonoverlapping(cur_ptr, hole, 1);
}
g.write = unsafe { g.write.unchecked_add_scalar(I::Scalar::ONE) };
g.read = unsafe { g.read.unchecked_add_scalar(I::Scalar::ONE) };
}
}
unsafe { g.v.set_len(g.write) };
core::mem::forget(g);
}
#[inline]
pub unsafe fn set_len(&mut self, length: I) {
debug_assert!(length <= self.capacity());
self.len = length;
}
pub fn drain<R>(&mut self, range: R) -> Drain<'_, I, T, N>
where
R: core::ops::RangeBounds<I>,
{
let range = resolve_range_bounds(&range, self.len);
let old_len = self.len;
assert!(
range.start <= range.end && range.end <= self.len,
"drain range out of bounds"
);
self.len = range.start;
Drain {
cur_start: range.start,
cur_end: range.end,
tail_start: range.end,
old_len,
inner: self,
}
}
}
#[derive(Debug)]
pub struct Drain<'a, I: IndexType, T, const N: usize> {
inner: &'a mut TypedArrayVec<I, T, N>,
cur_start: I,
cur_end: I,
tail_start: I,
old_len: I,
}
impl<I: IndexType, T, const N: usize> Iterator for Drain<'_, I, T, N> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.cur_start < self.cur_end {
let res = unsafe {
self.inner
.storage
.get_unchecked(self.cur_start)
.assume_init_read()
};
self.cur_start = unsafe { self.cur_start.unchecked_add_scalar(I::Scalar::ONE) };
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = unsafe { self.cur_end.unchecked_sub_index(self.cur_start) }.to_usize();
(remaining, Some(remaining))
}
}
impl<I: IndexType, T, const N: usize> DoubleEndedIterator for Drain<'_, I, T, N> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.cur_start < self.cur_end {
self.cur_end = unsafe { self.cur_end.unchecked_sub_scalar(I::Scalar::ONE) };
let res = unsafe {
self.inner
.storage
.get_unchecked(self.cur_end)
.assume_init_read()
};
Some(res)
} else {
None
}
}
}
impl<I: IndexType, T, const N: usize> ExactSizeIterator for Drain<'_, I, T, N> {}
impl<I: IndexType, T, const N: usize> FusedIterator for Drain<'_, I, T, N> {}
impl<I: IndexType, T, const N: usize> Drop for Drain<'_, I, T, N> {
fn drop(&mut self) {
while self.next().is_some() {}
let tail_len = unsafe { self.old_len.unchecked_sub_index(self.tail_start) };
if tail_len > I::Scalar::ZERO {
unsafe {
let storage_ptr = self.inner.storage.as_mut_ptr();
let src = storage_ptr.add(self.tail_start.to_raw_index());
let dst = storage_ptr.add(self.inner.len.to_raw_index());
core::ptr::copy(src, dst, tail_len.to_usize());
}
}
unsafe {
self.inner.len = self.inner.len.unchecked_add_scalar(tail_len);
}
}
}
impl<I: IndexType, T, const N: usize> Drop for TypedArrayVec<I, T, N> {
fn drop(&mut self) {
self.clear();
}
}
impl<I: IndexType, T, const N: usize> core::ops::Deref for TypedArrayVec<I, T, N> {
type Target = TypedSlice<I, T>;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<I: IndexType, T, const N: usize> core::ops::DerefMut for TypedArrayVec<I, T, N> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
impl<I: IndexType, T, const N: usize> Index<I> for TypedArrayVec<I, T, N> {
type Output = T;
#[inline]
fn index(&self, index: I) -> &Self::Output {
&self.as_slice()[index]
}
}
impl<I: IndexType, T, const N: usize> IndexMut<I> for TypedArrayVec<I, T, N> {
#[inline]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
&mut self.as_mut_slice()[index]
}
}
impl<I: IndexType, T: Clone, const N: usize> Clone for TypedArrayVec<I, T, N> {
fn clone(&self) -> Self {
let mut new = Self::new();
for item in self.as_slice().as_slice() {
let _ = new.push(item.clone());
}
new
}
}
impl<I: IndexType, T, const N: usize> Default for TypedArrayVec<I, T, N> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<I: IndexType, T: core::fmt::Debug, const N: usize> core::fmt::Debug
for TypedArrayVec<I, T, N>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(self.as_slice().as_slice(), f)
}
}
impl<I: IndexType, T: PartialEq, const N: usize> PartialEq for TypedArrayVec<I, T, N> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_slice().as_slice() == other.as_slice().as_slice()
}
}
impl<I: IndexType, T: Eq, const N: usize> Eq for TypedArrayVec<I, T, N> {}
impl<I: IndexType, T: PartialOrd, const N: usize> PartialOrd for TypedArrayVec<I, T, N> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.as_slice()
.as_slice()
.partial_cmp(other.as_slice().as_slice())
}
}
impl<I: IndexType, T: Ord, const N: usize> Ord for TypedArrayVec<I, T, N> {
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.as_slice().as_slice().cmp(other.as_slice().as_slice())
}
}
impl<I: IndexType, T: core::hash::Hash, const N: usize> core::hash::Hash
for TypedArrayVec<I, T, N>
{
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.as_slice().as_slice().hash(state);
}
}
impl<I: IndexType, T, const N: usize> AsRef<TypedSlice<I, T>> for TypedArrayVec<I, T, N> {
#[inline]
fn as_ref(&self) -> &TypedSlice<I, T> {
self.as_slice()
}
}
impl<I: IndexType, T, const N: usize> AsMut<TypedSlice<I, T>> for TypedArrayVec<I, T, N> {
#[inline]
fn as_mut(&mut self) -> &mut TypedSlice<I, T> {
self.as_mut_slice()
}
}
impl<I: IndexType, T, const N: usize> core::borrow::Borrow<TypedSlice<I, T>>
for TypedArrayVec<I, T, N>
{
#[inline]
fn borrow(&self) -> &TypedSlice<I, T> {
self.as_slice()
}
}
impl<I: IndexType, T, const N: usize> core::borrow::BorrowMut<TypedSlice<I, T>>
for TypedArrayVec<I, T, N>
{
#[inline]
fn borrow_mut(&mut self) -> &mut TypedSlice<I, T> {
self.as_mut_slice()
}
}
impl<I: IndexType, T, const N: usize> IntoIterator for TypedArrayVec<I, T, N> {
type Item = T;
type IntoIter = IntoIter<I, T, N>;
#[inline]
fn into_iter(mut self) -> Self::IntoIter {
let len = self.len;
self.len = I::ZERO;
let storage = unsafe { core::ptr::read(&self.storage) };
core::mem::forget(self);
IntoIter {
storage,
index: I::ZERO,
len,
}
}
}
pub struct IntoIter<I: IndexType, T, const N: usize> {
storage: TypedArray<I, MaybeUninit<T>, N>,
index: I,
len: I,
}
impl<I: IndexType, T, const N: usize> Iterator for IntoIter<I, T, N> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.len {
let res = unsafe { self.storage.get_unchecked(self.index).assume_init_read() };
self.index = unsafe { self.index.unchecked_add_scalar(I::Scalar::ONE) };
Some(res)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = unsafe { self.len.unchecked_sub_index(self.index).to_usize() };
(remaining, Some(remaining))
}
}
impl<I: IndexType, T, const N: usize> DoubleEndedIterator for IntoIter<I, T, N> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.index < self.len {
self.len = self.len.checked_sub_scalar(I::Scalar::ONE).unwrap();
let res = unsafe { self.storage.get_unchecked(self.len).assume_init_read() };
Some(res)
} else {
None
}
}
}
impl<I: IndexType, T, const N: usize> ExactSizeIterator for IntoIter<I, T, N> {}
impl<I: IndexType, T, const N: usize> core::iter::FusedIterator for IntoIter<I, T, N> {}
impl<I: IndexType, T, const N: usize> Drop for IntoIter<I, T, N> {
fn drop(&mut self) {
let remaining_ptr = unsafe {
self.storage
.as_mut_ptr()
.add(self.index.to_raw_index())
.cast::<T>()
};
let remaining_len = unsafe { self.len.unchecked_sub_index(self.index).to_usize() };
unsafe {
core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(
remaining_ptr,
remaining_len,
));
}
}
}
impl<'a, I: IndexType, T, const N: usize> IntoIterator for &'a TypedArrayVec<I, T, N> {
type Item = &'a T;
type IntoIter = core::slice::Iter<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'a, I: IndexType, T, const N: usize> IntoIterator for &'a mut TypedArrayVec<I, T, N> {
type Item = &'a mut T;
type IntoIter = core::slice::IterMut<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
impl<I: IndexType, T, const N: usize> Extend<T> for TypedArrayVec<I, T, N> {
fn extend<X: IntoIterator<Item = T>>(&mut self, iter: X) {
for item in iter {
self.push(item);
}
}
}
impl<I: IndexType, T, const N: usize> FromIterator<T> for TypedArrayVec<I, T, N> {
fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
let mut new = Self::new();
new.extend(iter);
new
}
}
impl<I: IndexType, T, const N: usize> From<crate::array::TypedArray<I, T, N>>
for TypedArrayVec<I, T, N>
{
fn from(array: crate::array::TypedArray<I, T, N>) -> Self {
let storage: TypedArray<I, MaybeUninit<T>, N> =
unsafe { core::mem::transmute_copy(&array) };
core::mem::forget(array);
Self {
storage,
len: unsafe { I::from_raw_index_unchecked(N) },
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CapacityError<T> {
element: T,
}
impl<T> CapacityError<T> {
pub const fn new(element: T) -> Self {
Self { element }
}
pub fn element(self) -> T {
self.element
}
}
impl<T> core::fmt::Display for CapacityError<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "insufficient capacity")
}
}
impl<T: core::fmt::Debug> core::error::Error for CapacityError<T> {}