extern crate owning_ref;
extern crate parking_lot;
extern crate serde;
#[cfg(test)]
mod tests;
use owning_ref::{OwningHandle, OwningRef};
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use serde::{
de::MapAccess, de::Visitor, ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer,
};
use std::marker::PhantomData;
use std::borrow::Borrow;
use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hash, Hasher};
use std::sync::atomic::{self, AtomicUsize};
use std::{cmp, fmt, iter, mem, ops};
const ORDERING: atomic::Ordering = atomic::Ordering::Relaxed;
const LENGTH_MULTIPLIER: usize = 4;
const MAX_LOAD_FACTOR_NUM: usize = 100 - 15;
const MAX_LOAD_FACTOR_DENOM: usize = 100;
const DEFAULT_INITIAL_CAPACITY: usize = 64;
const MINIMUM_CAPACITY: usize = 8;
#[derive(Clone)]
enum Bucket<K, V> {
Contains(K, V),
Empty,
Removed,
}
impl<K, V> Bucket<K, V> {
fn is_empty(&self) -> bool {
if let Bucket::Empty = *self {
true
} else {
false
}
}
fn is_removed(&self) -> bool {
if let Bucket::Removed = *self {
true
} else {
false
}
}
fn is_free(&self) -> bool {
match *self {
Bucket::Removed | Bucket::Empty => true,
Bucket::Contains(..) => false,
}
}
fn value(self) -> Option<V> {
if let Bucket::Contains(_, val) = self {
Some(val)
} else {
None
}
}
fn value_ref(&self) -> Result<&V, ()> {
if let Bucket::Contains(_, ref val) = *self {
Ok(val)
} else {
Err(())
}
}
fn key_matches(&self, key: &K) -> bool
where
K: PartialEq,
{
if let Bucket::Contains(ref candidate_key, _) = *self {
candidate_key == key
} else {
false
}
}
}
struct Table<K, V, S> {
hash_builder: S,
buckets: Vec<RwLock<Bucket<K, V>>>,
}
impl<K, V> Table<K, V, RandomState> {
fn new(buckets: usize) -> Self {
let mut vec = Vec::with_capacity(buckets);
for _ in 0..buckets {
vec.push(RwLock::new(Bucket::Empty));
}
Table {
hash_builder: RandomState::new(),
buckets: vec,
}
}
fn with_capacity(cap: usize) -> Self {
Table::new(cmp::max(
MINIMUM_CAPACITY,
cap * MAX_LOAD_FACTOR_DENOM / MAX_LOAD_FACTOR_NUM + 1,
))
}
}
impl<K, V, S: BuildHasher> Table<K, V, S> {
fn with_hasher(buckets: usize, hash_builder: S) -> Self {
let mut vec = Vec::with_capacity(buckets);
for _ in 0..buckets {
vec.push(RwLock::new(Bucket::Empty));
}
Table {
hash_builder,
buckets: vec,
}
}
fn with_capacity_and_hasher(cap: usize, hash_builder: S) -> Self {
Table::with_hasher(
cmp::max(
MINIMUM_CAPACITY,
cap * MAX_LOAD_FACTOR_DENOM / MAX_LOAD_FACTOR_NUM + 1,
),
hash_builder,
)
}
}
impl<K: PartialEq + Hash, V, S: BuildHasher> Table<K, V, S> {
fn hash<T: ?Sized>(&self, key: &T) -> usize
where
T: Hash,
{
let mut hasher = self.hash_builder.build_hasher();
key.hash(&mut hasher);
hasher.finish() as usize
}
fn scan<F, Q: ?Sized>(&self, key: &Q, matches: F) -> RwLockReadGuard<Bucket<K, V>>
where
F: Fn(&Bucket<K, V>) -> bool,
K: Borrow<Q>,
Q: Hash,
{
let hash = self.hash(key);
for i in 0..self.buckets.len() {
let lock = self.buckets[(hash + i) % self.buckets.len()].read();
if matches(&lock) {
return lock;
}
}
panic!("`CHashMap` scan failed! No entry found.");
}
fn scan_mut<F, Q: ?Sized>(&self, key: &Q, matches: F) -> RwLockWriteGuard<Bucket<K, V>>
where
F: Fn(&Bucket<K, V>) -> bool,
K: Borrow<Q>,
Q: Hash,
{
let hash = self.hash(key);
for i in 0..self.buckets.len() {
let lock = self.buckets[(hash + i) % self.buckets.len()].write();
if matches(&lock) {
return lock;
}
}
panic!("`CHashMap` scan_mut failed! No entry found.");
}
fn scan_mut_no_lock<F>(&mut self, key: &K, matches: F) -> &mut Bucket<K, V>
where
F: Fn(&Bucket<K, V>) -> bool,
{
let hash = self.hash(key);
let len = self.buckets.len();
for i in 0..self.buckets.len() {
let idx = (hash + i) % len;
if {
let bucket = self.buckets[idx].get_mut();
matches(&bucket)
} {
return self.buckets[idx].get_mut();
}
}
panic!("`CHashMap` scan_mut_no_lock failed! No entry found.");
}
fn lookup_or_free(&self, key: &K) -> RwLockWriteGuard<Bucket<K, V>> {
let hash = self.hash(key);
let mut free = None;
for i in 0..self.buckets.len() {
let lock = self.buckets[(hash + i) % self.buckets.len()].write();
if lock.key_matches(key) {
return lock;
} else if lock.is_empty() {
return free.unwrap_or(lock);
} else if lock.is_removed() && free.is_none() {
free = Some(lock)
}
}
free.expect("No free buckets found")
}
fn lookup<Q: ?Sized>(&self, key: &Q) -> RwLockReadGuard<Bucket<K, V>>
where
K: Borrow<Q>,
Q: PartialEq + Hash,
{
self.scan(key, |x| match *x {
Bucket::Contains(ref candidate_key, _) if key.eq(candidate_key.borrow()) => true,
Bucket::Empty => true,
_ => false,
})
}
fn lookup_mut<Q: ?Sized>(&self, key: &Q) -> RwLockWriteGuard<Bucket<K, V>>
where
K: Borrow<Q>,
Q: PartialEq + Hash,
{
self.scan_mut(key, |x| match *x {
Bucket::Contains(ref candidate_key, _) if key.eq(candidate_key.borrow()) => true,
Bucket::Empty => true,
_ => false,
})
}
fn find_free(&self, key: &K) -> RwLockWriteGuard<Bucket<K, V>> {
self.scan_mut(key, |x| x.is_free())
}
fn find_free_no_lock(&mut self, key: &K) -> &mut Bucket<K, V> {
self.scan_mut_no_lock(key, |x| x.is_free())
}
fn fill(&mut self, table: Self) {
for i in table.buckets {
if let Bucket::Contains(key, val) = i.into_inner() {
let bucket = self.scan_mut_no_lock(&key, |x| match *x {
Bucket::Empty => true,
_ => false,
});
*bucket = Bucket::Contains(key, val);
}
}
}
}
impl<K: Clone, V: Clone, S: Clone> Clone for Table<K, V, S> {
fn clone(&self) -> Self {
Table {
hash_builder: self.hash_builder.clone(),
buckets: self
.buckets
.iter()
.map(|x| RwLock::new(x.read().clone()))
.collect(),
}
}
}
impl<K: fmt::Debug, V: fmt::Debug, S> fmt::Debug for Table<K, V, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut map = f.debug_map();
for i in &self.buckets {
let lock = i.read();
if let Bucket::Contains(ref key, ref val) = *lock {
map.entry(key, val);
}
}
map.finish()
}
}
pub struct IntoIter<K, V, S> {
table: Table<K, V, S>,
}
impl<K, V, S> Iterator for IntoIter<K, V, S> {
type Item = (K, V);
fn next(&mut self) -> Option<(K, V)> {
while let Some(bucket) = self.table.buckets.pop() {
if let Bucket::Contains(key, val) = bucket.into_inner() {
return Some((key, val));
}
}
None
}
}
impl<K, V, S> IntoIterator for Table<K, V, S> {
type Item = (K, V);
type IntoIter = IntoIter<K, V, S>;
fn into_iter(self) -> Self::IntoIter {
IntoIter { table: self }
}
}
pub struct ReadGuard<'a, K: 'a, V: 'a, S> {
inner: OwningRef<
OwningHandle<RwLockReadGuard<'a, Table<K, V, S>>, RwLockReadGuard<'a, Bucket<K, V>>>,
V,
>,
}
impl<'a, K, V, S> ops::Deref for ReadGuard<'a, K, V, S> {
type Target = V;
fn deref(&self) -> &V {
&self.inner
}
}
impl<'a, K, V: PartialEq, S> cmp::PartialEq for ReadGuard<'a, K, V, S> {
fn eq(&self, other: &ReadGuard<'a, K, V, S>) -> bool {
self == other
}
}
impl<'a, K, V: Eq, S> cmp::Eq for ReadGuard<'a, K, V, S> {}
impl<'a, K: fmt::Debug, V: fmt::Debug, S> fmt::Debug for ReadGuard<'a, K, V, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ReadGuard({:?})", &**self)
}
}
pub struct WriteGuard<'a, K: 'a, V: 'a, S> {
inner: OwningHandle<
OwningHandle<RwLockReadGuard<'a, Table<K, V, S>>, RwLockWriteGuard<'a, Bucket<K, V>>>,
&'a mut V,
>,
}
impl<'a, K, V, S> ops::Deref for WriteGuard<'a, K, V, S> {
type Target = V;
fn deref(&self) -> &V {
&self.inner
}
}
impl<'a, K, V, S> ops::DerefMut for WriteGuard<'a, K, V, S> {
fn deref_mut(&mut self) -> &mut V {
&mut self.inner
}
}
impl<'a, K, V: PartialEq, S> cmp::PartialEq for WriteGuard<'a, K, V, S> {
fn eq(&self, other: &Self) -> bool {
self == other
}
}
impl<'a, K, V: Eq, S> cmp::Eq for WriteGuard<'a, K, V, S> {}
impl<'a, K: fmt::Debug, V: fmt::Debug, S> fmt::Debug for WriteGuard<'a, K, V, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "WriteGuard({:?})", &**self)
}
}
pub struct CHashMap<K, V, S = RandomState> {
table: RwLock<Table<K, V, S>>,
len: AtomicUsize,
}
impl<K, V> CHashMap<K, V, RandomState> {
pub fn with_capacity(cap: usize) -> Self {
CHashMap {
len: AtomicUsize::new(0),
table: RwLock::new(Table::with_capacity(cap)),
}
}
pub fn new() -> Self {
CHashMap::with_capacity(DEFAULT_INITIAL_CAPACITY)
}
}
impl<K, V, S> CHashMap<K, V, S> {
pub fn len(&self) -> usize {
self.len.load(ORDERING)
}
pub fn capacity(&self) -> usize {
cmp::max(MINIMUM_CAPACITY, self.buckets()) * MAX_LOAD_FACTOR_NUM / MAX_LOAD_FACTOR_DENOM
}
pub fn buckets(&self) -> usize {
self.table.read().buckets.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[deprecated]
pub fn filter<F>(&self, predicate: F)
where
F: Fn(&K, &V) -> bool,
{
self.retain(predicate)
}
pub fn retain<F>(&self, predicate: F)
where
F: Fn(&K, &V) -> bool,
{
let table = self.table.read();
for bucket in &table.buckets {
let mut lock = bucket.write();
if match *lock {
Bucket::Contains(ref key, ref val) => !predicate(key, val),
_ => false,
} {
*lock = Bucket::Removed;
self.len.fetch_sub(1, ORDERING);
}
}
}
}
impl<K, V, S: Default + BuildHasher> CHashMap<K, V, S> {
pub fn with_hasher_and_capacity(cap: usize, hash_builder: S) -> Self {
CHashMap {
len: AtomicUsize::new(0),
table: RwLock::new(Table::with_capacity_and_hasher(cap, hash_builder)),
}
}
pub fn with_hasher(hash_builder: S) -> Self {
CHashMap::with_hasher_and_capacity(DEFAULT_INITIAL_CAPACITY, hash_builder)
}
}
impl<K, V, S> CHashMap<K, V, S>
where
S: Default + BuildHasher,
{
pub fn clear(&self) -> CHashMap<K, V, S> {
let mut lock = self.table.write();
CHashMap {
table: RwLock::new(mem::replace(
&mut *lock,
Table::with_hasher(DEFAULT_INITIAL_CAPACITY, S::default()),
)),
len: AtomicUsize::new(self.len.swap(0, ORDERING)),
}
}
}
impl<K: PartialEq + Hash, V, S: BuildHasher> CHashMap<K, V, S> {
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<ReadGuard<K, V, S>>
where
K: Borrow<Q>,
Q: Hash + PartialEq,
{
if let Ok(inner) = OwningRef::new(OwningHandle::new_with_fn(self.table.read(), |x| {
unsafe { &*x }.lookup(key)
}))
.try_map(|x| x.value_ref())
{
Some(ReadGuard { inner: inner })
} else {
None
}
}
pub fn get_mut<Q: ?Sized>(&self, key: &Q) -> Option<WriteGuard<K, V, S>>
where
K: Borrow<Q>,
Q: Hash + PartialEq,
{
if let Ok(inner) = OwningHandle::try_new(
OwningHandle::new_with_fn(self.table.read(), |x| unsafe { &*x }.lookup_mut(key)),
|x| {
if let &mut Bucket::Contains(_, ref mut val) =
unsafe { &mut *(x as *mut Bucket<K, V>) }
{
Ok(val)
} else {
Err(())
}
},
) {
Some(WriteGuard { inner: inner })
} else {
None
}
}
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + PartialEq,
{
let lock = self.table.read();
let bucket = lock.lookup(key);
!bucket.is_free()
}
}
impl<K, V, S> CHashMap<K, V, S>
where
K: PartialEq + Hash,
S: BuildHasher + Default,
{
pub fn insert_new(&self, key: K, val: V) {
debug_assert!(
!self.contains_key(&key),
"Hash table contains already key, contrary to \
the assumptions about `insert_new`'s arguments."
);
let lock = self.table.read();
{
let mut bucket = lock.find_free(&key);
*bucket = Bucket::Contains(key, val);
}
self.expand(lock);
}
pub fn insert(&self, key: K, val: V) -> Option<V> {
let ret;
let lock = self.table.read();
{
let mut bucket = lock.lookup_or_free(&key);
ret = mem::replace(&mut *bucket, Bucket::Contains(key, val)).value();
}
if ret.is_none() {
self.expand(lock);
}
ret
}
pub fn upsert<F, G>(&self, key: K, insert: F, update: G)
where
F: FnOnce() -> V,
G: FnOnce(&mut V),
{
let lock = self.table.read();
{
let mut bucket = lock.lookup_or_free(&key);
match *bucket {
Bucket::Contains(_, ref mut val) => {
update(val);
return;
}
ref mut x => *x = Bucket::Contains(key, insert()),
}
}
self.expand(lock);
}
pub fn alter<F>(&self, key: K, f: F)
where
F: FnOnce(Option<V>) -> Option<V>,
{
let lock = self.table.read();
{
let mut bucket = lock.lookup_or_free(&key);
match mem::replace(&mut *bucket, Bucket::Removed) {
Bucket::Contains(_, val) => {
if let Some(new_val) = f(Some(val)) {
*bucket = Bucket::Contains(key, new_val);
return;
} else {
self.len.fetch_sub(1, ORDERING);
return;
}
}
_ => {
if let Some(new_val) = f(None) {
*bucket = Bucket::Contains(key, new_val);
} else {
return;
}
}
}
}
self.expand(lock);
}
pub fn remove<Q: ?Sized>(&self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: PartialEq + Hash,
{
let lock = self.table.read();
let mut bucket = lock.lookup_mut(&key);
match &mut *bucket {
&mut Bucket::Removed | &mut Bucket::Empty => None,
bucket => {
self.len.fetch_sub(1, ORDERING);
mem::replace(bucket, Bucket::Removed).value()
}
}
}
pub fn reserve(&self, additional: usize) {
let len = (self.len() + additional) * LENGTH_MULTIPLIER;
let mut lock = self.table.write();
if lock.buckets.len() < len {
let table = mem::replace(
&mut *lock,
Table::with_capacity_and_hasher(len, S::default()),
);
lock.fill(table);
}
}
pub fn shrink_to_fit(&self) {
let mut lock = self.table.write();
let table = mem::replace(
&mut *lock,
Table::with_capacity_and_hasher(self.len(), S::default()),
);
lock.fill(table);
}
fn expand(&self, lock: RwLockReadGuard<Table<K, V, S>>) {
let len = self.len.fetch_add(1, ORDERING) + 1;
if len * MAX_LOAD_FACTOR_DENOM > lock.buckets.len() * MAX_LOAD_FACTOR_NUM {
drop(lock);
self.reserve(1);
}
}
}
impl<K, V, S> CHashMap<K, V, S>
where
K: Clone,
{
pub fn keys(&self) -> Vec<K> {
let mut result = Vec::<K>::with_capacity(self.len());
let lock = self.table.read();
{
for bucket in lock.buckets.iter() {
{
if let Bucket::Contains(ref key, _) = *bucket.read() {
result.push(key.clone());
}
}
}
}
result
}
}
impl<K: Serialize, V: Serialize, S> Serialize for CHashMap<K, V, S> {
fn serialize<T>(&self, serializer: T) -> Result<T::Ok, T::Error>
where
T: Serializer,
{
let lock = self.table.read();
let mut map_serializer = serializer.serialize_map(Some(self.len()))?;
{
for bucket in lock.buckets.iter() {
{
if let Bucket::Contains(ref key, ref value) = *bucket.read() {
map_serializer.serialize_entry(key, value)?;
}
}
}
}
map_serializer.end()
}
}
impl<'de, K: Deserialize<'de> + PartialEq + Hash, V: Deserialize<'de>, S> Deserialize<'de>
for CHashMap<K, V, S>
where
S: Default + BuildHasher,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(ChashMapVisitor::new())
}
}
impl<K, V, S: Default + BuildHasher> Default for CHashMap<K, V, S> {
fn default() -> Self {
CHashMap::with_hasher(S::default())
}
}
impl<K: Clone, V: Clone, S: Clone> Clone for CHashMap<K, V, S> {
fn clone(&self) -> Self {
CHashMap {
table: RwLock::new(self.table.read().clone()),
len: AtomicUsize::new(self.len.load(ORDERING)),
}
}
}
impl<K: fmt::Debug, V: fmt::Debug, S> fmt::Debug for CHashMap<K, V, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(*self.table.read()).fmt(f)
}
}
impl<K, V, S> IntoIterator for CHashMap<K, V, S> {
type Item = (K, V);
type IntoIter = IntoIter<K, V, S>;
fn into_iter(self) -> IntoIter<K, V, S> {
self.table.into_inner().into_iter()
}
}
impl<K: PartialEq + Hash, V, S: Default + BuildHasher> iter::FromIterator<(K, V)>
for CHashMap<K, V, S>
{
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let vec: Vec<_> = iter.into_iter().collect();
let len = vec.len();
let mut table = Table::with_capacity_and_hasher(len, S::default());
for (key, val) in vec {
let bucket = table.find_free_no_lock(&key);
*bucket = Bucket::Contains(key, val);
}
CHashMap {
table: RwLock::new(table),
len: AtomicUsize::new(len),
}
}
}
struct ChashMapVisitor<K, V, S = RandomState> {
marker: PhantomData<fn() -> CHashMap<K, V, S>>,
}
impl<K, V, S> ChashMapVisitor<K, V, S> {
fn new() -> Self {
ChashMapVisitor {
marker: PhantomData,
}
}
}
impl<'de, K, V, S> Visitor<'de> for ChashMapVisitor<K, V, S>
where
K: Deserialize<'de> + PartialEq + Hash,
V: Deserialize<'de>,
S: Default + BuildHasher,
{
type Value = CHashMap<K, V, S>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("CHashMap")
}
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let map = CHashMap::<K, V, S>::with_hasher_and_capacity(
access.size_hint().unwrap_or(0),
S::default(), );
while let Some((key, value)) = access.next_entry()? {
map.insert(key, value);
}
Ok(map)
}
}