mirror of https://github.com/xacrimon/dashmap
Merge pull request #126 from xacrimon/acrimon/fci
v4 "The maintenance release"
This commit is contained in:
commit
63f8e06ba4
|
@ -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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "dashmap"
|
||||
version = "3.11.10"
|
||||
version = "4.0.0"
|
||||
authors = ["Acrimon <joel.wejdenstal@gmail.com>"]
|
||||
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]
|
||||
|
|
|
@ -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).
|
||||
|
|
22
src/iter.rs
22
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<K, V, S = RandomState> {
|
||||
map: DashMap<K, V, S>,
|
||||
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<K, V, S>> {
|
||||
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<K, V, S>> {
|
||||
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();
|
||||
|
||||
|
|
66
src/lib.rs
66
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<K, V, S> = hashbrown::HashMap<K, SharedValue<V>, S>;
|
||||
} else {
|
||||
pub(crate) type HashMap<K, V, S> = std::collections::HashMap<K, SharedValue<V>, S>;
|
||||
}
|
||||
}
|
||||
pub(crate) type HashMap<K, V, S> = std::collections::HashMap<K, SharedValue<V>, 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<HashMap<K, V, S>>`.
|
||||
/// To accomplish these all methods take `&self` instead modifying methods taking `&mut self`.
|
||||
/// This allows you to put a DashMap in an `Arc<T>` 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<K, V, S = RandomState> {
|
||||
shift: usize,
|
||||
shards: Box<[RwLock<HashMap<K, V, S>>]>,
|
||||
|
@ -117,7 +108,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a> DashMap<K, V, RandomState> {
|
|||
/// 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<K, V, RandomState> {
|
|||
/// 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<K, V, RandomState> {
|
|||
|
||||
impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
||||
/// 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<K, V, S> {
|
||||
ReadOnlyView::new(self)
|
||||
}
|
||||
|
@ -158,7 +146,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// 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<K, V, S> {
|
|||
/// 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<K, V, S> {
|
|||
|
||||
/// Hash a given item to produce a usize.
|
||||
/// Uses the provided or default HashBuilder.
|
||||
|
||||
pub fn hash_usize<T: Hash>(&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<K, V, S> {
|
|||
/// let map = DashMap::<(), ()>::new();
|
||||
/// println!("Amount of shards: {}", map.shards().len());
|
||||
/// ```
|
||||
|
||||
pub fn shards(&self) -> &[RwLock<HashMap<K, V, S>>] {
|
||||
&self.shards
|
||||
}
|
||||
} else {
|
||||
#[allow(dead_code)]
|
||||
|
||||
pub(crate) fn shards(&self) -> &[RwLock<HashMap<K, V, S>>] {
|
||||
&self.shards
|
||||
}
|
||||
|
@ -254,7 +237,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// map.insert("coca-cola", 1.4);
|
||||
/// println!("coca-cola is stored in shard: {}", map.determine_map("coca-cola"));
|
||||
/// ```
|
||||
|
||||
pub fn determine_map<Q>(&self, key: &Q) -> usize
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -282,7 +264,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// 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<K, V, S> {
|
|||
///
|
||||
/// ```rust
|
||||
/// use dashmap::DashMap;
|
||||
/// use ahash::RandomState;
|
||||
/// use std::collections::hash_map::RandomState;
|
||||
///
|
||||
/// let hasher = RandomState::new();
|
||||
/// let map: DashMap<i32, i32> = DashMap::new();
|
||||
|
@ -310,7 +291,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// ```
|
||||
///
|
||||
/// [`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<K, V, S> {
|
|||
/// let map = DashMap::new();
|
||||
/// map.insert("I am the key!", "And I am the value!");
|
||||
/// ```
|
||||
|
||||
pub fn insert(&self, key: K, value: V) -> Option<V> {
|
||||
self._insert(key, value)
|
||||
}
|
||||
|
@ -345,7 +324,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// soccer_team.insert("Jack", "Goalie");
|
||||
/// assert_eq!(soccer_team.remove("Jack").unwrap().1, "Goalie");
|
||||
/// ```
|
||||
|
||||
pub fn remove<Q>(&self, key: &Q) -> Option<(K, V)>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -375,7 +353,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// soccer_team.remove_if("Sam", |_, position| position == &"Forward");
|
||||
/// assert!(!soccer_team.contains_key("Sam"));
|
||||
/// ```
|
||||
|
||||
pub fn remove_if<Q>(&self, key: &Q, f: impl FnOnce(&K, &V) -> bool) -> Option<(K, V)>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -397,7 +374,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// words.insert("hello", "world");
|
||||
/// assert_eq!(words.iter().count(), 1);
|
||||
/// ```
|
||||
|
||||
pub fn iter(&'a self) -> Iter<'a, K, V, S, DashMap<K, V, S>> {
|
||||
self._iter()
|
||||
}
|
||||
|
@ -416,7 +392,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// 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<K, V, S>> {
|
||||
self._iter_mut()
|
||||
}
|
||||
|
@ -434,7 +409,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// youtubers.insert("Bosnian Bill", 457000);
|
||||
/// assert_eq!(*youtubers.get("Bosnian Bill").unwrap(), 457000);
|
||||
/// ```
|
||||
|
||||
pub fn get<Q>(&'a self, key: &Q) -> Option<Ref<'a, K, V, S>>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -457,7 +431,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// *class.get_mut("Albin").unwrap() -= 1;
|
||||
/// assert_eq!(*class.get("Albin").unwrap(), 14);
|
||||
/// ```
|
||||
|
||||
pub fn get_mut<Q>(&'a self, key: &Q) -> Option<RefMut<'a, K, V, S>>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -469,7 +442,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// 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<K, V, S> {
|
|||
/// 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<K, V, S> {
|
|||
/// 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<K, V, S> {
|
|||
/// 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<K, V, S> {
|
|||
/// 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<K, V, S> {
|
|||
/// 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<K, V, S> {
|
|||
/// # Panics
|
||||
///
|
||||
/// If the given closure panics, then `alter` will abort the process
|
||||
|
||||
pub fn alter<Q>(&self, key: &Q, f: impl FnOnce(&K, V) -> V)
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -608,7 +574,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// # 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<K, V, S> {
|
|||
/// team_sizes.insert("Dakota Cherries", 23);
|
||||
/// assert!(team_sizes.contains_key("Dakota Cherries"));
|
||||
/// ```
|
||||
|
||||
pub fn contains_key<Q>(&self, key: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -639,7 +603,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
|
|||
/// 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<K: Eq + Hash, V> FromIterator<(K, V)> for DashMap<K, V, RandomState> {
|
|||
}
|
||||
|
||||
#[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<u32, u32> = DashMap::default();
|
||||
|
||||
|
@ -981,7 +932,6 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
|
||||
fn test_multiple_hashes() {
|
||||
let dm: DashMap<u32, u32> = 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<u32, u32, RandomState> =
|
||||
DashMap::with_hasher(RandomState::new());
|
||||
|
|
55
src/lock.rs
55
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<T>,
|
||||
|
@ -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<T>,
|
||||
|
@ -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<T>,
|
||||
|
@ -101,7 +98,6 @@ impl<T: ?Sized> RwLock<T> {
|
|||
/// # 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<T: ?Sized> RwLock<T> {
|
|||
/// # 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<AtomicUsize>);
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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<K, V, S> ParallelExtend<(K, V)> for DashMap<K, V, S>
|
||||
where
|
||||
|
|
|
@ -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<K, S> ParallelExtend<K> for DashSet<K, S>
|
||||
where
|
||||
|
|
|
@ -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<K, V, S = RandomState> {
|
||||
map: DashMap<K, V, S>,
|
||||
}
|
||||
|
@ -33,7 +32,6 @@ impl<K, V, S> ReadOnlyView<K, V, S> {
|
|||
}
|
||||
|
||||
/// Consumes this `ReadOnlyView`, returning the underlying `DashMap`.
|
||||
|
||||
pub fn into_inner(self) -> DashMap<K, V, S> {
|
||||
self.map
|
||||
}
|
||||
|
@ -41,25 +39,21 @@ impl<K, V, S> ReadOnlyView<K, V, S> {
|
|||
|
||||
impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S> {
|
||||
/// 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<Q>(&'a self, key: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -75,7 +69,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
|
|||
}
|
||||
|
||||
/// Returns a reference to the value corresponding to the key.
|
||||
|
||||
pub fn get<Q>(&'a self, key: &Q) -> Option<&'a V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -91,7 +84,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
|
|||
}
|
||||
|
||||
/// Returns the key-value pair corresponding to the supplied key.
|
||||
|
||||
pub fn get_key_value<Q>(&'a self, key: &Q) -> Option<(&'a K, &'a V)>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -112,7 +104,6 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
|
|||
}
|
||||
|
||||
/// 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<Item = (&'a K, &'a V)> + '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<K, V, S>
|
|||
}
|
||||
|
||||
/// An iterator visiting all keys in arbitrary order. The iterator element type is `&'a K`.
|
||||
|
||||
pub fn keys(&'a self) -> impl Iterator<Item = &'a K> + '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<Item = &'a V> + 'a {
|
||||
self.shard_read_iter()
|
||||
.flat_map(|shard| shard.values())
|
||||
|
|
29
src/set.rs
29
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<K, S = RandomState> {
|
||||
pub(crate) inner: DashMap<K, (), S>,
|
||||
}
|
||||
|
@ -60,7 +59,6 @@ impl<'a, K: 'a + Eq + Hash> DashSet<K, RandomState> {
|
|||
/// 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<K, RandomState> {
|
|||
/// 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<K, S> {
|
|||
/// 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<K, S> {
|
|||
/// 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<K, S> {
|
|||
|
||||
/// Hash a given item to produce a usize.
|
||||
/// Uses the provided or default HashBuilder.
|
||||
|
||||
pub fn hash_usize<T: Hash>(&self, item: &T) -> usize {
|
||||
self.inner.hash_usize(item)
|
||||
}
|
||||
|
@ -142,7 +136,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
|
|||
/// let set = DashSet::<()>::new();
|
||||
/// println!("Amount of shards: {}", set.shards().len());
|
||||
/// ```
|
||||
|
||||
pub fn shards(&self) -> &[RwLock<HashMap<K, (), S>>] {
|
||||
self.inner.shards()
|
||||
}
|
||||
|
@ -166,7 +159,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
|
|||
/// set.insert("coca-cola");
|
||||
/// println!("coca-cola is stored in shard: {}", set.determine_map("coca-cola"));
|
||||
/// ```
|
||||
|
||||
pub fn determine_map<Q>(&self, key: &Q) -> usize
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -193,7 +185,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
|
|||
/// 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<K, S> {
|
|||
/// 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<K, S> {
|
|||
/// soccer_team.insert("Jack");
|
||||
/// assert_eq!(soccer_team.remove("Jack").unwrap(), "Jack");
|
||||
/// ```
|
||||
|
||||
pub fn remove<Q>(&self, key: &Q) -> Option<K>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -254,7 +243,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
|
|||
/// soccer_team.remove_if("Jacob", |player| player.starts_with("Ja"));
|
||||
/// assert!(!soccer_team.contains("Jacob"));
|
||||
/// ```
|
||||
|
||||
pub fn remove_if<Q>(&self, key: &Q, f: impl FnOnce(&K) -> bool) -> Option<K>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -275,7 +263,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
|
|||
/// words.insert("hello");
|
||||
/// assert_eq!(words.iter().count(), 1);
|
||||
/// ```
|
||||
|
||||
pub fn iter(&'a self) -> Iter<'a, K, S, DashMap<K, (), S>> {
|
||||
let iter = self.inner.iter();
|
||||
|
||||
|
@ -293,7 +280,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
|
|||
/// youtubers.insert("Bosnian Bill");
|
||||
/// assert_eq!(*youtubers.get("Bosnian Bill").unwrap(), "Bosnian Bill");
|
||||
/// ```
|
||||
|
||||
pub fn get<Q>(&'a self, key: &Q) -> Option<Ref<'a, K, S>>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -303,7 +289,6 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
|
|||
}
|
||||
|
||||
/// 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<K, S> {
|
|||
/// 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<K, S> {
|
|||
/// 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<K, S> {
|
|||
/// 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<K, S> {
|
|||
/// 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<K, S> {
|
|||
/// people.insert("Dakota Cherries");
|
||||
/// assert!(people.contains("Dakota Cherries"));
|
||||
/// ```
|
||||
|
||||
pub fn contains<Q>(&self, key: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -436,13 +414,10 @@ impl<K: Eq + Hash> FromIterator<K> for DashSet<K, RandomState> {
|
|||
}
|
||||
|
||||
#[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<u32> = DashSet::default();
|
||||
|
||||
|
@ -462,7 +436,6 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
|
||||
fn test_multiple_hashes() {
|
||||
let set = DashSet::<u32>::default();
|
||||
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
|
5
src/t.rs
5
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<K, V, S>;
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// The index must not be out of bounds.
|
||||
|
||||
unsafe fn _yield_read_shard(&'a self, i: usize) -> RwLockReadGuard<'a, HashMap<K, V, S>>;
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// The index must not be out of bounds.
|
||||
|
||||
unsafe fn _yield_write_shard(&'a self, i: usize) -> RwLockWriteGuard<'a, HashMap<K, V, S>>;
|
||||
|
||||
fn _insert(&self, key: K, value: V) -> Option<V>;
|
||||
|
|
46
src/util.rs
46
src/util.rs
|
@ -22,7 +22,6 @@ pub fn map_in_place_2<T, U, F: FnOnce(U, T) -> 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<T> {
|
||||
value: UnsafeCell<T>,
|
||||
}
|
||||
|
@ -67,7 +64,6 @@ unsafe impl<T: Sync> Sync for SharedValue<T> {}
|
|||
|
||||
impl<T> SharedValue<T> {
|
||||
/// Create a new `SharedValue<T>`
|
||||
|
||||
pub const fn new(value: T) -> Self {
|
||||
Self {
|
||||
value: UnsafeCell::new(value),
|
||||
|
@ -75,25 +71,21 @@ impl<T> SharedValue<T> {
|
|||
}
|
||||
|
||||
/// 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue