use alloc::vec::Vec;
use core::hash::{Hash, Hasher};
#[derive(Clone)]
pub(crate) struct SmallVec<T, const N: usize>(Storage<T, N>);
impl<T, const N: usize> SmallVec<T, N>
where
T: Copy + Default,
{
pub fn new() -> Self {
Self(Storage::Inline([T::default(); N], 0))
}
pub fn with_len(len: usize, value: T) -> Self {
if len <= N {
Self(Storage::Inline([value; N], len))
} else {
let mut vec = Vec::new();
vec.resize(len, value);
Self(Storage::Heap(vec))
}
}
pub fn clear(&mut self) {
match &mut self.0 {
Storage::Inline(_buf, len) => *len = 0,
Storage::Heap(vec) => vec.clear(),
}
}
pub fn try_reserve(&mut self, additional: usize) -> bool {
match &mut self.0 {
Storage::Inline(buf, len) => {
let new_cap = *len + additional;
if new_cap > N {
let mut vec = Vec::new();
if vec.try_reserve(new_cap).is_err() {
return false;
}
vec.extend_from_slice(&buf[..*len]);
self.0 = Storage::Heap(vec);
}
}
Storage::Heap(vec) => {
if vec.try_reserve(additional).is_err() {
return false;
}
}
}
true
}
pub fn push(&mut self, value: T) {
match &mut self.0 {
Storage::Inline(buf, len) => {
if *len + 1 > N {
let mut vec = Vec::with_capacity(*len + 1);
vec.extend_from_slice(&buf[..*len]);
vec.push(value);
self.0 = Storage::Heap(vec);
} else {
buf[*len] = value;
*len += 1;
}
}
Storage::Heap(vec) => vec.push(value),
}
}
pub fn pop(&mut self) -> Option<T> {
match &mut self.0 {
Storage::Inline(buf, len) => {
if *len > 0 {
*len -= 1;
Some(buf[*len])
} else {
None
}
}
Storage::Heap(vec) => vec.pop(),
}
}
pub fn truncate(&mut self, len: usize) {
match &mut self.0 {
Storage::Inline(_buf, inline_len) => {
*inline_len = len.min(*inline_len);
}
Storage::Heap(vec) => vec.truncate(len),
}
}
}
impl<T, const N: usize> SmallVec<T, N> {
pub fn as_slice(&self) -> &[T] {
match &self.0 {
Storage::Inline(buf, len) => &buf[..*len],
Storage::Heap(vec) => vec.as_slice(),
}
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
match &mut self.0 {
Storage::Inline(buf, len) => &mut buf[..*len],
Storage::Heap(vec) => vec.as_mut_slice(),
}
}
}
impl<T, const N: usize> Default for SmallVec<T, N>
where
T: Copy + Default,
{
fn default() -> Self {
Self::new()
}
}
impl<T, const N: usize> core::ops::Deref for SmallVec<T, N> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<T, const N: usize> core::ops::DerefMut for SmallVec<T, N> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
impl<T, const N: usize> Hash for SmallVec<T, N>
where
T: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_slice().hash(state);
}
}
impl<T, const N: usize> PartialEq for SmallVec<T, N>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<T, const N: usize> PartialEq<[T]> for SmallVec<T, N>
where
T: PartialEq,
{
fn eq(&self, other: &[T]) -> bool {
self.as_slice() == other
}
}
impl<T, const N: usize> Eq for SmallVec<T, N> where T: Eq {}
impl<T, const N: usize> core::fmt::Debug for SmallVec<T, N>
where
T: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_list().entries(self.as_slice().iter()).finish()
}
}
impl<'a, T, const N: usize> IntoIterator for &'a SmallVec<T, N> {
type IntoIter = core::slice::Iter<'a, T>;
type Item = &'a T;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'a, T, const N: usize> IntoIterator for &'a mut SmallVec<T, N> {
type IntoIter = core::slice::IterMut<'a, T>;
type Item = &'a mut T;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
impl<T, const N: usize> IntoIterator for SmallVec<T, N>
where
T: Copy,
{
type IntoIter = IntoIter<T, N>;
type Item = T;
fn into_iter(self) -> Self::IntoIter {
IntoIter { vec: self, pos: 0 }
}
}
#[derive(Clone)]
pub(crate) struct IntoIter<T, const N: usize> {
vec: SmallVec<T, N>,
pos: usize,
}
impl<T, const N: usize> Iterator for IntoIter<T, N>
where
T: Copy,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let value = self.vec.get(self.pos)?;
self.pos += 1;
Some(*value)
}
}
#[derive(Clone)]
enum Storage<T, const N: usize> {
Inline([T; N], usize),
Heap(Vec<T>),
}
#[cfg(test)]
mod test {
use super::{SmallVec, Storage};
#[test]
fn choose_inline() {
let vec = SmallVec::<_, 4>::with_len(4, 0);
assert!(matches!(vec.0, Storage::Inline(..)));
assert_eq!(vec.len(), 4);
}
#[test]
fn choose_heap() {
let vec = SmallVec::<_, 4>::with_len(5, 0);
assert!(matches!(vec.0, Storage::Heap(..)));
assert_eq!(vec.len(), 5);
}
#[test]
fn store_and_read_inline() {
let mut vec = SmallVec::<_, 8>::with_len(8, 0);
for (i, value) in vec.iter_mut().enumerate() {
*value = i * 2;
}
let expected = [0, 2, 4, 6, 8, 10, 12, 14];
assert_eq!(vec.as_slice(), &expected);
assert_eq!(format!("{vec:?}"), format!("{expected:?}"));
}
#[test]
fn store_and_read_heap() {
let mut vec = SmallVec::<_, 4>::with_len(8, 0);
for (i, value) in vec.iter_mut().enumerate() {
*value = i * 2;
}
let expected = [0, 2, 4, 6, 8, 10, 12, 14];
assert_eq!(vec.as_slice(), &expected);
assert_eq!(format!("{vec:?}"), format!("{expected:?}"));
}
#[test]
fn spill_to_heap() {
let mut vec = SmallVec::<_, 4>::new();
for i in 0..4 {
vec.push(i);
}
assert!(matches!(vec.0, Storage::Inline(..)));
vec.push(4);
assert!(matches!(vec.0, Storage::Heap(..)));
let expected = [0, 1, 2, 3, 4];
assert_eq!(vec.as_slice(), &expected);
}
#[test]
fn clear_inline() {
let mut vec = SmallVec::<_, 4>::new();
for i in 0..4 {
vec.push(i);
}
assert!(matches!(vec.0, Storage::Inline(..)));
assert_eq!(vec.len(), 4);
vec.clear();
assert_eq!(vec.len(), 0);
}
#[test]
fn clear_heap() {
let mut vec = SmallVec::<_, 3>::new();
for i in 0..4 {
vec.push(i);
}
assert!(matches!(vec.0, Storage::Heap(..)));
assert_eq!(vec.len(), 4);
vec.clear();
assert_eq!(vec.len(), 0);
}
#[test]
fn reserve() {
let mut vec = SmallVec::<_, 3>::new();
for i in 0..2 {
vec.push(i);
}
assert!(matches!(vec.0, Storage::Inline(..)));
assert!(vec.try_reserve(1));
assert!(matches!(vec.0, Storage::Inline(..)));
assert!(vec.try_reserve(2));
assert!(matches!(vec.0, Storage::Heap(..)));
}
#[test]
fn iter() {
let mut vec = SmallVec::<_, 3>::new();
for i in 0..3 {
vec.push(i);
}
assert!(&[0, 1, 2].iter().eq(vec.iter()));
}
#[test]
fn into_iter() {
let mut vec = SmallVec::<_, 3>::new();
for i in 0..3 {
vec.push(i);
}
assert!([0, 1, 2].into_iter().eq(vec.into_iter()));
}
}