Added extracted code from ccl. Hello new repo.

This commit is contained in:
Acrimon 2019-08-26 20:08:21 +02:00
parent f3ff93747d
commit 643ee5b9ae
6 changed files with 1334 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock

26
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,26 @@
image: 'rust:latest'
stages:
- rustfmt
- test
rustfmt:
stage: rustfmt
script:
- rustup install stable
- rustup component add rustfmt --toolchain stable-x86_64-unknown-linux-gnu
- cargo fmt --version
- cargo fmt -- --check
test:
stage: test
when: delayed
start_in: 15 seconds
script:
- rustc --version
- cargo --version
- cargo test --verbose
cache:
paths:
- target/

32
Cargo.toml Normal file
View File

@ -0,0 +1,32 @@
[package]
name = "dashmap"
version = "1.0.0"
authors = ["acrimon <joel.wejdenstal@gmail.com>"]
edition = "2018"
license = "MIT"
repository = "https://gitlab.nebulanet.cc/xacrimon/dashmap"
homepage = "https://gitlab.nebulanet.cc/xacrimon/dashmap"
description = "Extremely fast concurrent map."
readme = "README.md"
documentation = "https://docs.rs/dashmap"
keywords = ["atomic", "concurrent", "hashmap"]
categories = ["concurrency", "algorithms", "data-structures"]
[package.metadata.docs.rs]
rustdoc-args = ["--html-in-header", ".cargo/registry/src/github.com-1ecc6299db9ec823/pwnies-0.0.14/pwnies.html"]
[features]
nightly = ["parking_lot/nightly", "hashbrown/nightly"]
[dependencies]
hashbrown = "0.6.0"
parking_lot = { version = "0.9.0", features = ["owning_ref"] }
num_cpus = "1.10.1"
seahash = "3.0.6"
owning_ref = "0.4.0"
slab = "0.4.2"
stable_deref_trait = "1.1.1"
futures-preview = "=0.3.0-alpha.17"
[dev-dependencies]
rayon = "1.1.0"

302
src/fut_rwlock.rs Normal file
View File

@ -0,0 +1,302 @@
use parking_lot::Mutex as RegularMutex;
use parking_lot::RwLock as RegularRwLock;
use parking_lot::RwLockReadGuard as RegularRwLockReadGuard;
use parking_lot::RwLockWriteGuard as RegularRwLockWriteGuard;
use slab::Slab;
use stable_deref_trait::StableDeref;
use std::cell::UnsafeCell;
use std::future::Future;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
use std::time::Duration;
const WAIT_KEY_NONE: usize = std::usize::MAX;
enum Waiter {
Waiting(Waker),
Woken,
}
impl Waiter {
#[inline]
fn register(&mut self, w: &Waker) {
match self {
Waiter::Waiting(waker) if w.will_wake(waker) => {}
_ => *self = Waiter::Waiting(w.clone()),
}
}
#[inline]
fn wake(&mut self) {
match mem::replace(self, Waiter::Woken) {
Waiter::Waiting(waker) => waker.wake(),
Waiter::Woken => {}
}
}
}
pub struct RwLockReadGuard<'a, T> {
_inner_guard: Option<RegularRwLockReadGuard<'a, ()>>,
lock: &'a RwLock<T>,
}
impl<'a, T> Deref for RwLockReadGuard<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { &*self.lock.data.get() }
}
}
impl<'a, T> Drop for RwLockReadGuard<'a, T> {
#[inline]
fn drop(&mut self) {
drop(self._inner_guard.take());
let mut waiters = self.lock.waiters.lock();
if let Some((_i, waiter)) = waiters.iter_mut().next() {
waiter.wake();
}
}
}
pub struct RwLockWriteGuard<'a, T> {
_inner_guard: Option<RegularRwLockWriteGuard<'a, ()>>,
lock: &'a RwLock<T>,
}
impl<'a, T> Deref for RwLockWriteGuard<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { &*self.lock.data.get() }
}
}
impl<'a, T> DerefMut for RwLockWriteGuard<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.lock.data.get() }
}
}
impl<'a, T> Drop for RwLockWriteGuard<'a, T> {
#[inline]
fn drop(&mut self) {
drop(self._inner_guard.take());
let mut waiters = self.lock.waiters.lock();
if let Some((_i, waiter)) = waiters.iter_mut().next() {
waiter.wake();
}
}
}
pub struct RwLock<T> {
lock: RegularRwLock<()>,
waiters: RegularMutex<Slab<Waiter>>,
data: UnsafeCell<T>,
}
impl<T> RwLock<T> {
fn remove_waker(&self, wait_key: usize, wake_another: bool) {
if wait_key != WAIT_KEY_NONE {
let mut waiters = self.waiters.lock();
match waiters.remove(wait_key) {
Waiter::Waiting(_) => {}
Waiter::Woken => {
// We were awoken, but then dropped before we could
// wake up to acquire the lock. Wake up another
// waiter.
if wake_another {
if let Some((_i, waiter)) = waiters.iter_mut().next() {
waiter.wake();
}
}
}
}
}
}
pub fn new(data: T) -> Self {
Self {
lock: RegularRwLock::new(()),
waiters: RegularMutex::new(Slab::new()),
data: UnsafeCell::new(data),
}
}
#[inline]
pub fn try_read(&self) -> Option<RwLockReadGuard<'_, T>> {
self.lock.try_read().map(|guard| RwLockReadGuard {
_inner_guard: Some(guard),
lock: self,
})
}
#[inline]
pub fn try_read_for(&self, d: Duration) -> Option<RwLockReadGuard<'_, T>> {
self.lock.try_read_for(d).map(|guard| RwLockReadGuard {
_inner_guard: Some(guard),
lock: self,
})
}
#[inline]
pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T>> {
self.lock.try_write().map(|guard| RwLockWriteGuard {
_inner_guard: Some(guard),
lock: self,
})
}
#[inline]
pub fn try_write_for(&self, d: Duration) -> Option<RwLockWriteGuard<'_, T>> {
self.lock.try_write_for(d).map(|guard| RwLockWriteGuard {
_inner_guard: Some(guard),
lock: self,
})
}
#[inline]
pub fn read(&self) -> RwLockReadGuard<'_, T> {
RwLockReadGuard {
_inner_guard: Some(self.lock.read()),
lock: self,
}
}
#[inline]
pub fn write(&self) -> RwLockWriteGuard<'_, T> {
RwLockWriteGuard {
_inner_guard: Some(self.lock.write()),
lock: self,
}
}
#[inline]
pub fn async_read(&self) -> RwLockReadFuture<'_, T> {
RwLockReadFuture {
lock: Some(self),
wait_key: WAIT_KEY_NONE,
}
}
#[inline]
pub fn async_write(&self) -> RwLockWriteFuture<'_, T> {
RwLockWriteFuture {
lock: Some(self),
wait_key: WAIT_KEY_NONE,
}
}
}
pub struct RwLockReadFuture<'a, T> {
lock: Option<&'a RwLock<T>>,
wait_key: usize,
}
impl<'a, T> Drop for RwLockReadFuture<'a, T> {
#[inline]
fn drop(&mut self) {
if let Some(lock) = self.lock {
lock.remove_waker(self.wait_key, true);
}
}
}
impl<'a, T> Future for RwLockReadFuture<'a, T> {
type Output = RwLockReadGuard<'a, T>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let lock = self.lock.expect("polled after completion");
if let Some(guard) = lock.try_read() {
lock.remove_waker(self.wait_key, false);
self.lock = None;
return Poll::Ready(guard);
}
{
let mut waiters = lock.waiters.lock();
if self.wait_key == WAIT_KEY_NONE {
self.wait_key = waiters.insert(Waiter::Waiting(cx.waker().clone()));
} else {
waiters[self.wait_key].register(cx.waker())
}
}
if let Some(guard) = lock.try_read() {
lock.remove_waker(self.wait_key, false);
self.lock = None;
return Poll::Ready(guard);
}
Poll::Pending
}
}
pub struct RwLockWriteFuture<'a, T> {
lock: Option<&'a RwLock<T>>,
wait_key: usize,
}
impl<'a, T> Drop for RwLockWriteFuture<'a, T> {
#[inline]
fn drop(&mut self) {
if let Some(lock) = self.lock {
lock.remove_waker(self.wait_key, true);
}
}
}
impl<'a, T> Future for RwLockWriteFuture<'a, T> {
type Output = RwLockWriteGuard<'a, T>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let lock = self.lock.expect("polled after completion");
if let Some(guard) = lock.try_write() {
lock.remove_waker(self.wait_key, false);
self.lock = None;
return Poll::Ready(guard);
}
{
let mut waiters = lock.waiters.lock();
if self.wait_key == WAIT_KEY_NONE {
self.wait_key = waiters.insert(Waiter::Waiting(cx.waker().clone()));
} else {
waiters[self.wait_key].register(cx.waker())
}
}
if let Some(guard) = lock.try_write() {
lock.remove_waker(self.wait_key, false);
self.lock = None;
return Poll::Ready(guard);
}
Poll::Pending
}
}
unsafe impl<T: Send> Send for RwLock<T> {}
unsafe impl<T: Sync> Sync for RwLock<T> {}
unsafe impl<T: Send> Send for RwLockReadFuture<'_, T> {}
unsafe impl<T: Send> Sync for RwLockReadFuture<'_, T> {}
unsafe impl<T: Send> Send for RwLockWriteFuture<'_, T> {}
unsafe impl<T: Send> Sync for RwLockWriteFuture<'_, T> {}
unsafe impl<T: Send> Send for RwLockReadGuard<'_, T> {}
unsafe impl<T: Sync> Sync for RwLockReadGuard<'_, T> {}
unsafe impl<T: Send> Send for RwLockWriteGuard<'_, T> {}
unsafe impl<T: Sync> Sync for RwLockWriteGuard<'_, T> {}
unsafe impl<T> StableDeref for RwLockReadGuard<'_, T> {}
unsafe impl<T> StableDeref for RwLockWriteGuard<'_, T> {}

959
src/lib.rs Normal file
View File

@ -0,0 +1,959 @@
//! Please see the struct level documentation.
mod fut_rwlock;
mod util;
use fut_rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use futures::future::{Future, FutureExt};
use hashbrown::HashMap;
use owning_ref::{OwningRef, OwningRefMut};
use seahash::SeaHasher;
use std::borrow::Borrow;
use std::convert::TryInto;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use std::time::Duration;
use util::map_in_place;
/// DashMap is a threadsafe, versatile and concurrent hashmap with good performance and is balanced for both reads and writes.
///
/// The API mostly matches that of the standard library hashmap but there are some
/// differences to due to the design.
///
/// One of those limits is iteration, you cannot iterate over the elements directly.
/// Instead you have to iterate over chunks which can iterate over KV pairs.
/// This is needed in order to use the calling thread stack as scratch space to avoid heap allocations.
///
/// The iter method currently provides a more ergonomic iterator that is slightly less performant.
/// It should be extremely performant still but it is a tad slower than using the chunks interface.
///
/// Unsafe is used to avoid bounds checking when accessing chunks.
/// This is guaranteed to be safe since we cannot possibly get a value higher than the amount of chunks.
/// The amount of chunks cannot be altered after creation in any way.
///
/// This map is not lockfree but uses some clever locking internally. It has good average case performance
///
/// You should not rely on being able to hold any combination of references involving a mutable one as it may cause a deadlock.
/// This will be fixed in the future.
pub struct DashMap<K, V>
where
K: Hash + Eq,
{
ncb: usize,
submaps: Box<[RwLock<HashMap<K, V>>]>,
}
impl<'a, K: 'a, V: 'a> DashMap<K, V>
where
K: Hash + Eq,
{
/// Create a new DashMap.
/// If you do not have specific requirements and understand the code you should probably call `DashMap::default` instead. It will determine
/// the optimal parameters automagically.
/// The amount of chunks used is based on the formula 2^n where n is the value passed. The default method will automagically determine the optimal amount.
///
/// Will panic if the first parameter plugged into the formula 2^n produces a result higher than isize::MAX.
pub fn new(num_chunks_log_2: u8) -> Self {
let ncm = 1 << num_chunks_log_2 as usize;
Self {
ncb: num_chunks_log_2 as usize,
submaps: (0..ncm)
.map(|_| RwLock::new(HashMap::new()))
.collect::<Vec<_>>()
.into_boxed_slice(),
}
}
/// Create a new DashMap with a specified capacity.
///
/// Will panic if the first parameter plugged into the formula 2^n produces a result higher than isize::MAX.
pub fn with_capacity(num_chunks_log_2: u8, capacity: usize) -> Self {
let ncm = 1 << num_chunks_log_2 as usize;
let cpm = capacity / ncm;
Self {
ncb: num_chunks_log_2 as usize,
submaps: (0..ncm)
.map(|_| RwLock::new(HashMap::with_capacity(cpm)))
.collect::<Vec<_>>()
.into_boxed_slice(),
}
}
/// Insert an element into the map.
#[inline]
pub fn insert(&self, key: K, value: V) {
let mapi = self.determine_map(&key);
let mut submap = unsafe { self.submaps.get_unchecked(mapi).write() };
submap.insert(key, value);
}
/// Get or insert an element into the map if one does not exist.
#[inline]
pub fn get_or_insert(&'a self, key: &K, default: V) -> DashMapRefAny<'a, K, V>
where
K: Clone,
{
let key = key.borrow();
let mapi = self.determine_map(key);
{
let submap = unsafe { self.submaps.get_unchecked(mapi).read() };
if submap.contains_key(key) {
let or = OwningRef::new(submap);
let or = or.map(|v| v.get(key).unwrap());
return DashMapRefAny::Shared(DashMapRef { ptr: or });
}
}
let mut submap = unsafe { self.submaps.get_unchecked(mapi).write() };
if !submap.contains_key(key) {
submap.insert(key.clone(), default);
}
let or = OwningRefMut::new(submap);
let or = or.map_mut(|v| v.get_mut(key).unwrap());
DashMapRefAny::Unique(DashMapRefMut { ptr: or })
}
/// Get or insert an element into the map if one does not exist.
#[inline]
pub fn get_or_insert_with<F: FnOnce() -> V>(
&'a self,
key: &K,
default: F,
) -> DashMapRefAny<'a, K, V>
where
K: Clone,
{
let mapi = self.determine_map(key);
{
let submap = unsafe { self.submaps.get_unchecked(mapi).read() };
if submap.contains_key(key) {
let or = OwningRef::new(submap);
let or = or.map(|v| v.get(key).unwrap());
return DashMapRefAny::Shared(DashMapRef { ptr: or });
}
}
let mut submap = unsafe { self.submaps.get_unchecked(mapi).write() };
if !submap.contains_key(key) {
submap.insert(key.clone(), default());
}
let or = OwningRefMut::new(submap);
let or = or.map_mut(|v| v.get_mut(key).unwrap());
DashMapRefAny::Unique(DashMapRefMut { ptr: or })
}
/// Check if the map contains the specified key.
#[inline]
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mapi = self.determine_map(key);
let submap = unsafe { self.submaps.get_unchecked(mapi).read() };
submap.contains_key(&key)
}
#[inline]
pub fn get_raw_from_key<Q>(&'a self, key: &Q) -> RwLockReadGuard<'a, HashMap<K, V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mapi = self.determine_map(key);
unsafe { self.submaps.get_unchecked(mapi).read() }
}
#[inline]
pub fn get_raw_mut_from_key<Q>(&'a self, key: &Q) -> RwLockWriteGuard<'a, HashMap<K, V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mapi = self.determine_map(key);
unsafe { self.submaps.get_unchecked(mapi).write() }
}
/// Get a shared reference to an element contained within the map.
#[inline]
pub fn get<Q>(&'a self, key: &Q) -> Option<DashMapRef<'a, K, V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mapi = self.determine_map(key);
let submap = unsafe { self.submaps.get_unchecked(mapi).read() };
if submap.contains_key(&key) {
let or = OwningRef::new(submap);
let or = or.map(|v| v.get(key).unwrap());
Some(DashMapRef { ptr: or })
} else {
None
}
}
#[inline]
pub fn async_get<Q>(&'a self, key: Q) -> impl Future<Output = Option<DashMapRef<'a, K, V>>>
where
K: Borrow<Q>,
Q: Hash + Eq + Sized,
{
let mapi = self.determine_map(&key);
let submapfut = unsafe { self.submaps.get_unchecked(mapi).async_read() };
submapfut.map(move |submap| {
if submap.contains_key(&key) {
let or = OwningRef::new(submap);
let or = or.map(|v| v.get(&key).unwrap());
Some(DashMapRef { ptr: or })
} else {
None
}
})
}
/// Same as above but will return an error if the method would block at the current time.
#[inline]
pub fn try_get<Q>(&'a self, key: &Q) -> TryGetResult<DashMapRef<'a, K, V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mapi = self.determine_map(&key);
if let Some(submap) = unsafe { self.submaps.get_unchecked(mapi).try_read() } {
if submap.contains_key(&key) {
let or = OwningRef::new(submap);
let or = or.map(|v| v.get(key).unwrap());
Ok(DashMapRef { ptr: or })
} else {
Err(TryGetError::InvalidKey)
}
} else {
Err(TryGetError::WouldBlock)
}
}
/// Same as above but will return an error if the method would block at the current time.
#[inline]
pub fn try_get_with_timeout<Q>(
&'a self,
key: &Q,
timeout: Duration,
) -> TryGetResult<DashMapRef<'a, K, V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mapi = self.determine_map(&key);
if let Some(submap) = unsafe { self.submaps.get_unchecked(mapi).try_read_for(timeout) } {
if submap.contains_key(&key) {
let or = OwningRef::new(submap);
let or = or.map(|v| v.get(key).unwrap());
Ok(DashMapRef { ptr: or })
} else {
Err(TryGetError::InvalidKey)
}
} else {
Err(TryGetError::DidNotResolve)
}
}
/// Shortcut for a get followed by an unwrap.
#[inline]
pub fn index<Q>(&'a self, key: &Q) -> DashMapRef<'a, K, V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.get(key).expect("Key did not exist in map")
}
/// Get a unique reference to an element contained within the map.
#[inline]
pub fn get_mut<Q>(&'a self, key: &Q) -> Option<DashMapRefMut<'a, K, V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mapi = self.determine_map(&key);
let submap = unsafe { self.submaps.get_unchecked(mapi).write() };
if submap.contains_key(&key) {
let or = OwningRefMut::new(submap);
let or = or.map_mut(|v| v.get_mut(key).unwrap());
Some(DashMapRefMut { ptr: or })
} else {
None
}
}
#[inline]
pub fn async_get_mut<Q>(
&'a self,
key: Q,
) -> impl Future<Output = Option<DashMapRefMut<'a, K, V>>>
where
K: Borrow<Q>,
Q: Hash + Eq + Sized,
{
let mapi = self.determine_map(&key);
let submapfut = unsafe { self.submaps.get_unchecked(mapi).async_write() };
submapfut.map(move |submap| {
if submap.contains_key(&key) {
let or = OwningRefMut::new(submap);
let or = or.map_mut(|v| v.get_mut(&key).unwrap());
Some(DashMapRefMut { ptr: or })
} else {
None
}
})
}
/// Same as above but will return an error if the method would block at the current time.
#[inline]
pub fn try_get_mut<Q>(&'a self, key: &Q) -> TryGetResult<DashMapRefMut<'a, K, V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mapi = self.determine_map(&key);
if let Some(submap) = unsafe { self.submaps.get_unchecked(mapi).try_write() } {
if submap.contains_key(&key) {
let or = OwningRefMut::new(submap);
let or = or.map_mut(|v| v.get_mut(key).unwrap());
Ok(DashMapRefMut { ptr: or })
} else {
Err(TryGetError::InvalidKey)
}
} else {
Err(TryGetError::WouldBlock)
}
}
/// Same as above but will return an error if the method would block at the current time.
#[inline]
pub fn try_get_mut_with_timeout<Q>(
&'a self,
key: &Q,
timeout: Duration,
) -> TryGetResult<DashMapRefMut<'a, K, V>>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mapi = self.determine_map(&key);
if let Some(submap) = unsafe { self.submaps.get_unchecked(mapi).try_write_for(timeout) } {
if submap.contains_key(&key) {
let or = OwningRefMut::new(submap);
let or = or.map_mut(|v| v.get_mut(key).unwrap());
Ok(DashMapRefMut { ptr: or })
} else {
Err(TryGetError::InvalidKey)
}
} else {
Err(TryGetError::DidNotResolve)
}
}
/// Shortcut for a get_mut followed by an unwrap.
#[inline]
pub fn index_mut<Q>(&'a self, key: &Q) -> DashMapRefMut<'a, K, V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
self.get_mut(key).expect("Key did not exist in map")
}
/// Get the amount of elements stored within the map.
#[inline]
pub fn len(&self) -> usize {
self.submaps.iter().map(|s| s.read().len()).sum()
}
/// Check if the map is empty.
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Remove an element from the map if it exists. Will return the K, V pair.
#[inline]
pub fn remove<Q>(&self, key: &Q) -> Option<(K, V)>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mapi = self.determine_map(&key);
let mut submap = unsafe { self.submaps.get_unchecked(mapi).write() };
submap.remove_entry(key)
}
/// Retain all elements that the specified function returns `true` for.
#[inline]
pub fn retain<F: Clone + FnMut(&K, &mut V) -> bool>(&self, f: F) {
self.submaps.iter().for_each(|locked| {
let mut submap = locked.write();
submap.retain(f.clone());
});
}
/// Clear all elements from the map.
#[inline]
pub fn clear(&self) {
self.submaps.iter().for_each(|locked| {
let mut submap = locked.write();
submap.clear();
});
}
/// Apply a function to a a specified entry in the map.
#[inline]
pub fn alter<Q, F: FnOnce(V) -> V>(&self, k: &Q, f: F)
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let v = self.get_mut(k);
if let Some(mut v) = v {
unsafe {
map_in_place(&mut *v, f);
}
}
}
/// Apply a function to every item in the map.
#[inline]
pub fn alter_all<F: FnMut(V) -> V + Clone>(&self, f: F) {
self.chunks_write().for_each(|mut t| {
t.iter_mut().for_each(|v| unsafe {
map_in_place(&mut *v.1, f.clone());
})
});
}
/// Iterate over the (K, V) pairs stored in the map immutably.
#[inline]
pub fn iter(&'a self) -> Iter<'a, K, V> {
Iter::new(self)
}
/// Iterate over the (K, V) pairs stored in the map mutably.
#[inline]
pub fn iter_mut(&'a self) -> IterMut<'a, K, V> {
IterMut::new(self)
}
/// Iterate over chunks in a read only fashion.
#[inline]
pub fn chunks(&self) -> impl Iterator<Item = Chunk<K, V>> {
self.submaps.iter().map(|t| Chunk::new(t.read()))
}
/// Iterate over chunks in a read-write fashion.
#[inline]
pub fn chunks_write(&self) -> impl Iterator<Item = ChunkMut<K, V>> {
self.submaps.iter().map(|t| ChunkMut::new(t.write()))
}
#[inline]
pub(crate) fn determine_map<Q>(&self, key: &Q) -> usize
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mut hash_state = SeaHasher::new();
key.hash(&mut hash_state);
let hash = hash_state.finish();
let shift = util::ptr_size_bits() - self.ncb;
(hash >> shift) as usize
}
#[inline]
pub fn chunks_count(&self) -> usize {
self.submaps.len()
}
}
impl<K, V> Default for DashMap<K, V>
where
K: Hash + Eq,
{
/// Creates a new DashMap and automagically determines the optimal amount of chunks.
fn default() -> Self {
let vcount = num_cpus::get() * 8;
let base: usize = 2;
let mut p2exp: u32 = 1;
loop {
if vcount <= base.pow(p2exp) {
return Self::new(p2exp.try_into().unwrap());
} else {
p2exp += 1;
}
}
}
}
/// A shared reference into a DashMap created from an iterator.
pub struct DashMapIterRef<'a, K, V>
where
K: Hash + Eq,
{
guard: Option<Arc<RwLockReadGuard<'a, HashMap<K, V>>>>,
ptr_k: &'a K,
ptr_v: &'a V,
}
impl<'a, K, V> DashMapIterRef<'a, K, V>
where
K: Hash + Eq,
{
/// Get the key of the entry.
#[inline]
pub fn key(&self) -> &K {
self.ptr_k
}
/// Get the value of the entry.
#[inline]
pub fn value(&self) -> &V {
self.ptr_v
}
}
impl<'a, K, V> Drop for DashMapIterRef<'a, K, V>
where
K: Hash + Eq,
{
#[inline]
fn drop(&mut self) {
self.guard.take();
}
}
impl<'a, K, V> Deref for DashMapIterRef<'a, K, V>
where
K: Hash + Eq,
{
type Target = V;
#[inline]
fn deref(&self) -> &V {
self.ptr_v
}
}
/// An immutable iterator over a DashMap.
#[allow(clippy::type_complexity)]
pub struct Iter<'a, K, V>
where
K: Hash + Eq,
{
c_map_index: usize,
map: &'a DashMap<K, V>,
c_iter: Option<(
Arc<RwLockReadGuard<'a, HashMap<K, V>>>,
hashbrown::hash_map::Iter<'a, K, V>,
)>,
}
impl<'a, K, V> Iter<'a, K, V>
where
K: Hash + Eq,
{
fn new(map: &'a DashMap<K, V>) -> Self {
Self {
c_map_index: 0,
map,
c_iter: None,
}
}
fn slow_path_new_chunk(&mut self) -> Option<DashMapIterRef<'a, K, V>> {
if self.c_map_index == self.map.submaps.len() {
return None;
}
let guard = Arc::into_raw(Arc::new(self.map.submaps[self.c_map_index].read()));
let iter = unsafe { (&*guard).iter() };
std::mem::replace(
&mut self.c_iter,
Some((unsafe { Arc::from_raw(guard) }, iter)),
);
self.c_map_index += 1;
self.next()
}
}
impl<'a, K, V> Iterator for Iter<'a, K, V>
where
K: Hash + Eq,
{
type Item = DashMapIterRef<'a, K, V>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if let Some(c_iter) = &mut self.c_iter {
if let Some(i) = c_iter.1.next() {
let guard = Some(c_iter.0.clone());
let ptr_k = unsafe { &*(i.0 as *const _) };
let ptr_v = unsafe { &*(i.1 as *const _) };
return Some(DashMapIterRef {
guard,
ptr_k,
ptr_v,
});
}
}
self.slow_path_new_chunk()
}
}
/// A shared reference into a DashMap created from an iterator.
pub struct DashMapIterRefMut<'a, K, V>
where
K: Hash + Eq,
{
guard: Option<Arc<RwLockWriteGuard<'a, HashMap<K, V>>>>,
ptr_k: &'a K,
ptr_v: &'a mut V,
}
impl<'a, K, V> DashMapIterRefMut<'a, K, V>
where
K: Hash + Eq,
{
/// Get the key of the entry.
#[inline]
pub fn key(&self) -> &K {
self.ptr_k
}
/// Get the value of the entry.
#[inline]
pub fn value(&mut self) -> &mut V {
self.ptr_v
}
}
impl<'a, K, V> Drop for DashMapIterRefMut<'a, K, V>
where
K: Hash + Eq,
{
#[inline]
fn drop(&mut self) {
self.guard.take();
}
}
impl<'a, K, V> Deref for DashMapIterRefMut<'a, K, V>
where
K: Hash + Eq,
{
type Target = V;
#[inline]
fn deref(&self) -> &V {
self.ptr_v
}
}
impl<'a, K, V> DerefMut for DashMapIterRefMut<'a, K, V>
where
K: Hash + Eq,
{
#[inline]
fn deref_mut(&mut self) -> &mut V {
self.ptr_v
}
}
/// An mutable iterator over a DashMap.
#[allow(clippy::type_complexity)]
pub struct IterMut<'a, K, V>
where
K: Hash + Eq,
{
c_map_index: usize,
map: &'a DashMap<K, V>,
c_iter: Option<(
Arc<RwLockWriteGuard<'a, HashMap<K, V>>>,
hashbrown::hash_map::IterMut<'a, K, V>,
)>,
}
impl<'a, K, V> IterMut<'a, K, V>
where
K: Hash + Eq,
{
fn new(map: &'a DashMap<K, V>) -> Self {
Self {
c_map_index: 0,
map,
c_iter: None,
}
}
fn slow_path_new_chunk(&mut self) -> Option<DashMapIterRefMut<'a, K, V>> {
if self.c_map_index == self.map.submaps.len() {
return None;
}
let guard: *mut RwLockWriteGuard<'_, HashMap<K, V>> =
Arc::into_raw(Arc::new(self.map.submaps[self.c_map_index].write())) as _;
let gr: &mut RwLockWriteGuard<'_, HashMap<K, V>> = unsafe { &mut *guard };
let iter = gr.iter_mut();
std::mem::replace(
&mut self.c_iter,
Some((unsafe { Arc::from_raw(guard) }, iter)),
);
self.c_map_index += 1;
self.next()
}
}
impl<'a, K, V> Iterator for IterMut<'a, K, V>
where
K: Hash + Eq,
{
type Item = DashMapIterRefMut<'a, K, V>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if let Some(c_iter) = &mut self.c_iter {
if let Some(i) = c_iter.1.next() {
let guard = Some(c_iter.0.clone());
let ptr_k = unsafe { &*(i.0 as *const _) };
let ptr_v = unsafe { &mut *(i.1 as *mut _) };
return Some(DashMapIterRefMut {
guard,
ptr_k,
ptr_v,
});
}
}
self.slow_path_new_chunk()
}
}
/// A read only iterator interface to a chunk.
pub struct Chunk<'a, K, V>
where
K: Hash + Eq,
{
inner: RwLockReadGuard<'a, HashMap<K, V>>,
}
impl<'a, K: 'a, V: 'a> Chunk<'a, K, V>
where
K: Hash + Eq,
{
#[inline]
fn new(inner: RwLockReadGuard<'a, HashMap<K, V>>) -> Self {
Self { inner }
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
self.inner.iter()
}
}
/// A read-write iterator interface to a chunk.
pub struct ChunkMut<'a, K, V>
where
K: Hash + Eq,
{
inner: RwLockWriteGuard<'a, HashMap<K, V>>,
}
impl<'a, K: 'a, V: 'a> ChunkMut<'a, K, V>
where
K: Hash + Eq,
{
#[inline]
fn new(inner: RwLockWriteGuard<'a, HashMap<K, V>>) -> Self {
Self { inner }
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
self.inner.iter()
}
#[inline]
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
self.inner.iter_mut()
}
}
/// A shared reference into a DashMap.
pub struct DashMapRef<'a, K, V>
where
K: Hash + Eq,
{
ptr: OwningRef<RwLockReadGuard<'a, HashMap<K, V>>, V>,
}
impl<'a, K, V> Deref for DashMapRef<'a, K, V>
where
K: Hash + Eq,
{
type Target = V;
#[inline]
fn deref(&self) -> &V {
&*self.ptr
}
}
/// A unique reference into a DashMap.
pub struct DashMapRefMut<'a, K, V>
where
K: Hash + Eq,
{
ptr: OwningRefMut<RwLockWriteGuard<'a, HashMap<K, V>>, V>,
}
impl<'a, K, V> Deref for DashMapRefMut<'a, K, V>
where
K: Hash + Eq,
{
type Target = V;
#[inline]
fn deref(&self) -> &V {
&*self.ptr
}
}
impl<'a, K, V> DerefMut for DashMapRefMut<'a, K, V>
where
K: Hash + Eq,
{
#[inline]
fn deref_mut(&mut self) -> &mut V {
&mut *self.ptr
}
}
/// A unique reference into a DashMap.
pub enum DashMapRefAny<'a, K, V>
where
K: Hash + Eq,
{
Shared(DashMapRef<'a, K, V>),
Unique(DashMapRefMut<'a, K, V>),
Marker(PhantomData<&'a K>, PhantomData<&'a V>),
}
impl<'a, K, V> Deref for DashMapRefAny<'a, K, V>
where
K: Hash + Eq,
{
type Target = V;
#[inline]
fn deref(&self) -> &V {
match self {
DashMapRefAny::Shared(r) => &*r,
DashMapRefAny::Unique(r) => &*r,
DashMapRefAny::Marker(_, _) => unreachable!(),
}
}
}
/// A error possibly returned by the try_get family of methods for DashMap.
pub enum TryGetError {
/// Returned if the key did not exist in the map.
InvalidKey,
/// Returned if the operation was going to block.
WouldBlock,
/// Returned if the lock did not become available within the specified timeout.
DidNotResolve,
}
/// Alias for a Result with TryGetError as it's error type.
pub type TryGetResult<T> = Result<T, TryGetError>;
#[cfg(test)]
mod tests {
use super::*;
fn use_map(mut e: DashMapRefMut<i32, i32>) {
*e *= 2;
}
#[test]
fn move_deref() {
let map = DashMap::default();
map.insert(3, 69);
let e = map.index_mut(&3);
use_map(e);
println!("e: {}", *map.index_mut(&3));
}
#[test]
fn insert_then_assert_1024() {
let map = DashMap::default();
for i in 0..1024_i32 {
map.insert(i, i * 2);
}
map.alter_all(|v| v * 2);
for i in 0..1024_i32 {
assert_eq!(i * 4, *map.get(&i).unwrap());
}
}
#[test]
fn insert_then_iter_1024() {
let map = DashMap::default();
for i in 0..1024_i32 {
map.insert(i, i * 2);
}
map.alter_all(|v| v * 2);
assert_eq!(map.iter().count(), 1024);
}
#[test]
fn insert_then_iter_mut_map_1024() {
let map = DashMap::default();
for i in 0..1024_i32 {
map.insert(i, 4);
}
map.iter_mut().for_each(|mut r| *r *= 2);
assert_eq!(map.iter().fold(0, |acc, e| acc + *e), 8192);
}
#[test]
fn insert_then_assert_str() {
let map = DashMap::default();
map.insert("foo".to_string(), 51i32);
assert_eq!(*map.index("foo"), 51i32);
}
}

12
src/util.rs Normal file
View File

@ -0,0 +1,12 @@
use std::{mem, ptr};
#[inline]
pub const fn ptr_size_bits() -> usize {
mem::size_of::<usize>() * 8
}
/// Must not panic
#[inline]
pub unsafe fn map_in_place<T>(r: &mut T, f: impl FnOnce(T) -> T) {
ptr::write(r, f(ptr::read(r)));
}