use std::collections::{HashMap, HashSet};
use std::collections::hash_map::{Keys,Values};
use std::hash::Hash;
use std::borrow::Borrow;
use std::cmp::max;
use std::ops;
use super::ast::{Scope,Index};
#[derive(Debug)]
#[stable(feature = "forktable", since = "0.2.2")]
pub struct ForkTable<'a, K, V>
where K: 'a + Eq + Hash,
V: 'a
{
table: HashMap<K, V>,
whiteouts: HashSet<K>,
parent: Option<&'a ForkTable<'a, K,V>>,
level: usize
}
impl<'a, K, V> ForkTable<'a, K, V>
where K: Eq + Hash
{
#[stable(feature = "forktable", since = "0.2.2")]
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
where K: Borrow<Q>,
Q: Hash + Eq
{
if self.whiteouts.contains(key) {
None
} else {
self.table
.get(key)
.or(self.parent
.map_or(None, |ref parent| parent.get(key))
)
}
}
#[stable(feature = "forktable", since = "0.2.2")]
pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
where K: Borrow<Q>,
Q: Hash + Eq
{
self.table.get_mut(key)
}
#[stable(feature = "forktable", since="0.2.6")]
pub fn remove(&mut self, key: &K) -> Option<V>
where K: Clone
{
if self.table.contains_key(&key) {
self.table.remove(&key)
} else if self.chain_contains_key(&key) {
self.whiteouts.insert(key.clone());
None
} else {
None
}
}
#[stable(feature = "forktable", since = "0.0.3")]
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
if self.whiteouts.contains(&k) { self.whiteouts.remove(&k); };
self.table.insert(k, v)
}
#[stable(feature = "forktable", since = "0.2.2")]
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
where K: Borrow<Q>,
Q: Hash + Eq
{
!self.whiteouts.contains(key) &&
self.table.contains_key(key)
}
#[stable(feature = "forktable", since = "0.2.2")]
pub fn chain_contains_key<Q:? Sized>(&self, key: &Q) -> bool
where K: Borrow<Q>,
Q: Hash + Eq
{
self.table.contains_key(key) ||
(!self.whiteouts.contains(key) &&
self.parent
.map_or(false, |ref p| p.chain_contains_key(key))
)
}
#[unstable(feature = "forktable")]
pub fn fork(&'a self) -> ForkTable<'a, K,V> {
ForkTable {
table: HashMap::new(),
whiteouts: HashSet::new(),
parent: Some(self),
level: self.level + 1
}
}
#[stable(feature = "forktable",since="0.0.3")]
pub fn new() -> ForkTable<'a, K,V> {
ForkTable {
table: HashMap::new(),
whiteouts: HashSet::new(),
parent: None,
level: 0
}
}
#[unstable(feature="forktable")]
pub fn values<'b>(&'b self) -> Values<'b, K, V> {
self.table.values()
}
#[unstable(feature="forktable")]
pub fn keys<'b>(&'b self) -> Keys<'b, K, V>{
self.table.keys()
}
}
#[unstable(feature="forktable")]
impl<'a, 'b, K, Q: ?Sized, V> ops::Index<&'b Q> for ForkTable<'a, K, V>
where K: Eq + Hash + Borrow<Q>,
Q: Eq + Hash {
#[unstable(feature="forktable")]
type Output = V;
#[inline]
#[unstable(feature="forktable")]
fn index(&self, index: &Q) -> &Self::Output {
self.get(index)
.expect("undefined index")
}
}
#[unstable(feature="forktable")]
impl<'a, 'b, K, Q: ?Sized, V> ops::IndexMut<&'b Q> for ForkTable<'a, K, V>
where K: Eq + Hash + Borrow<Q>,
Q: Eq + Hash {
#[inline]
#[unstable(feature="forktable")]
fn index_mut(&mut self, index: &Q) -> &mut V {
self.get_mut(index)
.expect("undefined index")
}
}
#[stable(feature = "compile",since = "0.1.0")]
impl<'a> Scope<&'a str> for ForkTable<'a, &'a str, Index> {
#[stable(feature = "compile",since = "0.1.0")]
fn bind(&mut self,name: &'a str, lvl: u64) -> Index {
let idx = self.values()
.fold(0, |a,i| max(a,i.1)) + 1;
self.insert(name, (lvl,idx));
(self.level as u64, idx)
}
#[stable(feature = "compile",since = "0.2.2")]
fn lookup(&self, name: &&'a str) -> Option<Index> {
self.get(name) .map(|&( lvl, idx )| (lvl.clone(), idx.clone()) )
}
}