use std::{
fmt, iter, mem,
num::{NonZeroU32, ParseIntError},
ops::{Index, IndexMut},
ptr,
str::FromStr,
vec,
};
use std::ops::Deref;
use std::slice;
use unreachable::unreachable;
#[cfg(feature = "serde_support")]
use serde::{Deserialize, Serialize};
mod par;
pub use par::*;
#[derive(Clone)]
enum Slot<T> {
Vacant(u32),
Occupied(T),
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
pub struct ObjId(pub NonZeroU32);
impl ObjId {
pub fn from_index(index: u32) -> Self {
debug_assert!(index < u32::MAX, "index out of range");
Self(unsafe { NonZeroU32::new_unchecked(index + 1) })
}
pub const fn into_index(self) -> u32 {
self.0.get() - 1
}
}
impl std::fmt::Display for ObjId {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
self.0.fmt(f)
}
}
impl FromStr for ObjId {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(ObjId(s.parse::<NonZeroU32>()?))
}
}
impl Deref for ObjId {
type Target = NonZeroU32;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<NonZeroU32> for ObjId {
fn from(v: NonZeroU32) -> ObjId {
ObjId(v)
}
}
pub struct ObjPool<T> {
slots: Vec<Slot<T>>,
len: u32,
head: u32,
}
impl<T> AsRef<ObjPool<T>> for ObjPool<T> {
fn as_ref(&self) -> &ObjPool<T> {
self
}
}
impl<T> AsMut<ObjPool<T>> for ObjPool<T> {
fn as_mut(&mut self) -> &mut ObjPool<T> {
self
}
}
impl<T> ObjPool<T> {
#[inline]
pub const fn new() -> Self {
ObjPool {
slots: Vec::new(),
len: 0,
head: u32::MAX,
}
}
#[inline]
pub const fn obj_id_to_index(obj_id: ObjId) -> u32 {
obj_id.into_index()
}
#[inline]
pub fn index_to_obj_id(index: u32) -> ObjId {
ObjId::from_index(index)
}
#[inline]
pub fn with_capacity(cap: usize) -> Self {
ObjPool {
slots: Vec::with_capacity(cap),
len: 0,
head: u32::MAX,
}
}
#[inline]
pub fn capacity(&self) -> usize {
self.slots.capacity()
}
#[inline]
pub fn len(&self) -> u32 {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn next_vacant(&mut self) -> ObjId {
Self::index_to_obj_id(if self.head == u32::MAX {
self.len
} else {
self.head
})
}
pub fn insert(&mut self, object: T) -> ObjId {
self.len += 1;
if self.head == u32::MAX {
self.slots.push(Slot::Occupied(object));
Self::index_to_obj_id(self.len - 1)
} else {
let index = self.head;
match self.slots[index as usize] {
Slot::Vacant(next) => {
self.head = next;
self.slots[index as usize] = Slot::Occupied(object);
}
Slot::Occupied(_) => unreachable!(),
}
Self::index_to_obj_id(index)
}
}
pub fn remove(&mut self, obj_id: ObjId) -> Option<T> {
let index = Self::obj_id_to_index(obj_id);
match self.slots.get_mut(index as usize) {
None => None,
Some(&mut Slot::Vacant(_)) => None,
Some(slot @ &mut Slot::Occupied(_)) => {
if let Slot::Occupied(object) = mem::replace(slot, Slot::Vacant(self.head)) {
self.head = index;
self.len -= 1;
Some(object)
} else {
unreachable!();
}
}
}
}
#[inline]
pub fn clear(&mut self) {
self.slots.clear();
self.len = 0;
self.head = u32::MAX;
}
pub fn get(&self, obj_id: ObjId) -> Option<&T> {
let index = Self::obj_id_to_index(obj_id) as usize;
match self.slots.get(index) {
None => None,
Some(&Slot::Vacant(_)) => None,
Some(Slot::Occupied(object)) => Some(object),
}
}
#[inline]
pub fn get_mut(&mut self, obj_id: ObjId) -> Option<&mut T> {
let index = Self::obj_id_to_index(obj_id) as usize;
match self.slots.get_mut(index) {
None => None,
Some(&mut Slot::Vacant(_)) => None,
Some(&mut Slot::Occupied(ref mut object)) => Some(object),
}
}
pub unsafe fn get_unchecked(&self, obj_id: ObjId) -> &T {
match self.slots.get(Self::obj_id_to_index(obj_id) as usize) {
None => unsafe { unreachable() },
Some(Slot::Vacant(_)) => unsafe { unreachable() },
Some(Slot::Occupied(object)) => object,
}
}
pub unsafe fn get_unchecked_mut(&mut self, obj_id: ObjId) -> &mut T {
let index = Self::obj_id_to_index(obj_id) as usize;
match self.slots.get_mut(index) {
Some(&mut Slot::Vacant(_)) => unsafe { unreachable() },
Some(&mut Slot::Occupied(ref mut object)) => object,
_ => unsafe { unreachable() },
}
}
#[inline]
pub fn swap(&mut self, a: ObjId, b: ObjId) {
unsafe {
let fst = self.get_mut(a).unwrap() as *mut _;
let snd = self.get_mut(b).unwrap() as *mut _;
if a != b {
ptr::swap(fst, snd);
}
}
}
pub fn reserve(&mut self, additional: u32) {
let vacant = self.slots.len() as u32 - self.len;
if additional > vacant {
self.slots.reserve((additional - vacant) as usize);
}
}
pub fn reserve_exact(&mut self, additional: u32) {
let vacant = self.slots.len() as u32 - self.len;
if additional > vacant {
self.slots.reserve_exact((additional - vacant) as usize);
}
}
#[inline]
pub fn iter(&self) -> Iter<'_, T> {
Iter {
len: self.len as usize,
slots: self.slots.iter().enumerate(),
}
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut {
len: self.len as usize,
slots: self.slots.iter_mut().enumerate(),
}
}
pub fn shrink_to_fit(&mut self) {
self.slots.shrink_to_fit();
}
}
impl<T> fmt::Debug for ObjPool<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ObjPool {{ ... }}")
}
}
impl<T> Index<ObjId> for ObjPool<T> {
type Output = T;
#[inline]
fn index(&self, obj_id: ObjId) -> &T {
self.get(obj_id).expect("object not found")
}
}
impl<T> IndexMut<ObjId> for ObjPool<T> {
#[inline]
fn index_mut(&mut self, obj_id: ObjId) -> &mut T {
self.get_mut(obj_id).expect("object not found")
}
}
impl<T> Default for ObjPool<T> {
fn default() -> Self {
ObjPool::new()
}
}
impl<T: Clone> Clone for ObjPool<T> {
fn clone(&self) -> Self {
ObjPool {
slots: self.slots.clone(),
len: self.len,
head: self.head,
}
}
}
pub struct IntoIter<T> {
slots: iter::Enumerate<vec::IntoIter<Slot<T>>>,
len: usize,
}
impl<T> IntoIter<T> {
#[inline]
pub const fn obj_id_to_index(obj_id: ObjId) -> u32 {
obj_id.into_index()
}
#[inline]
pub fn index_to_obj_id(index: u32) -> ObjId {
ObjId::from_index(index)
}
}
impl<T> Iterator for IntoIter<T> {
type Item = (ObjId, T);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
for (index, slot) in self.slots.by_ref() {
if let Slot::Occupied(object) = slot {
self.len -= 1;
return Some((Self::index_to_obj_id(index as u32), object));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<T> ExactSizeIterator for IntoIter<T> {
fn len(&self) -> usize {
self.len
}
}
impl<T> iter::FusedIterator for IntoIter<T> {}
impl<T> IntoIterator for ObjPool<T> {
type Item = (ObjId, T);
type IntoIter = IntoIter<T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
IntoIter {
len: self.len as usize,
slots: self.slots.into_iter().enumerate(),
}
}
}
impl<T> iter::FromIterator<T> for ObjPool<T> {
fn from_iter<U: IntoIterator<Item = T>>(iter: U) -> ObjPool<T> {
let iter = iter.into_iter();
let mut obj_pool = ObjPool::with_capacity(iter.size_hint().0);
for i in iter {
obj_pool.insert(i);
}
obj_pool
}
}
impl<T> fmt::Debug for IntoIter<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "IntoIter {{ ... }}")
}
}
pub struct Iter<'a, T: 'a> {
slots: iter::Enumerate<slice::Iter<'a, Slot<T>>>,
len: usize,
}
impl<'a, T: 'a> Iter<'a, T> {
#[inline]
pub fn index_to_obj_id(index: u32) -> ObjId {
ObjId::from_index(index)
}
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = (ObjId, &'a T);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
for (index, slot) in self.slots.by_ref() {
if let Slot::Occupied(ref object) = *slot {
self.len -= 1;
return Some((Self::index_to_obj_id(index as u32), object));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<T> ExactSizeIterator for Iter<'_, T> {
fn len(&self) -> usize {
self.len
}
}
impl<T> iter::FusedIterator for Iter<'_, T> {}
impl<'a, T> IntoIterator for &'a ObjPool<T> {
type Item = (ObjId, &'a T);
type IntoIter = Iter<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T> fmt::Debug for Iter<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Iter {{ ... }}")
}
}
pub struct IterMut<'a, T: 'a> {
slots: iter::Enumerate<slice::IterMut<'a, Slot<T>>>,
len: usize,
}
impl<'a, T: 'a> IterMut<'a, T> {
#[inline]
pub const fn obj_id_to_index(obj_id: ObjId) -> u32 {
obj_id.into_index()
}
#[inline]
pub fn index_to_obj_id(index: u32) -> ObjId {
ObjId::from_index(index)
}
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = (ObjId, &'a mut T);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
for (index, slot) in self.slots.by_ref() {
if let Slot::Occupied(ref mut object) = *slot {
self.len -= 1;
return Some((Self::index_to_obj_id(index as u32), object));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<T> ExactSizeIterator for IterMut<'_, T> {
fn len(&self) -> usize {
self.len
}
}
impl<T> iter::FusedIterator for IterMut<'_, T> {}
impl<'a, T> IntoIterator for &'a mut ObjPool<T> {
type Item = (ObjId, &'a mut T);
type IntoIter = IterMut<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<'a, T> fmt::Debug for IterMut<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "IterMut {{ ... }}")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new() {
let obj_pool = ObjPool::<i32>::new();
assert!(obj_pool.is_empty());
assert_eq!(obj_pool.len(), 0);
assert_eq!(obj_pool.capacity(), 0);
}
#[test]
fn insert() {
let mut obj_pool = ObjPool::new();
for i in 0..10 {
let a = obj_pool.insert(i * 10);
assert_eq!(obj_pool[a], i * 10);
}
assert!(!obj_pool.is_empty());
assert_eq!(obj_pool.len(), 10);
}
#[test]
fn with_capacity() {
let mut obj_pool = ObjPool::with_capacity(10);
assert_eq!(obj_pool.capacity(), 10);
for _ in 0..10 {
obj_pool.insert(());
}
assert_eq!(obj_pool.len(), 10);
assert_eq!(obj_pool.capacity(), 10);
obj_pool.insert(());
assert_eq!(obj_pool.len(), 11);
assert!(obj_pool.capacity() > 10);
}
#[test]
fn remove() {
let mut obj_pool = ObjPool::new();
let a = obj_pool.insert(0);
let b = obj_pool.insert(10);
let c = obj_pool.insert(20);
obj_pool.insert(30);
assert_eq!(obj_pool.len(), 4);
assert_eq!(obj_pool.remove(b), Some(10));
assert_eq!(obj_pool.remove(c), Some(20));
assert_eq!(obj_pool.len(), 2);
obj_pool.insert(-1);
obj_pool.insert(-1);
assert_eq!(obj_pool.len(), 4);
assert_eq!(obj_pool.remove(a), Some(0));
obj_pool.insert(-1);
assert_eq!(obj_pool.len(), 4);
obj_pool.insert(400);
assert_eq!(obj_pool.len(), 5);
}
#[test]
fn clear() {
let mut obj_pool = ObjPool::new();
obj_pool.insert(10);
obj_pool.insert(20);
assert!(!obj_pool.is_empty());
assert_eq!(obj_pool.len(), 2);
let cap = obj_pool.capacity();
obj_pool.clear();
assert!(obj_pool.is_empty());
assert_eq!(obj_pool.len(), 0);
assert_eq!(obj_pool.capacity(), cap);
}
#[test]
fn indexing() {
let mut obj_pool = ObjPool::new();
let a = obj_pool.insert(10);
let b = obj_pool.insert(20);
let c = obj_pool.insert(30);
obj_pool[b] += obj_pool[c];
assert_eq!(obj_pool[a], 10);
assert_eq!(obj_pool[b], 50);
assert_eq!(obj_pool[c], 30);
}
#[test]
#[should_panic]
fn indexing_vacant() {
let mut obj_pool = ObjPool::new();
let _ = obj_pool.insert(10);
let b = obj_pool.insert(20);
let _ = obj_pool.insert(30);
obj_pool.remove(b);
obj_pool[b];
}
#[test]
#[should_panic]
fn invalid_indexing() {
let mut obj_pool = ObjPool::new();
obj_pool.insert(10);
obj_pool.insert(20);
let a = obj_pool.insert(30);
obj_pool.remove(a);
obj_pool[a];
}
#[test]
fn get() {
let mut obj_pool = ObjPool::new();
let a = obj_pool.insert(10);
let b = obj_pool.insert(20);
let c = obj_pool.insert(30);
*obj_pool.get_mut(b).unwrap() += *obj_pool.get(c).unwrap();
assert_eq!(obj_pool.get(a), Some(&10));
assert_eq!(obj_pool.get(b), Some(&50));
assert_eq!(obj_pool.get(c), Some(&30));
obj_pool.remove(b);
assert_eq!(obj_pool.get(b), None);
assert_eq!(obj_pool.get_mut(b), None);
}
#[test]
fn reserve() {
let mut obj_pool = ObjPool::new();
obj_pool.insert(1);
obj_pool.insert(2);
obj_pool.reserve(10);
assert!(obj_pool.capacity() >= 11);
}
#[test]
fn reserve_exact() {
let mut obj_pool = ObjPool::new();
obj_pool.insert(1);
obj_pool.insert(2);
obj_pool.reserve(10);
assert!(obj_pool.capacity() >= 11);
}
#[test]
fn iter() {
let mut arena = ObjPool::new();
let a = arena.insert(10);
let b = arena.insert(20);
let c = arena.insert(30);
let d = arena.insert(40);
arena.remove(b);
let mut it = arena.iter();
assert_eq!(it.next(), Some((a, &10)));
assert_eq!(it.next(), Some((c, &30)));
assert_eq!(it.next(), Some((d, &40)));
assert_eq!(it.next(), None);
}
#[test]
fn iter_mut() {
let mut obj_pool = ObjPool::new();
let a = obj_pool.insert(10);
let b = obj_pool.insert(20);
let c = obj_pool.insert(30);
let d = obj_pool.insert(40);
obj_pool.remove(b);
{
let mut it = obj_pool.iter_mut();
assert_eq!(it.next(), Some((a, &mut 10)));
assert_eq!(it.next(), Some((c, &mut 30)));
assert_eq!(it.next(), Some((d, &mut 40)));
assert_eq!(it.next(), None);
}
for (obj_id, value) in &mut obj_pool {
*value += obj_id.get();
}
let mut it = obj_pool.iter_mut();
assert_eq!(*it.next().unwrap().1, 10 + a.get());
assert_eq!(*it.next().unwrap().1, 30 + c.get());
assert_eq!(*it.next().unwrap().1, 40 + d.get());
assert_eq!(it.next(), None);
}
#[test]
fn from_iter() {
let obj_pool: ObjPool<usize> = [10, 20, 30, 40].iter().cloned().collect();
let mut it = obj_pool.iter();
assert_eq!(it.next(), Some((ObjPool::<usize>::index_to_obj_id(0), &10)));
assert_eq!(it.next(), Some((ObjPool::<usize>::index_to_obj_id(1), &20)));
assert_eq!(it.next(), Some((ObjPool::<usize>::index_to_obj_id(2), &30)));
assert_eq!(it.next(), Some((ObjPool::<usize>::index_to_obj_id(3), &40)));
assert_eq!(it.next(), None);
}
}