#![no_std]
#![allow(
// Clippy wants every single instance of the word "StaticVec" to be in syntax-highlight
// backticks, which IMO looks way too "noisy" when actually rendered.
clippy::doc_markdown,
// Clippy thinks inline always is a bad idea even for the most simple of one-liners, so
// IMO it's just not a particularly helpful lint.
clippy::inline_always,
// The "if-let" syntax Clippy recommends as an alternative to "match" in this lint is
// generally way less readable IMO.
clippy::match_bool,
// Without this, every single use of const generics is warned against.
incomplete_features
)]
#![feature(
adt_const_params,
const_assume,
const_eval_select,
const_fn_floating_point_arithmetic,
const_maybe_uninit_array_assume_init,
const_maybe_uninit_as_mut_ptr,
const_maybe_uninit_assume_init,
const_maybe_uninit_assume_init_read,
const_maybe_uninit_uninit_array,
const_maybe_uninit_zeroed,
const_mut_refs,
const_precise_live_drops,
const_ptr_is_null,
const_ptr_read,
const_ptr_write,
// this should be called `const_interior_mutability` IMO
const_refs_to_cell,
const_replace,
const_slice_from_raw_parts_mut,
const_swap,
const_trait_impl,
core_intrinsics,
doc_cfg,
exact_size_is_empty,
generic_const_exprs,
inline_const,
maybe_uninit_array_assume_init,
maybe_uninit_uninit_array,
pattern,
slice_partition_dedup,
specialization,
trusted_len,
trusted_random_access
)]
#![cfg_attr(feature = "std", feature(read_buf))]
use core::cmp::{Ord, PartialEq};
use core::intrinsics::assume;
use core::marker::PhantomData;
use core::mem::{self, size_of, MaybeUninit};
use core::ops::{
Add, Bound::Excluded, Bound::Included, Bound::Unbounded, Div, Mul, RangeBounds, Sub,
};
use core::ptr;
use core::slice::{from_raw_parts, from_raw_parts_mut};
pub use crate::errors::{CapacityError, PushCapacityError};
pub use crate::heap::{
StaticHeap, StaticHeapDrainSorted, StaticHeapIntoIterSorted, StaticHeapPeekMut,
};
pub use crate::iterators::{
StaticVecDrain, StaticVecIntoIter, StaticVecIterConst, StaticVecIterMut, StaticVecSplice,
};
pub use crate::string::{StaticString, StringError};
use crate::utils::{const_min, quicksort_internal, reverse_copy, zst_ptr_add, zst_ptr_add_mut};
#[cfg(any(feature = "std", rustdoc))]
extern crate alloc;
#[cfg(any(feature = "std", rustdoc))]
use alloc::vec::Vec;
#[cfg(feature = "std")]
extern crate std;
mod errors;
mod heap;
mod iterators;
#[macro_use]
mod macros;
mod string;
mod trait_impls;
#[doc(hidden)]
pub mod utils;
pub struct StaticVec<T, const N: usize> {
data: MaybeUninit<[T; N]>,
length: usize,
}
impl<T, const N: usize> StaticVec<T, N> {
#[inline(always)]
pub const fn new() -> Self {
Self {
data: Self::new_data_uninit(),
length: 0,
}
}
#[inline]
pub const fn new_from_slice(values: &[T]) -> Self
where T: Copy {
let length = const_min(values.len(), N);
Self {
data: {
let mut data = Self::new_data_uninit();
unsafe {
values
.as_ptr()
.copy_to_nonoverlapping(Self::first_ptr_mut(&mut data), length);
data
}
},
length,
}
}
#[inline]
pub fn new_from_array<const N2: usize>(values: [T; N2]) -> Self {
if N == N2 {
Self::from(values)
} else {
Self {
data: {
unsafe {
let mut data = Self::new_data_uninit();
values
.as_ptr()
.copy_to_nonoverlapping(Self::first_ptr_mut(&mut data), N2.min(N));
let mut forgotten = MaybeUninit::new(values);
ptr::drop_in_place(forgotten.assume_init_mut().get_unchecked_mut(N2.min(N)..N2));
data
}
},
length: N2.min(N),
}
}
}
#[inline(always)]
pub const fn new_from_const_array(values: [T; N]) -> Self {
Self {
data: MaybeUninit::new(values),
length: N,
}
}
#[inline(always)]
pub const fn len(&self) -> usize {
self.length
}
#[inline(always)]
pub const fn capacity(&self) -> usize {
N
}
#[inline(always)]
pub const fn cap() -> usize {
N
}
pub const CAPACITY: usize = N;
#[inline(always)]
pub const fn remaining_capacity(&self) -> usize {
N - self.length
}
#[inline(always)]
pub const fn size_in_bytes(&self) -> usize {
size_of::<T>() * self.length
}
#[inline(always)]
pub const unsafe fn set_len(&mut self, new_len: usize) {
debug_assert!(
new_len <= N,
"A `new_len` greater than `N` was passed to `StaticVec::set_len`!"
);
self.length = new_len;
}
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.length == 0
}
#[allow(clippy::len_zero)]
#[inline(always)]
pub const fn is_not_empty(&self) -> bool {
self.length > 0
}
#[inline(always)]
pub const fn is_full(&self) -> bool {
self.length == N
}
#[inline(always)]
pub const fn is_not_full(&self) -> bool {
self.length < N
}
#[inline(always)]
pub const fn as_ptr(&self) -> *const T {
let res = self.data.as_ptr() as *const T;
unsafe {
assume(!res.is_null());
}
res
}
#[inline(always)]
pub const fn as_mut_ptr(&mut self) -> *mut T {
let res = self.data.as_mut_ptr() as *mut T;
unsafe {
assume(!res.is_null());
}
res
}
#[inline(always)]
pub const fn as_slice(&self) -> &[T] {
unsafe { from_raw_parts(self.as_ptr(), self.length) }
}
#[inline(always)]
pub const fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { from_raw_parts_mut(self.as_mut_ptr(), self.length) }
}
#[inline(always)]
pub const unsafe fn ptr_at_unchecked(&self, index: usize) -> *const T {
debug_assert!(
index <= N,
"Bounds check failure in `StaticVec::ptr_at_unchecked`!",
);
self.as_ptr().add(index)
}
#[inline(always)]
pub const unsafe fn mut_ptr_at_unchecked(&mut self, index: usize) -> *mut T {
debug_assert!(
index <= N,
"Bounds check failure in `StaticVec::mut_ptr_at_unchecked`!",
);
self.as_mut_ptr().add(index)
}
#[inline(always)]
pub const fn ptr_at(&self, index: usize) -> *const T {
assert!(
index < self.length,
"Bounds check failure in `StaticVec::ptr_at`!"
);
unsafe { self.ptr_at_unchecked(index) }
}
#[inline(always)]
pub const fn mut_ptr_at(&mut self, index: usize) -> *mut T {
assert!(
index < self.length,
"Bounds check failure in `StaticVec::mut_ptr_at`!"
);
unsafe { self.mut_ptr_at_unchecked(index) }
}
#[inline(always)]
pub const unsafe fn get_unchecked(&self, index: usize) -> &T {
debug_assert!(
index < N,
"Bounds check failure in `StaticVec::get_unchecked`!"
);
&*self.ptr_at_unchecked(index)
}
#[inline(always)]
pub const unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
debug_assert!(
index < N,
"Bounds check failure in `StaticVec::get_unchecked_mut`!"
);
&mut *self.mut_ptr_at_unchecked(index)
}
#[inline(always)]
pub const unsafe fn push_unchecked(&mut self, value: T) {
debug_assert!(
self.is_not_full(),
"`StaticVec::push_unchecked` was called through a StaticVec already at maximum capacity!"
);
let length = self.length;
self.mut_ptr_at_unchecked(length).write(value);
self.set_len(length + 1);
}
#[inline(always)]
pub const unsafe fn pop_unchecked(&mut self) -> T {
debug_assert!(
self.is_not_empty(),
"`StaticVec::pop_unchecked` was called through an empty StaticVec!"
);
let new_length = self.length - 1;
self.set_len(new_length);
self.ptr_at_unchecked(new_length).read()
}
#[inline(always)]
pub const fn try_push(&mut self, value: T) -> Result<(), PushCapacityError<T, N>> {
if self.is_not_full() {
unsafe { self.push_unchecked(value) };
Ok(())
} else {
Err(PushCapacityError::new(value))
}
}
#[inline(always)]
pub const fn push(&mut self, value: T) {
assert!(
self.is_not_full(),
"`StaticVec::push` was called through a StaticVec already at maximum capacity!"
);
unsafe { self.push_unchecked(value) };
}
#[inline(always)]
pub const fn pop(&mut self) -> Option<T> {
if self.is_empty() {
None
} else {
Some(unsafe { self.pop_unchecked() })
}
}
#[inline(always)]
pub const fn first(&self) -> Option<&T> {
if self.is_empty() {
None
} else {
Some(unsafe { self.get_unchecked(0) })
}
}
#[inline(always)]
pub const fn first_mut(&mut self) -> Option<&mut T> {
if self.is_empty() {
None
} else {
Some(unsafe { self.get_unchecked_mut(0) })
}
}
#[inline(always)]
pub const fn last(&self) -> Option<&T> {
if self.is_empty() {
None
} else {
Some(unsafe { self.get_unchecked(self.length - 1) })
}
}
#[inline(always)]
pub const fn last_mut(&mut self) -> Option<&mut T> {
if self.is_empty() {
None
} else {
Some(unsafe { self.get_unchecked_mut(self.length - 1) })
}
}
#[inline]
pub(crate) const fn remove_unchecked(&mut self, index: usize) -> T {
let old_length = self.length;
unsafe {
let self_ptr = self.mut_ptr_at_unchecked(index);
let res = self_ptr.read();
self_ptr.offset(1).copy_to(self_ptr, old_length - index - 1);
self.set_len(old_length - 1);
res
}
}
#[inline]
pub const fn remove(&mut self, index: usize) -> T {
let old_length = self.length;
assert!(
index < old_length,
"Bounds check failure in `StaticVec::remove`!"
);
unsafe {
let self_ptr = self.mut_ptr_at_unchecked(index);
assume(!self_ptr.is_null());
let res = self_ptr.read();
self_ptr.offset(1).copy_to(self_ptr, old_length - index - 1);
self.set_len(old_length - 1);
res
}
}
#[allow(clippy::manual_map)]
#[inline(always)]
pub fn remove_item(&mut self, item: &T) -> Option<T>
where T: PartialEq {
if let Some(pos) = self.iter().position(|x| *x == *item) {
Some(self.remove(pos))
} else {
None
}
}
#[inline(always)]
pub const fn swap_pop(&mut self, index: usize) -> Option<T> {
if index < self.length {
unsafe {
let new_length = self.length - 1;
let last_value = self.ptr_at_unchecked(new_length).read();
self.set_len(new_length);
Some(ptr::replace(self.mut_ptr_at_unchecked(index), last_value))
}
} else {
None
}
}
#[inline(always)]
pub const fn swap_remove(&mut self, index: usize) -> T {
assert!(
index < self.length,
"Bounds check failure in `StaticVec::swap_remove`!"
);
unsafe {
let new_length = self.length - 1;
let last_value = self.ptr_at_unchecked(new_length).read();
self.set_len(new_length);
ptr::replace(self.mut_ptr_at_unchecked(index), last_value)
}
}
#[inline]
pub const fn insert(&mut self, index: usize, value: T) {
let old_length = self.length;
assert!(
old_length < N && index <= old_length,
"Insufficient remaining capacity or bounds check failure in `StaticVec::insert`!"
);
unsafe {
let self_ptr = self.mut_ptr_at_unchecked(index);
self_ptr.copy_to(self_ptr.offset(1), old_length - index);
self_ptr.write(value);
self.set_len(old_length + 1);
}
}
#[inline]
pub fn insert_many<I: IntoIterator<Item = T>>(&mut self, index: usize, iter: I)
where I::IntoIter: ExactSizeIterator<Item = T> {
let old_length = self.length;
assert!(
old_length < N && index <= old_length,
"Insufficient remaining capacity or bounds check failure in `StaticVec::insert_many`!"
);
let mut it = iter.into_iter();
if index == old_length {
return self.extend(it);
}
let iter_size = it.len();
assert!(
index + iter_size >= index && (old_length - index) + iter_size < N,
"Insufficient remaining capacity or bounds check failure in `StaticVec::insert_many`!"
);
unsafe {
let mut self_ptr = self.mut_ptr_at_unchecked(index);
self_ptr.copy_to(self_ptr.add(iter_size), old_length - index);
self.length = index;
let mut item_count = 0;
while item_count < N {
if let Some(item) = it.next() {
let mut current = self_ptr.add(item_count);
if item_count >= iter_size {
self_ptr = self.mut_ptr_at_unchecked(index);
current = self_ptr.add(item_count);
current.copy_to(current.offset(1), old_length - index);
}
current.write(item);
item_count += 1;
} else {
break;
}
}
self.set_len(old_length + item_count);
}
}
#[inline]
pub const fn insert_from_slice(&mut self, index: usize, values: &[T])
where T: Copy {
let old_length = self.length;
let values_length = values.len();
assert!(
old_length < N && index <= old_length && values_length <= self.remaining_capacity(),
"Insufficient remaining capacity or bounds check failure in `StaticVec::insert_from_slice`!"
);
unsafe {
let self_ptr = self.mut_ptr_at_unchecked(index);
self_ptr.copy_to(self_ptr.add(values_length), old_length - index);
self_ptr.copy_from_nonoverlapping(values.as_ptr(), values_length);
self.set_len(old_length + values_length);
}
}
#[inline]
pub fn try_insert(&mut self, index: usize, value: T) -> Result<(), CapacityError<N>> {
let old_length = self.length;
if old_length < N && index <= old_length {
unsafe {
let self_ptr = self.mut_ptr_at_unchecked(index);
self_ptr.copy_to(self_ptr.offset(1), old_length - index);
self_ptr.write(value);
self.set_len(old_length + 1);
}
Ok(())
} else {
Err(CapacityError {})
}
}
#[inline]
pub const fn try_insert_from_slice(
&mut self,
index: usize,
values: &[T],
) -> Result<(), CapacityError<N>>
where
T: Copy,
{
let old_length = self.length;
let values_length = values.len();
if old_length < N && index <= old_length && values_length <= self.remaining_capacity() {
unsafe {
let self_ptr = self.mut_ptr_at_unchecked(index);
self_ptr.copy_to(self_ptr.add(values_length), old_length - index);
self_ptr.copy_from_nonoverlapping(values.as_ptr(), values_length);
self.set_len(old_length + values_length);
}
Ok(())
} else {
Err(CapacityError {})
}
}
#[inline(always)]
pub fn contains(&self, value: &T) -> bool
where T: PartialEq {
self.iter().any(|current| current == value)
}
#[inline(always)]
pub fn clear(&mut self) {
unsafe { ptr::drop_in_place(self.as_mut_slice()) };
self.length = 0;
}
#[inline(always)]
pub const fn iter(&self) -> StaticVecIterConst<T, N> {
let start_ptr = self.as_ptr();
unsafe {
assume(!start_ptr.is_null());
StaticVecIterConst {
start: start_ptr,
end: match size_of::<T>() {
0 => zst_ptr_add(start_ptr, self.length),
_ => start_ptr.add(self.length),
},
marker: PhantomData,
}
}
}
#[inline(always)]
pub const fn iter_mut(&mut self) -> StaticVecIterMut<T, N> {
let start_ptr = self.as_mut_ptr();
unsafe {
assume(!start_ptr.is_null());
StaticVecIterMut {
start: start_ptr,
end: match size_of::<T>() {
0 => zst_ptr_add_mut(start_ptr, self.length),
_ => start_ptr.add(self.length),
},
marker: PhantomData,
}
}
}
#[cfg(feature = "std")]
#[doc(cfg(feature = "std"))]
#[inline]
pub fn sorted(&self) -> Self
where T: Copy + Ord {
let mut res = self.clone();
res.sort();
res
}
#[inline]
pub fn sorted_unstable(&self) -> Self
where T: Copy + Ord {
let mut res = self.clone();
res.sort_unstable();
res
}
#[inline]
pub const fn quicksorted_unstable(&self) -> Self
where T: Copy + ~const PartialOrd {
let length = self.length;
if length < 2 {
return self.clone();
}
let mut res = Self::new_data_uninit();
let res_ptr = Self::first_ptr_mut(&mut res);
unsafe { self.as_ptr().copy_to_nonoverlapping(res_ptr, length) };
quicksort_internal(res_ptr, 0, (length - 1) as isize);
Self { data: res, length }
}
#[inline]
pub const fn quicksort_unstable(&mut self)
where T: Copy + ~const PartialOrd {
let length = self.length;
if length < 2 {
return;
}
let self_ptr = self.as_mut_ptr();
unsafe { assume(!self_ptr.is_null()) };
quicksort_internal(self_ptr, 0, (length - 1) as isize);
}
#[inline(always)]
pub const fn reversed(&self) -> Self
where T: Copy {
Self {
data: reverse_copy(self.length, &self.data),
length: self.length,
}
}
#[inline]
pub fn filled_with<F: FnMut() -> T>(mut initializer: F) -> Self {
let mut res = Self::new();
for i in 0..N {
unsafe {
res.mut_ptr_at_unchecked(i).write(initializer());
}
res.length += 1;
}
res
}
#[inline]
pub fn filled_with_by_index<F: FnMut(usize) -> T>(mut initializer: F) -> Self {
let mut res = Self::new();
for i in 0..N {
unsafe {
res.mut_ptr_at_unchecked(i).write(initializer(i));
}
res.length += 1;
}
res
}
#[inline(always)]
pub const fn extend_from_slice(&mut self, values: &[T])
where T: Copy {
let old_length = self.length;
let added_length = const_min(values.len(), N - old_length);
unsafe {
values
.as_ptr()
.copy_to_nonoverlapping(self.mut_ptr_at_unchecked(old_length), added_length);
self.set_len(old_length + added_length);
}
}
#[inline(always)]
pub fn try_extend_from_slice(&mut self, values: &[T]) -> Result<(), CapacityError<N>>
where T: Copy {
let old_length = self.length;
let added_length = values.len();
if N - old_length < added_length {
return Err(CapacityError {});
}
unsafe {
values
.as_ptr()
.copy_to_nonoverlapping(self.mut_ptr_at_unchecked(old_length), added_length);
self.set_len(old_length + added_length);
}
Ok(())
}
#[inline]
pub const fn append<const N2: usize>(&mut self, other: &mut StaticVec<T, N2>) {
let old_length = self.length;
let item_count = const_min(N - old_length, other.length);
let other_new_length = other.length - item_count;
unsafe {
self
.mut_ptr_at_unchecked(old_length)
.copy_from_nonoverlapping(other.as_ptr(), item_count);
other
.as_mut_ptr()
.copy_from(other.ptr_at_unchecked(item_count), other_new_length);
other.set_len(other_new_length);
self.set_len(old_length + item_count);
}
}
#[inline]
pub const fn concat<const N2: usize>(
&self,
other: &StaticVec<T, N2>,
) -> StaticVec<T, { N + N2 }>
where
T: Copy,
{
let length = self.length;
let other_length = other.length;
let mut res = StaticVec::new_data_uninit();
let res_ptr = res.as_mut_ptr() as *mut T;
unsafe {
self.as_ptr().copy_to_nonoverlapping(res_ptr, length);
other
.as_ptr()
.copy_to_nonoverlapping(res_ptr.add(length), other_length);
}
StaticVec {
data: res,
length: length + other_length,
}
}
#[inline]
pub fn concat_clone<const N2: usize>(
&self,
other: &StaticVec<T, N2>,
) -> StaticVec<T, { N + N2 }>
where
T: Clone,
{
let mut res = StaticVec::new();
for item in self {
unsafe { res.push_unchecked(item.clone()) };
}
for item in other {
unsafe { res.push_unchecked(item.clone()) };
}
res
}
#[inline]
pub const fn intersperse(&self, separator: T) -> StaticVec<T, { N * 2 }>
where T: Copy {
if self.is_empty() {
return StaticVec::new();
}
let mut res = StaticVec::new_data_uninit();
let mut res_ptr = StaticVec::first_ptr_mut(&mut res) as *mut T;
let mut i = 0;
let length = self.length;
while i < length - 1 {
unsafe {
res_ptr.write(self.ptr_at_unchecked(i).read());
res_ptr.offset(1).write(separator);
res_ptr = res_ptr.offset(2);
}
i += 1;
}
unsafe {
res_ptr.write(self.ptr_at_unchecked(i).read());
}
StaticVec {
data: res,
length: (length * 2) - 1,
}
}
#[inline]
pub fn intersperse_clone(&self, separator: T) -> StaticVec<T, { N * 2 }>
where T: Clone {
if self.is_empty() {
return StaticVec::new();
}
let mut res = StaticVec::new();
let length = self.length;
unsafe {
for i in 0..length - 1 {
res.push_unchecked(self.get_unchecked(i).clone());
res.push_unchecked(separator.clone());
}
res.push_unchecked(self.get_unchecked(length - 1).clone());
}
res
}
#[cfg(feature = "std")]
#[doc(cfg(feature = "std"))]
#[inline]
pub fn from_vec(mut vec: Vec<T>) -> Self {
let vec_len = vec.len();
let item_count = vec_len.min(N);
Self {
data: {
unsafe { vec.set_len(0) };
let mut data = Self::new_data_uninit();
unsafe {
vec
.as_ptr()
.copy_to_nonoverlapping(Self::first_ptr_mut(&mut data), item_count);
if vec_len > item_count {
ptr::drop_in_place(from_raw_parts_mut(
vec.as_mut_ptr().add(item_count),
vec_len - item_count,
));
}
data
}
},
length: item_count,
}
}
#[cfg(feature = "std")]
#[doc(cfg(feature = "std"))]
#[inline(always)]
pub fn into_vec(mut self) -> Vec<T> {
let mut res = Vec::with_capacity(N);
let length = self.length;
unsafe {
self
.as_ptr()
.copy_to_nonoverlapping(res.as_mut_ptr(), length);
res.set_len(length);
self.set_len(0);
res
}
}
#[inline(always)]
pub const fn into_inner(self) -> Result<[T; N], Self> {
if self.is_not_full() {
Err(self)
} else {
unsafe {
Ok(
MaybeUninit::new(self)
.assume_init_mut()
.data
.assume_init_read(),
)
}
}
}
#[inline]
pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> Self {
let old_length = self.length;
let start = match range.start_bound() {
Included(&idx) => idx,
Excluded(&idx) => idx + 1,
Unbounded => 0,
};
let end = match range.end_bound() {
Included(&idx) => idx + 1,
Excluded(&idx) => idx,
Unbounded => old_length,
};
assert!(
start <= end && end <= old_length,
"Bounds check failure in `StaticVec::drain`!"
);
let res_length = end - start;
Self {
data: {
let mut res = Self::new_data_uninit();
unsafe {
self
.ptr_at_unchecked(start)
.copy_to_nonoverlapping(Self::first_ptr_mut(&mut res), res_length);
let mp = self.as_mut_ptr();
mp.add(end).copy_to(mp.add(start), old_length - end);
self.set_len(old_length - res_length);
res
}
},
length: res_length,
}
}
#[inline]
pub fn drain_iter<R: RangeBounds<usize>>(&mut self, range: R) -> StaticVecDrain<T, N> {
let length = self.length;
let start = match range.start_bound() {
Included(&idx) => idx,
Excluded(&idx) => idx + 1,
Unbounded => 0,
};
let end = match range.end_bound() {
Included(&idx) => idx + 1,
Excluded(&idx) => idx,
Unbounded => length,
};
assert!(
start <= end && end <= length,
"Bounds check failure in `StaticVec::drain_iter`!"
);
unsafe {
self.set_len(start);
let start_ptr = match size_of::<T>() {
0 => zst_ptr_add(self.as_ptr(), start),
_ => self.ptr_at_unchecked(start),
};
assume(!start_ptr.is_null());
StaticVecDrain {
start: end,
length: length - end,
iter: StaticVecIterConst {
start: start_ptr,
end: match size_of::<T>() {
0 => zst_ptr_add(self.as_ptr(), end),
_ => self.ptr_at_unchecked(end),
},
marker: PhantomData,
},
vec: self,
}
}
}
#[inline]
pub fn drain_filter<F: FnMut(&mut T) -> bool>(&mut self, mut filter: F) -> Self {
let old_length = self.length;
self.length = 0;
let mut res = Self::new();
let mut res_length = 0;
unsafe {
for i in 0..old_length {
if filter(self.get_unchecked_mut(i)) {
res
.mut_ptr_at_unchecked(res_length)
.write(self.ptr_at_unchecked(i).read());
res_length += 1;
} else if res_length > 0 {
let mp = self.as_mut_ptr();
mp.add(i).copy_to_nonoverlapping(mp.add(i - res_length), 1);
}
}
}
self.length = old_length - res_length;
res.length = res_length;
res
}
#[inline]
pub fn splice<R: RangeBounds<usize>, I: IntoIterator<Item = T>>(
&mut self,
range: R,
replace_with: I,
) -> StaticVecSplice<T, I::IntoIter, N> {
let length = self.length;
let start = match range.start_bound() {
Included(&idx) => idx,
Excluded(&idx) => idx + 1,
Unbounded => 0,
};
let end = match range.end_bound() {
Included(&idx) => idx + 1,
Excluded(&idx) => idx,
Unbounded => length,
};
assert!(
start <= end && end <= length,
"Bounds check failure in `StaticVec::splice`!"
);
StaticVecSplice {
start,
end,
replace_with: replace_with.into_iter(),
vec: self,
}
}
#[inline(always)]
pub fn retain<F: FnMut(&T) -> bool>(&mut self, mut filter: F) {
self.drain_filter(|val| !filter(val));
}
#[inline(always)]
pub fn truncate(&mut self, length: usize) {
if length < self.length {
let old_length = self.length;
unsafe {
self.set_len(length);
ptr::drop_in_place(from_raw_parts_mut(
self.mut_ptr_at_unchecked(length),
old_length - length,
));
}
}
}
#[inline]
pub const fn split_off(&mut self, at: usize) -> Self {
let old_length = self.length;
assert!(
at <= old_length,
"Bounds check failure in `StaticVec::split_off`!"
);
let split_length = old_length - at;
Self {
data: unsafe {
self.set_len(at);
let mut split = Self::new_data_uninit();
self
.ptr_at_unchecked(at)
.copy_to_nonoverlapping(Self::first_ptr_mut(&mut split), split_length);
split
},
length: split_length,
}
}
#[inline]
pub const fn split_at<const M: usize>(self) -> (StaticVec<T, M>, StaticVec<T, { N - M }>) {
let old_length = self.length;
assert!(
M <= old_length,
"Bounds check failure in `StaticVec::split_at'!"
);
let mut left = MaybeUninit::<[T; M]>::uninit();
let mut right = MaybeUninit::<[T; N - M]>::uninit();
let self_ptr = self.as_ptr();
let left_ptr = StaticVec::first_ptr_mut(&mut left);
let right_ptr = StaticVec::first_ptr_mut(&mut right);
let right_length = old_length - M;
unsafe {
self_ptr.copy_to_nonoverlapping(left_ptr, M);
self_ptr
.add(M)
.copy_to_nonoverlapping(right_ptr, right_length);
mem::forget(self);
(
StaticVec {
data: left,
length: M,
},
StaticVec {
data: right,
length: right_length,
},
)
}
}
#[inline(always)]
pub fn dedup_by<F: FnMut(&mut T, &mut T) -> bool>(&mut self, same_bucket: F) {
let new_length = self.as_mut_slice().partition_dedup_by(same_bucket).0.len();
self.truncate(new_length);
}
#[inline(always)]
pub fn dedup(&mut self)
where T: PartialEq {
self.dedup_by(|a, b| a == b)
}
#[inline(always)]
pub fn dedup_by_key<F: FnMut(&mut T) -> K, K: PartialEq<K>>(&mut self, mut key: F) {
self.dedup_by(|a, b| key(a) == key(b))
}
#[inline]
pub fn difference<const N2: usize>(&self, other: &StaticVec<T, N2>) -> Self
where T: Clone + PartialEq {
let mut res = Self::new();
for left in self {
let mut found = false;
for right in other {
if left == right {
found = true;
break;
}
}
if !found {
unsafe { res.push_unchecked(left.clone()) }
}
}
res
}
#[inline]
pub fn symmetric_difference<const N2: usize>(
&self,
other: &StaticVec<T, N2>,
) -> StaticVec<T, { N + N2 }>
where
T: Clone + PartialEq,
{
let mut res = StaticVec::new();
for left in self {
let mut found = false;
for right in other {
if left == right {
found = true;
break;
}
}
if !found {
unsafe { res.push_unchecked(left.clone()) }
}
}
for right in other {
let mut found = false;
for left in self {
if right == left {
found = true;
break;
}
}
if !found {
unsafe { res.push_unchecked(right.clone()) }
}
}
res
}
#[inline]
pub fn intersection<const N2: usize>(&self, other: &StaticVec<T, N2>) -> Self
where T: Clone + PartialEq {
let mut res = Self::new();
for left in self {
let mut found = false;
for right in other {
if left == right {
found = true;
break;
}
}
if found && !res.contains(left) {
unsafe { res.push_unchecked(left.clone()) }
}
}
res
}
#[allow(clippy::from_iter_instead_of_collect)]
#[inline]
#[rustfmt::skip]
pub fn union<const N2: usize>(&self, other: &StaticVec<T, N2>) -> StaticVec<T, { N + N2 }>
where T: Clone + PartialEq {
if self.length <= other.length {
let mut res = StaticVec::from_iter(self.iter().chain(other.difference(self).iter()).cloned());
res.dedup();
res
} else {
let mut res = StaticVec::from_iter(other.iter().chain(self.difference(other).iter()).cloned());
res.dedup();
res
}
}
#[inline(always)]
pub const fn triple(&self) -> (*const T, usize, usize) {
(self.as_ptr(), self.length, N)
}
#[inline(always)]
pub const fn triple_mut(&mut self) -> (*mut T, usize, usize) {
(self.as_mut_ptr(), self.length, N)
}
#[inline(always)]
pub fn added(&self, other: &Self) -> Self
where T: Copy + Add<Output = T> {
assert!(
self.is_full() && other.is_full(),
"In `StaticVec::added`, both `self` and `other` must be at maximum capacity!"
);
let mut res = Self::new();
for i in 0..N {
unsafe {
res
.mut_ptr_at_unchecked(i)
.write(*self.get_unchecked(i) + *other.get_unchecked(i));
}
}
res.length = N;
res
}
#[inline(always)]
pub fn subtracted(&self, other: &Self) -> Self
where T: Copy + Sub<Output = T> {
assert!(
self.is_full() && other.is_full(),
"In `StaticVec::subtracted`, both `self` and `other` must be at maximum capacity!"
);
let mut res = Self::new();
for i in 0..N {
unsafe {
res
.mut_ptr_at_unchecked(i)
.write(*self.get_unchecked(i) - *other.get_unchecked(i));
}
}
res.length = N;
res
}
#[inline(always)]
pub fn multiplied(&self, other: &Self) -> Self
where T: Copy + Mul<Output = T> {
assert!(
self.is_full() && other.is_full(),
"In `StaticVec::multiplied`, both `self` and `other` must be at maximum capacity!"
);
let mut res = Self::new();
for i in 0..N {
unsafe {
res
.mut_ptr_at_unchecked(i)
.write(*self.get_unchecked(i) * *other.get_unchecked(i));
}
}
res.length = N;
res
}
#[inline(always)]
pub fn divided(&self, other: &Self) -> Self
where T: Copy + Div<Output = T> {
assert!(
self.is_full() && other.is_full(),
"In `StaticVec::divided`, both `self` and `other` must be at maximum capacity!"
);
let mut res = Self::new();
for i in 0..N {
unsafe {
res
.mut_ptr_at_unchecked(i)
.write(*self.get_unchecked(i) / *other.get_unchecked(i));
}
}
res.length = N;
res
}
#[inline(always)]
pub(crate) const fn new_data_uninit() -> MaybeUninit<[T; N]> {
MaybeUninit::uninit()
}
#[inline(always)]
pub(crate) const fn first_ptr(this: &MaybeUninit<[T; N]>) -> *const T {
let res = this.as_ptr() as *const T;
unsafe {
assume(!res.is_null());
}
res
}
#[inline(always)]
pub(crate) const fn first_ptr_mut(this: &mut MaybeUninit<[T; N]>) -> *mut T {
let res = this.as_mut_ptr() as *mut T;
unsafe {
assume(!res.is_null());
}
res
}
}
impl<const N: usize> StaticVec<u8, N> {
#[doc(hidden)]
#[inline(always)]
pub(crate) const fn new_from_str_data(data: MaybeUninit<[u8; N]>, length: usize) -> Self {
Self { data, length }
}
#[doc(hidden)]
#[inline]
pub(crate) const fn bytes_to_data(values: &[u8]) -> MaybeUninit<[u8; N]> {
let mut res = MaybeUninit::uninit_array::<N>();
let mut i = 0;
while i < values.len() {
res[i] = MaybeUninit::new(values[i]);
i += 1;
}
let mut i = values.len();
while i < N {
res[i] = MaybeUninit::zeroed();
i += 1;
}
MaybeUninit::new(unsafe { MaybeUninit::array_assume_init(res) })
}
#[doc(hidden)]
#[inline(always)]
pub const fn __new_from_const_str(values: &str) -> Self {
assert!(
values.len() <= N,
"Attempted to create a `StaticString` with insufficient capacity from an `&str` literal!"
);
Self::new_from_str_data(Self::bytes_to_data(values.as_bytes()), values.len())
}
}