#![doc = include_str!("../doc/lib.md")]
use std::{hint::unreachable_unchecked, ops::{Index, IndexMut}, mem::replace};
#[derive(PartialEq, Debug, Clone)]
enum Slot<T> {
Value(T),
Next(usize),
Empty
}
impl <T>Slot<T> {
#[inline(always)]
const fn from_value(value: T) -> Self {
Self::Value(value)
}
#[inline(always)]
unsafe fn to_some_unchecked(self) -> Option<T> {
match self {
Slot::Value(value) => Some(value),
_ => unsafe { unreachable_unchecked() }
}
}
#[inline(always)]
unsafe fn as_value_unchecked(&self) -> &T {
match self {
Slot::Value(value) => value,
_ => unsafe { unreachable_unchecked() }
}
}
#[inline(always)]
unsafe fn as_value_unchecked_mut(&mut self) -> &mut T {
match self {
Slot::Value(value) => value,
_ => unsafe { unreachable_unchecked() }
}
}
}
#[doc = include_str!("../doc/freelist.md")]
#[derive(Debug, Clone)]
pub struct Freelist<T> {
slots: Vec<Slot<T>>,
next: Slot<T>,
filled_length: usize,
}
impl<T> Freelist<T> {
#[inline]
pub const fn new() -> Self {
Self {
slots: Vec::new(),
next: Slot::Empty,
filled_length: 0
}
}
#[inline]
pub fn push(&mut self, value: T) -> usize {
self.filled_length += 1;
let item = Slot::Value(value);
match self.next {
Slot::Next(index) => unsafe {
self.next = replace(self.slots.get_unchecked_mut(index), item);
index
},
_ => {
self.slots.push(item);
self.filled_length - 1
}
}
}
#[inline]
pub fn next_available(&self) -> usize {
match self.next {
Slot::Next(index) => index,
_ => self.filled_length
}
}
#[inline]
pub fn remove(&mut self, index: usize) -> Option<T> {
match &mut self.slots[index] {
value @ Slot::Value(_) => unsafe {
self.filled_length -= 1;
replace(value, replace(&mut self.next, Slot::Next(index)))
.to_some_unchecked()
},
_ => None
}
}
#[inline]
pub const fn filled(&self) -> usize {
self.filled_length
}
#[inline]
pub fn size(&self) -> usize {
self.slots.len()
}
#[inline]
pub fn free(&self) -> usize {
self.slots.len() - self.filled_length
}
#[inline]
pub fn clear(&mut self) {
self.slots.clear();
self.next = Slot::Empty;
self.filled_length = 0;
}
#[inline]
pub fn reserve(&mut self, n: usize) {
self.slots.reserve_exact(n - self.free());
}
#[inline]
pub fn get(&self, index: usize) -> Option<&T> {
match self.slots[index] {
Slot::Value(ref value) => Some(value),
_ => None,
}
}
#[inline]
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
match self.slots[index] {
Slot::Value(ref mut value) => Some(value),
_ => None,
}
}
#[inline]
pub unsafe fn get_unchecked(&self, index: usize) -> &T {
unsafe { self.slots.get_unchecked(index).as_value_unchecked() }
}
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
unsafe { self.slots.get_unchecked_mut(index).as_value_unchecked_mut() }
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.slots.iter().filter_map(|c| match c {
Slot::Value(value) => Some(value),
_ => None
})
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.slots.iter_mut().filter_map(|c| match c {
Slot::Value(value) => Some(value),
_ => None
})
}
pub fn into_iter(self) -> impl Iterator<Item = T> {
self.slots.into_iter().filter_map(|c| match c {
Slot::Value(value) => Some(value),
_ => None
})
}
}
impl<T> Default for Freelist<T> {
fn default() -> Self {
Self { slots: Vec::new(), next: Slot::Empty, filled_length: 0 }
}
}
impl<T> Index<usize> for Freelist<T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
match &self.slots[index] {
Slot::Value(element) => element,
_ => panic!("attempted to access an empty slot")
}
}
}
impl<T> IndexMut<usize> for Freelist<T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match &mut self.slots[index] {
Slot::Value(element) => element,
_ => panic!("attempted to access an empty slot")
}
}
}
impl<T> From<Vec<T>> for Freelist<T> {
fn from(data: Vec<T>) -> Self {
Self {
filled_length: data.len(),
next: Slot::Empty,
slots: data.into_iter()
.map(Slot::from_value)
.collect(),
}
}
}
impl<T, const N: usize> From<[T; N]> for Freelist<T> {
fn from(data: [T; N]) -> Self {
Self {
filled_length: N,
next: Slot::Empty,
slots: data.into_iter()
.map(Slot::from_value)
.collect(),
}
}
}
impl<T> FromIterator<T> for Freelist<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut len = 0;
let data = iter.into_iter()
.inspect(|_| len += 1)
.map(Slot::from_value)
.collect();
Self {
slots: data,
filled_length: len,
next: Slot::Empty
}
}
}
#[cfg(test)]
mod tests {
use super::{
Slot::*,
Freelist
};
#[test]
fn push() {
let mut list = Freelist::<f32>::new();
list.push(0.0);
list.push(1.0);
list.push(2.0);
assert_eq!(list.slots, vec![Value(0.0), Value(1.0), Value(2.0)]);
println!("{:?}", list.slots);
}
#[test]
fn remove() {
let mut list = Freelist::<f32> {
slots: vec![Value(0.0), Value(1.0), Value(2.0)],
next: Empty,
filled_length: 3,
};
let removed = list.remove(1);
assert_eq!(removed, Some(1.0));
assert_eq!(list.next, Next(1));
assert_eq!(list.slots, vec![Value(0.0), Empty, Value(2.0)]);
}
#[test]
fn remove_then_push() {
let mut list = Freelist::<f32> {
slots: vec![Value(0.0), Value(1.0), Value(2.0)],
next: Empty,
filled_length: 3,
};
list.remove(1);
list.push(3.0);
assert_eq!(list.next, Empty);
assert_eq!(list.slots, vec![Value(0.0), Value(3.0), Value(2.0)]);
}
#[test]
fn remove_then_push_multiple() {
let mut list = Freelist::<f32> {
slots: vec![Value(0.0), Value(1.0), Value(2.0)],
next: Empty,
filled_length: 3,
};
list.remove(1);
list.remove(2);
list.push(3.0);
list.push(4.0);
list.push(5.0);
assert_eq!(list.next, Empty);
assert_eq!(list.slots, vec![Value(0.0), Value(4.0), Value(3.0), Value(5.0)]);
}
#[test]
fn clear() {
let mut list = Freelist::<f32> {
slots: vec![Value(0.0), Value(1.0), Value(2.0)],
next: Empty,
filled_length: 3,
};
list.clear();
assert_eq!(list.next, Empty);
assert_eq!(list.slots, vec![]);
}
}