use std::fmt::Debug;
#[derive(Default, Clone)]
pub struct ReuseList<T> {
items: Vec<Option<T>>,
slots: Vec<usize>,
last_slot_idx: usize,
len: usize,
slot_size: usize,
}
impl<T: Debug> Debug for ReuseList<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ReuseList")
.field("items", &self.items)
.field("slots", &self.slots)
.finish()
}
}
impl<T> ReuseList<T> {
pub fn new() -> Self {
Self::with_capacity(0)
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
items: Vec::with_capacity(capacity),
slots: Vec::with_capacity(capacity >> 2),
last_slot_idx: 0,
len: 0,
slot_size: 0,
}
}
pub fn append(&mut self, item: T) -> usize {
if self.slot_size > 0 {
let slot = self.slots[self.last_slot_idx - 1];
if slot > 0 {
self.items[slot - 1] = Some(item);
self.slots[self.last_slot_idx - 1] = 0;
if self.last_slot_idx > 1 {
self.last_slot_idx -= 1;
}
self.len += 1;
return slot - 1;
}
}
self.items.push(Some(item));
self.len += 1;
self.items.len() - 1
}
pub fn remove(&mut self, index: usize) -> Option<T> {
if index >= self.items.len() {
return None;
}
let item = self.items[index].take();
if item.is_some() {
if self.slot_size > 0 && self.slots[self.last_slot_idx - 1] == 0 {
self.slots[self.last_slot_idx - 1] = index + 1;
} else {
self.slots.push(index + 1);
self.last_slot_idx += 1;
self.slot_size += 1;
}
self.len -= 1;
}
item
}
pub fn get(&self, index: usize) -> Option<&T> {
if index >= self.items.len() {
None
} else {
self.items[index].as_ref()
}
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
if index >= self.items.len() {
None
} else {
self.items[index].as_mut()
}
}
pub fn capacity(&self) -> usize {
self.items.capacity()
}
pub fn len(&self) -> usize {
self.len
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.items.iter().filter_map(|x| x.as_ref())
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.items.iter_mut().filter_map(|x| x.as_mut())
}
pub fn clear(&mut self) {
self.items.clear();
self.slots.clear();
self.last_slot_idx = 0;
self.len = 0;
self.slot_size = 0;
}
pub fn optimize(&mut self) {
let mut new_items = Vec::with_capacity(self.len);
for item in self.items.iter_mut() {
let a = item.take();
if a.is_some() {
new_items.push(a);
}
}
self.items = new_items;
self.slots.clear();
self.last_slot_idx = 0;
self.slot_size = 0;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new() {
let list: ReuseList<i32> = ReuseList::new();
assert_eq!(list.len(), 0);
assert_eq!(list.capacity(), 0);
assert_eq!(list.items.len(), 0);
assert_eq!(list.slots.len(), 0);
}
#[test]
fn test_with_capacity() {
let list: ReuseList<i32> = ReuseList::with_capacity(10);
assert_eq!(list.len(), 0);
assert_eq!(list.capacity(), 10);
assert_eq!(list.items.len(), 0);
assert_eq!(list.slots.len(), 0);
}
#[test]
fn test_append() {
let mut list = ReuseList::new();
assert_eq!(list.append(1), 0);
assert_eq!(list.append(2), 1);
assert_eq!(list.append(3), 2);
assert_eq!(list.len(), 3);
let items: Vec<i32> = list.iter().cloned().collect();
assert_eq!(items, vec![1, 2, 3]);
assert_eq!(list.items, vec![Some(1), Some(2), Some(3)]);
assert_eq!(list.slots, vec![]);
}
#[test]
fn test_remove() {
let mut list = ReuseList::new();
list.append(1);
list.append(2);
list.append(3);
assert_eq!(list.remove(1), Some(2));
assert_eq!(list.len(), 2);
let items: Vec<i32> = list.iter().cloned().collect();
assert_eq!(items, vec![1, 3]);
assert_eq!(list.items, vec![Some(1), None, Some(3)]);
assert_eq!(list.slots, vec![2]);
assert_eq!(list.remove(5), None);
}
#[test]
fn test_reuse_slots() {
let mut list = ReuseList::new();
list.append(1);
list.append(2);
list.append(3);
list.remove(1); assert_eq!(list.append(4), 1);
let items: Vec<i32> = list.iter().cloned().collect();
assert_eq!(items, vec![1, 4, 3]);
assert_eq!(list.items, vec![Some(1), Some(4), Some(3)]);
assert_eq!(list.slots, vec![0]);
}
#[test]
fn test_get() {
let mut list = ReuseList::new();
list.append(1);
list.append(2);
assert_eq!(list.get(0), Some(&1));
assert_eq!(list.get(1), Some(&2));
assert_eq!(list.get(2), None);
assert_eq!(list.items, vec![Some(1), Some(2)]);
assert_eq!(list.slots, vec![]);
}
#[test]
fn test_get_mut() {
let mut list = ReuseList::new();
list.append(1);
list.append(2);
if let Some(value) = list.get_mut(0) {
*value = 10;
}
assert_eq!(list.get(0), Some(&10));
assert_eq!(list.items, vec![Some(10), Some(2)]);
assert_eq!(list.slots, vec![]);
}
#[test]
fn test_iter() {
let mut list = ReuseList::new();
list.append(1);
list.append(2);
list.append(3);
list.remove(1);
let items: Vec<i32> = list.iter().cloned().collect();
assert_eq!(items, vec![1, 3]);
assert_eq!(list.items, vec![Some(1), None, Some(3)]);
assert_eq!(list.slots, vec![2]);
}
#[test]
fn test_iter_mut() {
let mut list = ReuseList::new();
list.append(1);
list.append(2);
list.append(3);
for item in list.iter_mut() {
*item *= 2;
}
let items: Vec<i32> = list.iter().cloned().collect();
assert_eq!(items, vec![2, 4, 6]);
assert_eq!(list.items, vec![Some(2), Some(4), Some(6)]);
assert_eq!(list.slots, vec![]);
}
#[test]
fn test_multiple_removes() {
let mut list = ReuseList::new();
for i in 0..5 {
list.append(i);
}
list.remove(1);
list.remove(3);
let items: Vec<i32> = list.iter().cloned().collect();
assert_eq!(items, vec![0, 2, 4]);
assert_eq!(list.items, vec![Some(0), None, Some(2), None, Some(4)]);
assert_eq!(list.slots, vec![2, 4]);
list.append(10);
list.append(11);
let items: Vec<i32> = list.iter().cloned().collect();
assert_eq!(items, vec![0, 11, 2, 10, 4]);
assert_eq!(
list.items,
vec![Some(0), Some(11), Some(2), Some(10), Some(4)]
);
assert_eq!(list.slots, vec![0, 0]);
list.remove(0);
let items: Vec<i32> = list.iter().cloned().collect();
assert_eq!(items, vec![11, 2, 10, 4]);
assert_eq!(list.items, vec![None, Some(11), Some(2), Some(10), Some(4)]);
assert_eq!(list.slots, vec![1, 0]);
list.append(20);
let items: Vec<i32> = list.iter().cloned().collect();
assert_eq!(items, vec![20, 11, 2, 10, 4]);
assert_eq!(
list.items,
vec![Some(20), Some(11), Some(2), Some(10), Some(4)]
);
assert_eq!(list.slots, vec![0, 0]);
list.clear();
}
#[test]
fn test_optimize() {
let mut list = ReuseList::new();
list.append(1);
list.append(2);
list.append(3);
list.remove(1);
assert_eq!(list.items, vec![Some(1), None, Some(3)]);
assert_eq!(list.slots, vec![2]);
list.optimize();
assert_eq!(list.items, vec![Some(1), Some(3)]);
assert_eq!(list.slots, vec![]);
assert_eq!(list.last_slot_idx, 0);
assert_eq!(list.slot_size, 0);
let items: Vec<i32> = list.iter().cloned().collect();
assert_eq!(items, vec![1, 3]);
}
}