use std::fmt;
use std::mem::MaybeUninit;
pub struct SmallVector<T, const N: usize> {
inline: [MaybeUninit<T>; N],
heap: Vec<T>,
len: usize,
}
impl<T, const N: usize> SmallVector<T, N> {
pub fn new() -> Self {
Self {
inline: unsafe { MaybeUninit::uninit().assume_init() },
heap: Vec::new(),
len: 0,
}
}
pub fn from_elem(elem: T) -> Self {
let mut sv = Self::new();
sv.push(elem);
sv
}
#[inline]
pub fn size(&self) -> usize {
self.len
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn is_inline(&self) -> bool {
self.len <= N
}
#[inline]
pub fn get(&self, index: usize) -> Option<&T> {
if index >= self.len {
return None;
}
if index < N {
Some(unsafe { self.inline[index].assume_init_ref() })
} else {
self.heap.get(index - N)
}
}
#[inline]
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
if index >= self.len {
return None;
}
if index < N {
Some(unsafe { self.inline[index].assume_init_mut() })
} else {
self.heap.get_mut(index - N)
}
}
#[inline]
pub fn front(&self) -> Option<&T> {
self.get(0)
}
#[inline]
pub fn back(&self) -> Option<&T> {
if self.len == 0 {
None
} else {
self.get(self.len - 1)
}
}
pub fn push(&mut self, elem: T) {
if self.len < N {
self.inline[self.len] = MaybeUninit::new(elem);
self.len += 1;
} else {
self.heap.push(elem);
self.len += 1;
}
}
pub fn pop(&mut self) -> Option<T> {
if self.len == 0 {
return None;
}
self.len -= 1;
if self.len < N {
let slot = std::mem::replace(&mut self.inline[self.len], MaybeUninit::uninit());
Some(unsafe { slot.assume_init() })
} else {
self.heap.pop()
}
}
pub fn clear(&mut self) {
for i in 0..(self.len.min(N)) {
unsafe { self.inline[i].assume_init_drop() };
}
self.heap.clear();
self.len = 0;
}
pub fn reserve(&mut self, additional: usize) {
let needed = self.len + additional;
if needed > N {
let heap_needed = needed - N;
self.heap.reserve(heap_needed);
}
}
pub fn iter(&self) -> SmallVectorIter<'_, T, N> {
SmallVectorIter { sv: self, idx: 0 }
}
pub fn iter_mut(&mut self) -> SmallVectorIterMut<'_, T, N> {
SmallVectorIterMut { sv: self, idx: 0 }
}
pub fn as_slice(&self) -> Option<&[T]> {
if self.len <= N {
let ptr = self.inline.as_ptr() as *const T;
Some(unsafe { std::slice::from_raw_parts(ptr, self.len) })
} else if self.len > N && N == 0 {
Some(self.heap.as_slice())
} else {
None
}
}
}
pub struct SmallVectorIter<'a, T, const N: usize> {
sv: &'a SmallVector<T, N>,
idx: usize,
}
impl<'a, T, const N: usize> Iterator for SmallVectorIter<'a, T, N> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
let item = self.sv.get(self.idx);
if item.is_some() {
self.idx += 1;
}
item
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.sv.len() - self.idx;
(remaining, Some(remaining))
}
}
pub struct SmallVectorIterMut<'a, T, const N: usize> {
sv: &'a mut SmallVector<T, N>,
idx: usize,
}
impl<'a, T, const N: usize> Iterator for SmallVectorIterMut<'a, T, N> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
if self.idx >= self.sv.len() {
return None;
}
let idx = self.idx;
self.idx += 1;
unsafe {
let ptr: *mut SmallVector<T, N> = self.sv;
Some((*ptr).get_mut(idx).unwrap())
}
}
}
impl<T: Clone, const N: usize> Clone for SmallVector<T, N> {
fn clone(&self) -> Self {
let mut out = Self::new();
for elem in self.iter() {
out.push(elem.clone());
}
out
}
}
impl<T: fmt::Debug, const N: usize> fmt::Debug for SmallVector<T, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<T: PartialEq, const N: usize> PartialEq for SmallVector<T, N> {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
for i in 0..self.len() {
if self.get(i) != other.get(i) {
return false;
}
}
true
}
}
impl<T: Eq, const N: usize> Eq for SmallVector<T, N> {}
impl<T, const N: usize> Drop for SmallVector<T, N> {
fn drop(&mut self) {
for i in 0..(self.len.min(N)) {
unsafe { self.inline[i].assume_init_drop() };
}
}
}
impl<T, const N: usize> std::ops::Index<usize> for SmallVector<T, N> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
self.get(index).expect("SmallVector index out of bounds")
}
}
impl<T, const N: usize> std::ops::IndexMut<usize> for SmallVector<T, N> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_mut(index)
.expect("SmallVector index out of bounds")
}
}
impl<T, const N: usize> Default for SmallVector<T, N> {
fn default() -> Self {
Self::new()
}
}