use std::cmp::Ordering;
use std::collections::binary_heap::BinaryHeap;
use std::marker::PhantomData;
use super::handle::{HandleIndex, HandleLike};
#[derive(PartialEq, Eq)]
struct InverseHandleIndex(HandleIndex);
impl PartialOrd for InverseHandleIndex {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
other.0.partial_cmp(&self.0)
}
}
impl Ord for InverseHandleIndex {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
pub struct HandlePool<T: HandleLike> {
versions: Vec<HandleIndex>,
frees: BinaryHeap<InverseHandleIndex>,
_marker: PhantomData<T>,
}
impl<T: HandleLike> Default for HandlePool<T> {
fn default() -> Self {
HandlePool {
versions: Vec::new(),
frees: BinaryHeap::new(),
_marker: PhantomData::default(),
}
}
}
impl<T: HandleLike> HandlePool<T> {
pub fn new() -> HandlePool<T> {
Default::default()
}
pub fn with_capacity(capacity: usize) -> HandlePool<T> {
let versions = Vec::with_capacity(capacity);
let mut frees = BinaryHeap::with_capacity(capacity);
for i in 0..versions.len() {
frees.push(InverseHandleIndex(i as HandleIndex));
}
HandlePool {
versions,
frees,
_marker: PhantomData::default(),
}
}
pub fn create(&mut self) -> T {
if !self.frees.is_empty() {
let index = self.frees.pop().unwrap().0 as usize;
self.versions[index] += 1;
T::new(index as HandleIndex, self.versions[index])
} else {
self.versions.push(1);
T::new(self.versions.len() as HandleIndex - 1, 1)
}
}
pub fn contains(&self, handle: T) -> bool {
let index = handle.index() as usize;
(index < self.versions.len())
&& ((self.versions[index] & 0x1) == 1)
&& (self.versions[index] == handle.version())
}
pub fn free(&mut self, handle: T) -> bool {
if !self.contains(handle) {
false
} else {
self.versions[handle.index() as usize] += 1;
self.frees.push(InverseHandleIndex(handle.index()));
true
}
}
pub fn retain<P>(&mut self, mut predicate: P)
where
P: FnMut(T) -> bool,
{
unsafe {
for i in 0..self.versions.len() {
let v = *self.versions.get_unchecked(i);
if v & 0x1 == 1 && !predicate(T::new(i as u32, v)) {
self.versions[i] += 1;
self.frees.push(InverseHandleIndex(i as u32));
}
}
}
}
pub fn clear(&mut self) {
self.frees.clear();
self.versions.clear();
}
#[inline]
pub fn len(&self) -> usize {
self.versions.len() - self.frees.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn iter(&self) -> Iter<T> {
Iter::new(self)
}
}
impl<'a, T: HandleLike> IntoIterator for &'a HandlePool<T> {
type Item = T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
Iter::new(self)
}
}
impl<'a, T: HandleLike> IntoIterator for &'a mut HandlePool<T> {
type Item = T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
Iter::new(self)
}
}
#[derive(Copy, Clone)]
pub struct Iter<'a, T: HandleLike> {
versions: &'a [HandleIndex],
start: HandleIndex,
end: HandleIndex,
_marker: PhantomData<T>,
}
impl<'a, T: HandleLike> Iter<'a, T> {
fn new(handles: &'a HandlePool<T>) -> Self {
Iter {
versions: &handles.versions,
start: 0,
end: handles.versions.len() as u32,
_marker: handles._marker,
}
}
pub fn split_at(&self, len: usize) -> (Iter<'a, T>, Iter<'a, T>) {
let len = len as HandleIndex;
let mid = if self.start + len >= self.end {
self.end
} else {
self.start + len
};
let left = Iter {
versions: self.versions,
start: self.start,
end: mid,
_marker: self._marker,
};
let right = Iter {
versions: self.versions,
start: mid,
end: self.end,
_marker: self._marker,
};
(left, right)
}
#[inline]
pub fn split(&self) -> (Iter<'a, T>, Iter<'a, T>) {
let mid = (self.end - self.start) / 2;
self.split_at(mid as usize)
}
#[inline]
pub fn len(&self) -> usize {
(self.end - self.start) as usize
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a, T: HandleLike> Iterator for Iter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
unsafe {
for i in self.start..self.end {
let v = self.versions.get_unchecked(i as usize);
if v & 0x1 == 1 {
self.start = i + 1;
return Some(T::new(i, *v));
}
}
}
None
}
}
impl<'a, T: HandleLike> DoubleEndedIterator for Iter<'a, T> {
fn next_back(&mut self) -> Option<T> {
unsafe {
for i in (self.start..self.end).rev() {
let v = self.versions.get_unchecked(i as usize);
if v & 0x1 == 1 {
self.end = i;
return Some(T::new(i, *v));
}
}
}
None
}
}