use std::
{
vec,
vec::Vec,
collections::VecDeque,
iter,
slice
};
use crate::Index;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
struct AllocatedIndex
{
is_free: bool,
generation: usize
}
#[derive(Default, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct IndexAllocator
{
free_indices: VecDeque<usize>,
active_indices: Vec<AllocatedIndex>
}
impl IndexAllocator
{
pub fn new() -> IndexAllocator
{
IndexAllocator
{
free_indices: VecDeque::new(),
active_indices: Vec::new()
}
}
pub fn with_capacity(capacity: usize) -> IndexAllocator
{
IndexAllocator
{
free_indices: VecDeque::with_capacity(capacity),
active_indices: Vec::with_capacity(capacity)
}
}
pub fn allocate(&mut self) -> Index
{
match self.free_indices.pop_front()
{
Some(index) =>
{
match self.active_indices.get_mut(index)
{
Some(AllocatedIndex{ is_free, generation }) if *is_free =>
{
*is_free = false;
*generation += 1;
Index { index: index, generation: *generation }
},
_ => self.allocate()
}
},
_ =>
{
self.active_indices.push(AllocatedIndex{ is_free: false, generation: 0 });
Index{ index: self.active_indices.len().saturating_sub(1), generation: 0 }
}
}
}
pub fn deallocate(&mut self, index: Index)
{
if self.is_active(index)
{
self.active_indices[index.index].is_free = true;
self.free_indices.push_back(index.index);
}
}
pub fn deallocate_all(&mut self)
{
for (index, alloc_index) in self.active_indices.iter_mut().enumerate()
{
alloc_index.is_free = true;
self.free_indices.push_back(index);
}
}
pub fn capacity(&self) -> usize
{
self.active_indices.capacity()
}
pub fn reserve(&mut self, additional: usize)
{
if additional > 0
{
self.active_indices.reserve(additional);
self.free_indices.reserve(additional);
if self.active_indices.len() > 0
{
let last_index = self.active_indices.len().saturating_sub(1);
for i in last_index..(last_index+additional)
{
self.free_indices.push_back(i);
self.active_indices.push(AllocatedIndex{ is_free: true, generation: 0 });
}
}
}
}
pub fn is_active(&self, index: Index) -> bool
{
match self.active_indices.get(index.index)
{
Some(AllocatedIndex{ is_free, generation }) => *generation == index.generation && !*is_free,
_ => false
}
}
pub fn num_free(&self) -> usize
{
self.free_indices.len()
}
pub fn num_active(&self) -> usize
{
self.active_indices.len().saturating_sub(self.free_indices.len())
}
pub fn iter(&self) -> Iter
{
Iter
{
internal: self.active_indices.iter().enumerate()
}
}
}
#[derive(Debug)]
pub struct IntoIter
{
internal: iter::Enumerate<vec::IntoIter<AllocatedIndex>>
}
impl Iterator for IntoIter
{
type Item = Index;
fn next(&mut self) -> Option<Self::Item>
{
loop
{
match self.internal.next()
{
Some((index, allocated_index)) if !allocated_index.is_free => return Some(Index { index, generation: allocated_index.generation }),
Some((_, _)) => continue,
_ => return None
}
}
}
}
impl IntoIterator for IndexAllocator
{
type Item = Index;
type IntoIter = IntoIter;
fn into_iter(self) -> Self::IntoIter
{
IntoIter
{
internal: self.active_indices.into_iter().enumerate()
}
}
}
#[derive(Debug)]
pub struct Iter<'a>
{
internal: iter::Enumerate<slice::Iter<'a, AllocatedIndex>>
}
impl<'a> Iterator for Iter<'a>
{
type Item = Index;
fn next(&mut self) -> Option<Self::Item>
{
loop
{
loop
{
match self.internal.next()
{
Some((index, allocated_index)) if !allocated_index.is_free => return Some(Index { index, generation: allocated_index.generation }),
Some((_, _)) => continue,
_ => return None
}
}
}
}
}
impl<'a> IntoIterator for &'a IndexAllocator
{
type Item = Index;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter
{
self.iter()
}
}
#[cfg(test)]
mod allocator_tests
{
use crate::exposed::*;
use crate::Index;
#[test]
fn allocate()
{
let mut allocator = IndexAllocator::new();
let index = allocator.allocate();
assert_eq!(index.index, 0);
assert_eq!(index.generation, 0);
let index = allocator.allocate();
assert_eq!(index.index, 1);
assert_eq!(index.generation, 0);
}
#[test]
fn deallocate()
{
let mut allocator = IndexAllocator::new();
let index = allocator.allocate();
allocator.allocate();
allocator.deallocate(index);
let index = allocator.allocate();
assert_eq!(index.index, 0);
assert_eq!(index.generation, 1);
}
#[test]
fn deallocate_all()
{
let mut allocator: IndexAllocator = IndexAllocator::new();
for _ in 0..10
{
allocator.allocate();
}
assert_eq!(allocator.num_active(), 10);
assert_eq!(allocator.num_free(), 0);
allocator.deallocate_all();
assert_eq!(allocator.num_active(), 0);
assert_eq!(allocator.num_free(), 10);
}
#[test]
fn capacity()
{
let mut allocator = IndexAllocator::new();
assert_eq!(allocator.capacity(), 0);
allocator.allocate();
assert!(allocator.capacity() >= 1);
allocator = IndexAllocator::with_capacity(3);
assert!(allocator.capacity() >= 3);
allocator.allocate();
allocator.allocate();
allocator.reserve(4);
assert!(allocator.capacity() >= 5);
}
#[test]
fn active()
{
let mut allocator = IndexAllocator::new();
let index = allocator.allocate();
allocator.allocate();
assert_eq!(allocator.num_active(), 2);
assert_eq!(allocator.num_free(), 0);
assert!(allocator.is_active(index));
allocator.deallocate(index);
assert!(!allocator.is_active(index));
assert_eq!(allocator.num_active(), 1);
assert_eq!(allocator.num_free(), 1);
}
#[test]
fn iter()
{
let mut allocator = IndexAllocator::new();
allocator.allocate();
allocator.allocate();
let i = allocator.allocate();
allocator.deallocate(i);
let mut iter = allocator.iter();
assert_eq!(iter.next(), Some(Index { index: 0, generation: 0 }));
assert_eq!(iter.next(), Some(Index { index: 1, generation: 0}));
assert_eq!(iter.next(), None);
}
}