use crate::data_structures::id_pool::IdPool;
#[derive(Clone, Debug)]
pub struct StableVec<T> {
data: Vec<Option<T>>,
indices: IdPool,
}
impl<T> StableVec<T> {
#[inline(always)]
pub const fn new() -> Self {
Self {
data: Vec::new(),
indices: IdPool::new(),
}
}
#[inline(always)]
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: Vec::with_capacity(capacity),
indices: IdPool::with_capacity(capacity),
}
}
#[inline(always)]
pub fn push(&mut self, element: T) -> usize {
let index = self.indices.alloc() as usize;
if index >= self.data.len() {
self.data.push(Some(element));
} else {
self.data[index] = Some(element);
}
index
}
#[inline(always)]
pub fn next_push_index(&self) -> usize {
self.indices.next_id() as usize
}
#[inline(always)]
pub fn remove(&mut self, index: usize) -> T {
self.try_remove(index).unwrap_or_else(|| {
panic!("no element at index {} in StableVec::remove", index);
})
}
#[inline(always)]
pub fn try_remove(&mut self, index: usize) -> Option<T> {
if index >= self.data.len() {
return None;
}
let element = self.data[index].take();
if element.is_some() {
self.indices.free(index as u32);
}
element
}
#[inline(always)]
pub fn clear(&mut self) {
self.data.clear();
self.indices.clear();
}
#[inline(always)]
pub fn get(&self, index: usize) -> Option<&T> {
self.data.get(index)?.as_ref()
}
#[inline(always)]
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
self.data.get_mut(index)?.as_mut()
}
#[inline(always)]
pub unsafe fn get_unchecked(&self, index: usize) -> &T {
unsafe { self.data.get_unchecked(index).as_ref().unwrap_unchecked() }
}
#[inline(always)]
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
unsafe {
self.data
.get_unchecked_mut(index)
.as_mut()
.unwrap_unchecked()
}
}
#[inline(always)]
pub fn get_disjoint_mut2(&mut self, index1: usize, index2: usize) -> Option<[&mut T; 2]> {
let [first, second] = self.data.get_disjoint_mut([index1, index2]).ok()?;
Some([first.as_mut()?, second.as_mut()?])
}
#[inline(always)]
pub unsafe fn get_disjoint_mut_unchecked(
&mut self,
index1: usize,
index2: usize,
) -> [&mut T; 2] {
unsafe {
let [first, second] = self.data.get_disjoint_unchecked_mut([index1, index2]);
[
first.as_mut().unwrap_unchecked(),
second.as_mut().unwrap_unchecked(),
]
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.indices.len()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline(always)]
pub fn capacity(&self) -> usize {
self.data.capacity()
}
#[inline(always)]
pub fn iter(&self) -> impl Iterator<Item = (usize, &T)> {
self.data
.iter()
.enumerate()
.filter_map(|(i, opt)| opt.as_ref().map(|v| (i, v)))
}
#[inline(always)]
pub fn iter_mut(&mut self) -> impl Iterator<Item = (usize, &mut T)> {
self.data
.iter_mut()
.enumerate()
.filter_map(|(i, opt)| opt.as_mut().map(|v| (i, v)))
}
}
impl<T> Default for StableVec<T> {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl<T> core::ops::Index<usize> for StableVec<T> {
type Output = T;
#[inline(always)]
fn index(&self, index: usize) -> &Self::Output {
self.get(index).unwrap_or_else(|| {
panic!("no element at index {} in StableVec::index", index);
})
}
}
impl<T> core::ops::IndexMut<usize> for StableVec<T> {
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_mut(index).unwrap_or_else(|| {
panic!("no element at index {} in StableVec::index_mut", index);
})
}
}
impl<T> IntoIterator for StableVec<T> {
type Item = T;
type IntoIter = StableVecIntoIterator<T>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
StableVecIntoIterator {
inner: self.data.into_iter(),
}
}
}
pub struct StableVecIntoIterator<T> {
inner: alloc::vec::IntoIter<Option<T>>,
}
impl<T> Iterator for StableVecIntoIterator<T> {
type Item = T;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.inner.by_ref().flatten().next()
}
}
impl<T> DoubleEndedIterator for StableVecIntoIterator<T> {
#[inline(always)]
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.by_ref().flatten().next_back()
}
}
impl<T> core::iter::FusedIterator for StableVecIntoIterator<T> {}
#[cfg(test)]
mod tests {
use super::StableVec;
#[test]
fn test_stable_vec_push_remove() {
let mut sv = StableVec::new();
let idx1 = sv.push(10);
let idx2 = sv.push(20);
assert_eq!(sv.len(), 2);
assert_eq!(sv[idx1], 10);
assert_eq!(sv[idx2], 20);
let val = sv.remove(idx1);
assert_eq!(val, 10);
assert_eq!(sv.len(), 1);
assert!(sv.get(idx1).is_none());
let idx3 = sv.push(30);
assert_eq!(idx3, idx1); assert_eq!(sv[idx3], 30);
}
#[test]
fn test_stable_vec_clear() {
let mut sv = StableVec::new();
sv.push(1);
sv.push(2);
sv.clear();
assert_eq!(sv.len(), 0);
}
#[test]
fn test_stable_vec_iter() {
let mut sv = StableVec::new();
sv.push(1);
sv.push(2);
sv.push(3);
let collected: Vec<_> = sv.into_iter().collect();
assert_eq!(collected, vec![1, 2, 3]);
}
}