extern crate parking_lot;
extern crate owning_ref;
#[cfg(test)]
mod tests;
use owning_ref::{OwningHandle, OwningRef};
use parking_lot::{RwLock, RwLockWriteGuard, RwLockReadGuard};
use std::collections::hash_map;
use std::hash::{Hash, Hasher, BuildHasher};
use std::sync::atomic::{self, AtomicUsize};
use std::{mem, ops, cmp, fmt, iter};
use std::borrow::Borrow;
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> {
hash_builder: hash_map::RandomState,
buckets: Vec<RwLock<Bucket<K, V>>>,
}
impl<K, V> Table<K, V> {
fn new(buckets: usize) -> Table<K, V> {
let mut vec = Vec::with_capacity(buckets);
for _ in 0..buckets {
vec.push(RwLock::new(Bucket::Empty));
}
Table {
hash_builder: hash_map::RandomState::new(),
buckets: vec,
}
}
fn with_capacity(cap: usize) -> Table<K, V> {
Table::new(cmp::max(MINIMUM_CAPACITY, cap * LENGTH_MULTIPLIER))
}
}
impl<K: PartialEq + Hash, V> Table<K, V> {
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: Table<K, V>) {
for i in table.buckets {
if let Bucket::Contains(key, val) = i.into_inner() {
let mut bucket = self.scan_mut_no_lock(&key, |x| match *x {
Bucket::Empty => true,
_ => false,
});
*bucket = Bucket::Contains(key, val);
}
}
}
}
impl<K: Clone, V: Clone> Clone for Table<K, V> {
fn clone(&self) -> Table<K, V> {
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> fmt::Debug for Table<K, V> {
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> {
table: Table<K, V>,
}
impl<K, V> Iterator for IntoIter<K, V> {
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> IntoIterator for Table<K, V> {
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
fn into_iter(self) -> IntoIter<K, V> {
IntoIter {
table: self,
}
}
}
pub struct ReadGuard<'a, K: 'a, V: 'a> {
inner: OwningRef<OwningHandle<RwLockReadGuard<'a, Table<K, V>>, RwLockReadGuard<'a, Bucket<K, V>>>, V>,
}
impl<'a, K, V> ops::Deref for ReadGuard<'a, K, V> {
type Target = V;
fn deref(&self) -> &V {
&self.inner
}
}
impl<'a, K, V: PartialEq> cmp::PartialEq for ReadGuard<'a, K, V> {
fn eq(&self, other: &ReadGuard<'a, K, V>) -> bool {
self == other
}
}
impl<'a, K, V: Eq> cmp::Eq for ReadGuard<'a, K, V> {}
impl<'a, K: fmt::Debug, V: fmt::Debug> fmt::Debug for ReadGuard<'a, K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ReadGuard({:?})", &**self)
}
}
pub struct WriteGuard<'a, K: 'a, V: 'a> {
inner: OwningHandle<OwningHandle<RwLockReadGuard<'a, Table<K, V>>, RwLockWriteGuard<'a, Bucket<K, V>>>, &'a mut V>,
}
impl<'a, K, V> ops::Deref for WriteGuard<'a, K, V> {
type Target = V;
fn deref(&self) -> &V {
&self.inner
}
}
impl<'a, K, V> ops::DerefMut for WriteGuard<'a, K, V> {
fn deref_mut(&mut self) -> &mut V {
&mut self.inner
}
}
impl<'a, K, V: PartialEq> cmp::PartialEq for WriteGuard<'a, K, V> {
fn eq(&self, other: &WriteGuard<'a, K, V>) -> bool {
self == other
}
}
impl<'a, K, V: Eq> cmp::Eq for WriteGuard<'a, K, V> {}
impl<'a, K: fmt::Debug, V: fmt::Debug> fmt::Debug for WriteGuard<'a, K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "WriteGuard({:?})", &**self)
}
}
pub struct CHashMap<K, V> {
table: RwLock<Table<K, V>>,
len: AtomicUsize,
}
impl<K, V> CHashMap<K, V> {
pub fn with_capacity(cap: usize) -> CHashMap<K, V> {
CHashMap {
len: AtomicUsize::new(0),
table: RwLock::new(Table::with_capacity(cap)),
}
}
pub fn new() -> CHashMap<K, V> {
CHashMap::with_capacity(DEFAULT_INITIAL_CAPACITY)
}
pub fn len(&self) -> usize {
self.len.load(ORDERING)
}
pub fn capacity(&self) -> usize {
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
}
pub fn clear(&self) -> CHashMap<K, V> {
let mut lock = self.table.write();
CHashMap {
table: RwLock::new(mem::replace(&mut *lock, Table::new(DEFAULT_INITIAL_CAPACITY))),
len: AtomicUsize::new(self.len.swap(0, ORDERING)),
}
}
#[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: PartialEq + Hash, V> CHashMap<K, V> {
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<ReadGuard<K, V>>
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>>
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()
}
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;
let mut lock = self.table.write();
if lock.buckets.len() < len * LENGTH_MULTIPLIER {
let table = mem::replace(&mut *lock, Table::with_capacity(len));
lock.fill(table);
}
}
pub fn shrink_to_fit(&self) {
let mut lock = self.table.write();
let table = mem::replace(&mut *lock, Table::with_capacity(self.len()));
lock.fill(table);
}
fn expand(&self, lock: RwLockReadGuard<Table<K, V>>) {
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> Default for CHashMap<K, V> {
fn default() -> CHashMap<K, V> {
CHashMap::new()
}
}
impl<K: Clone, V: Clone> Clone for CHashMap<K, V> {
fn clone(&self) -> CHashMap<K, V> {
CHashMap {
table: RwLock::new(self.table.read().clone()),
len: AtomicUsize::new(self.len.load(ORDERING)),
}
}
}
impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for CHashMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(*self.table.read()).fmt(f)
}
}
impl<K, V> IntoIterator for CHashMap<K, V> {
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
fn into_iter(self) -> IntoIter<K, V> {
self.table.into_inner().into_iter()
}
}
impl<K: PartialEq + Hash, V> iter::FromIterator<(K, V)> for CHashMap<K, V> {
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> CHashMap<K, V> {
let vec: Vec<_> = iter.into_iter().collect();
let len = vec.len();
let mut table = Table::with_capacity(len);
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),
}
}
}