#![deny(missing_docs, unsafe_code, missing_debug_implementations)]
use ahash::RandomState;
use indexmap::{Equivalent, IndexMap};
use std::borrow::Borrow;
use std::default::Default;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};
pub use symbolmap_trait::{MutSymbolMap, SymbolMap};
#[derive(Clone, Eq, PartialEq)]
pub struct SymbolTable<K: Hash + Eq, V, S: BuildHasher = RandomState> {
symbols: IndexMap<K, Vec<(V, usize)>, S>,
scopes: Vec<Vec<usize>>,
}
impl<K: Hash + Eq + Debug, V: Debug, S: BuildHasher> Debug for SymbolTable<K, V, S> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
fmt.debug_struct("SymbolTable")
.field("symbols", &self.symbols)
.field("scopes", &self.scopes)
.finish()
}
}
impl<K: Hash + Eq, V> SymbolTable<K, V> {
pub fn new() -> SymbolTable<K, V> {
Self::default()
}
}
impl<K: Hash + Eq, V, S: BuildHasher> SymbolTable<K, V, S>
where
S: Default,
{
pub fn with_capacity(n: usize) -> SymbolTable<K, V, S> {
Self::with_capacity_and_hasher(n, S::default())
}
}
impl<K: Hash + Eq, V, S: BuildHasher> Default for SymbolTable<K, V, S>
where
IndexMap<K, Vec<(V, usize)>, S>: Default,
{
fn default() -> SymbolTable<K, V, S> {
SymbolTable {
symbols: IndexMap::default(),
scopes: vec![Vec::new()],
}
}
}
impl<K: Hash + Eq, V, S: BuildHasher> SymbolMap<K> for SymbolTable<K, V, S> {
type Value = V;
#[inline]
fn get<Q>(&self, key: &Q) -> Option<&V>
where
Q: ?Sized + Hash + Eq,
K: Borrow<Q>,
{
self.get_full(key).map(|(v, _)| v)
}
#[inline]
fn insert(&mut self, key: K, value: V) {
let depth = self.depth();
let entry = self.symbols.entry(key);
let index = entry.index();
let v = entry.or_insert_with(Vec::new);
if let Some((old_value, old_depth)) = v.last_mut() {
if depth == *old_depth {
*old_value = value;
return;
}
}
v.push((value, depth));
self.scopes.last_mut().unwrap().push(index);
}
#[inline]
fn depth(&self) -> usize {
self.scopes.len() - 1
}
#[inline]
fn try_get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
where
Q: ?Sized + Hash + Equivalent<K>,
{
if let Some((value, _depth)) = self.get_full_mut(key) {
Some(value)
} else {
None
}
}
#[inline]
fn push(&mut self) {
self.jump(self.depth() + 1);
}
#[inline]
fn pop(&mut self) {
self.jump(self.depth().saturating_sub(1))
}
#[inline]
fn is_empty(&self) -> bool {
self.symbols.is_empty()
}
}
impl<K: Hash + Eq, V, S: BuildHasher> MutSymbolMap<K> for SymbolTable<K, V, S> {}
impl<K: Hash + Eq, V, S: BuildHasher> SymbolTable<K, V, S> {
pub fn with_hasher(hash_builder: S) -> SymbolTable<K, V, S> {
SymbolTable {
symbols: IndexMap::with_hasher(hash_builder),
scopes: vec![Vec::new()],
}
}
pub fn with_capacity_and_hasher(n: usize, hash_builder: S) -> SymbolTable<K, V, S> {
SymbolTable {
symbols: IndexMap::with_capacity_and_hasher(n, hash_builder),
scopes: vec![Vec::new()],
}
}
pub fn try_insert(&mut self, key: K, value: V) -> Result<(), V> {
let depth = self.depth();
let entry = self.symbols.entry(key);
let index = entry.index();
let v = entry.or_insert_with(Vec::new);
if let Some((_, old_depth)) = v.last_mut() {
if depth == *old_depth {
return Err(value);
}
}
v.push((value, depth));
self.scopes.last_mut().unwrap().push(index);
Ok(())
}
pub fn get_defs<Q>(&self, key: &Q) -> &[(V, usize)]
where
Q: ?Sized + Hash + Equivalent<K>,
{
self.symbols.get(key).map(|vec| &vec[..]).unwrap_or(&[])
}
pub fn get_full<Q>(&self, key: &Q) -> Option<(&V, usize)>
where
Q: ?Sized + Hash + Equivalent<K>,
{
self.get_defs(key).last().map(|(v, d)| (v, *d))
}
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
Q: ?Sized + Hash + Equivalent<K>,
{
self.symbols
.get(key)
.map(|v| !v.is_empty())
.unwrap_or(false)
}
pub fn get_full_mut<Q>(&mut self, key: &Q) -> Option<(&mut V, usize)>
where
Q: ?Sized + Hash + Equivalent<K>,
{
self.symbols
.get_mut(key)
.map(|v| v.last_mut().map(|(v, d)| (v, *d)))
.flatten()
}
pub fn jump(&mut self, depth: usize) {
let target = depth + 1;
while target > self.scopes.len() {
self.scopes.push(Vec::new());
}
while self.scopes.len() > target {
for ix in self.scopes.pop().unwrap() {
let (_, v) = if let Some(v) = self.symbols.get_index_mut(ix) {
v
} else {
continue;
};
v.pop();
}
}
}
#[inline]
pub fn popn(&mut self, n: usize) {
self.jump(self.depth().saturating_sub(n))
}
pub fn reserve(&mut self, additional: usize) {
self.symbols.reserve(additional)
}
pub fn capacity(&self) -> usize {
self.symbols.capacity()
}
pub fn clear(&mut self) {
self.symbols.clear();
self.scopes.clear();
self.scopes.push(Vec::new());
}
}
#[cfg(test)]
mod tests {
use super::*;
use symbolmap_trait::testing;
#[test]
fn basic_symbol_table_test() {
testing::basic_symbol_table_test(&mut SymbolTable::new())
}
#[test]
fn inserting_back_twice_works() {
let mut table = SymbolTable::<usize, usize>::new();
table.insert(5, 3);
table.push();
table.insert(5, 4);
table.push();
table.insert(5, 5);
assert_eq!(table.get(&5), Some(&5));
table.pop();
assert_eq!(table.get(&5), Some(&4));
table.pop();
assert_eq!(table.get(&5), Some(&3));
table.pop();
assert_eq!(table.get(&5), Some(&3));
assert!(!table.is_empty());
table.clear();
assert_eq!(table.get(&5), None);
assert!(table.is_empty());
}
}