diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 605e94a9..223580ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,8 +26,7 @@ jobs: i686-unknown-linux-gnu, aarch64-unknown-linux-gnu, armv7-linux-androideabi, - powerpc-unknown-linux-gnu, - wasm32-unknown-emscripten + powerpc-unknown-linux-gnu ] steps: - uses: actions/checkout@v2 diff --git a/Cargo.toml b/Cargo.toml index 2ce5f0c1..30754108 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dashmap" -version = "3.11.10" +version = "4.0.0" authors = ["Acrimon "] edition = "2018" license = "MIT" @@ -15,14 +15,11 @@ categories = ["concurrency", "algorithms", "data-structures"] [features] default = [] raw-api = [] -no_std = ["hashbrown"] [dependencies] num_cpus = "1.13.0" -ahash = "0.3.8" -serde = { version = "1.0.114", optional = true, features = ["derive"] } +serde = { version = "1.0.118", optional = true, features = ["derive"] } cfg-if = "1.0.0" -hashbrown = { version = "0.8.0", optional = true } rayon = { version = "1.5.0", optional = true } [package.metadata.docs.rs] diff --git a/README.md b/README.md index a6599ed8..fa886d58 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,12 @@ If you have any suggestions or tips do not hesitate to open an issue or a PR. ## Cargo features -- `no_std` - Enable no_std + alloc support. - - `serde` - Enables serde support. - `raw-api` - Enables the unstable raw-shard api. +- `rayon` - Enables rayon support. + ## Support me [![Foo](https://c5.patreon.com/external/logo/become_a_patron_button@2x.png)](https://patreon.com/acrimon) @@ -47,6 +47,9 @@ Do not hesitate to open issues or PR's. I will take a look as soon as I have time for it. +That said I do not get paid (yet) to work on open-source. This means +that my time is limited and my work here comes after my personal life. + ## Performance A comprehensive benchmark suite including DashMap can be found [here](https://github.com/xacrimon/conc-map-bench). diff --git a/src/iter.rs b/src/iter.rs index 3f25bfef..e88c1cae 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -4,19 +4,11 @@ use crate::lock::{RwLockReadGuard, RwLockWriteGuard}; use crate::t::Map; use crate::util::SharedValue; use crate::{DashMap, HashMap}; -use ahash::RandomState; use core::hash::{BuildHasher, Hash}; use core::mem; - -cfg_if::cfg_if! { - if #[cfg(feature = "no_std")] { - use alloc::sync::Arc; - use hashbrown::hash_map; - } else { - use std::sync::Arc; - use std::collections::hash_map; - } -} +use std::collections::hash_map; +use std::collections::hash_map::RandomState; +use std::sync::Arc; /// Iterator over a DashMap yielding key value pairs. /// @@ -31,7 +23,6 @@ cfg_if::cfg_if! { /// let pairs: Vec<(&'static str, &'static str)> = map.into_iter().collect(); /// assert_eq!(pairs.len(), 2); /// ``` - pub struct OwningIter { map: DashMap, shard_i: usize, @@ -121,7 +112,6 @@ type GuardIterMut<'a, K, V, S> = ( /// map.insert("hello", "world"); /// assert_eq!(map.iter().count(), 1); /// ``` - pub struct Iter<'a, K, V, S = RandomState, M = DashMap> { map: &'a M, shard_i: usize, @@ -200,7 +190,6 @@ impl<'a, K: Eq + Hash, V, S: 'a + BuildHasher + Clone, M: Map<'a, K, V, S>> Iter /// map.iter_mut().for_each(|mut r| *r += 1); /// assert_eq!(*map.get("Johnny").unwrap(), 22); /// ``` - pub struct IterMut<'a, K, V, S = RandomState, M = DashMap> { map: &'a M, shard_i: usize, @@ -276,13 +265,10 @@ impl<'a, K: Eq + Hash, V, S: 'a + BuildHasher + Clone, M: Map<'a, K, V, S>> Iter } #[cfg(test)] - mod tests { - use crate::DashMap; #[test] - fn iter_mut_manual_count() { let map = DashMap::new(); @@ -300,7 +286,6 @@ mod tests { } #[test] - fn iter_mut_count() { let map = DashMap::new(); @@ -312,7 +297,6 @@ mod tests { } #[test] - fn iter_count() { let map = DashMap::new(); diff --git a/src/lib.rs b/src/lib.rs index f6229784..0e7cd523 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -#![cfg_attr(all(feature = "no_std", not(test)), no_std)] // Note: Concurrency tests require std for threading/channels #![allow(clippy::type_complexity)] pub mod iter; @@ -19,7 +18,6 @@ pub mod rayon { pub mod set; } -use ahash::RandomState; use cfg_if::cfg_if; use core::borrow::Borrow; use core::fmt; @@ -33,6 +31,7 @@ use mapref::multiple::RefMulti; use mapref::one::{Ref, RefMut}; pub use read_only::ReadOnlyView; pub use set::DashSet; +use std::collections::hash_map::RandomState; pub use t::Map; cfg_if! { @@ -43,17 +42,7 @@ cfg_if! { } } -cfg_if! { - if #[cfg(feature = "no_std")] { - extern crate alloc; - - use alloc::{vec::Vec, boxed::Box}; - - pub(crate) type HashMap = hashbrown::HashMap, S>; - } else { - pub(crate) type HashMap = std::collections::HashMap, S>; - } -} +pub(crate) type HashMap = std::collections::HashMap, S>; fn shard_amount() -> usize { (num_cpus::get() * 4).next_power_of_two() @@ -71,7 +60,9 @@ fn ncb(shard_amount: usize) -> usize { /// DashMap tries to be very simple to use and to be a direct replacement for `RwLock>`. /// To accomplish these all methods take `&self` instead modifying methods taking `&mut self`. /// This allows you to put a DashMap in an `Arc` and share it between threads while being able to modify it. - +/// +/// Documentation mentioning locking behaviour acts in the reference frame of the calling thread. +/// This means that it is safe to ignore it across multiple threads. pub struct DashMap { shift: usize, shards: Box<[RwLock>]>, @@ -117,7 +108,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a> DashMap { /// let reviews = DashMap::new(); /// reviews.insert("Veloren", "What a fantastic game!"); /// ``` - pub fn new() -> Self { DashMap::with_hasher(RandomState::default()) } @@ -133,7 +123,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a> DashMap { /// mappings.insert(2, 4); /// mappings.insert(8, 16); /// ``` - pub fn with_capacity(capacity: usize) -> Self { DashMap::with_capacity_and_hasher(capacity, RandomState::default()) } @@ -141,7 +130,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a> DashMap { impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// Wraps this `DashMap` into a read-only view. This view allows to obtain raw references to the stored values. - pub fn into_read_only(self) -> ReadOnlyView { ReadOnlyView::new(self) } @@ -158,7 +146,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// let reviews = DashMap::with_hasher(s); /// reviews.insert("Veloren", "What a fantastic game!"); /// ``` - pub fn with_hasher(hasher: S) -> Self { Self::with_capacity_and_hasher(0, hasher) } @@ -176,7 +163,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// mappings.insert(2, 4); /// mappings.insert(8, 16); /// ``` - pub fn with_capacity_and_hasher(mut capacity: usize, hasher: S) -> Self { let shard_amount = shard_amount(); let shift = util::ptr_size_bits() - ncb(shard_amount); @@ -200,7 +186,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// Hash a given item to produce a usize. /// Uses the provided or default HashBuilder. - pub fn hash_usize(&self, item: &T) -> usize { let mut hasher = self.hasher.build_hasher(); @@ -224,13 +209,11 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// let map = DashMap::<(), ()>::new(); /// println!("Amount of shards: {}", map.shards().len()); /// ``` - pub fn shards(&self) -> &[RwLock>] { &self.shards } } else { #[allow(dead_code)] - pub(crate) fn shards(&self) -> &[RwLock>] { &self.shards } @@ -254,7 +237,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// map.insert("coca-cola", 1.4); /// println!("coca-cola is stored in shard: {}", map.determine_map("coca-cola")); /// ``` - pub fn determine_map(&self, key: &Q) -> usize where K: Borrow, @@ -282,7 +264,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// let hash = map.hash_usize(&key); /// println!("hash is stored in shard: {}", map.determine_shard(hash)); /// ``` - pub fn determine_shard(&self, hash: usize) -> usize { // Leave the high 7 bits for the HashBrown SIMD tag. (hash << 7) >> self.shift @@ -302,7 +283,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// /// ```rust /// use dashmap::DashMap; - /// use ahash::RandomState; + /// use std::collections::hash_map::RandomState; /// /// let hasher = RandomState::new(); /// let map: DashMap = DashMap::new(); @@ -310,7 +291,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// ``` /// /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html - pub fn hasher(&self) -> &S { &self.hasher } @@ -327,7 +307,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// let map = DashMap::new(); /// map.insert("I am the key!", "And I am the value!"); /// ``` - pub fn insert(&self, key: K, value: V) -> Option { self._insert(key, value) } @@ -345,7 +324,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// soccer_team.insert("Jack", "Goalie"); /// assert_eq!(soccer_team.remove("Jack").unwrap().1, "Goalie"); /// ``` - pub fn remove(&self, key: &Q) -> Option<(K, V)> where K: Borrow, @@ -375,7 +353,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// soccer_team.remove_if("Sam", |_, position| position == &"Forward"); /// assert!(!soccer_team.contains_key("Sam")); /// ``` - pub fn remove_if(&self, key: &Q, f: impl FnOnce(&K, &V) -> bool) -> Option<(K, V)> where K: Borrow, @@ -397,7 +374,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// words.insert("hello", "world"); /// assert_eq!(words.iter().count(), 1); /// ``` - pub fn iter(&'a self) -> Iter<'a, K, V, S, DashMap> { self._iter() } @@ -416,7 +392,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// map.iter_mut().for_each(|mut r| *r += 1); /// assert_eq!(*map.get("Johnny").unwrap(), 22); /// ``` - pub fn iter_mut(&'a self) -> IterMut<'a, K, V, S, DashMap> { self._iter_mut() } @@ -434,7 +409,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// youtubers.insert("Bosnian Bill", 457000); /// assert_eq!(*youtubers.get("Bosnian Bill").unwrap(), 457000); /// ``` - pub fn get(&'a self, key: &Q) -> Option> where K: Borrow, @@ -457,7 +431,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// *class.get_mut("Albin").unwrap() -= 1; /// assert_eq!(*class.get("Albin").unwrap(), 14); /// ``` - pub fn get_mut(&'a self, key: &Q) -> Option> where K: Borrow, @@ -469,7 +442,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// Remove excess capacity to reduce memory usage. /// /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. - pub fn shrink_to_fit(&self) { self._shrink_to_fit(); } @@ -491,7 +463,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// people.retain(|_, v| *v > 20); /// assert_eq!(people.len(), 2); /// ``` - pub fn retain(&self, f: impl FnMut(&K, &mut V) -> bool) { self._retain(f); } @@ -511,7 +482,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// people.insert("Charlie", 27); /// assert_eq!(people.len(), 3); /// ``` - pub fn len(&self) -> usize { self._len() } @@ -528,7 +498,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// let map = DashMap::<(), ()>::new(); /// assert!(map.is_empty()); /// ``` - pub fn is_empty(&self) -> bool { self._is_empty() } @@ -548,7 +517,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// stats.clear(); /// assert!(stats.is_empty()); /// ``` - pub fn clear(&self) { self._clear(); } @@ -556,7 +524,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// Returns how many key-value pairs the map can store without reallocating. /// /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. - pub fn capacity(&self) -> usize { self._capacity() } @@ -579,7 +546,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// # Panics /// /// If the given closure panics, then `alter` will abort the process - pub fn alter(&self, key: &Q, f: impl FnOnce(&K, V) -> V) where K: Borrow, @@ -608,7 +574,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// # Panics /// /// If the given closure panics, then `alter_all` will abort the process - pub fn alter_all(&self, f: impl FnMut(&K, V) -> V) { self._alter_all(f); } @@ -626,7 +591,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// team_sizes.insert("Dakota Cherries", 23); /// assert!(team_sizes.contains_key("Dakota Cherries")); /// ``` - pub fn contains_key(&self, key: &Q) -> bool where K: Borrow, @@ -639,7 +603,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { /// See the documentation on `dashmap::mapref::entry` for more details. /// /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. - pub fn entry(&'a self, key: K) -> Entry<'a, K, V, S> { self._entry(key) } @@ -946,22 +909,11 @@ impl FromIterator<(K, V)> for DashMap { } #[cfg(test)] - mod tests { - use crate::DashMap; - - cfg_if::cfg_if! { - if #[cfg(feature = "no_std")] { - use alloc::string::String; - use ahash::RandomState; - } else { - use std::collections::hash_map::RandomState; - } - } + use std::collections::hash_map::RandomState; #[test] - fn test_basic() { let dm = DashMap::new(); @@ -971,7 +923,6 @@ mod tests { } #[test] - fn test_default() { let dm: DashMap = DashMap::default(); @@ -981,7 +932,6 @@ mod tests { } #[test] - fn test_multiple_hashes() { let dm: DashMap = DashMap::default(); @@ -1005,7 +955,6 @@ mod tests { } #[test] - fn test_more_complex_values() { #[derive(Hash, PartialEq, Debug, Clone)] @@ -1031,7 +980,6 @@ mod tests { } #[test] - fn test_different_hashers_randomstate() { let dm_hm_default: DashMap = DashMap::with_hasher(RandomState::new()); diff --git a/src/lock.rs b/src/lock.rs index ecc57df4..b2802e7b 100644 --- a/src/lock.rs +++ b/src/lock.rs @@ -19,7 +19,6 @@ const UPGRADED: usize = 1 << 1; const WRITER: usize = 1; #[derive(Debug)] - pub struct RwLockReadGuard<'a, T: 'a + ?Sized> { lock: &'a AtomicUsize, data: NonNull, @@ -30,7 +29,6 @@ unsafe impl<'a, T: Send> Send for RwLockReadGuard<'a, T> {} unsafe impl<'a, T: Sync> Sync for RwLockReadGuard<'a, T> {} #[derive(Debug)] - pub struct RwLockWriteGuard<'a, T: 'a + ?Sized> { lock: &'a AtomicUsize, data: NonNull, @@ -43,7 +41,6 @@ unsafe impl<'a, T: Send> Send for RwLockWriteGuard<'a, T> {} unsafe impl<'a, T: Sync> Sync for RwLockWriteGuard<'a, T> {} #[derive(Debug)] - pub struct RwLockUpgradeableGuard<'a, T: 'a + ?Sized> { lock: &'a AtomicUsize, data: NonNull, @@ -101,7 +98,6 @@ impl RwLock { /// # Safety /// /// This is only safe if the lock is currently locked in read mode and the number of readers is not 0. - pub unsafe fn force_read_decrement(&self) { debug_assert!(self.lock.load(Ordering::Relaxed) & !WRITER > 0); @@ -111,7 +107,6 @@ impl RwLock { /// # Safety /// /// The lock must be locked in write mode. - pub unsafe fn force_write_unlock(&self) { debug_assert_eq!(self.lock.load(Ordering::Relaxed) & !(WRITER | UPGRADED), 0); @@ -334,9 +329,7 @@ fn compare_exchange( } #[cfg(test)] - mod tests { - use super::*; use std::prelude::v1::*; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -345,31 +338,22 @@ mod tests { use std::thread; #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); #[test] - fn smoke() { let l = RwLock::new(()); - drop(l.read()); - drop(l.write()); - drop((l.read(), l.read())); - drop(l.write()); } #[cfg(not(target_arch = "wasm32"))] #[test] - fn test_rw_arc() { let arc = Arc::new(RwLock::new(0)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); thread::spawn(move || { @@ -377,11 +361,8 @@ mod tests { for _ in 0..10 { let tmp = *lock; - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; } @@ -395,7 +376,6 @@ mod tests { children.push(thread::spawn(move || { let lock = arc3.read(); - assert!(*lock >= 0); })); } @@ -405,18 +385,14 @@ mod tests { } rx.recv().unwrap(); - let lock = arc.read(); - assert_eq!(*lock, 10); } #[cfg(not(target_arch = "wasm32"))] #[test] - fn test_rw_access_in_unwind() { let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); let _ = thread::spawn(move || { @@ -439,20 +415,16 @@ mod tests { .join(); let lock = arc.read(); - assert_eq!(*lock, 2); } #[test] - fn test_rwlock_unsized() { let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); { let b = &mut *rw.write(); - b[0] = 4; - b[2] = 5; } @@ -462,14 +434,11 @@ mod tests { } #[test] - fn test_rwlock_try_write() { use std::mem::drop; let lock = RwLock::new(0isize); - let read_guard = lock.read(); - let write_result = lock.try_write(); match write_result { @@ -481,7 +450,6 @@ mod tests { } #[test] - fn test_rw_try_read() { let m = RwLock::new(0); @@ -491,7 +459,6 @@ mod tests { } #[test] - fn test_into_inner() { let m = RwLock::new(NonCopy(10)); @@ -499,7 +466,6 @@ mod tests { } #[test] - fn test_into_inner_drop() { struct Foo(Arc); @@ -510,14 +476,11 @@ mod tests { } let num_drops = Arc::new(AtomicUsize::new(0)); - let m = RwLock::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); { let _inner = m.into_inner(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); } @@ -525,21 +488,15 @@ mod tests { } #[test] - fn test_force_read_decrement() { let m = RwLock::new(()); - ::std::mem::forget(m.read()); - ::std::mem::forget(m.read()); - ::std::mem::forget(m.read()); - assert!(m.try_write().is_none()); unsafe { m.force_read_decrement(); - m.force_read_decrement(); } @@ -553,7 +510,6 @@ mod tests { } #[test] - fn test_force_write_unlock() { let m = RwLock::new(()); @@ -569,39 +525,28 @@ mod tests { } #[test] - fn test_upgrade_downgrade() { let m = RwLock::new(()); { let _r = m.read(); - let upg = m.try_upgradeable_read().unwrap(); - assert!(m.try_read().is_none()); - assert!(m.try_write().is_none()); - assert!(upg.try_upgrade().is_err()); } { let w = m.write(); - assert!(m.try_upgradeable_read().is_none()); - let _r = w.downgrade(); - assert!(m.try_upgradeable_read().is_some()); - assert!(m.try_read().is_some()); - assert!(m.try_write().is_none()); } { let _u = m.upgradeable_read(); - assert!(m.try_upgradeable_read().is_none()); } diff --git a/src/mapref/entry.rs b/src/mapref/entry.rs index f565a21d..7a609ee6 100644 --- a/src/mapref/entry.rs +++ b/src/mapref/entry.rs @@ -3,10 +3,10 @@ use crate::lock::RwLockWriteGuard; use crate::util; use crate::util::SharedValue; use crate::HashMap; -use ahash::RandomState; use core::hash::{BuildHasher, Hash}; use core::mem; use core::ptr; +use std::collections::hash_map::RandomState; pub enum Entry<'a, K, V, S = RandomState> { Occupied(OccupiedEntry<'a, K, V, S>), @@ -15,7 +15,6 @@ pub enum Entry<'a, K, V, S = RandomState> { impl<'a, K: Eq + Hash, V, S: BuildHasher> Entry<'a, K, V, S> { /// Apply a function to the stored value if it exists. - pub fn and_modify(self, f: impl FnOnce(&mut V)) -> Self { match self { Entry::Occupied(mut entry) => { @@ -29,7 +28,6 @@ impl<'a, K: Eq + Hash, V, S: BuildHasher> Entry<'a, K, V, S> { } /// Get the key of the entry. - pub fn key(&self) -> &K { match *self { Entry::Occupied(ref entry) => entry.key(), @@ -38,7 +36,6 @@ impl<'a, K: Eq + Hash, V, S: BuildHasher> Entry<'a, K, V, S> { } /// Into the key of the entry. - pub fn into_key(self) -> K { match self { Entry::Occupied(entry) => entry.into_key(), @@ -48,7 +45,6 @@ impl<'a, K: Eq + Hash, V, S: BuildHasher> Entry<'a, K, V, S> { /// Return a mutable reference to the element if it exists, /// otherwise insert the default and return a mutable reference to that. - pub fn or_default(self) -> RefMut<'a, K, V, S> where V: Default, @@ -61,7 +57,6 @@ impl<'a, K: Eq + Hash, V, S: BuildHasher> Entry<'a, K, V, S> { /// Return a mutable reference to the element if it exists, /// otherwise a provided value and return a mutable reference to that. - pub fn or_insert(self, value: V) -> RefMut<'a, K, V, S> { match self { Entry::Occupied(entry) => entry.into_ref(), @@ -71,7 +66,6 @@ impl<'a, K: Eq + Hash, V, S: BuildHasher> Entry<'a, K, V, S> { /// Return a mutable reference to the element if it exists, /// otherwise insert the result of a provided function and return a mutable reference to that. - pub fn or_insert_with(self, value: impl FnOnce() -> V) -> RefMut<'a, K, V, S> { match self { Entry::Occupied(entry) => entry.into_ref(), diff --git a/src/mapref/multiple.rs b/src/mapref/multiple.rs index 35b6c0e9..4d30aee4 100644 --- a/src/mapref/multiple.rs +++ b/src/mapref/multiple.rs @@ -1,17 +1,10 @@ use crate::lock::{RwLockReadGuard, RwLockWriteGuard}; use crate::HashMap; -use ahash::RandomState; use core::hash::BuildHasher; use core::hash::Hash; use core::ops::{Deref, DerefMut}; - -cfg_if::cfg_if! { - if #[cfg(feature = "no_std")] { - use alloc::sync::Arc; - } else { - use std::sync::Arc; - } -} +use std::collections::hash_map::RandomState; +use std::sync::Arc; // -- Shared pub struct RefMulti<'a, K, V, S = RandomState> { diff --git a/src/mapref/one.rs b/src/mapref/one.rs index b040dbb1..67c1706e 100644 --- a/src/mapref/one.rs +++ b/src/mapref/one.rs @@ -1,8 +1,8 @@ use crate::lock::{RwLockReadGuard, RwLockWriteGuard}; use crate::HashMap; -use ahash::RandomState; use core::hash::{BuildHasher, Hash}; use core::ops::{Deref, DerefMut}; +use std::collections::hash_map::RandomState; // -- Shared pub struct Ref<'a, K, V, S = RandomState> { diff --git a/src/rayon/map.rs b/src/rayon/map.rs index 1a5ac0d8..48fdeacf 100644 --- a/src/rayon/map.rs +++ b/src/rayon/map.rs @@ -2,18 +2,11 @@ use crate::lock::RwLock; use crate::mapref::multiple::{RefMulti, RefMutMulti}; use crate::util; use crate::{DashMap, HashMap}; -use ahash::RandomState; use core::hash::{BuildHasher, Hash}; use rayon::iter::plumbing::UnindexedConsumer; use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; - -cfg_if::cfg_if! { - if #[cfg(feature = "no_std")] { - use alloc::{boxed::Box, sync::Arc, vec::Vec}; - } else { - use std::sync::Arc; - } -} +use std::collections::hash_map::RandomState; +use std::sync::Arc; impl ParallelExtend<(K, V)> for DashMap where diff --git a/src/rayon/set.rs b/src/rayon/set.rs index d2a64cf3..11c06ccb 100644 --- a/src/rayon/set.rs +++ b/src/rayon/set.rs @@ -1,9 +1,9 @@ use crate::setref::multiple::RefMulti; use crate::DashSet; -use ahash::RandomState; use core::hash::{BuildHasher, Hash}; use rayon::iter::plumbing::UnindexedConsumer; use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; +use std::collections::hash_map::RandomState; impl ParallelExtend for DashSet where diff --git a/src/read_only.rs b/src/read_only.rs index 4d6edf94..b0e7a65e 100644 --- a/src/read_only.rs +++ b/src/read_only.rs @@ -1,12 +1,11 @@ use crate::t::Map; use crate::{DashMap, HashMap}; -use ahash::RandomState; use core::borrow::Borrow; use core::fmt; use core::hash::{BuildHasher, Hash}; +use std::collections::hash_map::RandomState; /// A read-only view into a `DashMap`. Allows to obtain raw references to the stored values. - pub struct ReadOnlyView { map: DashMap, } @@ -33,7 +32,6 @@ impl ReadOnlyView { } /// Consumes this `ReadOnlyView`, returning the underlying `DashMap`. - pub fn into_inner(self) -> DashMap { self.map } @@ -41,25 +39,21 @@ impl ReadOnlyView { impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView { /// Returns the number of elements in the map. - pub fn len(&self) -> usize { self.map.len() } /// Returns `true` if the map contains no elements. - pub fn is_empty(&self) -> bool { self.map.is_empty() } /// Returns the number of elements the map can hold without reallocating. - pub fn capacity(&self) -> usize { self.map.capacity() } /// Returns `true` if the map contains a value for the specified key. - pub fn contains_key(&'a self, key: &Q) -> bool where K: Borrow, @@ -75,7 +69,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView } /// Returns a reference to the value corresponding to the key. - pub fn get(&'a self, key: &Q) -> Option<&'a V> where K: Borrow, @@ -91,7 +84,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView } /// Returns the key-value pair corresponding to the supplied key. - pub fn get_key_value(&'a self, key: &Q) -> Option<(&'a K, &'a V)> where K: Borrow, @@ -112,7 +104,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView } /// An iterator visiting all key-value pairs in arbitrary order. The iterator element type is `(&'a K, &'a V)`. - pub fn iter(&'a self) -> impl Iterator + 'a { self.shard_read_iter() .flat_map(|shard| shard.iter()) @@ -120,13 +111,11 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView } /// An iterator visiting all keys in arbitrary order. The iterator element type is `&'a K`. - pub fn keys(&'a self) -> impl Iterator + 'a { self.shard_read_iter().flat_map(|shard| shard.keys()) } /// An iterator visiting all values in arbitrary order. The iterator element type is `&'a V`. - pub fn values(&'a self) -> impl Iterator + 'a { self.shard_read_iter() .flat_map(|shard| shard.values()) diff --git a/src/set.rs b/src/set.rs index b5c552e8..e4d77df1 100644 --- a/src/set.rs +++ b/src/set.rs @@ -5,18 +5,17 @@ use crate::setref::one::Ref; use crate::DashMap; #[cfg(feature = "raw-api")] use crate::HashMap; -use ahash::RandomState; use cfg_if::cfg_if; use core::borrow::Borrow; use core::fmt; use core::hash::{BuildHasher, Hash}; use core::iter::FromIterator; +use std::collections::hash_map::RandomState; /// DashSet is a thin wrapper around [`DashMap`] using `()` as the value type. It uses /// methods and types which are more convenient to work with on a set. /// /// [`DashMap`]: struct.DashMap.html - pub struct DashSet { pub(crate) inner: DashMap, } @@ -60,7 +59,6 @@ impl<'a, K: 'a + Eq + Hash> DashSet { /// let games = DashSet::new(); /// games.insert("Veloren"); /// ``` - pub fn new() -> Self { Self::with_hasher(RandomState::default()) } @@ -76,7 +74,6 @@ impl<'a, K: 'a + Eq + Hash> DashSet { /// numbers.insert(2); /// numbers.insert(8); /// ``` - pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_and_hasher(capacity, RandomState::default()) } @@ -95,7 +92,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// let games = DashSet::with_hasher(s); /// games.insert("Veloren"); /// ``` - pub fn with_hasher(hasher: S) -> Self { Self::with_capacity_and_hasher(0, hasher) } @@ -113,7 +109,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// numbers.insert(2); /// numbers.insert(8); /// ``` - pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { Self { inner: DashMap::with_capacity_and_hasher(capacity, hasher), @@ -122,7 +117,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// Hash a given item to produce a usize. /// Uses the provided or default HashBuilder. - pub fn hash_usize(&self, item: &T) -> usize { self.inner.hash_usize(item) } @@ -142,7 +136,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// let set = DashSet::<()>::new(); /// println!("Amount of shards: {}", set.shards().len()); /// ``` - pub fn shards(&self) -> &[RwLock>] { self.inner.shards() } @@ -166,7 +159,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// set.insert("coca-cola"); /// println!("coca-cola is stored in shard: {}", set.determine_map("coca-cola")); /// ``` - pub fn determine_map(&self, key: &Q) -> usize where K: Borrow, @@ -193,7 +185,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// let hash = set.hash_usize(&key); /// println!("hash is stored in shard: {}", set.determine_shard(hash)); /// ``` - pub fn determine_shard(&self, hash: usize) -> usize { self.inner.determine_shard(hash) } @@ -210,7 +201,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// let set = DashSet::new(); /// set.insert("I am the key!"); /// ``` - pub fn insert(&self, key: K) -> bool { self.inner.insert(key, ()).is_none() } @@ -226,7 +216,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// soccer_team.insert("Jack"); /// assert_eq!(soccer_team.remove("Jack").unwrap(), "Jack"); /// ``` - pub fn remove(&self, key: &Q) -> Option where K: Borrow, @@ -254,7 +243,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// soccer_team.remove_if("Jacob", |player| player.starts_with("Ja")); /// assert!(!soccer_team.contains("Jacob")); /// ``` - pub fn remove_if(&self, key: &Q, f: impl FnOnce(&K) -> bool) -> Option where K: Borrow, @@ -275,7 +263,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// words.insert("hello"); /// assert_eq!(words.iter().count(), 1); /// ``` - pub fn iter(&'a self) -> Iter<'a, K, S, DashMap> { let iter = self.inner.iter(); @@ -293,7 +280,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// youtubers.insert("Bosnian Bill"); /// assert_eq!(*youtubers.get("Bosnian Bill").unwrap(), "Bosnian Bill"); /// ``` - pub fn get(&'a self, key: &Q) -> Option> where K: Borrow, @@ -303,7 +289,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { } /// Remove excess capacity to reduce memory usage. - pub fn shrink_to_fit(&self) { self.inner.shrink_to_fit() } @@ -323,9 +308,7 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// people.retain(|name| name.contains('i')); /// assert_eq!(people.len(), 2); /// ``` - pub fn retain(&self, mut f: impl FnMut(&K) -> bool) { - // TODO: Don't create another closure self.inner.retain(|k, _| f(k)) } @@ -342,7 +325,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// people.insert("Charlie"); /// assert_eq!(people.len(), 3); /// ``` - pub fn len(&self) -> usize { self.inner.len() } @@ -357,7 +339,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// let map = DashSet::<()>::new(); /// assert!(map.is_empty()); /// ``` - pub fn is_empty(&self) -> bool { self.inner.is_empty() } @@ -375,13 +356,11 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// people.clear(); /// assert!(people.is_empty()); /// ``` - pub fn clear(&self) { self.inner.clear() } /// Returns how many keys the set can store without reallocating. - pub fn capacity(&self) -> usize { self.inner.capacity() } @@ -397,7 +376,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { /// people.insert("Dakota Cherries"); /// assert!(people.contains("Dakota Cherries")); /// ``` - pub fn contains(&self, key: &Q) -> bool where K: Borrow, @@ -436,13 +414,10 @@ impl FromIterator for DashSet { } #[cfg(test)] - mod tests { - use crate::DashSet; #[test] - fn test_basic() { let set = DashSet::new(); @@ -452,7 +427,6 @@ mod tests { } #[test] - fn test_default() { let set: DashSet = DashSet::default(); @@ -462,7 +436,6 @@ mod tests { } #[test] - fn test_multiple_hashes() { let set = DashSet::::default(); diff --git a/src/setref/multiple.rs b/src/setref/multiple.rs index 10b3957a..21e7ed4a 100644 --- a/src/setref/multiple.rs +++ b/src/setref/multiple.rs @@ -1,8 +1,7 @@ use crate::mapref; -use ahash::RandomState; use core::hash::{BuildHasher, Hash}; use core::ops::Deref; - +use std::collections::hash_map::RandomState; pub struct RefMulti<'a, K, S = RandomState> { inner: mapref::multiple::RefMulti<'a, K, (), S>, } diff --git a/src/setref/one.rs b/src/setref/one.rs index 56f181e8..ef034215 100644 --- a/src/setref/one.rs +++ b/src/setref/one.rs @@ -1,8 +1,7 @@ use crate::mapref; -use ahash::RandomState; use core::hash::{BuildHasher, Hash}; use core::ops::Deref; - +use std::collections::hash_map::RandomState; pub struct Ref<'a, K, S = RandomState> { inner: mapref::one::Ref<'a, K, (), S>, } diff --git a/src/t.rs b/src/t.rs index fe54f8f2..6c2e81a6 100644 --- a/src/t.rs +++ b/src/t.rs @@ -1,4 +1,5 @@ //! Central map trait to ease modifications and extensions down the road. + use crate::iter::{Iter, IterMut}; use crate::lock::{RwLockReadGuard, RwLockWriteGuard}; use crate::mapref::entry::Entry; @@ -8,26 +9,22 @@ use core::borrow::Borrow; use core::hash::{BuildHasher, Hash}; /// Implementation detail that is exposed due to generic constraints in public types. - pub trait Map<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + Clone + BuildHasher> { fn _shard_count(&self) -> usize; /// # Safety /// /// The index must not be out of bounds. - unsafe fn _get_read_shard(&'a self, i: usize) -> &'a HashMap; /// # Safety /// /// The index must not be out of bounds. - unsafe fn _yield_read_shard(&'a self, i: usize) -> RwLockReadGuard<'a, HashMap>; /// # Safety /// /// The index must not be out of bounds. - unsafe fn _yield_write_shard(&'a self, i: usize) -> RwLockWriteGuard<'a, HashMap>; fn _insert(&self, key: K, value: V) -> Option; diff --git a/src/util.rs b/src/util.rs index e9ccfb4f..d84e37db 100644 --- a/src/util.rs +++ b/src/util.rs @@ -22,7 +22,6 @@ pub fn map_in_place_2 T>((k, v): (U, &mut T), f: F) { /// /// Requires that you ensure the reference does not become invalid. /// The object has to outlive the reference. - pub unsafe fn change_lifetime_const<'a, 'b, T>(x: &'a T) -> &'b T { &*(x as *const T) } @@ -31,7 +30,6 @@ pub unsafe fn change_lifetime_const<'a, 'b, T>(x: &'a T) -> &'b T { /// /// Requires that you ensure the reference does not become invalid. /// The object has to outlive the reference. - pub unsafe fn change_lifetime_mut<'a, 'b, T>(x: &'a mut T) -> &'b mut T { &mut *(x as *mut T) } @@ -46,7 +44,6 @@ pub unsafe fn change_lifetime_mut<'a, 'b, T>(x: &'a mut T) -> &'b mut T { /// /// This type is meant to be an implementation detail, but must be exposed due to the `Dashmap::shards` #[repr(transparent)] - pub struct SharedValue { value: UnsafeCell, } @@ -67,7 +64,6 @@ unsafe impl Sync for SharedValue {} impl SharedValue { /// Create a new `SharedValue` - pub const fn new(value: T) -> Self { Self { value: UnsafeCell::new(value), @@ -75,25 +71,21 @@ impl SharedValue { } /// Get a shared reference to `T` - pub fn get(&self) -> &T { unsafe { &*self.value.get() } } /// Get an unique reference to `T` - pub fn get_mut(&mut self) -> &mut T { unsafe { &mut *self.value.get() } } /// Unwraps the value - pub fn into_inner(self) -> T { self.value.into_inner() } /// Get a mutable raw pointer to the underlying value - pub(crate) fn as_ptr(&self) -> *mut T { self.value.get() } @@ -103,42 +95,8 @@ struct AbortOnPanic; impl Drop for AbortOnPanic { fn drop(&mut self) { - cfg_if::cfg_if! { - if #[cfg(feature = "no_std")] { - // Note: This is hard, as core/no_std has no concept of threads or knowledge of panicking. - // An alternative would be to do this: - // - // ```rust - // // Elsewhere in the library/host binary - // use core::sync::atomic::{AtomicBool, Ordering}; - // - // static UNWINDING: AtomicBool = AtomicBool::new(false); - // - // #[panic_handler] - // fn panic(info: &PanicInfo) -> ! { - // UNWINDING.store(true, Ordering::Relaxed); - // - // unsafe { - // core::intrinsics::abort(); - // } - // } - // - // // In AbortOnPanic::drop - // if UNWINDING.load(Ordering::Relaxed) { - // unsafe { - // core::intrinsics::abort(); - // } - // } - // ``` - // - // Now, this isn't an ideal solution for multiple reasons, as it uses intrinsics which require a feature - // and can be overwritten by the user without them even knowing. That being said, *most* users of no_std - // do tend to use panic = "abort", which solves this problem for us by aborting on panics. - } else { - if std::thread::panicking() { - std::process::abort() - } - } + if std::thread::panicking() { + std::process::abort() } } }