#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Handle {
pub(crate) generation: u32,
pub(crate) index: usize,
}
#[derive(Debug)]
struct Slot<T> {
item: Option<T>,
generation: u32,
}
#[derive(Debug)]
pub struct GenVec<T> {
items: Vec<Slot<T>>,
freed: Vec<usize>,
}
impl<T> GenVec<T> {
pub fn new() -> Self {
Self {
items: vec![],
freed: vec![],
}
}
pub fn add(&mut self, item: T) -> Handle {
if let Some(idx) = self.freed.pop() {
let slot = &mut self.items[idx];
slot.item = Some(item);
Handle {
generation: slot.generation,
index: idx,
}
} else {
let idx = self.items.len();
self.items.push(Slot {
generation: 0,
item: Some(item),
});
Handle {
generation: 0,
index: idx,
}
}
}
pub fn remove(&mut self, handle: Handle) -> Option<T> {
if handle.index >= self.items.len() {
return None;
} let slot = &mut self.items[handle.index];
if slot.generation != handle.generation {
return None;
} slot.generation += 1; self.freed.push(handle.index);
slot.item.take()
}
pub fn get_mut(&mut self, handle: Handle) -> Option<&mut T> {
if handle.index >= self.items.len() {
return None;
}
let slot = &mut self.items[handle.index];
if slot.generation != handle.generation {
return None;
}
slot.item.as_mut()
}
pub fn get(&self, handle: Handle) -> Option<&T> {
if handle.index >= self.items.len() {
return None;
}
let slot = &self.items[handle.index];
if slot.generation != handle.generation {
return None;
}
slot.item.as_ref()
}
pub fn iter(&self) -> impl Iterator<Item = (Handle, &T)> {
self.items.iter().enumerate().filter_map(|(idx, slot)| {
slot.item.as_ref().map(|val| {
(
Handle {
index: idx,
generation: slot.generation,
},
val,
)
})
})
}
pub fn iter_from(&self, start_index: usize) -> impl Iterator<Item = (Handle, &T)> {
self.items
.iter()
.enumerate()
.skip(start_index)
.filter_map(|(idx, slot)| {
slot.item.as_ref().map(|val| {
(
Handle {
index: idx,
generation: slot.generation,
},
val,
)
})
})
}
pub fn iter_mut_from(&mut self, start_index: usize) -> impl Iterator<Item = (Handle, &mut T)> {
self.items
.iter_mut()
.enumerate()
.skip(start_index)
.filter_map(|(idx, slot)| {
slot.item.as_mut().map(|val| {
(
Handle {
index: idx,
generation: slot.generation,
},
val,
)
})
})
}
pub(crate) fn get_index(&self, idx: usize) -> Option<&T> {
if idx >= self.items.len() {
return None;
}
self.items[idx].item.as_ref()
}
pub(crate) fn get_mut_index(&mut self, idx: usize) -> Option<&mut T> {
if idx >= self.items.len() {
return None;
}
self.items[idx].item.as_mut()
}
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn test_gen_vec_invalid_handle() {
let mut g = GenVec::new();
let h1 = g.add(1);
assert_eq!(h1.index, 0);
assert_eq!(h1.generation, 0);
let removed = g.remove(h1);
assert_eq!(removed, Some(1));
assert!(g.get_mut(h1).is_none());
assert!(g.remove(h1).is_none());
let h2 = g.add(2);
assert_eq!(h2.index, 0);
assert_eq!(h2.generation, 1);
assert!(g.get_mut(h1).is_none());
assert_eq!(g.get_mut(h2), Some(&mut 2));
}
#[test]
pub fn test_gen_vec_fills() {
let mut g = GenVec::new();
let h1 = g.add(1);
let h2 = g.add(2);
g.remove(h1);
g.remove(h2);
let h3 = g.add(3);
let h4 = g.add(4);
let h5 = g.add(5);
assert_eq!(h3.index, 1);
assert_eq!(h4.index, 0);
assert_eq!(h5.index, 2);
assert_eq!(g.freed.len(), 0);
assert_eq!(g.items.len(), 3);
}
}