#![no_std]
#![warn(clippy::pedantic, missing_docs)]
//! A space-optimized version of `alloc::vec::Vec` that's only the size of a single pointer!
//! Ideal for low-level APIs where ABI calling conventions will typically require most structs be
//! spilled onto the stack and copied instead of being passed solely in registers.
//!
//! For example, in the [x64 msvc ABI](https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-160):
//! > There's a strict one-to-one correspondence between a function call's arguments and the
//! > registers used for those arguments. Any argument that doesn't fit in 8 bytes, or isn't
//! > 1, 2, 4, or 8 bytes, must be passed by reference. A single argument is never spread across
//! > multiple registers.
//!
//! In addition, its single word size makes it ideal for use as a struct member where multiple
//! inclusions of `Vec` as a field can balloon the size.
//!
//!
//! `MiniVec` is a `#[repr(transparent)]` struct so its layout is that of `core::ptr::NonNull<u8>`.
//!
//! ---
//!
//! In general, `MiniVec` aims to be API compatible with what's currently stable in the stdlib so some
//! Nightly features are not supported. `MiniVec` also supports myriad extensions, one such being
//! support for over-alignment via the associated function [`with_alignment`](MiniVec::with_alignment).
//!
//! `MiniVec` has stable implementations of the following nightly-only associated functions on `Vec`:
//! * [`into_raw_parts`](MiniVec::into_raw_parts)
//! * [`shrink_to`](MiniVec::shrink_to)
//! * [`spare_capacity_mut`](MiniVec::spare_capacity_mut)
//! * [`drain_filter`](MiniVec::drain_filter)
//! * [`split_at_spare_mut`](MiniVec::split_at_spare_mut)
//! * [`extend_from_within`](MiniVec::extend_from_within)
//!
//! `MiniVec` has the following associated functions not found in `Vec`:
//! * [`with_alignment`](MiniVec::with_alignment)
//! * [`from_raw_part`](MiniVec::from_raw_part)
//! * [`drain_vec`](MiniVec::drain_vec)
//! * [`assume_minivec_init`](MiniVec::assume_minivec_init)
//!
//! `MiniVec` has the following extensions to the existing `Vec` API:
//! * [`push`](MiniVec::push) returns a mutable reference to the newly created element
//!
//! Eventual TODO's:
//! * add `try_reserve` methods once stable
//! * add myriad specializations to associated functions such as `FromIterator` once stable
//! * add Allocator support once stable
//!
extern crate alloc;
mod r#impl;
mod as_mut;
mod as_ref;
mod borrow;
mod clone;
mod debug;
mod default;
mod deref;
mod drop;
mod eq;
mod extend;
mod from;
mod from_iterator;
mod hash;
mod index;
mod into_iterator;
mod ord;
mod partial_eq;
#[cfg(feature = "serde")]
mod serde;
use crate::r#impl::drain::make_drain_iterator;
use crate::r#impl::drain_filter::make_drain_filter_iterator;
use crate::r#impl::helpers::{make_layout, max_align, next_aligned, next_capacity};
use crate::r#impl::splice::make_splice_iterator;
pub use crate::r#impl::{Drain, DrainFilter, IntoIter, Splice};
/// `MiniVec` is a space-optimized implementation of `alloc::vec::Vec` that is only the size of a single pointer and
/// also extends portions of its API, including support for over-aligned allocations. `MiniVec` also aims to bring as
/// many Nightly features from `Vec` to stable toolchains as is possible. In many cases, it is a drop-in replacement
/// for the "real" `Vec`.
///
#[repr(transparent)]
pub struct MiniVec<T> {
buf: core::ptr::NonNull<u8>,
phantom: core::marker::PhantomData<T>,
}
/// `LayoutErr` is the error type returned by the alignment-based associated functions for `MiniVec`
///
#[derive(core::fmt::Debug)]
pub enum LayoutErr {
/// `AlignmentTooSmall` is returned when the user-supplied alignment fails to meet the base minimum alignment
/// requirements for the backing allocation of the `MiniVec`.
///
/// The minimum alignment requirement is `core::mem::align_of::<*const ()>()`.
///
AlignmentTooSmall,
/// `AlignmentNotDivisibleByTwo` is returned when the user-supplied alignment fails to meet the requirement of being
/// a power of two.
///
AlignmentNotDivisibleByTwo,
}
#[derive(Clone, Copy)]
struct Header {
len: usize,
cap: usize,
alignment: usize,
}
#[test]
#[allow(clippy::clone_on_copy)]
fn header_clone() {
let header = Header {
len: 0,
cap: 0,
alignment: 0,
};
let header2 = header.clone();
assert_eq!(header2.len, header.len);
assert_eq!(header2.cap, header.cap);
assert_eq!(header2.alignment, header.alignment);
}
static DEFAULT_U8: u8 = 137;
impl<T> MiniVec<T> {
#[allow(clippy::cast_ptr_alignment)]
fn is_default(&self) -> bool {
core::ptr::eq(self.buf.as_ptr(), &DEFAULT_U8)
}
fn header(&self) -> &Header {
#[allow(clippy::cast_ptr_alignment)]
unsafe {
&*(self.buf.as_ptr() as *const Header)
}
}
fn header_mut(&mut self) -> &mut Header {
#[allow(clippy::cast_ptr_alignment)]
unsafe {
&mut *self.buf.as_ptr().cast::<Header>()
}
}
fn data(&self) -> *mut T {
debug_assert!(!self.is_default());
let count = next_aligned(core::mem::size_of::<Header>(), self.alignment());
unsafe { self.buf.as_ptr().add(count).cast::<T>() }
}
fn alignment(&self) -> usize {
if self.capacity() == 0 {
max_align::<T>()
} else {
self.header().alignment
}
}
fn grow(&mut self, capacity: usize, alignment: usize) {
debug_assert!(capacity >= self.len());
let old_capacity = self.capacity();
let new_capacity = capacity;
if new_capacity == old_capacity {
return;
}
let new_layout = make_layout::<T>(new_capacity, alignment);
let len = self.len();
let new_buf = if self.is_default() {
unsafe { alloc::alloc::alloc(new_layout) }
} else {
let old_layout = make_layout::<T>(old_capacity, alignment);
unsafe { alloc::alloc::realloc(self.buf.as_ptr(), old_layout, new_layout.size()) }
};
if new_buf.is_null() {
alloc::alloc::handle_alloc_error(new_layout);
}
let header = Header {
len,
cap: new_capacity,
alignment,
};
#[allow(clippy::cast_ptr_alignment)]
unsafe {
core::ptr::write(new_buf.cast::<Header>(), header);
}
self.buf = unsafe { core::ptr::NonNull::<u8>::new_unchecked(new_buf) };
}
/// `append` moves every element from `other` to the back of `self`. `other.is_empty()` is `true` once this operation
/// completes and its capacity is unaffected.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3];
/// let mut vec2 = minivec::mini_vec![4, 5, 6];
/// vec.append(&mut vec2);
/// assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
/// assert_eq!(vec2, []);
/// ```
///
pub fn append(&mut self, other: &mut MiniVec<T>) {
if other.is_empty() {
return;
}
let other_len = other.len();
self.reserve(other_len);
unsafe {
core::ptr::copy_nonoverlapping(other.as_ptr(), self.as_mut_ptr().add(self.len()), other_len);
};
unsafe {
other.set_len(0);
self.set_len(self.len() + other_len);
};
}
/// `as_mut_ptr` returns a `*mut T` to the underlying array.
///
/// * May return a null pointer.
/// * May be invalidated by calls to [`reserve()`](MiniVec::reserve)
/// * Can outlive its backing `MiniVec`
///
/// # Example
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3, 4];
/// let mut p = vec.as_mut_ptr();
///
/// for idx in 0..vec.len() {
/// unsafe {
/// *p.add(idx) = *p.add(idx) + 3;
/// }
/// }
///
/// assert_eq!(vec, [4, 5, 6, 7]);
/// ```
///
pub fn as_mut_ptr(&mut self) -> *mut T {
if self.is_default() {
return core::ptr::null_mut();
}
self.data()
}
/// `as_mut_slice` obtains a mutable reference to a slice that's attached to the backing array.
///
/// # Example
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3];
/// {
/// let as_slice: &mut [_] = vec.as_mut_slice();
/// as_slice[0] = 1337;
/// }
/// assert_eq!(vec[0], 1337);
/// ```
///
pub fn as_mut_slice(&mut self) -> &mut [T] {
self
}
/// `as_ptr` obtains a `*const T` to the underlying allocation.
///
/// * May return a null pointer.
/// * May be invalidated by calls to `reserve()`
/// * Can outlive its backing `MiniVec`
/// * May allow access to unitialized memory/non-existent objects
/// * May create out-of-bounds memory access
///
/// # Example
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3, 4];
/// let mut p = vec.as_mut_ptr();
///
/// let mut sum = 0;
/// for idx in 0..vec.len() {
/// unsafe {
/// sum += *p.add(idx);
/// }
/// }
///
/// assert_eq!(sum, 1 + 2 + 3 + 4);
/// ```
///
#[must_use]
pub fn as_ptr(&self) -> *const T {
if self.is_default() {
return core::ptr::null();
}
self.data()
}
/// `as_slice` obtains a reference to the backing array as an immutable slice of `T`.
///
/// # Example
/// ```
/// let vec = minivec::mini_vec![1, 2, 3, 4];
/// let mut sum = 0;
///
/// let as_slice : &[_] = vec.as_slice();
///
/// for idx in 0..vec.len() {
/// sum += as_slice[idx];
/// }
///
/// assert_eq!(sum, 1 + 2 + 3 + 4);
/// ```
///
#[must_use]
pub fn as_slice(&self) -> &[T] {
self
}
/// `capacity` obtains the number of elements that can be inserted into the `MiniVec` before a
/// reallocation will be required.
///
/// Note: `MiniVec` aims to use the same reservation policy as `alloc::vec::Vec`.
///
/// # Example
///
/// ```
/// let vec = minivec::MiniVec::<i32>::with_capacity(128);
///
/// assert_eq!(vec.len(), 0);
/// assert_eq!(vec.capacity(), 128);
/// ```
///
#[must_use]
pub fn capacity(&self) -> usize {
if self.is_default() {
0
} else {
self.header().cap
}
}
/// `clear` clears the current contents of the `MiniVec`. Afterwards, [`len()`](MiniVec::len)
/// will return 0. [`capacity()`](MiniVec::capacity) is not affected.
///
/// Logically equivalent to calling [`minivec::MiniVec::truncate(0)`](MiniVec::truncate).
///
/// Note: destruction order of the contained elements is not guaranteed.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![-1; 256];
///
/// let cap = vec.capacity();
///
/// assert_eq!(vec.len(), 256);
///
/// vec.clear();
///
/// assert_eq!(vec.len(), 0);
/// assert_eq!(vec.capacity(), cap);
/// ```
///
pub fn clear(&mut self) {
self.truncate(0);
}
/// `dedeup` "de-duplicates" all adjacent identical values in the vector.
///
/// Logically equivalent to calling [`minivec::MiniVec::dedup_by(|x, y| x == y)`](MiniVec::dedup_by).
///
/// # Example
///
/// ```
/// let mut v = minivec::mini_vec![1, 2, 1, 1, 3, 3, 3, 4, 5, 4];
/// v.dedup();
///
/// assert_eq!(v, [1, 2, 1, 3, 4, 5, 4]);
/// ```
///
pub fn dedup(&mut self)
where
T: PartialEq,
{
self.dedup_by(|x, y| x == y);
}
/// `dedup_by` "de-duplicates" all adjacent elements for which the supplied binary predicate
/// returns true.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
///
/// vec.dedup_by(|x, y| *x + *y < 8);
///
/// // 1 + 2 < 8
/// // 1 + 3 < 8
/// // 1 + 4 < 8...
/// // 1 + 7 == 8
/// assert_eq!(vec, [1, 7, 8, 9, 10]);
/// ```
///
pub fn dedup_by<F>(&mut self, mut pred: F)
where
F: FnMut(&mut T, &mut T) -> bool,
{
// In essence copy what the C++ stdlib does:
// https://github.com/llvm/llvm-project/blob/032810f58986cd568980227c9531de91d8bcb1cd/libcxx/include/algorithm#L2174-L2191
//
let len = self.len();
if len < 2 {
return;
}
let data = self.as_mut_ptr();
let mut read = unsafe { data.add(1) };
let mut write = read;
let last = unsafe { data.add(len) };
while read < last {
let matches = unsafe { pred(&mut *read, &mut *write.sub(1)) };
if !matches {
if read != write {
unsafe {
core::mem::swap(&mut *read, &mut *write);
}
}
write = unsafe { write.add(1) };
}
read = unsafe { read.add(1) };
}
self.truncate((write as usize - data as usize) / core::mem::size_of::<T>());
}
/// `dedup_by_key` "de-duplicates" all adjacent elements where `key(elem1) == key(elem2)`.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec!["a", "b", "c", "aa", "bbb", "cc", "dd"];
///
/// vec.dedup_by_key(|x| x.len());
///
/// assert_eq!(vec, ["a", "aa", "bbb", "cc"]);
/// ```
///
pub fn dedup_by_key<F, K>(&mut self, mut key: F)
where
F: FnMut(&mut T) -> K,
K: PartialEq<K>,
{
self.dedup_by(|a, b| key(a) == key(b));
}
/// `drain` returns a [`minivec::Drain`](Drain) iterator which lazily removes elements from the supplied
/// `range`.
///
/// If the returned iterator is not iterated until exhaustion then the `Drop` implementation
/// for `Drain` will remove the remaining elements.
///
/// # Panics
///
/// Panics if the supplied range would be outside the vector
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
///
/// let other_vec : minivec::MiniVec<_> = vec.drain(1..7).map(|x| x + 2).collect();
///
/// assert_eq!(vec, [1, 8, 9, 10]);
/// assert_eq!(other_vec, [4, 5, 6, 7, 8, 9]);
/// ```
///
pub fn drain<R>(&mut self, range: R) -> Drain<T>
where
R: core::ops::RangeBounds<usize>,
{
let len = self.len();
let start_idx = match range.start_bound() {
core::ops::Bound::Included(&n) => n,
core::ops::Bound::Excluded(&n) => {
n.checked_add(1).expect("Start idx exceeded numeric limits")
}
core::ops::Bound::Unbounded => 0,
};
let end_idx = match range.end_bound() {
core::ops::Bound::Included(&n) => n.checked_add(1).expect("End idx exceeded numeric limits"),
core::ops::Bound::Excluded(&n) => n,
core::ops::Bound::Unbounded => len,
};
if start_idx > end_idx {
panic!(
"start drain index (is {}) should be <= end drain index (is {})",
start_idx, end_idx
);
}
if end_idx > len {
panic!(
"end drain index (is {}) should be <= len (is {})",
end_idx, len
);
}
let data = self.as_mut_ptr();
if !data.is_null() {
unsafe {
self.set_len(start_idx);
}
}
make_drain_iterator(self, data, len - end_idx, start_idx, end_idx)
}
/// `drain_filter` creates a new [`DrainFilter`](DrainFilter) iterator that when iterated will
/// remove all elements for which the supplied `pred` returns `true`.
///
/// Removal of elements is done by transferring ownership of the element to the iterator.
///
/// Note: if the supplied predicate panics then `DrainFilter` will stop all usage of it and then
/// backshift all untested elements and adjust the `MiniVec`'s length accordingly.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![
/// 1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37,
/// 39,
/// ];
///
/// let removed = vec.drain_filter(|x| *x % 2 == 0).collect::<minivec::MiniVec<_>>();
/// assert_eq!(removed.len(), 10);
/// assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
///
/// assert_eq!(vec.len(), 14);
/// assert_eq!(
/// vec,
/// vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
/// );
/// ```
///
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
where
F: core::ops::FnMut(&mut T) -> bool,
{
make_drain_filter_iterator(self, pred)
}
#[inline]
#[must_use]
/// `drain_vec` returns a new instance of a `MiniVec`, created by moving the content out of `self`.
///
/// Compared to `drain` method, this is just simple swap of pointers. As result, any pointer to `self` becomes
/// invalid.
///
/// # Example
///
/// ```
/// use minivec::mini_vec;
///
/// let mut vec = mini_vec![1, 2, 3, 4, 5, 6, 7, 9];
/// let new_vec = vec.drain_vec();
///
/// assert_eq!(vec.len(), 0);
/// assert_eq!(new_vec, [1, 2, 3, 4, 5, 6, 7, 9]);
///
/// let new_vec = vec.drain_vec();
/// assert_eq!(vec.len(), 0);
/// assert_eq!(new_vec, []);
/// ```
pub fn drain_vec(&mut self) -> Self {
let mut result = Self::new();
core::mem::swap(&mut result, self);
result
}
/// `from_raw_part` reconstructs a `MiniVec` from a previous call to [`MiniVec::as_mut_ptr`](MiniVec::as_mut_ptr)
/// or the pointer from [`into_raw_parts`](MiniVec::into_raw_parts).
///
/// # Safety
///
/// `from_raw_part` is incredibly unsafe and can only be used with the value of
/// `MiniVec::as_mut_ptr`. This is because the allocation for the backing array stores metadata
/// at its head and is not guaranteed to be stable so users are discouraged from attempting to
/// support this directly.
///
/// # Panics
///
/// Panics in debug mode if the supplied pointer is null.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3, 4];
///
/// let ptr = vec.as_mut_ptr();
///
/// std::mem::forget(vec);
///
/// let new_vec = unsafe { minivec::MiniVec::from_raw_part(ptr) };
///
/// assert_eq!(new_vec, [1, 2, 3, 4]);
/// ```
///
#[allow(clippy::cast_ptr_alignment)]
pub unsafe fn from_raw_part(ptr: *mut T) -> MiniVec<T> {
debug_assert!(!ptr.is_null());
let header_size = core::mem::size_of::<Header>();
let aligned = next_aligned(header_size, core::mem::align_of::<T>());
let p = ptr.cast::<u8>();
let buf = p.sub(aligned);
MiniVec {
buf: core::ptr::NonNull::<u8>::new_unchecked(buf),
phantom: core::marker::PhantomData,
}
}
/// `from_raw_parts` is an API-compatible version of `alloc::vec::Vec::from_raw_parts`. Because
/// of `MiniVec`'s optimized layout, it's not strictly required for a user to pass the length
/// and capacity explicitly.
///
/// Like [`MiniVec::from_raw_part`](MiniVec::from_raw_part), this function is only safe to use
/// with the result of a call to [`MiniVec::as_mut_ptr()`](MiniVec::as_mut_ptr).
///
/// # Panics
///
/// Panics in debug mode if the supplied pointer is null.
///
/// # Safety
///
/// A very unsafe function that should only really be used when passing the vector to a C API.
///
/// Does not support over-aligned allocations. The alignment of the pointer must be that of its natural alignment.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3, 4];
/// let len = vec.len();
/// let cap = vec.capacity();
///
/// let ptr = vec.as_mut_ptr();
///
/// std::mem::forget(vec);
///
/// let new_vec = unsafe { minivec::MiniVec::from_raw_parts(ptr, len, cap) };
///
/// assert_eq!(new_vec, [1, 2, 3, 4]);
/// ```
///
#[allow(clippy::cast_ptr_alignment)]
pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> MiniVec<T> {
debug_assert!(!ptr.is_null());
let header_size = core::mem::size_of::<Header>();
let aligned = next_aligned(header_size, core::mem::align_of::<T>());
let p = ptr.cast::<u8>();
let buf = p.sub(aligned);
debug_assert!((*buf.cast::<Header>()).len == length);
debug_assert!((*buf.cast::<Header>()).cap == capacity);
MiniVec {
buf: core::ptr::NonNull::<u8>::new_unchecked(buf),
phantom: core::marker::PhantomData,
}
}
/// `insert` places an element at the specified index, subsequently shifting all elements to the
/// right of the insertion index by 1
///
/// # Panics
///
/// Will panic when `index > vec.len()`.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![0, 1, 2, 3];
/// vec.insert(1, 1337);
/// assert_eq!(vec, [0, 1337, 1, 2, 3]);
///
/// vec.insert(vec.len(), 7331);
/// assert_eq!(vec, [0, 1337, 1, 2, 3, 7331]);
/// ```
///
pub fn insert(&mut self, index: usize, element: T) {
let len = self.len();
if index > len {
panic!(
"insertion index (is {}) should be <= len (is {})",
index, len
);
}
if len == self.capacity() {
self.reserve(1);
}
let p = unsafe { self.as_mut_ptr().add(index) };
unsafe {
core::ptr::copy(p, p.add(1), len - index);
core::ptr::write(p, element);
self.set_len(len + 1);
}
}
/// `into_raw_parts` will leak the underlying allocation and return a tuple containing a pointer
/// to the start of the backing array and its length and capacity.
///
/// The results of this function are directly compatible with [`from_raw_parts`](MiniVec::from_raw_parts).
///
/// # Example
///
/// ```
/// let vec = minivec::mini_vec![1, 2, 3, 4, 5];
/// let (old_len, old_cap) = (vec.len(), vec.capacity());
///
/// let (ptr, len, cap) = vec.into_raw_parts();
/// assert_eq!(len, old_len);
/// assert_eq!(cap, old_cap);
///
/// let vec = unsafe { minivec::MiniVec::from_raw_parts(ptr, len, cap) };
/// assert_eq!(vec, [1, 2, 3, 4, 5]);
/// ```
///
#[must_use]
pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
let mut v = core::mem::ManuallyDrop::new(self);
(v.as_mut_ptr(), v.len(), v.capacity())
}
/// `is_empty()` returns whether or not the `MiniVec` has a length greater than 0.
///
/// Logically equivalent to manually writing: `v.len() == 0`.
///
/// # Example
///
/// ```
/// let vec = minivec::MiniVec::<i32>::with_capacity(256);
/// assert!(vec.is_empty());
/// assert!(vec.capacity() > 0);
/// ```
///
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// `leak` "leaks" the supplied `MiniVec`, i.e. turn it into a [`ManuallyDrop`](core::mem::ManuallyDrop)
/// instance and return a reference to the backing array via `&'a [T]` where `'a` is a
/// user-supplied lifetime.
///
/// Most useful for turning an allocation with dynamic duration into one with static duration.
///
/// # Example
///
/// ```
/// # #[cfg(not(miri))]
/// # fn main() {
/// let vec = minivec::mini_vec![1, 2, 3];
/// let static_ref: &'static mut [i32] = minivec::MiniVec::leak(vec);
/// static_ref[0] += 1;
/// assert_eq!(static_ref, &[2, 2, 3]);
/// # }
///
/// # #[cfg(miri)]
/// # fn main() {}
/// ```
///
#[must_use]
pub fn leak<'a>(vec: MiniVec<T>) -> &'a mut [T]
where
T: 'a,
{
let len = vec.len();
let mut vec = core::mem::ManuallyDrop::new(vec);
let vec: &mut MiniVec<T> = &mut *vec;
unsafe { core::slice::from_raw_parts_mut(vec.as_mut_ptr(), len) }
}
/// `len` returns the current lenght of the vector, i.e. the number of actual elements in it
///
/// `capacity() >= len()` is true for all cases
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![-1; 256];
/// assert_eq!(vec.len(), 256);
/// ```
///
#[must_use]
pub fn len(&self) -> usize {
if self.is_default() {
0
} else {
self.header().len
}
}
/// `MiniVec::new` constructs an empty `MiniVec`.
///
/// Note: does not allocate any memory.
///
/// # Panics
///
/// Panics when a zero-sized type is attempted to be used.
///
/// # Example
///
/// ```
/// let mut vec = minivec::MiniVec::<i32>::new();
///
/// assert_eq!(vec.as_mut_ptr(), std::ptr::null_mut());
/// assert_eq!(vec.len(), 0);
/// assert_eq!(vec.capacity(), 0);
/// ```
///
#[must_use]
#[allow(clippy::ptr_as_ptr)]
pub fn new() -> MiniVec<T> {
assert!(
core::mem::size_of::<T>() > 0,
"ZSTs currently not supported"
);
let buf =
unsafe { core::ptr::NonNull::<u8>::new_unchecked(&DEFAULT_U8 as *const u8 as *mut u8) };
MiniVec {
buf,
phantom: core::marker::PhantomData,
}
}
/// `pop` removes the last element from the vector, should it exist, and returns an [`Option`](core::option::Option)
/// which owns the removed element.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![Box::new(1)];
/// let ptr = vec.pop().unwrap();
/// assert_eq!(*ptr, 1);
///
/// assert_eq!(vec.pop(), None);
/// ```
///
pub fn pop(&mut self) -> Option<T> {
let len = self.len();
if len == 0 {
return None;
}
let v = unsafe { core::ptr::read(self.as_ptr().add(len - 1)) };
unsafe {
self.set_len(len - 1);
}
Some(v)
}
/// `push` appends an element `value` to the end of the vector. `push` automatically reallocates
/// if the vector does not have sufficient capacity.
///
/// Unlike the standard library `Vec`, `MiniVec::push` returns a mutable reference to the newly created element that's
/// been placed at the back of the vector.
///
/// # Example
///
/// ```
/// let mut vec = minivec::MiniVec::<i32>::with_capacity(64);
///
/// for idx in 0..128 {
/// vec.push(idx);
/// }
///
/// assert_eq!(vec.len(), 128);
/// ```
///
pub fn push(&mut self, value: T) -> &mut T {
let (len, capacity, alignment) = (self.len(), self.capacity(), self.alignment());
if len == capacity {
self.grow(next_capacity::<T>(capacity), alignment);
}
let len = self.len();
let data = self.data();
let dst = unsafe { data.add(len) };
unsafe {
core::ptr::write(dst, value);
};
let mut header = self.header_mut();
header.len += 1;
unsafe { &mut *dst }
}
/// `remove` moves the element at the specified `index` and then returns it to the user. This
/// operation shifts all elements to the right `index` to the left by one so it has a linear
/// time complexity of `vec.len() - index`.
///
/// # Panics
///
/// Panics if `index >= len()`.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![0, 1, 2, 3];
/// vec.remove(0);
///
/// assert_eq!(vec, [1, 2, 3]);
/// ```
///
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);
}
unsafe {
let p = self.as_mut_ptr().add(index);
let x = core::ptr::read(p);
let src = p.add(1);
let dst = p;
let count = len - index - 1;
core::ptr::copy(src, dst, count);
self.set_len(len - 1);
x
}
}
/// `remove_item` removes the first element identical to the supplied `item` using a
/// left-to-right traversal of the elements.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![0, 1, 1, 1, 2, 3, 4];
/// vec.remove_item(&1);
///
/// assert_eq!(vec, [0, 1, 1, 2, 3, 4]);
/// ```
///
pub fn remove_item<V>(&mut self, item: &V) -> Option<T>
where
T: PartialEq<V>,
{
let len = self.len();
for i in 0..len {
if self[i] == *item {
return Some(self.remove(i));
}
}
None
}
/// `reserve` ensures there is sufficient capacity for `additional` extra elements to be either
/// inserted or appended to the end of the vector. Will reallocate if needed otherwise this
/// function is a no-op.
///
/// Guarantees that the new capacity is greater than or equal to `len() + additional`.
///
/// # Example
///
/// ```
/// let mut vec = minivec::MiniVec::<i32>::new();
///
/// assert_eq!(vec.capacity(), 0);
///
/// vec.reserve(128);
///
/// assert!(vec.capacity() >= 128);
/// ```
///
pub fn reserve(&mut self, additional: usize) {
let capacity = self.capacity();
let total_required = self.len() + additional;
if total_required <= capacity {
return;
}
let mut new_capacity = next_capacity::<T>(capacity);
while new_capacity < total_required {
new_capacity = next_capacity::<T>(new_capacity);
}
self.grow(new_capacity, self.alignment());
}
/// `reserve_exact` ensures that the capacity of the vector is exactly equal to
/// `len() + additional` unless the capacity is already sufficient in which case no operation is
/// performed.
///
/// # Example
///
/// ```
/// let mut vec = minivec::MiniVec::<i32>::new();
/// vec.reserve_exact(57);
///
/// assert_eq!(vec.capacity(), 57);
/// ```
///
pub fn reserve_exact(&mut self, additional: usize) {
let capacity = self.capacity();
let len = self.len();
let total_required = len + additional;
if capacity >= total_required {
return;
}
self.grow(total_required, self.alignment());
}
/// `resize` will clone the supplied `value` as many times as required until `len()` becomes
/// `new_len`. If the current [`len()`](MiniVec::len) is greater than `new_len` then the vector
/// is truncated in a way that's identical to calling `vec.truncate(new_len)`. If the `len()`
/// and `new_len` match then no operation is performed.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![-1; 256];
///
/// vec.resize(512, -1);
/// assert_eq!(vec.len(), 512);
///
/// vec.resize(64, -1);
/// assert_eq!(vec.len(), 64);
/// ```
///
pub fn resize(&mut self, new_len: usize, value: T)
where
T: Clone,
{
let len = self.len();
match new_len.cmp(&len) {
core::cmp::Ordering::Equal => {}
core::cmp::Ordering::Greater => {
let num_elems = new_len - len;
self.reserve(num_elems);
for _i in 0..num_elems {
self.push(value.clone());
}
}
core::cmp::Ordering::Less => {
self.truncate(new_len);
}
}
}
/// `resize_with` will invoke the supplied callable `f` as many times as is required until
/// `len() == new_len` is true. If the `new_len` exceeds the current [`len()`](MiniVec::len)
/// then the vector will be resized via a call to `truncate(new_len)`. If the `new_len` and
/// `len()` are equal then no operation is performed.
///
/// # Example
///
/// ```
/// let mut vec = minivec::MiniVec::<i32>::new();
///
/// vec.resize_with(128, || 1337);
/// assert_eq!(vec.len(), 128);
/// ```
///
pub fn resize_with<F>(&mut self, new_len: usize, mut f: F)
where
F: FnMut() -> T,
{
use core::cmp::Ordering::{Equal, Greater, Less};
let len = self.len();
match new_len.cmp(&len) {
Equal => {}
Greater => {
let num_elems = new_len - len;
self.reserve(num_elems);
for _i in 0..num_elems {
self.push(f());
}
}
Less => {
self.truncate(new_len);
}
}
}
/// `retain` removes all elements from the vector for with `f(elem)` is `false` using a
/// left-to-right traversal.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3, 4, 5, 6];
///
/// let is_even = |x: &i32| *x % 2 == 0;
/// vec.retain(is_even);
/// assert_eq!(vec, [2, 4, 6]);
/// ```
///
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&T) -> bool,
{
let len = self.len();
let data = self.as_mut_ptr();
let mut read = data;
let mut write = read;
let last = unsafe { data.add(len) };
while read < last {
let should_retain = unsafe { f(&mut *read) };
if should_retain {
if read != write {
unsafe {
core::mem::swap(&mut *read, &mut *write);
}
}
write = unsafe { write.add(1) };
}
read = unsafe { read.add(1) };
}
self.truncate((write as usize - data as usize) / core::mem::size_of::<T>());
}
/// `set_len` reassigns the internal `len_` data member to the user-supplied `len`.
///
/// # Safety
///
/// This function is unsafe in the sense that it will NOT call `.drop()` on the elements
/// excluded from the new len so this function should only be called when `T` is a `Copy` type.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3, 4];
/// unsafe { vec.set_len(2) };
///
/// assert_eq!(vec.len(), 2);
/// ```
///
pub unsafe fn set_len(&mut self, len: usize) {
self.header_mut().len = len;
}
/// `shrink_to` will attempt to adjust the backing allocation such that it has space for at
/// least `min_capacity` elements.
///
/// If the `min_capacity` is smaller than the current length of the vector then the capacity
/// will be shrunk down to [`len()`](MiniVec::len).
///
/// If the [`capacity()`](MiniVec::capacity) is identical to `min_capacity` then this function
/// does nothing.
///
/// # Panics
///
/// If the `min_capacity` is larger than the current capacity this function will panic.
///
/// Otherwise, the allocation is reallocated with the new `min_capacity` kept in mind.
///
/// # Example
///
/// ```
/// let mut vec = minivec::MiniVec::<i32>::with_capacity(128);
/// assert!(vec.capacity() >= 128);
///
/// vec.shrink_to(64);
/// assert_eq!(vec.capacity(), 64);
/// ```
///
pub fn shrink_to(&mut self, min_capacity: usize) {
let (len, capacity) = (self.len(), self.capacity());
if min_capacity < len {
self.shrink_to_fit();
return;
}
if capacity == min_capacity {
return;
}
if capacity < min_capacity {
panic!("Tried to shrink to a larger capacity");
}
self.grow(min_capacity, self.alignment());
}
/// `shrink_to_fit` will re-adjust the backing allocation such that its capacity is now equal
/// to its length
///
/// # Example
///
/// ```
/// let mut vec = minivec::MiniVec::with_capacity(512);
///
/// vec.push(1);
/// vec.push(2);
/// vec.push(3);
///
/// vec.shrink_to_fit();
///
/// assert_eq!(vec.capacity(), 3);
/// ```
///
pub fn shrink_to_fit(&mut self) {
let len = self.len();
if len == self.capacity() {
return;
}
let capacity = len;
self.grow(capacity, self.alignment());
}
/// `spare_capacity_mut` returns a mutable slice to [`MaybeUninit<T>`](core::mem::MaybeUninit).
/// This is a more structured way of interacting with `MiniVec` as an unitialized allocation vs
/// simply creating a vector with capacity and then mutating its contents directly via
/// [`as_mut_ptr`](MiniVec::as_mut_ptr).
///
/// Once manipulation of the unitialized elements has been completed, a call to [`set_len`](MiniVec::set_len)
/// is required otherwise the contained elements cannot be accessed by `MiniVec`'s normal
/// methods nor will the elements be dropped.
///
/// # Example
///
/// ```
/// let mut vec = minivec::MiniVec::<i32>::with_capacity(24);
/// let mut buf = vec.spare_capacity_mut();
///
/// for idx in 0..4 {
/// unsafe { buf[idx].as_mut_ptr().write(idx as i32) };
/// }
///
/// unsafe { vec.set_len(4) };
///
/// assert_eq!(vec, [0, 1, 2, 3]);
/// ```
///
pub fn spare_capacity_mut(&mut self) -> &mut [core::mem::MaybeUninit<T>] {
let capacity = self.capacity();
if capacity == 0 {
return &mut [];
}
let len = self.len();
let data = unsafe { self.data().add(len).cast::<core::mem::MaybeUninit<T>>() };
let spare_len = capacity - len;
unsafe { core::slice::from_raw_parts_mut(data, spare_len) }
}
/// `splice` returns a [`Splice`](Splice) iterator. `Splice` is similar in spirit to [`Drain`](Drain)
/// but instead of simply shifting the remaining elements from the vector after it's been
/// drained, the range is replaced with the `Iterator` specified by `replace_with`.
///
/// Much like `Drain`, if the `Splice` iterator is not iterated until exhaustion then the
/// remaining elements will be removed when the iterator is dropped.
///
/// `Splice` only fills the removed region when it is dropped.
///
/// # Panics
///
/// Panics if the supplied `range` is outside of the vector's bounds.
///
/// # Example
///
/// ```
/// let mut x = minivec::mini_vec![1, 2, 3, 4, 5, 6];
/// let new = [7, 8];
///
/// let y: minivec::MiniVec<_> = x.splice(1..4, new.iter().cloned()).collect();
///
/// assert_eq!(x, &[1, 7, 8, 5, 6]);
/// assert_eq!(y, &[2, 3, 4]);
/// ```
///
pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<<I as IntoIterator>::IntoIter>
where
I: IntoIterator<Item = T>,
R: core::ops::RangeBounds<usize>,
{
let len = self.len();
let start_idx = match range.start_bound() {
core::ops::Bound::Included(&n) => n,
core::ops::Bound::Excluded(&n) => {
n.checked_add(1).expect("Start idx exceeded numeric limits")
}
core::ops::Bound::Unbounded => 0,
};
let end_idx = match range.end_bound() {
core::ops::Bound::Included(&n) => n.checked_add(1).expect("End idx exceeded numeric limits"),
core::ops::Bound::Excluded(&n) => n,
core::ops::Bound::Unbounded => len,
};
if start_idx > end_idx {
panic!(
"start splice index (is {}) should be <= end splice index (is {})",
start_idx, end_idx
);
}
if end_idx > len {
panic!(
"end splice index (is {}) should be <= len (is {})",
end_idx, len
);
}
let data = self.as_mut_ptr();
if !data.is_null() {
unsafe {
self.set_len(start_idx);
}
}
make_splice_iterator(
self,
data,
len - end_idx,
start_idx,
end_idx,
replace_with.into_iter(),
)
}
/// `split_at_spare_mut` returns a pair containing two mutable slices: one referring to the currently
/// initialized elements and the other pointing to the spare capacity of the backing allocation as a
/// `&mut [MaybeUninit<T>]`.
///
/// This is a convenience API that handles borrowing issues when attempting to do something like:
/// ```ignore
/// let (init, uninit) = (vec.as_mut_slice(), vec.spare_capacity_mut());
/// ```
///
/// which results in borrowing errors from the compiler:
/// > cannot borrow `vec` as mutable more than once at a time
///
/// # Safety
///
/// When working with uninitialized storage, it is required that the user call `set_len()` appropriately
/// to readjust the length of the vector. This ensures that newly inserted elements are dropped when
/// needed.
///
/// # Example
///
/// ```
/// let mut vec = minivec::MiniVec::<String>::with_capacity(4);
/// vec.push(String::from("hello"));
/// vec.push(String::from("world"));
///
/// let (_, uninit) = vec.split_at_spare_mut();
/// uninit[0] = core::mem::MaybeUninit::<String>::new(String::from("rawr"));
/// uninit[1] = core::mem::MaybeUninit::<String>::new(String::from("RAWR"));
///
/// unsafe { vec.set_len(4) };
///
/// assert_eq!(vec[2], "rawr");
/// assert_eq!(vec[3], "RAWR");
/// ```
///
pub fn split_at_spare_mut(&mut self) -> (&mut [T], &mut [core::mem::MaybeUninit<T>]) {
let capacity = self.capacity();
if capacity == 0 {
return (&mut [], &mut []);
}
let (p, len) = (self.as_mut_ptr(), self.len());
let init = unsafe { core::slice::from_raw_parts_mut(p, len) };
let uninit = unsafe {
core::slice::from_raw_parts_mut(
p.add(len).cast::<core::mem::MaybeUninit<T>>(),
capacity - len,
)
};
(init, uninit)
}
/// `split_off` will segment the vector into two, returning the new segment to the user.
///
/// After this function call, `self` will have kept elements `[0, at)` while the new segment
/// contains elements `[at, len)`.
///
/// # Panics
///
/// Panics if `at` is greater than [`len()`](MiniVec::len).
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
///
/// let tail = vec.split_off(7);
///
/// assert_eq!(vec, [0, 1, 2, 3, 4, 5, 6]);
/// assert_eq!(tail, [7, 8, 9, 10]);
/// ```
///
#[allow(clippy::ptr_as_ptr)]
pub fn split_off(&mut self, at: usize) -> MiniVec<T> {
let len = self.len();
if at > len {
panic!("`at` split index (is {}) should be <= len (is {})", at, len);
}
if len == 0 {
let other = if self.capacity() > 0 {
MiniVec::with_capacity(self.capacity())
} else {
MiniVec::new()
};
return other;
}
if at == 0 {
let orig_cap = self.capacity();
let other = MiniVec {
buf: self.buf,
phantom: core::marker::PhantomData,
};
self.buf =
unsafe { core::ptr::NonNull::<u8>::new_unchecked(&DEFAULT_U8 as *const u8 as *mut u8) };
self.reserve_exact(orig_cap);
return other;
}
let mut other = MiniVec::with_capacity(self.capacity());
unsafe {
self.set_len(at);
other.set_len(len - at);
}
let src = unsafe { self.as_ptr().add(at) };
let dst = other.as_mut_ptr();
let count = len - at;
unsafe {
core::ptr::copy_nonoverlapping(src, dst, count);
}
other
}
/// `swap_remove` removes the element located at `index` and replaces it with the last value
/// in the vector, returning the removed element to the caller.
///
/// # Panics
///
/// Panics if `index >= len()`.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3, 4];
///
/// let num = vec.swap_remove(0);
/// assert_eq!(num, 1);
/// assert_eq!(vec, [4, 2, 3]);
/// ```
///
pub fn swap_remove(&mut self, index: usize) -> T {
let len = self.len();
if index >= len {
panic!(
"swap_remove index (is {}) should be < len (is {})",
index, len
);
}
let src = unsafe { core::ptr::read(self.as_ptr().add(len - 1)) };
self.header_mut().len -= 1;
let dst = unsafe { self.as_mut_ptr().add(index) };
unsafe { core::ptr::replace(dst, src) }
}
/// `truncate` adjusts the length of the vector to be `len`. If `len` is greater than or equal
/// to the current length no operation is performed. Otherwise, the vector's length is
/// readjusted to `len` and any remaining elements to the right of `len` are dropped.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3, 4, 5];
/// vec.truncate(2);
///
/// assert_eq!(vec, [1, 2]);
/// ```
///
pub fn truncate(&mut self, len: usize) {
let self_len = self.len();
if len >= self_len {
return;
}
self.header_mut().len = len;
if !core::mem::needs_drop::<T>() {
return;
}
let s = unsafe { core::slice::from_raw_parts_mut(self.data().add(len), self_len - len) };
unsafe {
core::ptr::drop_in_place(s);
}
}
/// `with_alignment` is similar to its counterpart [`with_capacity`](MiniVec::with_capacity)
/// except it takes an additional argument: the alignment to use for the allocation.
///
/// The supplied alignment must be a number divisible by 2 and larger than or equal to the
/// result of `core::mem::align_of::<*const ()>()`.
///
/// The internal allocation used to store the header information for `MiniVec` is aligned to the
/// supplied value and then sufficient padding is inserted such that the result of [`as_ptr()`](MiniVec::as_ptr)
/// will always be aligned as well.
///
/// This is useful for creating over-aligned allocations for primitive types such as when using
/// `SIMD` intrinsics. For example, some vectorized floating point loads and stores _must_ be
/// aligned on a 32 byte boundary. `with_alignment` is intended to make this possible with a
/// `Vec`-like container.
///
/// # Errors
///
/// Returns a `Result` that contains either `MiniVec<T>` or a `LayoutErr`.
///
/// # Example
/// ```
/// # #[cfg(not(miri))]
/// # fn main() {
/// #[cfg(target_arch = "x86")]
/// use std::arch::x86::*;
/// #[cfg(target_arch = "x86_64")]
/// use std::arch::x86_64::*;
///
/// let alignment = 32;
/// let num_elems = 2048;
/// let mut v1 = minivec::MiniVec::<f32>::with_alignment(num_elems, alignment).unwrap();
/// let mut v2 = minivec::MiniVec::<f32>::with_alignment(num_elems, alignment).unwrap();
///
/// v1
/// .spare_capacity_mut()
/// .iter_mut()
/// .zip(v2.spare_capacity_mut().iter_mut())
/// .enumerate()
/// .for_each(|(idx, (x1, x2))| {
/// *x1 = core::mem::MaybeUninit::new(idx as f32);
/// *x2 = core::mem::MaybeUninit::new(idx as f32);
/// });
///
/// unsafe {
/// v1.set_len(num_elems);
/// v2.set_len(num_elems);
///
/// // use vectorization to speed up the summation of two vectors
/// //
/// for idx in 0..(num_elems / 8) {
/// let offset = idx * 8;
///
/// let p = v1.as_mut_ptr().add(offset);
/// let q = v2.as_mut_ptr().add(offset);
///
/// let r1 = _mm256_load_ps(p);
/// let r2 = _mm256_load_ps(q);
/// let r3 = _mm256_add_ps(r1, r2);
///
/// _mm256_store_ps(p, r3);
/// }
/// }
///
/// v1
/// .iter()
/// .enumerate()
/// .for_each(|(idx, v)| {
/// assert_eq!(*v, idx as f32 * 2.0);
/// });
/// # }
///
/// # #[cfg(miri)]
/// # fn main() {}
/// ```
///
pub fn with_alignment(capacity: usize, alignment: usize) -> Result<MiniVec<T>, LayoutErr> {
if alignment < max_align::<T>() {
return Err(LayoutErr::AlignmentTooSmall);
}
if alignment % 2 > 0 {
return Err(LayoutErr::AlignmentNotDivisibleByTwo);
}
let mut v = MiniVec::new();
v.grow(capacity, alignment);
Ok(v)
}
/// `with_capacity` is a static factory function that returns a `MiniVec` that contains space
/// for `capacity` elements.
///
/// This function is logically equivalent to calling [`.reserve_exact()`](MiniVec::reserve_exact)
/// on a vector with `0` capacity.
///
/// # Example
///
/// ```
/// let mut vec = minivec::MiniVec::<i32>::with_capacity(128);
///
/// assert_eq!(vec.len(), 0);
/// assert_eq!(vec.capacity(), 128);
/// ```
///
#[must_use]
pub fn with_capacity(capacity: usize) -> MiniVec<T> {
let mut v = MiniVec::new();
v.reserve_exact(capacity);
v
}
#[doc(hidden)]
pub unsafe fn unsafe_write(&mut self, idx: usize, elem: T) {
self.data().add(idx).write(elem);
}
}
impl<T: Clone> MiniVec<T> {
/// `extend_from_slice` will append each element from `elems` in a left-to-right order, cloning
/// each value in `elems`.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![1, 2];
///
/// let s : &[i32] = &[3, 4];
///
/// vec.extend_from_slice(s);
///
/// assert_eq!(vec, [1, 2, 3, 4]);
/// ```
///
pub fn extend_from_slice(&mut self, elems: &[T]) {
self.reserve(elems.len());
for x in elems {
self.push((*x).clone());
}
}
/// `extend_from_within` clones the elements contained in the provided `Range` and appends them
/// to the end of the vector, allocating extra space as required.
///
/// # Panics
///
/// Panics if the provided range exceeds the bounds of `[0, len)`.
///
/// # Example
///
/// ```
/// let mut vec = minivec::mini_vec![1, 2, 3, 4, 5];
/// vec.extend_from_within(1..4);
///
/// assert_eq!(vec, [1, 2, 3, 4, 5, 2, 3, 4]);
/// ```
///
pub fn extend_from_within<Range>(&mut self, range: Range)
where
Range: core::ops::RangeBounds<usize>,
{
struct PanicGuard<'a, T>
where
T: Clone,
{
count: usize,
start_idx: usize,
end_idx: usize,
vec: &'a mut MiniVec<T>,
}
impl<'a, T> Drop for PanicGuard<'a, T>
where
T: Clone,
{
fn drop(&mut self) {
unsafe {
self.vec.set_len(self.vec.len() + self.count);
}
}
}
impl<'a, 'b, T> PanicGuard<'a, T>
where
T: Clone,
{
fn extend(&mut self) {
let count = &mut self.count;
let (init, uninit) = self.vec.split_at_spare_mut();
init[self.start_idx..self.end_idx]
.iter()
.cloned()
.zip(uninit.iter_mut())
.for_each(|(val, p)| {
*p = core::mem::MaybeUninit::new(val);
*count += 1;
});
}
}
let len = self.len();
let start_idx = match range.start_bound() {
core::ops::Bound::Included(&n) => n,
core::ops::Bound::Excluded(&n) => {
n.checked_add(1).expect("Start idx exceeded numeric limits")
}
core::ops::Bound::Unbounded => 0,
};
let end_idx = match range.end_bound() {
core::ops::Bound::Included(&n) => n.checked_add(1).expect("End idx exceeded numeric limits"),
core::ops::Bound::Excluded(&n) => n,
core::ops::Bound::Unbounded => len,
};
if start_idx > end_idx {
panic!(
"start extend_from_within index (is {}) should be <= end (is {})",
start_idx, end_idx
);
}
if end_idx > len {
panic!(
"end extend_from_within index (is {}) should be <= len (is {})",
end_idx, len
);
}
if len == 0 {
return;
}
self.reserve(end_idx - start_idx);
let mut guard = PanicGuard {
count: 0,
start_idx,
end_idx,
vec: self,
};
guard.extend();
}
}
impl<T> MiniVec<core::mem::MaybeUninit<T>> {
/// `assume_minivec_init` is a helper designed to make working with uninitialized memory more ergonomic.
///
/// # Safety
/// Whatever length the current `MiniVec` has, it is consumed and then returned to the caller as a `MiniVec<T>` thus
/// making the function `unsafe` as it relies on the caller to uphold length invariants.
///
/// # Example
///
/// ```
/// let mut buf = minivec::mini_vec![core::mem::MaybeUninit::<u8>::uninit(); 512];
/// buf
/// .iter_mut()
/// .for_each(|v| *v = core::mem::MaybeUninit::new(137));
///
/// unsafe { buf.set_len(512) };
///
/// let bytes = unsafe { buf.assume_minivec_init() };
/// assert_eq!(bytes[0], 137);
/// assert_eq!(bytes[511], 137);
/// ```
///
#[must_use]
pub unsafe fn assume_minivec_init(self) -> MiniVec<T> {
let (ptr, len, cap) = self.into_raw_parts();
MiniVec::<T>::from_raw_parts(ptr.cast::<T>(), len, cap)
}
}
unsafe impl<T: core::marker::Send> core::marker::Send for MiniVec<T> {}
unsafe impl<T: core::marker::Sync> core::marker::Sync for MiniVec<T> {}
/// `mini_vec!` is a macro similar in spirit to the stdlib's `vec!`.
///
/// It supports the creation of `MiniVec` with:
/// * `mini_vec!()`
/// * `mini_vec![val1, val2, val3, ...]`
/// * `mini_vec![val; num_elems]`
///
#[macro_export]
macro_rules! mini_vec {
() => (
$crate::MiniVec::new()
);
($elem:expr; $n:expr) => {
{
let len = $n;
let mut tmp = $crate::MiniVec::with_capacity(len);
for idx in 0..len {
unsafe { tmp.unsafe_write(idx, $elem.clone()) };
}
if len > 0 {
unsafe { tmp.set_len(len) };
}
tmp
}
};
($($x:expr),+ $(,)?) => {
{
let mut tmp = $crate::MiniVec::new();
$(
tmp.push($x);
)*
tmp
}
};
}