use std::{
fmt,
marker::PhantomData,
};
#[derive(Debug)]
pub struct Handle<T> {
index: usize,
generation: u32,
phantom: PhantomData<T>,
}
impl<T> Handle<T> {
fn new(index: usize, generation: u32) -> Self {
Self {
index,
generation,
phantom: PhantomData,
}
}
}
pub struct GenerationalBuffer<T> {
entries: Vec<T>,
max_capacity: usize,
next_index: usize,
current_generation: u32,
}
impl<T> GenerationalBuffer<T> {
pub fn new(max_capacity: usize) -> Self {
Self {
entries: Vec::new(),
max_capacity,
next_index: 0,
current_generation: 0,
}
}
pub fn capacity(&self) -> usize {
self.max_capacity
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn clear(&mut self) {
self.entries.clear();
self.next_index = 0;
self.current_generation += 2;
}
pub fn is_full(&self) -> bool {
self.entries.len() == self.max_capacity
}
pub fn push(&mut self, value: T) -> Handle<T> {
let index = self.next_index;
let generation = self.current_generation;
if self.entries.len() < self.max_capacity {
self.entries.push(value);
} else {
self.entries[index] = value;
}
let handle = Handle::new(index, generation);
self.next_index = (self.next_index + 1) % self.max_capacity;
if self.next_index == 0 {
self.current_generation = self.current_generation.wrapping_add(1);
}
handle
}
pub fn get(&self, handle: Handle<T>) -> Option<&T> {
if self.is_valid(handle) {
Some(&self.entries[handle.index])
} else {
None
}
}
pub fn get_mut(&mut self, handle: Handle<T>) -> Option<&mut T> {
if self.is_valid(handle) {
Some(&mut self.entries[handle.index])
} else {
None
}
}
pub fn is_valid(&self, handle: Handle<T>) -> bool {
if handle.index >= self.entries.len() {
return false;
}
handle.generation == self.calculate_generation_at_index(handle.index)
}
pub fn iter(&self) -> impl Iterator<Item = (Handle<T>, &T)> {
self.entries.iter().enumerate().map(|(i, value)| {
let generation = self.calculate_generation_at_index(i);
(Handle::new(i, generation), value)
})
}
pub fn values(&self) -> impl Iterator<Item = &T> {
self.entries.iter()
}
pub fn handles(&self) -> impl Iterator<Item = Handle<T>> + '_ {
(0..self.entries.len()).map(move |i| {
let generation = self.calculate_generation_at_index(i);
Handle::new(i, generation)
})
}
fn calculate_generation_at_index(&self, index: usize) -> u32 {
if index < self.next_index {
self.current_generation
} else {
self.current_generation.saturating_sub(1)
}
}
}
impl<T: fmt::Debug> fmt::Debug for GenerationalBuffer<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GenerationalBuffer")
.field("capacity", &self.capacity())
.field("len", &self.len())
.field("next_index", &self.next_index)
.field("current_generation", &self.current_generation)
.field("entries", &self.entries)
.finish()
}
}
impl<O> PartialEq for Handle<O> {
fn eq(&self, other: &Self) -> bool {
self.index == other.index && self.generation == other.generation
}
}
impl<O> Eq for Handle<O> {}
impl<O> Clone for Handle<O> {
fn clone(&self) -> Self {
*self
}
}
impl<O> Copy for Handle<O> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_operations() {
let mut buffer = GenerationalBuffer::new(3);
let h1 = buffer.push(10);
let h2 = buffer.push(20);
let h3 = buffer.push(30);
assert_eq!(buffer.get(h1), Some(&10));
assert_eq!(buffer.get(h2), Some(&20));
assert_eq!(buffer.get(h3), Some(&30));
assert_eq!(buffer.len(), 3);
assert!(buffer.is_full());
}
#[test]
fn test_circular_wrapping() {
let mut buffer = GenerationalBuffer::new(2);
let h1 = buffer.push(10);
let h2 = buffer.push(20);
let h3 = buffer.push(30);
assert_eq!(buffer.get(h1), None);
assert_eq!(buffer.get(h2), Some(&20));
assert_eq!(buffer.get(h3), Some(&30));
assert!(!buffer.is_valid(h1));
assert!(buffer.is_valid(h2));
assert!(buffer.is_valid(h3));
assert_eq!(buffer.len(), 2);
let h4 = buffer.push(40); let h5 = buffer.push(50); assert_eq!(buffer.get(h4), Some(&40));
assert_eq!(buffer.get(h5), Some(&50));
assert!(!buffer.is_valid(h2)); assert!(!buffer.is_valid(h3));
buffer.clear();
assert!(buffer.is_empty());
assert!(!buffer.is_valid(h4)); let h6 = buffer.push(60); assert_eq!(buffer.get(h6), Some(&60));
}
#[test]
fn test_generation_calculation() {
let mut buffer = GenerationalBuffer::new(3);
let handles: Vec<_> = (0..10).map(|i| buffer.push(i)).collect();
for (i, &handle) in handles.iter().enumerate() {
if i < 7 {
assert!(!buffer.is_valid(handle), "Handle {i} should be invalid");
} else {
assert!(buffer.is_valid(handle), "Handle {i} should be valid");
}
}
}
#[test]
fn test_iterator() {
let mut buffer = GenerationalBuffer::new(3);
buffer.push(10);
buffer.push(20);
buffer.push(30);
buffer.push(40);
buffer.push(50);
buffer.push(60);
buffer.push(70);
buffer.push(80);
let mut values: Vec<i32> = buffer.values().cloned().collect();
values.sort(); assert_eq!(values, vec![60, 70, 80]);
let handles: Vec<_> = buffer.handles().collect();
assert_eq!(handles.len(), 3);
for handle in handles {
assert!(buffer.is_valid(handle));
}
}
#[test]
fn test_growing_buffer() {
let mut buffer = GenerationalBuffer::new(5);
let h1 = buffer.push(1);
let h2 = buffer.push(2);
let h3 = buffer.push(3);
assert_eq!(buffer.len(), 3);
assert!(!buffer.is_full());
assert!(buffer.is_valid(h1));
assert!(buffer.is_valid(h2));
assert!(buffer.is_valid(h3));
assert_eq!(buffer.get(h1), Some(&1));
assert_eq!(buffer.get(h2), Some(&2));
assert_eq!(buffer.get(h3), Some(&3));
}
}