use std::fmt;
use std::fmt::Debug;
use std::mem;
use allocative::Allocative;
use hashbrown::HashTable;
use starlark_derive::Trace;
use starlark_map::Hashed;
use crate as starlark;
use crate::collections::symbol::symbol::Symbol;
use crate::values::StringValue;
#[derive(Clone, Trace, Allocative)]
pub(crate) struct SymbolMap<T>(HashTable<(Symbol, T)>);
impl<T: Debug> Debug for SymbolMap<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map()
.entries(self.iter().map(|x| (&x.0, &x.1)))
.finish()
}
}
impl<T> SymbolMap<T> {
pub(crate) fn new() -> Self {
SymbolMap::with_capacity(0)
}
pub(crate) fn with_capacity(capacity: usize) -> Self {
SymbolMap(HashTable::with_capacity(capacity))
}
pub(crate) fn insert(&mut self, key: &str, value: T) -> Option<T> {
let s = Symbol::new(key);
if let Some((_, item)) = self.0.find_mut(s.hash(), |x| s == x.0) {
Some(mem::replace(item, value))
} else {
self.0.insert_unique(s.hash(), (s, value), |x| x.0.hash());
None
}
}
#[inline]
pub(crate) fn get(&self, key: &Symbol) -> Option<&T> {
self.0.find(key.hash(), |x| key == &x.0).map(|x| &x.1)
}
pub(crate) fn get_str(&self, key: &str) -> Option<&T> {
self.get_hashed_str(Hashed::new(key))
}
pub(crate) fn get_hashed_str(&self, key: Hashed<&str>) -> Option<&T> {
self.0
.find(key.hash().promote(), |x| x.0.as_str() == *key.key())
.map(|x| &x.1)
}
pub(crate) fn get_hashed_string_value(&self, key: Hashed<StringValue>) -> Option<&T> {
self.0
.find(key.hash().promote(), |x| {
x.0.as_aligned_padded_str() == key.key().as_aligned_padded_str()
})
.map(|x| &x.1)
}
pub(crate) fn len(&self) -> usize {
self.0.len()
}
pub(crate) fn iter<'a>(&'a self) -> impl ExactSizeIterator<Item = &'a (Symbol, T)> + 'a {
self.0.iter()
}
pub(crate) fn keys<'a>(&'a self) -> impl ExactSizeIterator<Item = &'a Symbol> + 'a {
self.iter().map(|x| &x.0)
}
pub(crate) fn values<'a>(&'a self) -> impl ExactSizeIterator<Item = &'a T> + 'a {
self.iter().map(|x| &x.1)
}
}