extern crate free_ranges;
use free_ranges::FreeRanges;
use free_ranges::Range;
use std::error::Error;
use std::fmt;
use std::usize;
pub mod iter;
#[derive(Debug)]
pub struct IndexPool {
next_id: usize,
in_use: usize,
free_list: FreeRanges,
}
impl IndexPool {
#[inline]
pub fn new() -> Self {
Self::with_initial_index(0)
}
pub fn with_initial_index(index: usize) -> Self {
IndexPool {
next_id: index,
in_use: 0,
free_list: FreeRanges::new(),
}
}
#[inline]
pub fn new_id(&mut self) -> usize {
self.in_use += 1;
if let Some(id) = self.free_list.set_first_used() {
return id;
}
let id = self.next_id;
self.next_id += 1;
return id;
}
#[inline]
pub fn request_id(&mut self, id: usize) -> Result<(), AlreadyInUse> {
assert!(id < usize::MAX);
if id == self.next_id {
self.next_id += 1;
self.in_use += 1;
Ok(())
} else if id > self.next_id {
self.free_list.set_range_free(Range {
min: self.next_id,
max: id - 1,
});
self.next_id = id + 1;
self.in_use += 1;
Ok(())
} else if self.free_list.set_used(id) {
self.in_use += 1;
Ok(())
} else {
Err(AlreadyInUse)
}
}
#[inline]
pub fn return_id(&mut self, id: usize) -> Result<(), AlreadyReturned> {
if id >= self.next_id {
return Err(AlreadyReturned);
}
if id + 1 == self.next_id {
self.next_id -= 1;
} else {
if !self.free_list.set_free(id) {
return Err(AlreadyReturned);
}
assert!(self.free_list.is_free(id));
}
self.in_use -= 1;
while self.collapse_next() {}
Ok(())
}
#[inline]
pub fn maximum(&self) -> usize {
self.next_id
}
#[inline]
pub fn in_use(&self) -> usize {
self.in_use
}
#[inline]
pub fn is_free(&self, id: usize) -> bool {
id >= self.next_id || self.free_list.is_free(id)
}
#[inline]
pub fn all_indices(&self) -> iter::IndexIter {
iter::IndexIter::new(self.free_list.free_ranges(), self.next_id)
}
#[inline]
pub fn all_indices_after(&self, after: usize) -> iter::IndexAfterIter {
iter::IndexAfterIter::new(self.free_list.free_ranges_after(after), after, self.next_id)
}
#[inline]
fn collapse_next(&mut self) -> bool {
if let Some(last_range) = self.free_list.free_ranges().rev().nth(0).cloned() {
if last_range.max + 1 == self.next_id {
self.free_list.remove_last_contiguous();
self.next_id = last_range.min;
return true;
}
}
false
}
#[inline]
pub fn clear(&mut self) {
self.free_list.clear();
self.in_use = 0;
self.next_id = 0;
}
}
impl Default for IndexPool {
#[inline]
fn default() -> Self {
IndexPool::new()
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct AlreadyReturned;
impl fmt::Display for AlreadyReturned {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(self.description())
}
}
impl Error for AlreadyReturned {
fn description(&self) -> &str {
"An index was tried to be returned to the pool, but it was already marked as free."
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct AlreadyInUse;
impl fmt::Display for AlreadyInUse {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(self.description())
}
}
impl Error for AlreadyInUse {
fn description(&self) -> &str {
"An index was requested which was already marked as in use."
}
}