use std::borrow::Borrow;
use std::collections::HashMap;
use std::mem;
use std::marker::PhantomData;
use std::ops::Deref;
use num_traits::{Bounded, ToPrimitive, FromPrimitive};
use stable_deref_trait::StableDeref;
use traits::Map;
pub struct ArenaSet<O: StableDeref, I = usize, M = HashMap<&'static < O as Deref >::Target, I>> {
map: M,
interned: Vec<Slot<O>>,
head: usize,
max_idx: usize,
_i: PhantomData<I>,
}
impl<O, I, M> ArenaSet<O, I, M>
where O: StableDeref,
I: Bounded + ToPrimitive + FromPrimitive,
M: Map {
#[inline]
pub fn new() -> Result<Self, Error> {
Self::with_capacity(0)
}
#[inline]
pub fn with_capacity(capacity: usize) -> Result<Self, Error> {
Self::bounded_with_capacity(
I::max_value().to_usize().ok_or(Error::FromIdFailed)? -
I::min_value().to_usize().ok_or(Error::FromIdFailed)?,
capacity)
}
#[inline]
pub fn bounded_with_capacity(max_idx: usize, capacity: usize) -> Result<Self, Error> {
let max_possible = I::max_value().to_usize().ok_or(Error::FromIdFailed)?
- I::min_value().to_usize().ok_or(Error::FromIdFailed)?;
if max_idx > max_possible {
return Err(Error::IdOverflow);
}
Ok(ArenaSet {
map: M::with_capacity(capacity),
max_idx: max_idx,
head: !0,
interned: Vec::with_capacity(capacity),
_i: PhantomData,
})
}
#[inline]
pub fn count(&self) -> usize {
self.map.len()
}
#[inline]
pub fn capacity(&self) -> usize {
self.interned.capacity()
}
#[inline]
pub fn resolve<'a, U, Q: ? Sized>(&'a self, id: U) -> Result<&'a Q, Error>
where U: Borrow<I>,
O: Borrow<Q> {
let ix = id.borrow().to_usize().ok_or(Error::FromIdFailed)?;
let owned = self.interned.get(ix).ok_or(Error::InvalidId)?;
match *owned {
Slot::Occupied(ref item) => Ok(item.borrow()),
_ => Err(Error::InvalidId)
}
}
}
macro_rules! insert {
( $this:ident, $item:ident, $to_owned:expr ) => { {
if let Some(entry) = $this.map.get(make_static($item.borrow())) {
return Ok(*entry);
}
let cnt = $this.count();
if cnt != 0 && cnt - 1 == $this.max_idx {
return Err(Error::IdOverflow);
}
let owned = $to_owned($item);
let reference = make_static(owned.deref());
let ix =
if $this.head == !0 {
$this.interned.push(Slot::Occupied(owned));
$this.interned.len() - 1
} else {
let ix = $this.head;
if let Slot::Vacant(next) = mem::replace(unsafe { $this.interned.get_unchecked_mut(ix) },
Slot::Occupied(owned)) {
$this.head = next;
ix
} else {
unreachable!()
}
};
match I::from_usize(ix).ok_or(Error::ToIdFailed) {
Ok(id) => {
$this.map.insert(reference, id);
Ok(id)
}
Err(err) => {
*unsafe { $this.interned.get_unchecked_mut(ix) } = Slot::Vacant($this.head);
$this.head = ix;
Err(err)
}
}
} }
}
macro_rules! disintern {
( $this:expr, $id:ident) => { {
let ix = $id.borrow().to_usize().ok_or(Error::FromIdFailed)?;
match $this.interned.get_mut(ix) {
None => Err(Error::InvalidId),
Some(&mut Slot::Vacant(_)) => Err(Error::InvalidId),
Some(occupied) => {
if let Slot::Occupied(item) = mem::replace(occupied, Slot::Vacant($this.head)) {
$this.map.remove(make_static(item.deref()));
$this.head = ix;
Ok(item)
} else {
unreachable!()
}
}
}
} }
}
macro_rules! shrink {
($this:ident, $t:ty) => { {
let mut remap = <$t>::new();
let mut shrunk = Vec::with_capacity($this.count());
for (ix, oi) in $this.interned.drain(..).enumerate() {
if let Slot::Occupied(i) = oi {
let i_static = make_static(i.deref());
match (I::from_usize(ix), I::from_usize(shrunk.len())) {
(Some(old_id), Some(new_id)) => {
remap.insert(old_id, new_id);
shrunk.push(Slot::Occupied(i))
}
_ => { $this.map.remove(i_static); }
}
}
}
$this.interned = shrunk;
$this.head = !0;
$this.map.shrink_to_fit();
remap
} }
}
impl<O, I, M> ArenaSet<O, I, M>
where O: StableDeref,
O::Target: 'static,
I: Copy + ToPrimitive + FromPrimitive + Bounded,
M: Map<Key = &'static O::Target, Value = I>
{
pub fn intern<Q>(&mut self, item: Q) -> Result<I, Error>
where Q: Borrow<O::Target>,
O: From<Q> {
insert!(self, item, |item: Q| { O::from(item) })
}
pub fn disintern<'a, U: Borrow<I>>(&'a mut self, id: U) -> Result<O, Error> {
disintern!(self, id)
}
pub fn shrink<T: Map<Key = I, Value = I>>(&mut self) -> T
{
shrink!(self, T)
}
}
pub struct StadiumSet<O: StableDeref<Target = R>, R: ? Sized + StableDeref = < O as Deref >::Target, I = usize, M = HashMap<&'static < R as Deref >::Target, I>>(pub ArenaSet<O, I, M>);
impl<O, R, I, M> StadiumSet<O, R, I, M>
where O: StableDeref<Target = R>,
R: 'static + StableDeref,
I: Copy + ToPrimitive + FromPrimitive + Bounded,
M: Map<Key = &'static < R as Deref >::Target, Value = I>
{
pub fn intern<Q>(&mut self, item: Q) -> Result<I, Error>
where Q: Borrow<< O::Target as Deref >::Target>,
O::Target: From<Q>,
O: From<< O as Deref >::Target> {
let ref mut this = self.0;
insert!(this, item, |item: Q| { O::from(O::Target::from(item)) })
}
pub fn disintern<'a, U: Borrow<I>>(&'a mut self, id: U) -> Result<O, Error> {
let ref mut this = self.0;
disintern!(this, id)
}
#[inline]
pub fn resolve<'a, U, Q: ? Sized>(&'a self, id: U) -> Result<&'a Q, Error>
where U: Borrow<I>,
O: Borrow<Q> {
self.0.resolve(id)
}
pub fn shrink<T: Map<Key = I, Value = I>>(&mut self) -> T
{
let ref mut this = self.0;
shrink!(this, T)
}
}
#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub enum Error {
InvalidId,
FromIdFailed,
ToIdFailed,
IdOverflow,
}
#[derive(Clone)]
enum Slot<T> {
Vacant(usize),
Occupied(T),
}
fn make_static<T: ? Sized>(t: &T) -> &'static T {
unsafe { &*(t as *const T) }
}