use std::{
cell::UnsafeCell,
collections::hash_map::RandomState,
hash::{BuildHasher, Hash, Hasher},
mem,
};
use hashbrown::raw::RawTable;
use super::{RawValue, ValueKind};
type DictMap = RawTable<(RawValue, RawValue)>;
type DictHashBuilder = RandomState;
#[derive(Default, Clone)]
struct DictInner {
table: DictMap,
state: DictHashBuilder,
}
#[derive(Default, Debug)]
pub struct Dict {
inner: UnsafeCell<DictInner>,
}
impl Dict {
pub fn new() -> Self {
Self::default()
}
pub fn len(&self) -> usize {
let inner = unsafe { &*self.inner.get() };
inner.table.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn insert(&self, key: RawValue, value: RawValue) -> RawValue {
let inner = unsafe { &mut *self.inner.get() };
let hasher = make_hasher(&inner.state);
let key_hash = hasher(&(key, value));
if let Some((_, item)) = inner.table.get_mut(key_hash, equivalent_key(key)) {
mem::replace(item, value)
} else {
inner.table.insert(key_hash, (key, value), hasher);
RawValue::from(())
}
}
pub fn remove(&self, key: RawValue) -> RawValue {
let inner = unsafe { &mut *self.inner.get() };
match inner
.table
.remove_entry(key.hash(&mut inner.state.build_hasher()), equivalent_key(key))
{
Some((_, v)) => v,
None => RawValue::from(()),
}
}
pub fn get(&self, key: RawValue) -> Option<RawValue> {
let inner = unsafe { &*self.inner.get() };
if inner.table.is_empty() {
None
} else {
let hash = key.hash(&mut inner.state.build_hasher());
inner.table.get(hash, equivalent_key(key)).map(|&(_key, value)| value)
}
}
pub fn contains_key(&self, key: RawValue) -> bool {
self.get(key).is_some()
}
pub(crate) unsafe fn iter(&self) -> impl Iterator<Item = (RawValue, RawValue)> + '_ {
let inner = &*self.inner.get();
let iterator = inner.table.iter();
iterator.map(|bucket| bucket.read())
}
pub(crate) unsafe fn raw_iter(&self) -> hashbrown::raw::RawIter<(RawValue, RawValue)> {
let inner = &*self.inner.get();
inner.table.iter()
}
}
impl Clone for Dict {
fn clone(&self) -> Self {
Self { inner: UnsafeCell::new((unsafe { &*self.inner.get() }).clone()) }
}
}
impl PartialEq for Dict {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
unsafe { self.iter() }.all(|(key, value)| other.get(key).map_or(false, |v| value == v))
}
}
impl RawValue {
pub fn hash<H>(&self, state: &mut H) -> u64
where
H: Hasher,
{
self.kind().hash(state);
unsafe {
match self.kind() {
ValueKind::Nil => (),
ValueKind::Boolean => self.get_boolean_unchecked().hash(state),
ValueKind::Number => self.get_number_unchecked().to_bits().hash(state),
ValueKind::String => self.get_raw_string_unchecked().get().hash(state),
ValueKind::Function => self.get_raw_function_unchecked().get_raw().hash(state),
ValueKind::Struct => self.get_raw_struct_unchecked().get_raw().hash(state),
ValueKind::Trait => self.get_raw_trait_unchecked().get_raw().hash(state),
ValueKind::List => {
let slice = self.get_raw_list_unchecked().get().as_slice();
slice.len().hash(state);
for value in slice.iter() {
value.hash(state);
}
}
ValueKind::Dict => {
let dict = self.get_raw_dict_unchecked().get();
for (key, value) in dict.iter() {
key.hash(state);
value.hash(state);
}
}
ValueKind::UserData => self.get_raw_user_data_unchecked().get_raw().hash(state),
}
}
state.finish()
}
}
fn make_hasher(builder: &DictHashBuilder) -> impl Fn(&(RawValue, RawValue)) -> u64 + '_ {
move |&(key, _value)| key.hash(&mut builder.build_hasher())
}
fn equivalent_key(key: RawValue) -> impl Fn(&(RawValue, RawValue)) -> bool {
move |&(key2, _value)| key == key2
}