├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── rust-toolchain.toml └── src ├── arbitrary.rs ├── iter.rs ├── iter_set.rs ├── lib.rs ├── lock.rs ├── mapref ├── entry.rs ├── entry_ref.rs ├── mod.rs ├── multiple.rs └── one.rs ├── rayon ├── map.rs ├── read_only.rs └── set.rs ├── read_only.rs ├── serde.rs ├── set.rs ├── setref ├── mod.rs ├── multiple.rs └── one.rs ├── try_result.rs └── util.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | lint: 7 | runs-on: ubuntu-22.04 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: style 11 | run: cargo fmt -- --check 12 | - name: clippy 13 | run: cargo clippy --all-targets --all-features -- -D warnings 14 | 15 | test: 16 | runs-on: ubuntu-22.04 17 | strategy: 18 | matrix: 19 | target: [ 20 | x86_64-unknown-linux-gnu, 21 | i686-unknown-linux-gnu, 22 | aarch64-unknown-linux-gnu, 23 | armv7-linux-androideabi, 24 | powerpc-unknown-linux-gnu 25 | ] 26 | steps: 27 | - uses: actions/checkout@v2 28 | - name: setup 29 | run: | 30 | # install misc packages 31 | echo "installing misc packages" 32 | sudo apt-get update 33 | sudo apt-get install apt-transport-https ca-certificates curl software-properties-common 34 | # -- 35 | # add docker ppa 36 | echo "adding docker ppa" 37 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 38 | sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" 39 | # -- 40 | # install docker 41 | echo "installing docker" 42 | sudo apt-get update 43 | sudo apt-get install docker-ce 44 | # -- 45 | # configure docker permissions 46 | echo "configuring docker permissions" 47 | sudo usermod -aG docker ${USER} 48 | sudo -u ${USER} /bin/bash 49 | # -- 50 | # install cross 51 | echo "installing cross" 52 | cargo install cross --locked --version 0.2.5 53 | # -- 54 | - name: test 55 | run: cross test --target ${{ matrix.target }} 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "arbitrary" 7 | version = "1.4.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" 10 | 11 | [[package]] 12 | name = "autocfg" 13 | version = "1.4.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 16 | 17 | [[package]] 18 | name = "bitflags" 19 | version = "2.8.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" 22 | 23 | [[package]] 24 | name = "cfg-if" 25 | version = "1.0.0" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 28 | 29 | [[package]] 30 | name = "crossbeam-deque" 31 | version = "0.8.6" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" 34 | dependencies = [ 35 | "crossbeam-epoch", 36 | "crossbeam-utils", 37 | ] 38 | 39 | [[package]] 40 | name = "crossbeam-epoch" 41 | version = "0.9.18" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 44 | dependencies = [ 45 | "crossbeam-utils", 46 | ] 47 | 48 | [[package]] 49 | name = "crossbeam-utils" 50 | version = "0.8.21" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 53 | 54 | [[package]] 55 | name = "dashmap" 56 | version = "7.0.0-rc2" 57 | dependencies = [ 58 | "arbitrary", 59 | "cfg-if", 60 | "crossbeam-utils", 61 | "equivalent", 62 | "hashbrown", 63 | "lock_api", 64 | "parking_lot_core", 65 | "rayon", 66 | "serde", 67 | "typesize", 68 | ] 69 | 70 | [[package]] 71 | name = "either" 72 | version = "1.13.0" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 75 | 76 | [[package]] 77 | name = "equivalent" 78 | version = "1.0.1" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 81 | 82 | [[package]] 83 | name = "hashbrown" 84 | version = "0.15.2" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 87 | 88 | [[package]] 89 | name = "libc" 90 | version = "0.2.169" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 93 | 94 | [[package]] 95 | name = "lock_api" 96 | version = "0.4.12" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 99 | dependencies = [ 100 | "autocfg", 101 | "scopeguard", 102 | ] 103 | 104 | [[package]] 105 | name = "parking_lot_core" 106 | version = "0.9.10" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 109 | dependencies = [ 110 | "cfg-if", 111 | "libc", 112 | "redox_syscall", 113 | "smallvec", 114 | "windows-targets", 115 | ] 116 | 117 | [[package]] 118 | name = "proc-macro2" 119 | version = "1.0.93" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 122 | dependencies = [ 123 | "unicode-ident", 124 | ] 125 | 126 | [[package]] 127 | name = "quote" 128 | version = "1.0.38" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 131 | dependencies = [ 132 | "proc-macro2", 133 | ] 134 | 135 | [[package]] 136 | name = "rayon" 137 | version = "1.10.0" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" 140 | dependencies = [ 141 | "either", 142 | "rayon-core", 143 | ] 144 | 145 | [[package]] 146 | name = "rayon-core" 147 | version = "1.12.1" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" 150 | dependencies = [ 151 | "crossbeam-deque", 152 | "crossbeam-utils", 153 | ] 154 | 155 | [[package]] 156 | name = "redox_syscall" 157 | version = "0.5.8" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" 160 | dependencies = [ 161 | "bitflags", 162 | ] 163 | 164 | [[package]] 165 | name = "scopeguard" 166 | version = "1.2.0" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 169 | 170 | [[package]] 171 | name = "serde" 172 | version = "1.0.217" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 175 | dependencies = [ 176 | "serde_derive", 177 | ] 178 | 179 | [[package]] 180 | name = "serde_derive" 181 | version = "1.0.217" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 184 | dependencies = [ 185 | "proc-macro2", 186 | "quote", 187 | "syn", 188 | ] 189 | 190 | [[package]] 191 | name = "smallvec" 192 | version = "1.13.2" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 195 | 196 | [[package]] 197 | name = "syn" 198 | version = "2.0.98" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" 201 | dependencies = [ 202 | "proc-macro2", 203 | "quote", 204 | "unicode-ident", 205 | ] 206 | 207 | [[package]] 208 | name = "typesize" 209 | version = "0.1.13" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "e29e4cac0f1acdbbe7b4deb46876a04246dc6abf60b6f2587bef8ae327cd134c" 212 | dependencies = [ 213 | "hashbrown", 214 | "typesize-derive", 215 | ] 216 | 217 | [[package]] 218 | name = "typesize-derive" 219 | version = "0.1.11" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "536b6812192bda8551cfa0e52524e328c6a951b48e66529ee4522d6c721243d6" 222 | dependencies = [ 223 | "proc-macro2", 224 | "quote", 225 | "syn", 226 | ] 227 | 228 | [[package]] 229 | name = "unicode-ident" 230 | version = "1.0.16" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" 233 | 234 | [[package]] 235 | name = "windows-targets" 236 | version = "0.52.6" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 239 | dependencies = [ 240 | "windows_aarch64_gnullvm", 241 | "windows_aarch64_msvc", 242 | "windows_i686_gnu", 243 | "windows_i686_gnullvm", 244 | "windows_i686_msvc", 245 | "windows_x86_64_gnu", 246 | "windows_x86_64_gnullvm", 247 | "windows_x86_64_msvc", 248 | ] 249 | 250 | [[package]] 251 | name = "windows_aarch64_gnullvm" 252 | version = "0.52.6" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 255 | 256 | [[package]] 257 | name = "windows_aarch64_msvc" 258 | version = "0.52.6" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 261 | 262 | [[package]] 263 | name = "windows_i686_gnu" 264 | version = "0.52.6" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 267 | 268 | [[package]] 269 | name = "windows_i686_gnullvm" 270 | version = "0.52.6" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 273 | 274 | [[package]] 275 | name = "windows_i686_msvc" 276 | version = "0.52.6" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 279 | 280 | [[package]] 281 | name = "windows_x86_64_gnu" 282 | version = "0.52.6" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 285 | 286 | [[package]] 287 | name = "windows_x86_64_gnullvm" 288 | version = "0.52.6" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 291 | 292 | [[package]] 293 | name = "windows_x86_64_msvc" 294 | version = "0.52.6" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 297 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dashmap" 3 | version = "7.0.0-rc2" 4 | authors = ["Joel Wejdenstål "] 5 | edition = "2021" 6 | rust-version = "1.70" 7 | license = "MIT" 8 | repository = "https://github.com/xacrimon/dashmap" 9 | homepage = "https://github.com/xacrimon/dashmap" 10 | description = "Blazing fast concurrent HashMap for Rust." 11 | readme = "README.md" 12 | documentation = "https://docs.rs/dashmap" 13 | keywords = ["atomic", "concurrent", "hashmap"] 14 | categories = ["concurrency", "algorithms", "data-structures"] 15 | 16 | [features] 17 | all = ["raw-api", "typesize", "serde", "rayon", "arbitrary"] 18 | raw-api = [] 19 | typesize = ["dep:typesize"] 20 | inline-more = ["hashbrown/inline-more"] 21 | 22 | [dependencies] 23 | lock_api = "0.4.12" 24 | parking_lot_core = "0.9.10" 25 | equivalent = "1.0.1" 26 | hashbrown = { version = "0.15.2", default-features = false } 27 | serde = { version = "1.0.217", optional = true, features = ["derive"] } 28 | cfg-if = "1.0.0" 29 | rayon = { version = "1.10.0", optional = true } 30 | arbitrary = { version = "1.4.1", optional = true } 31 | crossbeam-utils = "0.8" 32 | typesize = { version = "0.1.13", default-features = false, features = ["hashbrown_15"], optional = true } 33 | 34 | [package.metadata.docs.rs] 35 | features = ["all"] 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Joel Wejdenstål 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DashMap 2 | 3 | Blazingly fast concurrent map in Rust. 4 | 5 | DashMap is an implementation of a concurrent associative array/hashmap in Rust. 6 | 7 | DashMap tries to implement an easy to use API similar to `std::collections::HashMap` 8 | with some slight changes to handle concurrency. 9 | 10 | DashMap tries to be very simple to use and to be a direct replacement for `RwLock>`. 11 | To accomplish these goals, all methods take `&self` instead of modifying methods taking `&mut self`. 12 | This allows you to put a DashMap in an `Arc` and share it between threads while still being able to modify it. 13 | 14 | DashMap puts great effort into performance and aims to be as fast as possible. 15 | If you have any suggestions or tips do not hesitate to open an issue or a PR. 16 | 17 | The current MSRV is 1.70 and is not changed in patch releases. You can pin a minor version if you want 18 | perfect stability. Though `dashmap` always stays at least 1 year behind the current stable release. 19 | 20 | [![version](https://img.shields.io/crates/v/dashmap)](https://crates.io/crates/dashmap) 21 | 22 | [![documentation](https://docs.rs/dashmap/badge.svg)](https://docs.rs/dashmap) 23 | 24 | [![downloads](https://img.shields.io/crates/d/dashmap)](https://crates.io/crates/dashmap) 25 | 26 | [![minimum rustc version](https://img.shields.io/badge/rustc-1.70-orange.svg)](https://crates.io/crates/dashmap) 27 | 28 | ## Cargo features 29 | 30 | - `serde` - Enables serde support. 31 | 32 | - `raw-api` - Enables the unstable raw-shard api. 33 | 34 | - `rayon` - Enables rayon support. 35 | 36 | - `inline-more` - Enables `inline-more` feature from the `hashbrown` crate. Comes with the usual tradeoffs of possibly excessive inlining. 37 | 38 | - `arbitrary` - Enables support for the `arbitrary` crate. 39 | 40 | ## Contributing 41 | 42 | DashMap gladly accepts contributions! 43 | Do not hesitate to open issues or PR's. 44 | 45 | I will take a look as soon as I have time for it. 46 | 47 | That said I do not get paid (yet) to work on open-source. This means 48 | that my time is limited and my work here comes after my personal life. 49 | 50 | ## Performance 51 | 52 | A comprehensive benchmark suite including DashMap can be found [here](https://github.com/xacrimon/conc-map-bench). 53 | 54 | ## Special thanks 55 | 56 | - [Conrad Ludgate](https://github.com/conradludgate) 57 | 58 | - [Jon Gjengset](https://github.com/jonhoo) 59 | 60 | - [Yato](https://github.com/RustyYato) 61 | 62 | - [Karl Bergström](https://github.com/kabergstrom) 63 | 64 | - [Dylan DPC](https://github.com/Dylan-DPC) 65 | 66 | - [Lokathor](https://github.com/Lokathor) 67 | 68 | - [namibj](https://github.com/namibj) 69 | 70 | ## License 71 | 72 | This project is licensed under MIT. 73 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.70" 3 | components = ["rustfmt", "clippy"] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /src/arbitrary.rs: -------------------------------------------------------------------------------- 1 | use arbitrary::{Arbitrary, Unstructured}; 2 | use core::hash::BuildHasher; 3 | 4 | impl<'a, K, V, S> Arbitrary<'a> for crate::DashMap 5 | where 6 | K: Eq + std::hash::Hash + Arbitrary<'a>, 7 | V: Arbitrary<'a>, 8 | S: Default + BuildHasher + Clone, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { 11 | u.arbitrary_iter()?.collect() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/iter.rs: -------------------------------------------------------------------------------- 1 | use crossbeam_utils::CachePadded; 2 | use hashbrown::hash_table; 3 | 4 | use super::mapref::multiple::{RefMulti, RefMutMulti}; 5 | use crate::lock::{RwLock, RwLockReadGuardDetached, RwLockWriteGuardDetached}; 6 | use crate::{DashMap, HashMap}; 7 | use core::hash::Hash; 8 | use std::sync::Arc; 9 | 10 | /// Iterator over a DashMap yielding key value pairs. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use dashmap::DashMap; 16 | /// 17 | /// let map = DashMap::new(); 18 | /// map.insert("hello", "world"); 19 | /// map.insert("alex", "steve"); 20 | /// let pairs: Vec<(&'static str, &'static str)> = map.into_iter().collect(); 21 | /// assert_eq!(pairs.len(), 2); 22 | /// ``` 23 | pub struct OwningIter { 24 | shards: std::vec::IntoIter>>>, 25 | current: Option>, 26 | } 27 | 28 | impl OwningIter { 29 | pub(crate) fn new(map: DashMap) -> Self { 30 | Self { 31 | shards: map.shards.into_vec().into_iter(), 32 | current: None, 33 | } 34 | } 35 | } 36 | 37 | type GuardOwningIter = hash_table::IntoIter<(K, V)>; 38 | 39 | impl Iterator for OwningIter { 40 | type Item = (K, V); 41 | 42 | fn next(&mut self) -> Option { 43 | loop { 44 | if let Some(current) = self.current.as_mut() { 45 | if let Some((k, v)) = current.next() { 46 | return Some((k, v)); 47 | } 48 | } 49 | 50 | let iter = self.shards.next()?.into_inner().into_inner().into_iter(); 51 | self.current = Some(iter); 52 | } 53 | } 54 | } 55 | 56 | type GuardIter<'a, K, V> = ( 57 | Arc>, 58 | hash_table::Iter<'a, (K, V)>, 59 | ); 60 | 61 | type GuardIterMut<'a, K, V> = ( 62 | Arc>, 63 | hash_table::IterMut<'a, (K, V)>, 64 | ); 65 | 66 | /// Iterator over a DashMap yielding immutable references. 67 | /// 68 | /// # Examples 69 | /// 70 | /// ``` 71 | /// use dashmap::DashMap; 72 | /// 73 | /// let map = DashMap::new(); 74 | /// map.insert("hello", "world"); 75 | /// assert_eq!(map.iter().count(), 1); 76 | /// ``` 77 | pub struct Iter<'a, K, V> { 78 | shards: std::slice::Iter<'a, CachePadded>>>, 79 | current: Option>, 80 | } 81 | 82 | impl<'i, K: Clone + Hash + Eq, V: Clone> Clone for Iter<'i, K, V> { 83 | fn clone(&self) -> Self { 84 | Iter { 85 | shards: self.shards.clone(), 86 | current: self.current.clone(), 87 | } 88 | } 89 | } 90 | 91 | impl<'a, K: Eq + Hash + 'a, V: 'a> Iter<'a, K, V> { 92 | pub(crate) fn new(map: &'a DashMap) -> Self { 93 | Self { 94 | shards: map.shards.iter(), 95 | current: None, 96 | } 97 | } 98 | } 99 | 100 | impl<'a, K: Eq + Hash + 'a, V: 'a> Iterator for Iter<'a, K, V> { 101 | type Item = RefMulti<'a, K, V>; 102 | 103 | fn next(&mut self) -> Option { 104 | loop { 105 | if let Some(current) = self.current.as_mut() { 106 | if let Some((k, v)) = current.1.next() { 107 | let guard = current.0.clone(); 108 | return Some(RefMulti::new(guard, k, v)); 109 | } 110 | } 111 | 112 | let guard = self.shards.next()?.read(); 113 | // SAFETY: we keep the guard alive with the shard iterator, 114 | // and with any refs produced by the iterator 115 | let (guard, shard) = unsafe { RwLockReadGuardDetached::detach_from(guard) }; 116 | 117 | let iter = shard.iter(); 118 | 119 | self.current = Some((Arc::new(guard), iter)); 120 | } 121 | } 122 | } 123 | 124 | /// Iterator over a DashMap yielding mutable references. 125 | /// 126 | /// # Examples 127 | /// 128 | /// ``` 129 | /// use dashmap::DashMap; 130 | /// 131 | /// let map = DashMap::new(); 132 | /// map.insert("Johnny", 21); 133 | /// map.iter_mut().for_each(|mut r| *r += 1); 134 | /// assert_eq!(*map.get("Johnny").unwrap(), 22); 135 | /// ``` 136 | pub struct IterMut<'a, K, V> { 137 | shards: std::slice::Iter<'a, CachePadded>>>, 138 | current: Option>, 139 | } 140 | 141 | impl<'a, K: Eq + Hash + 'a, V: 'a> IterMut<'a, K, V> { 142 | pub(crate) fn new(map: &'a DashMap) -> Self { 143 | Self { 144 | shards: map.shards.iter(), 145 | current: None, 146 | } 147 | } 148 | } 149 | 150 | impl<'a, K: Eq + Hash + 'a, V: 'a> Iterator for IterMut<'a, K, V> { 151 | type Item = RefMutMulti<'a, K, V>; 152 | 153 | fn next(&mut self) -> Option { 154 | loop { 155 | if let Some(current) = self.current.as_mut() { 156 | if let Some((k, v)) = current.1.next() { 157 | let guard = current.0.clone(); 158 | return Some(RefMutMulti::new(guard, k, v)); 159 | } 160 | } 161 | 162 | let guard = self.shards.next()?.write(); 163 | 164 | // SAFETY: we keep the guard alive with the shard iterator, 165 | // and with any refs produced by the iterator 166 | let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(guard) }; 167 | 168 | let iter = shard.iter_mut(); 169 | 170 | self.current = Some((Arc::new(guard), iter)); 171 | } 172 | } 173 | } 174 | 175 | #[cfg(test)] 176 | mod tests { 177 | use crate::DashMap; 178 | 179 | #[test] 180 | fn iter_mut_manual_count() { 181 | let map = DashMap::new(); 182 | 183 | map.insert("Johnny", 21); 184 | 185 | assert_eq!(map.len(), 1); 186 | 187 | let mut c = 0; 188 | 189 | for shard in map.shards() { 190 | c += shard.write().iter().count(); 191 | } 192 | 193 | assert_eq!(c, 1); 194 | } 195 | 196 | #[test] 197 | fn iter_mut_count() { 198 | let map = DashMap::new(); 199 | 200 | map.insert("Johnny", 21); 201 | 202 | assert_eq!(map.len(), 1); 203 | 204 | assert_eq!(map.iter_mut().count(), 1); 205 | } 206 | 207 | #[test] 208 | fn iter_count() { 209 | let map = DashMap::new(); 210 | 211 | map.insert("Johnny", 21); 212 | 213 | assert_eq!(map.len(), 1); 214 | 215 | assert_eq!(map.iter().count(), 1); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/iter_set.rs: -------------------------------------------------------------------------------- 1 | use crate::setref::multiple::RefMulti; 2 | use core::hash::Hash; 3 | 4 | pub struct OwningIter { 5 | inner: crate::iter::OwningIter, 6 | } 7 | 8 | impl OwningIter { 9 | pub(crate) fn new(inner: crate::iter::OwningIter) -> Self { 10 | Self { inner } 11 | } 12 | } 13 | 14 | impl Iterator for OwningIter { 15 | type Item = K; 16 | 17 | fn next(&mut self) -> Option { 18 | self.inner.next().map(|(k, _)| k) 19 | } 20 | } 21 | 22 | pub struct Iter<'a, K> { 23 | inner: crate::iter::Iter<'a, K, ()>, 24 | } 25 | 26 | impl<'a, K: Eq + Hash + 'a> Iter<'a, K> { 27 | pub(crate) fn new(inner: crate::iter::Iter<'a, K, ()>) -> Self { 28 | Self { inner } 29 | } 30 | } 31 | 32 | impl<'a, K: Eq + Hash + 'a> Iterator for Iter<'a, K> { 33 | type Item = RefMulti<'a, K>; 34 | 35 | fn next(&mut self) -> Option { 36 | self.inner.next().map(RefMulti::new) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![allow(clippy::type_complexity)] 3 | 4 | #[cfg(feature = "arbitrary")] 5 | mod arbitrary; 6 | pub mod iter; 7 | pub mod iter_set; 8 | mod lock; 9 | pub mod mapref; 10 | mod read_only; 11 | #[cfg(feature = "serde")] 12 | mod serde; 13 | mod set; 14 | pub mod setref; 15 | pub mod try_result; 16 | mod util; 17 | 18 | #[cfg(feature = "rayon")] 19 | pub mod rayon { 20 | pub mod map; 21 | pub mod read_only; 22 | pub mod set; 23 | } 24 | 25 | #[cfg(not(feature = "raw-api"))] 26 | use crate::lock::RwLock; 27 | 28 | #[cfg(feature = "raw-api")] 29 | pub use crate::lock::{RawRwLock, RwLock}; 30 | use crate::mapref::entry_ref::EntryRef; 31 | use crate::mapref::entry_ref::OccupiedEntryRef; 32 | use crate::mapref::entry_ref::VacantEntryRef; 33 | 34 | use cfg_if::cfg_if; 35 | use core::fmt; 36 | use core::hash::{BuildHasher, Hash, Hasher}; 37 | use core::iter::FromIterator; 38 | use core::ops::{BitAnd, BitOr, Shl, Shr, Sub}; 39 | use crossbeam_utils::CachePadded; 40 | pub use equivalent::Equivalent; 41 | use hashbrown::hash_table; 42 | use iter::{Iter, IterMut, OwningIter}; 43 | use lock::{RwLockReadGuardDetached, RwLockWriteGuardDetached}; 44 | pub use mapref::entry::{Entry, OccupiedEntry, VacantEntry}; 45 | use mapref::multiple::RefMulti; 46 | use mapref::one::{Ref, RefMut}; 47 | pub use read_only::ReadOnlyView; 48 | pub use set::DashSet; 49 | use std::collections::hash_map::RandomState; 50 | use std::sync::OnceLock; 51 | use try_result::TryResult; 52 | 53 | pub(crate) type HashMap = hash_table::HashTable<(K, V)>; 54 | 55 | // Temporary reimplementation of [`std::collections::TryReserveError`] 56 | // util [`std::collections::TryReserveError`] stabilises. 57 | // We cannot easily create `std::collections` error type from `hashbrown` error type 58 | // without access to `TryReserveError::kind` method. 59 | #[non_exhaustive] 60 | #[derive(Clone, PartialEq, Eq, Debug)] 61 | pub struct TryReserveError {} 62 | 63 | fn default_shard_amount() -> usize { 64 | static DEFAULT_SHARD_AMOUNT: OnceLock = OnceLock::new(); 65 | *DEFAULT_SHARD_AMOUNT.get_or_init(|| { 66 | (std::thread::available_parallelism().map_or(1, usize::from) * 4).next_power_of_two() 67 | }) 68 | } 69 | 70 | fn ncb(shard_amount: usize) -> usize { 71 | shard_amount.trailing_zeros() as usize 72 | } 73 | 74 | /// DashMap is an implementation of a concurrent associative array/hashmap in Rust. 75 | /// 76 | /// DashMap tries to implement an easy to use API similar to `std::collections::HashMap` 77 | /// with some slight changes to handle concurrency. 78 | /// 79 | /// DashMap tries to be very simple to use and to be a direct replacement for `RwLock>`. 80 | /// To accomplish this, all methods take `&self` instead of modifying methods taking `&mut self`. 81 | /// This allows you to put a DashMap in an `Arc` and share it between threads while being able to modify it. 82 | /// 83 | /// Documentation mentioning locking behaviour acts in the reference frame of the calling thread. 84 | /// This means that it is safe to ignore it across multiple threads. 85 | pub struct DashMap { 86 | shift: usize, 87 | shards: Box<[CachePadded>>]>, 88 | hasher: S, 89 | } 90 | 91 | impl Clone for DashMap { 92 | fn clone(&self) -> Self { 93 | fn clone_rwlock(lock: &CachePadded>) -> CachePadded> { 94 | CachePadded::new(RwLock::new(lock.read().clone())) 95 | } 96 | 97 | Self { 98 | shift: self.shift, 99 | shards: self.shards.iter().map(clone_rwlock).collect(), 100 | hasher: self.hasher.clone(), 101 | } 102 | } 103 | } 104 | 105 | impl Default for DashMap 106 | where 107 | K: Eq + Hash, 108 | S: Default + BuildHasher + Clone, 109 | { 110 | fn default() -> Self { 111 | Self::with_hasher(Default::default()) 112 | } 113 | } 114 | 115 | impl<'a, K: 'a + Eq + Hash, V: 'a> DashMap { 116 | /// Creates a new DashMap with a capacity of 0. 117 | /// 118 | /// # Examples 119 | /// 120 | /// ``` 121 | /// use dashmap::DashMap; 122 | /// 123 | /// let reviews = DashMap::new(); 124 | /// reviews.insert("Veloren", "What a fantastic game!"); 125 | /// ``` 126 | pub fn new() -> Self { 127 | DashMap::with_hasher(RandomState::default()) 128 | } 129 | 130 | /// Creates a new DashMap with a specified starting capacity. 131 | /// 132 | /// # Examples 133 | /// 134 | /// ``` 135 | /// use dashmap::DashMap; 136 | /// 137 | /// let mappings = DashMap::with_capacity(2); 138 | /// mappings.insert(2, 4); 139 | /// mappings.insert(8, 16); 140 | /// ``` 141 | pub fn with_capacity(capacity: usize) -> Self { 142 | DashMap::with_capacity_and_hasher(capacity, RandomState::default()) 143 | } 144 | 145 | /// Creates a new DashMap with a specified shard amount 146 | /// 147 | /// shard_amount should greater than 0 and be a power of two. 148 | /// If a shard_amount which is not a power of two is provided, the function will panic. 149 | /// 150 | /// # Examples 151 | /// 152 | /// ``` 153 | /// use dashmap::DashMap; 154 | /// 155 | /// let mappings = DashMap::with_shard_amount(32); 156 | /// mappings.insert(2, 4); 157 | /// mappings.insert(8, 16); 158 | /// ``` 159 | pub fn with_shard_amount(shard_amount: usize) -> Self { 160 | Self::with_capacity_and_hasher_and_shard_amount(0, RandomState::default(), shard_amount) 161 | } 162 | 163 | /// Creates a new DashMap with a specified capacity and shard amount. 164 | /// 165 | /// shard_amount should greater than 0 and be a power of two. 166 | /// If a shard_amount which is not a power of two is provided, the function will panic. 167 | /// 168 | /// # Examples 169 | /// 170 | /// ``` 171 | /// use dashmap::DashMap; 172 | /// 173 | /// let mappings = DashMap::with_capacity_and_shard_amount(32, 32); 174 | /// mappings.insert(2, 4); 175 | /// mappings.insert(8, 16); 176 | /// ``` 177 | pub fn with_capacity_and_shard_amount(capacity: usize, shard_amount: usize) -> Self { 178 | Self::with_capacity_and_hasher_and_shard_amount( 179 | capacity, 180 | RandomState::default(), 181 | shard_amount, 182 | ) 183 | } 184 | } 185 | 186 | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap { 187 | /// Wraps this `DashMap` into a read-only view. This view allows to obtain raw references to the stored values. 188 | pub fn into_read_only(self) -> ReadOnlyView { 189 | ReadOnlyView::new(self) 190 | } 191 | 192 | /// Creates a new DashMap with a capacity of 0 and the provided hasher. 193 | /// 194 | /// # Examples 195 | /// 196 | /// ``` 197 | /// use dashmap::DashMap; 198 | /// use std::collections::hash_map::RandomState; 199 | /// 200 | /// let s = RandomState::new(); 201 | /// let reviews = DashMap::with_hasher(s); 202 | /// reviews.insert("Veloren", "What a fantastic game!"); 203 | /// ``` 204 | pub fn with_hasher(hasher: S) -> Self { 205 | Self::with_capacity_and_hasher(0, hasher) 206 | } 207 | 208 | /// Creates a new DashMap with a specified starting capacity and hasher. 209 | /// 210 | /// # Examples 211 | /// 212 | /// ``` 213 | /// use dashmap::DashMap; 214 | /// use std::collections::hash_map::RandomState; 215 | /// 216 | /// let s = RandomState::new(); 217 | /// let mappings = DashMap::with_capacity_and_hasher(2, s); 218 | /// mappings.insert(2, 4); 219 | /// mappings.insert(8, 16); 220 | /// ``` 221 | pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { 222 | Self::with_capacity_and_hasher_and_shard_amount(capacity, hasher, default_shard_amount()) 223 | } 224 | 225 | /// Creates a new DashMap with a specified hasher and shard amount 226 | /// 227 | /// shard_amount should be greater than 0 and a power of two. 228 | /// If a shard_amount which is not a power of two is provided, the function will panic. 229 | /// 230 | /// # Examples 231 | /// 232 | /// ``` 233 | /// use dashmap::DashMap; 234 | /// use std::collections::hash_map::RandomState; 235 | /// 236 | /// let s = RandomState::new(); 237 | /// let mappings = DashMap::with_hasher_and_shard_amount(s, 32); 238 | /// mappings.insert(2, 4); 239 | /// mappings.insert(8, 16); 240 | /// ``` 241 | pub fn with_hasher_and_shard_amount(hasher: S, shard_amount: usize) -> Self { 242 | Self::with_capacity_and_hasher_and_shard_amount(0, hasher, shard_amount) 243 | } 244 | 245 | /// Creates a new DashMap with a specified starting capacity, hasher and shard_amount. 246 | /// 247 | /// shard_amount should greater than 0 and be a power of two. 248 | /// If a shard_amount which is not a power of two is provided, the function will panic. 249 | /// 250 | /// # Examples 251 | /// 252 | /// ``` 253 | /// use dashmap::DashMap; 254 | /// use std::collections::hash_map::RandomState; 255 | /// 256 | /// let s = RandomState::new(); 257 | /// let mappings = DashMap::with_capacity_and_hasher_and_shard_amount(2, s, 32); 258 | /// mappings.insert(2, 4); 259 | /// mappings.insert(8, 16); 260 | /// ``` 261 | pub fn with_capacity_and_hasher_and_shard_amount( 262 | mut capacity: usize, 263 | hasher: S, 264 | shard_amount: usize, 265 | ) -> Self { 266 | assert!(shard_amount > 1); 267 | assert!(shard_amount.is_power_of_two()); 268 | 269 | let shift = util::ptr_size_bits() - ncb(shard_amount); 270 | 271 | if capacity != 0 { 272 | capacity = (capacity + (shard_amount - 1)) & !(shard_amount - 1); 273 | } 274 | 275 | let cps = capacity / shard_amount; 276 | 277 | let shards = (0..shard_amount) 278 | .map(|_| CachePadded::new(RwLock::new(HashMap::with_capacity(cps)))) 279 | .collect(); 280 | 281 | Self { 282 | shift, 283 | shards, 284 | hasher, 285 | } 286 | } 287 | 288 | /// Hash a given item to produce a usize. 289 | /// Uses the provided or default HashBuilder. 290 | pub fn hash_usize(&self, item: &T) -> usize { 291 | self.hash_u64(item) as usize 292 | } 293 | 294 | fn hash_u64(&self, item: &T) -> u64 { 295 | let mut hasher = self.hasher.build_hasher(); 296 | 297 | item.hash(&mut hasher); 298 | 299 | hasher.finish() 300 | } 301 | 302 | cfg_if! { 303 | if #[cfg(feature = "raw-api")] { 304 | /// Allows you to peek at the inner shards that store your data. 305 | /// You should probably not use this unless you know what you are doing. 306 | /// 307 | /// Requires the `raw-api` feature to be enabled. 308 | /// 309 | /// # Examples 310 | /// 311 | /// ``` 312 | /// use dashmap::DashMap; 313 | /// 314 | /// let map = DashMap::<(), ()>::new(); 315 | /// println!("Amount of shards: {}", map.shards().len()); 316 | /// ``` 317 | pub fn shards(&self) -> &[CachePadded>>] { 318 | &self.shards 319 | } 320 | 321 | /// Provides mutable access to the inner shards that store your data. 322 | /// You should probably not use this unless you know what you are doing. 323 | /// 324 | /// Requires the `raw-api` feature to be enabled. 325 | /// 326 | /// # Examples 327 | /// 328 | /// ``` 329 | /// use dashmap::DashMap; 330 | /// use std::hash::{Hash, Hasher, BuildHasher}; 331 | /// 332 | /// let mut map = DashMap::::new(); 333 | /// let shard_ind = map.determine_map(&42); 334 | /// let mut factory = map.hasher().clone(); 335 | /// let hasher = |tuple: &(i32, &'static str)| { 336 | /// let mut hasher = factory.build_hasher(); 337 | /// tuple.0.hash(&mut hasher); 338 | /// hasher.finish() 339 | /// }; 340 | /// let data = (42, "forty two"); 341 | /// let hash = hasher(&data); 342 | /// map.shards_mut()[shard_ind].get_mut().insert_unique(hash, data, hasher); 343 | /// assert_eq!(*map.get(&42).unwrap(), "forty two"); 344 | /// ``` 345 | pub fn shards_mut(&mut self) -> &mut [CachePadded>>] { 346 | &mut self.shards 347 | } 348 | 349 | /// Consumes this `DashMap` and returns the inner shards. 350 | /// You should probably not use this unless you know what you are doing. 351 | /// 352 | /// Requires the `raw-api` feature to be enabled. 353 | /// 354 | /// See [`DashMap::shards()`] and [`DashMap::shards_mut()`] for more information. 355 | pub fn into_shards(self) -> Box<[CachePadded>>]> { 356 | self.shards 357 | } 358 | } else { 359 | #[allow(dead_code)] 360 | pub(crate) fn shards(&self) -> &[CachePadded>>] { 361 | &self.shards 362 | } 363 | 364 | #[allow(dead_code)] 365 | pub(crate) fn shards_mut(&mut self) -> &mut [CachePadded>>] { 366 | &mut self.shards 367 | } 368 | 369 | #[allow(dead_code)] 370 | pub(crate) fn into_shards(self) -> Box<[CachePadded>>]> { 371 | self.shards 372 | } 373 | } 374 | } 375 | 376 | cfg_if! { 377 | if #[cfg(feature = "raw-api")] { 378 | /// Finds which shard a certain key is stored in. 379 | /// You should probably not use this unless you know what you are doing. 380 | /// Note that shard selection is dependent on the default or provided HashBuilder. 381 | /// 382 | /// Requires the `raw-api` feature to be enabled. 383 | /// 384 | /// # Examples 385 | /// 386 | /// ``` 387 | /// use dashmap::DashMap; 388 | /// 389 | /// let map = DashMap::new(); 390 | /// map.insert("coca-cola", 1.4); 391 | /// println!("coca-cola is stored in shard: {}", map.determine_map("coca-cola")); 392 | /// ``` 393 | pub fn determine_map(&self, key: &Q) -> usize 394 | where 395 | Q: Hash + Equivalent + ?Sized, 396 | { 397 | let hash = self.hash_usize(&key); 398 | self.determine_shard(hash) 399 | } 400 | } 401 | } 402 | 403 | cfg_if! { 404 | if #[cfg(feature = "raw-api")] { 405 | /// Finds which shard a certain hash is stored in. 406 | /// 407 | /// Requires the `raw-api` feature to be enabled. 408 | /// 409 | /// # Examples 410 | /// 411 | /// ``` 412 | /// use dashmap::DashMap; 413 | /// 414 | /// let map: DashMap = DashMap::new(); 415 | /// let key = "key"; 416 | /// let hash = map.hash_usize(&key); 417 | /// println!("hash is stored in shard: {}", map.determine_shard(hash)); 418 | /// ``` 419 | pub fn determine_shard(&self, hash: usize) -> usize { 420 | // Leave the high 7 bits for the HashBrown SIMD tag. 421 | let idx = (hash << 7) >> self.shift; 422 | 423 | // hint to llvm that the panic bounds check can be removed 424 | if idx >= self.shards.len() { 425 | if cfg!(debug_assertions) { 426 | unreachable!("invalid shard index") 427 | } else { 428 | // SAFETY: shards is always a power of two, 429 | // and shift is calculated such that the resulting idx is always 430 | // less than the shards length 431 | unsafe { 432 | std::hint::unreachable_unchecked(); 433 | } 434 | } 435 | } 436 | 437 | idx 438 | } 439 | } else { 440 | 441 | pub(crate) fn determine_shard(&self, hash: usize) -> usize { 442 | // Leave the high 7 bits for the HashBrown SIMD tag. 443 | let idx = (hash << 7) >> self.shift; 444 | 445 | // hint to llvm that the panic bounds check can be removed 446 | if idx >= self.shards.len() { 447 | if cfg!(debug_assertions) { 448 | unreachable!("invalid shard index") 449 | } else { 450 | // SAFETY: shards is always a power of two, 451 | // and shift is calculated such that the resulting idx is always 452 | // less than the shards length 453 | unsafe { 454 | std::hint::unreachable_unchecked(); 455 | } 456 | } 457 | } 458 | 459 | idx 460 | } 461 | } 462 | } 463 | 464 | /// Returns a reference to the map's [`BuildHasher`]. 465 | /// 466 | /// # Examples 467 | /// 468 | /// ```rust 469 | /// use dashmap::DashMap; 470 | /// use std::collections::hash_map::RandomState; 471 | /// 472 | /// let hasher = RandomState::new(); 473 | /// let map: DashMap = DashMap::new(); 474 | /// let hasher: &RandomState = map.hasher(); 475 | /// ``` 476 | /// 477 | /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html 478 | pub fn hasher(&self) -> &S { 479 | &self.hasher 480 | } 481 | 482 | /// Inserts a key and a value into the map. Returns the old value associated with the key if there was one. 483 | /// Does not update the key if it was already present. 484 | /// 485 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 486 | /// 487 | /// # Examples 488 | /// 489 | /// ``` 490 | /// use dashmap::DashMap; 491 | /// 492 | /// let map = DashMap::new(); 493 | /// map.insert("I am the key!", "And I am the value!"); 494 | /// ``` 495 | pub fn insert(&self, key: K, value: V) -> Option { 496 | self._insert(key, value) 497 | } 498 | 499 | /// Removes an entry from the map, returning the key and value if they existed in the map. 500 | /// 501 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 502 | /// 503 | /// # Examples 504 | /// 505 | /// ``` 506 | /// use dashmap::DashMap; 507 | /// 508 | /// let soccer_team = DashMap::new(); 509 | /// soccer_team.insert("Jack", "Goalie"); 510 | /// assert_eq!(soccer_team.remove("Jack").unwrap().1, "Goalie"); 511 | /// ``` 512 | pub fn remove(&self, key: &Q) -> Option<(K, V)> 513 | where 514 | Q: Hash + Equivalent + ?Sized, 515 | { 516 | self._remove(key) 517 | } 518 | 519 | /// Removes an entry from the map, returning the key and value 520 | /// if the entry existed and the provided conditional function returned true. 521 | /// 522 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 523 | /// 524 | /// ``` 525 | /// use dashmap::DashMap; 526 | /// 527 | /// let soccer_team = DashMap::new(); 528 | /// soccer_team.insert("Sam", "Forward"); 529 | /// soccer_team.remove_if("Sam", |_, position| position == &"Goalie"); 530 | /// assert!(soccer_team.contains_key("Sam")); 531 | /// ``` 532 | /// ``` 533 | /// use dashmap::DashMap; 534 | /// 535 | /// let soccer_team = DashMap::new(); 536 | /// soccer_team.insert("Sam", "Forward"); 537 | /// soccer_team.remove_if("Sam", |_, position| position == &"Forward"); 538 | /// assert!(!soccer_team.contains_key("Sam")); 539 | /// ``` 540 | pub fn remove_if(&self, key: &Q, f: impl FnOnce(&K, &V) -> bool) -> Option<(K, V)> 541 | where 542 | Q: Hash + Equivalent + ?Sized, 543 | { 544 | self._remove_if(key, f) 545 | } 546 | 547 | pub fn remove_if_mut(&self, key: &Q, f: impl FnOnce(&K, &mut V) -> bool) -> Option<(K, V)> 548 | where 549 | Q: Hash + Equivalent + ?Sized, 550 | { 551 | self._remove_if_mut(key, f) 552 | } 553 | 554 | /// Creates an iterator over a DashMap yielding immutable references. 555 | /// 556 | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. 557 | /// 558 | /// # Examples 559 | /// 560 | /// ``` 561 | /// use dashmap::DashMap; 562 | /// 563 | /// let words = DashMap::new(); 564 | /// words.insert("hello", "world"); 565 | /// assert_eq!(words.iter().count(), 1); 566 | /// ``` 567 | pub fn iter(&'a self) -> Iter<'a, K, V> { 568 | self._iter() 569 | } 570 | 571 | /// Iterator over a DashMap yielding mutable references. 572 | /// 573 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 574 | /// 575 | /// # Examples 576 | /// 577 | /// ``` 578 | /// use dashmap::DashMap; 579 | /// 580 | /// let map = DashMap::new(); 581 | /// map.insert("Johnny", 21); 582 | /// map.iter_mut().for_each(|mut r| *r += 1); 583 | /// assert_eq!(*map.get("Johnny").unwrap(), 22); 584 | /// ``` 585 | pub fn iter_mut(&'a self) -> IterMut<'a, K, V> { 586 | self._iter_mut() 587 | } 588 | 589 | /// Get an immutable reference to an entry in the map 590 | /// 591 | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. 592 | /// 593 | /// # Examples 594 | /// 595 | /// ``` 596 | /// use dashmap::DashMap; 597 | /// 598 | /// let youtubers = DashMap::new(); 599 | /// youtubers.insert("Bosnian Bill", 457000); 600 | /// assert_eq!(*youtubers.get("Bosnian Bill").unwrap(), 457000); 601 | /// ``` 602 | pub fn get(&'a self, key: &Q) -> Option> 603 | where 604 | Q: Hash + Equivalent + ?Sized, 605 | { 606 | self._get(key) 607 | } 608 | 609 | /// Get a mutable reference to an entry in the map 610 | /// 611 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 612 | /// 613 | /// # Examples 614 | /// 615 | /// ``` 616 | /// use dashmap::DashMap; 617 | /// 618 | /// let class = DashMap::new(); 619 | /// class.insert("Albin", 15); 620 | /// *class.get_mut("Albin").unwrap() -= 1; 621 | /// assert_eq!(*class.get("Albin").unwrap(), 14); 622 | /// ``` 623 | pub fn get_mut(&'a self, key: &Q) -> Option> 624 | where 625 | Q: Hash + Equivalent + ?Sized, 626 | { 627 | self._get_mut(key) 628 | } 629 | 630 | /// Get an immutable reference to an entry in the map, if the shard is not locked. 631 | /// If the shard is locked, the function will return [TryResult::Locked]. 632 | /// 633 | /// # Examples 634 | /// 635 | /// ``` 636 | /// use dashmap::DashMap; 637 | /// use dashmap::try_result::TryResult; 638 | /// 639 | /// let map = DashMap::new(); 640 | /// map.insert("Johnny", 21); 641 | /// 642 | /// assert_eq!(*map.try_get("Johnny").unwrap(), 21); 643 | /// 644 | /// let _result1_locking = map.get_mut("Johnny"); 645 | /// 646 | /// let result2 = map.try_get("Johnny"); 647 | /// assert!(result2.is_locked()); 648 | /// ``` 649 | pub fn try_get(&'a self, key: &Q) -> TryResult> 650 | where 651 | Q: Hash + Equivalent + ?Sized, 652 | { 653 | self._try_get(key) 654 | } 655 | 656 | /// Get a mutable reference to an entry in the map, if the shard is not locked. 657 | /// If the shard is locked, the function will return [TryResult::Locked]. 658 | /// 659 | /// # Examples 660 | /// 661 | /// ``` 662 | /// use dashmap::DashMap; 663 | /// use dashmap::try_result::TryResult; 664 | /// 665 | /// let map = DashMap::new(); 666 | /// map.insert("Johnny", 21); 667 | /// 668 | /// *map.try_get_mut("Johnny").unwrap() += 1; 669 | /// assert_eq!(*map.get("Johnny").unwrap(), 22); 670 | /// 671 | /// let _result1_locking = map.get("Johnny"); 672 | /// 673 | /// let result2 = map.try_get_mut("Johnny"); 674 | /// assert!(result2.is_locked()); 675 | /// ``` 676 | pub fn try_get_mut(&'a self, key: &Q) -> TryResult> 677 | where 678 | Q: Hash + Equivalent + ?Sized, 679 | { 680 | self._try_get_mut(key) 681 | } 682 | 683 | /// Remove excess capacity to reduce memory usage. 684 | /// 685 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 686 | /// # Examples 687 | /// 688 | /// ``` 689 | /// use dashmap::DashMap; 690 | /// use dashmap::try_result::TryResult; 691 | /// 692 | /// let map = DashMap::new(); 693 | /// map.insert("Johnny", 21); 694 | /// assert!(map.capacity() > 0); 695 | /// map.remove("Johnny"); 696 | /// map.shrink_to_fit(); 697 | /// assert_eq!(map.capacity(), 0); 698 | /// ``` 699 | pub fn shrink_to_fit(&self) { 700 | self._shrink_to_fit(); 701 | } 702 | 703 | /// Retain elements that whose predicates return true 704 | /// and discard elements whose predicates return false. 705 | /// 706 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 707 | /// 708 | /// # Examples 709 | /// 710 | /// ``` 711 | /// use dashmap::DashMap; 712 | /// 713 | /// let people = DashMap::new(); 714 | /// people.insert("Albin", 15); 715 | /// people.insert("Jones", 22); 716 | /// people.insert("Charlie", 27); 717 | /// people.retain(|_, v| *v > 20); 718 | /// assert_eq!(people.len(), 2); 719 | /// ``` 720 | pub fn retain(&self, f: impl FnMut(&K, &mut V) -> bool) { 721 | self._retain(f); 722 | } 723 | 724 | /// Fetches the total number of key-value pairs stored in the map. 725 | /// 726 | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. 727 | /// 728 | /// # Examples 729 | /// 730 | /// ``` 731 | /// use dashmap::DashMap; 732 | /// 733 | /// let people = DashMap::new(); 734 | /// people.insert("Albin", 15); 735 | /// people.insert("Jones", 22); 736 | /// people.insert("Charlie", 27); 737 | /// assert_eq!(people.len(), 3); 738 | /// ``` 739 | pub fn len(&self) -> usize { 740 | self._len() 741 | } 742 | 743 | /// Checks if the map is empty or not. 744 | /// 745 | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. 746 | /// 747 | /// # Examples 748 | /// 749 | /// ``` 750 | /// use dashmap::DashMap; 751 | /// 752 | /// let map = DashMap::<(), ()>::new(); 753 | /// assert!(map.is_empty()); 754 | /// ``` 755 | pub fn is_empty(&self) -> bool { 756 | self._is_empty() 757 | } 758 | 759 | /// Removes all key-value pairs in the map. 760 | /// 761 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 762 | /// 763 | /// # Examples 764 | /// 765 | /// ``` 766 | /// use dashmap::DashMap; 767 | /// 768 | /// let stats = DashMap::new(); 769 | /// stats.insert("Goals", 4); 770 | /// assert!(!stats.is_empty()); 771 | /// stats.clear(); 772 | /// assert!(stats.is_empty()); 773 | /// ``` 774 | pub fn clear(&self) { 775 | self._clear(); 776 | } 777 | 778 | /// Returns how many key-value pairs the map can store without reallocating. 779 | /// 780 | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. 781 | pub fn capacity(&self) -> usize { 782 | self._capacity() 783 | } 784 | 785 | /// Modify a specific value according to a function. 786 | /// 787 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 788 | /// 789 | /// # Examples 790 | /// 791 | /// ``` 792 | /// use dashmap::DashMap; 793 | /// 794 | /// let stats = DashMap::new(); 795 | /// stats.insert("Goals", 4); 796 | /// stats.alter("Goals", |_, v| v * 2); 797 | /// assert_eq!(*stats.get("Goals").unwrap(), 8); 798 | /// ``` 799 | /// 800 | /// # Panics 801 | /// 802 | /// If the given closure panics, then `alter` will abort the process 803 | pub fn alter(&self, key: &Q, f: impl FnOnce(&K, V) -> V) 804 | where 805 | Q: Hash + Equivalent + ?Sized, 806 | { 807 | self._alter(key, f); 808 | } 809 | 810 | /// Modify every value in the map according to a function. 811 | /// 812 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 813 | /// 814 | /// # Examples 815 | /// 816 | /// ``` 817 | /// use dashmap::DashMap; 818 | /// 819 | /// let stats = DashMap::new(); 820 | /// stats.insert("Wins", 4); 821 | /// stats.insert("Losses", 2); 822 | /// stats.alter_all(|_, v| v + 1); 823 | /// assert_eq!(*stats.get("Wins").unwrap(), 5); 824 | /// assert_eq!(*stats.get("Losses").unwrap(), 3); 825 | /// ``` 826 | /// 827 | /// # Panics 828 | /// 829 | /// If the given closure panics, then `alter_all` will abort the process 830 | pub fn alter_all(&self, f: impl FnMut(&K, V) -> V) { 831 | self._alter_all(f); 832 | } 833 | 834 | /// Scoped access into an item of the map according to a function. 835 | /// 836 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 837 | /// 838 | /// # Examples 839 | /// 840 | /// ``` 841 | /// use dashmap::DashMap; 842 | /// 843 | /// let warehouse = DashMap::new(); 844 | /// warehouse.insert(4267, ("Banana", 100)); 845 | /// warehouse.insert(2359, ("Pear", 120)); 846 | /// let fruit = warehouse.view(&4267, |_k, v| *v); 847 | /// assert_eq!(fruit, Some(("Banana", 100))); 848 | /// ``` 849 | /// 850 | /// # Panics 851 | /// 852 | /// If the given closure panics, then `view` will abort the process 853 | pub fn view(&self, key: &Q, f: impl FnOnce(&K, &V) -> R) -> Option 854 | where 855 | Q: Hash + Equivalent + ?Sized, 856 | { 857 | self._view(key, f) 858 | } 859 | 860 | /// Checks if the map contains a specific key. 861 | /// 862 | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. 863 | /// 864 | /// # Examples 865 | /// 866 | /// ``` 867 | /// use dashmap::DashMap; 868 | /// 869 | /// let team_sizes = DashMap::new(); 870 | /// team_sizes.insert("Dakota Cherries", 23); 871 | /// assert!(team_sizes.contains_key("Dakota Cherries")); 872 | /// ``` 873 | pub fn contains_key(&self, key: &Q) -> bool 874 | where 875 | Q: Hash + Equivalent + ?Sized, 876 | { 877 | self._contains_key(key) 878 | } 879 | 880 | /// Advanced entry API that tries to mimic `std::collections::HashMap`. 881 | /// See the documentation on `dashmap::mapref::entry` for more details. 882 | /// 883 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 884 | pub fn entry(&'a self, key: K) -> Entry<'a, K, V> { 885 | self._entry(key) 886 | } 887 | 888 | /// Advanced entry API that tries to mimic `std::collections::HashMap`. 889 | /// See the documentation on `dashmap::mapref::entry` for more details. 890 | /// 891 | /// Returns None if the shard is currently locked. 892 | pub fn try_entry(&'a self, key: K) -> Option> { 893 | self._try_entry(key) 894 | } 895 | 896 | /// Advanced entry API that tries to mimic `hashbrown::HashMap::entry_ref`. 897 | /// See the documentation on `dashmap::mapref::entry_ref` for more details. 898 | /// 899 | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. 900 | pub fn entry_ref<'q, Q>(&'a self, key: &'q Q) -> EntryRef<'a, 'q, K, Q, V> 901 | where 902 | Q: Hash + Equivalent, 903 | { 904 | self._entry_ref(key) 905 | } 906 | 907 | /// Advanced entry API that tries to mimic `std::collections::HashMap::try_reserve`. 908 | /// Tries to reserve capacity for at least `shard * additional` 909 | /// and may reserve more space to avoid frequent reallocations. 910 | /// 911 | /// # Errors 912 | /// 913 | /// If the capacity overflows, or the allocator reports a failure, then an error is returned. 914 | // TODO: return std::collections::TryReserveError once std::collections::TryReserveErrorKind stabilises. 915 | pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { 916 | for shard in self.shards.iter() { 917 | shard 918 | .write() 919 | .try_reserve(additional, |(k, _v)| { 920 | let mut hasher = self.hasher.build_hasher(); 921 | k.hash(&mut hasher); 922 | hasher.finish() 923 | }) 924 | .map_err(|_| TryReserveError {})?; 925 | } 926 | Ok(()) 927 | } 928 | } 929 | 930 | impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap { 931 | fn _insert(&self, key: K, value: V) -> Option { 932 | match self.entry(key) { 933 | Entry::Occupied(mut o) => Some(o.insert(value)), 934 | Entry::Vacant(v) => { 935 | v.insert(value); 936 | None 937 | } 938 | } 939 | } 940 | 941 | fn _remove(&self, key: &Q) -> Option<(K, V)> 942 | where 943 | Q: Hash + Equivalent + ?Sized, 944 | { 945 | let hash = self.hash_u64(&key); 946 | 947 | let idx = self.determine_shard(hash as usize); 948 | 949 | let mut shard = self.shards[idx].write(); 950 | 951 | if let Ok(entry) = shard.find_entry(hash, |(k, _v)| key.equivalent(k)) { 952 | let ((k, v), _) = entry.remove(); 953 | Some((k, v)) 954 | } else { 955 | None 956 | } 957 | } 958 | 959 | fn _remove_if(&self, key: &Q, f: impl FnOnce(&K, &V) -> bool) -> Option<(K, V)> 960 | where 961 | Q: Hash + Equivalent + ?Sized, 962 | { 963 | let hash = self.hash_u64(&key); 964 | 965 | let idx = self.determine_shard(hash as usize); 966 | 967 | let mut shard = self.shards[idx].write(); 968 | 969 | if let Ok(entry) = shard.find_entry(hash, |(k, _v)| key.equivalent(k)) { 970 | let (k, v) = entry.get(); 971 | if f(k, v) { 972 | let ((k, v), _) = entry.remove(); 973 | Some((k, v)) 974 | } else { 975 | None 976 | } 977 | } else { 978 | None 979 | } 980 | } 981 | 982 | fn _remove_if_mut(&self, key: &Q, f: impl FnOnce(&K, &mut V) -> bool) -> Option<(K, V)> 983 | where 984 | Q: Hash + Equivalent + ?Sized, 985 | { 986 | let hash = self.hash_u64(&key); 987 | 988 | let idx = self.determine_shard(hash as usize); 989 | 990 | let mut shard = self.shards[idx].write(); 991 | 992 | if let Ok(mut entry) = shard.find_entry(hash, |(k, _v)| key.equivalent(k)) { 993 | let (k, v) = entry.get_mut(); 994 | if f(k, v) { 995 | let ((k, v), _) = entry.remove(); 996 | Some((k, v)) 997 | } else { 998 | None 999 | } 1000 | } else { 1001 | None 1002 | } 1003 | } 1004 | 1005 | fn _iter(&'a self) -> Iter<'a, K, V> { 1006 | Iter::new(self) 1007 | } 1008 | 1009 | fn _iter_mut(&'a self) -> IterMut<'a, K, V> { 1010 | IterMut::new(self) 1011 | } 1012 | 1013 | fn _get(&'a self, key: &Q) -> Option> 1014 | where 1015 | Q: Hash + Equivalent + ?Sized, 1016 | { 1017 | let hash = self.hash_u64(&key); 1018 | 1019 | let idx = self.determine_shard(hash as usize); 1020 | 1021 | let shard = self.shards[idx].read(); 1022 | // SAFETY: The data will not outlive the guard, since we pass the guard to `Ref`. 1023 | let (guard, shard) = unsafe { RwLockReadGuardDetached::detach_from(shard) }; 1024 | 1025 | if let Some((k, v)) = shard.find(hash, |(k, _v)| key.equivalent(k)) { 1026 | Some(Ref::new(guard, k, v)) 1027 | } else { 1028 | None 1029 | } 1030 | } 1031 | 1032 | fn _get_mut(&'a self, key: &Q) -> Option> 1033 | where 1034 | Q: Hash + Equivalent + ?Sized, 1035 | { 1036 | let hash = self.hash_u64(&key); 1037 | 1038 | let idx = self.determine_shard(hash as usize); 1039 | 1040 | let shard = self.shards[idx].write(); 1041 | // SAFETY: The data will not outlive the guard, since we pass the guard to `RefMut`. 1042 | let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) }; 1043 | 1044 | if let Some((k, v)) = shard.find_mut(hash, |(k, _v)| key.equivalent(k)) { 1045 | Some(RefMut::new(guard, k, v)) 1046 | } else { 1047 | None 1048 | } 1049 | } 1050 | 1051 | fn _try_get(&'a self, key: &Q) -> TryResult> 1052 | where 1053 | Q: Hash + Equivalent + ?Sized, 1054 | { 1055 | let hash = self.hash_u64(&key); 1056 | 1057 | let idx = self.determine_shard(hash as usize); 1058 | 1059 | let shard = match self.shards[idx].try_read() { 1060 | Some(shard) => shard, 1061 | None => return TryResult::Locked, 1062 | }; 1063 | // SAFETY: The data will not outlive the guard, since we pass the guard to `Ref`. 1064 | let (guard, shard) = unsafe { RwLockReadGuardDetached::detach_from(shard) }; 1065 | 1066 | if let Some((k, v)) = shard.find(hash, |(k, _v)| key.equivalent(k)) { 1067 | TryResult::Present(Ref::new(guard, k, v)) 1068 | } else { 1069 | TryResult::Absent 1070 | } 1071 | } 1072 | 1073 | fn _try_get_mut(&'a self, key: &Q) -> TryResult> 1074 | where 1075 | Q: Hash + Equivalent + ?Sized, 1076 | { 1077 | let hash = self.hash_u64(&key); 1078 | 1079 | let idx = self.determine_shard(hash as usize); 1080 | 1081 | let shard = match self.shards[idx].try_write() { 1082 | Some(shard) => shard, 1083 | None => return TryResult::Locked, 1084 | }; 1085 | // SAFETY: The data will not outlive the guard, since we pass the guard to `RefMut`. 1086 | let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) }; 1087 | 1088 | if let Some((k, v)) = shard.find_mut(hash, |(k, _v)| key.equivalent(k)) { 1089 | TryResult::Present(RefMut::new(guard, k, v)) 1090 | } else { 1091 | TryResult::Absent 1092 | } 1093 | } 1094 | 1095 | fn _shrink_to_fit(&self) { 1096 | self.shards.iter().for_each(|s| { 1097 | let mut shard = s.write(); 1098 | let size = shard.len(); 1099 | shard.shrink_to(size, |(k, _v)| { 1100 | let mut hasher = self.hasher.build_hasher(); 1101 | k.hash(&mut hasher); 1102 | hasher.finish() 1103 | }) 1104 | }); 1105 | } 1106 | 1107 | fn _retain(&self, mut f: impl FnMut(&K, &mut V) -> bool) { 1108 | self.shards.iter().for_each(|s| { 1109 | s.write().retain(|(k, v)| f(k, v)); 1110 | }); 1111 | } 1112 | 1113 | fn _len(&self) -> usize { 1114 | self.shards.iter().map(|s| s.read().len()).sum() 1115 | } 1116 | 1117 | fn _capacity(&self) -> usize { 1118 | self.shards.iter().map(|s| s.read().capacity()).sum() 1119 | } 1120 | 1121 | fn _alter(&self, key: &Q, f: impl FnOnce(&K, V) -> V) 1122 | where 1123 | Q: Hash + Equivalent + ?Sized, 1124 | { 1125 | if let Some(mut r) = self.get_mut(key) { 1126 | util::map_in_place_2(r.pair_mut(), f); 1127 | } 1128 | } 1129 | 1130 | fn _alter_all(&self, mut f: impl FnMut(&K, V) -> V) { 1131 | self.iter_mut() 1132 | .for_each(|mut m| util::map_in_place_2(m.pair_mut(), &mut f)); 1133 | } 1134 | 1135 | fn _view(&self, key: &Q, f: impl FnOnce(&K, &V) -> R) -> Option 1136 | where 1137 | Q: Hash + Equivalent + ?Sized, 1138 | { 1139 | self.get(key).map(|r| { 1140 | let (k, v) = r.pair(); 1141 | f(k, v) 1142 | }) 1143 | } 1144 | 1145 | fn _entry(&'a self, key: K) -> Entry<'a, K, V> { 1146 | let hash = self.hash_u64(&key); 1147 | 1148 | let idx = self.determine_shard(hash as usize); 1149 | 1150 | let shard = self.shards[idx].write(); 1151 | // SAFETY: The data will not outlive the guard, since we pass the guard to `Entry`. 1152 | let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) }; 1153 | 1154 | match shard.entry( 1155 | hash, 1156 | |(k, _v)| k == &key, 1157 | |(k, _v)| { 1158 | let mut hasher = self.hasher.build_hasher(); 1159 | k.hash(&mut hasher); 1160 | hasher.finish() 1161 | }, 1162 | ) { 1163 | hash_table::Entry::Occupied(entry) => { 1164 | Entry::Occupied(OccupiedEntry::new(guard, key, entry)) 1165 | } 1166 | hash_table::Entry::Vacant(entry) => Entry::Vacant(VacantEntry::new(guard, key, entry)), 1167 | } 1168 | } 1169 | 1170 | fn _try_entry(&'a self, key: K) -> Option> { 1171 | let hash = self.hash_u64(&key); 1172 | 1173 | let idx = self.determine_shard(hash as usize); 1174 | 1175 | let shard = match self.shards[idx].try_write() { 1176 | Some(shard) => shard, 1177 | None => return None, 1178 | }; 1179 | // SAFETY: The data will not outlive the guard, since we pass the guard to `Entry`. 1180 | let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) }; 1181 | 1182 | match shard.entry( 1183 | hash, 1184 | |(k, _v)| k == &key, 1185 | |(k, _v)| { 1186 | let mut hasher = self.hasher.build_hasher(); 1187 | k.hash(&mut hasher); 1188 | hasher.finish() 1189 | }, 1190 | ) { 1191 | hash_table::Entry::Occupied(entry) => { 1192 | Some(Entry::Occupied(OccupiedEntry::new(guard, key, entry))) 1193 | } 1194 | hash_table::Entry::Vacant(entry) => { 1195 | Some(Entry::Vacant(VacantEntry::new(guard, key, entry))) 1196 | } 1197 | } 1198 | } 1199 | 1200 | fn _entry_ref<'q, Q>(&'a self, key: &'q Q) -> EntryRef<'a, 'q, K, Q, V> 1201 | where 1202 | Q: Hash + Equivalent, 1203 | { 1204 | let hash = self.hash_u64(&key); 1205 | 1206 | let idx = self.determine_shard(hash as usize); 1207 | 1208 | let shard = self.shards[idx].write(); 1209 | // SAFETY: The data will not outlive the guard, since we pass the guard to `Entry`. 1210 | let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) }; 1211 | 1212 | match shard.entry( 1213 | hash, 1214 | |(k, _v)| key.equivalent(k), 1215 | |(k, _v)| { 1216 | let mut hasher = self.hasher.build_hasher(); 1217 | k.hash(&mut hasher); 1218 | hasher.finish() 1219 | }, 1220 | ) { 1221 | hash_table::Entry::Occupied(entry) => { 1222 | EntryRef::Occupied(OccupiedEntryRef::new(guard, key, entry)) 1223 | } 1224 | hash_table::Entry::Vacant(entry) => { 1225 | EntryRef::Vacant(VacantEntryRef::new(guard, key, entry)) 1226 | } 1227 | } 1228 | } 1229 | 1230 | fn _try_entry_ref<'q, Q>(&'a self, key: &'q Q) -> Option> 1231 | where 1232 | Q: Hash + Equivalent, 1233 | { 1234 | let hash = self.hash_u64(&key); 1235 | 1236 | let idx = self.determine_shard(hash as usize); 1237 | 1238 | let shard = match self.shards[idx].try_write() { 1239 | Some(shard) => shard, 1240 | None => return None, 1241 | }; 1242 | // SAFETY: The data will not outlive the guard, since we pass the guard to `Entry`. 1243 | let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) }; 1244 | 1245 | match shard.entry( 1246 | hash, 1247 | |(k, _v)| key.equivalent(k), 1248 | |(k, _v)| { 1249 | let mut hasher = self.hasher.build_hasher(); 1250 | k.hash(&mut hasher); 1251 | hasher.finish() 1252 | }, 1253 | ) { 1254 | hash_table::Entry::Occupied(entry) => { 1255 | Some(EntryRef::Occupied(OccupiedEntryRef::new(guard, key, entry))) 1256 | } 1257 | hash_table::Entry::Vacant(entry) => { 1258 | Some(EntryRef::Vacant(VacantEntryRef::new(guard, key, entry))) 1259 | } 1260 | } 1261 | } 1262 | 1263 | fn _clear(&self) { 1264 | self._retain(|_, _| false) 1265 | } 1266 | 1267 | fn _contains_key(&'a self, key: &Q) -> bool 1268 | where 1269 | Q: Hash + Equivalent + ?Sized, 1270 | { 1271 | self._get(key).is_some() 1272 | } 1273 | 1274 | fn _is_empty(&self) -> bool { 1275 | self._len() == 0 1276 | } 1277 | } 1278 | 1279 | impl fmt::Debug 1280 | for DashMap 1281 | { 1282 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1283 | let mut pmap = f.debug_map(); 1284 | 1285 | for r in self { 1286 | let (k, v) = r.pair(); 1287 | 1288 | pmap.entry(k, v); 1289 | } 1290 | 1291 | pmap.finish() 1292 | } 1293 | } 1294 | 1295 | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> Shl<(K, V)> for &'a DashMap { 1296 | type Output = Option; 1297 | 1298 | fn shl(self, pair: (K, V)) -> Self::Output { 1299 | self.insert(pair.0, pair.1) 1300 | } 1301 | } 1302 | 1303 | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> Shr<&Q> for &'a DashMap 1304 | where 1305 | Q: Hash + Equivalent + ?Sized, 1306 | { 1307 | type Output = Ref<'a, K, V>; 1308 | 1309 | fn shr(self, key: &Q) -> Self::Output { 1310 | self.get(key).unwrap() 1311 | } 1312 | } 1313 | 1314 | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> BitOr<&Q> for &'a DashMap 1315 | where 1316 | Q: Hash + Equivalent + ?Sized, 1317 | { 1318 | type Output = RefMut<'a, K, V>; 1319 | 1320 | fn bitor(self, key: &Q) -> Self::Output { 1321 | self.get_mut(key).unwrap() 1322 | } 1323 | } 1324 | 1325 | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> Sub<&Q> for &'a DashMap 1326 | where 1327 | Q: Hash + Equivalent + ?Sized, 1328 | { 1329 | type Output = Option<(K, V)>; 1330 | 1331 | fn sub(self, key: &Q) -> Self::Output { 1332 | self.remove(key) 1333 | } 1334 | } 1335 | 1336 | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> BitAnd<&Q> for &'a DashMap 1337 | where 1338 | Q: Hash + Equivalent + ?Sized, 1339 | { 1340 | type Output = bool; 1341 | 1342 | fn bitand(self, key: &Q) -> Self::Output { 1343 | self.contains_key(key) 1344 | } 1345 | } 1346 | 1347 | impl<'a, K: 'a + Eq + Hash, V: 'a + PartialEq, S: BuildHasher + Clone> PartialEq 1348 | for DashMap 1349 | { 1350 | fn eq(&self, other: &Self) -> bool { 1351 | self.len() == other.len() 1352 | && self.iter().all(|r| { 1353 | other 1354 | .get(r.key()) 1355 | .map_or(false, |ro| r.value() == ro.value()) 1356 | }) 1357 | } 1358 | } 1359 | 1360 | impl<'a, K: 'a + Eq + Hash, V: 'a + Eq, S: BuildHasher + Clone> Eq for DashMap {} 1361 | 1362 | impl IntoIterator for DashMap { 1363 | type Item = (K, V); 1364 | 1365 | type IntoIter = OwningIter; 1366 | 1367 | fn into_iter(self) -> Self::IntoIter { 1368 | OwningIter::new(self) 1369 | } 1370 | } 1371 | 1372 | impl<'a, K: Eq + Hash, V, S: BuildHasher + Clone> IntoIterator for &'a DashMap { 1373 | type Item = RefMulti<'a, K, V>; 1374 | 1375 | type IntoIter = Iter<'a, K, V>; 1376 | 1377 | fn into_iter(self) -> Self::IntoIter { 1378 | self.iter() 1379 | } 1380 | } 1381 | 1382 | impl Extend<(K, V)> for DashMap { 1383 | fn extend>(&mut self, intoiter: I) { 1384 | for pair in intoiter.into_iter() { 1385 | self.insert(pair.0, pair.1); 1386 | } 1387 | } 1388 | } 1389 | 1390 | impl FromIterator<(K, V)> for DashMap { 1391 | fn from_iter>(intoiter: I) -> Self { 1392 | let mut map = DashMap::default(); 1393 | 1394 | map.extend(intoiter); 1395 | 1396 | map 1397 | } 1398 | } 1399 | 1400 | #[cfg(feature = "typesize")] 1401 | impl typesize::TypeSize for DashMap 1402 | where 1403 | K: typesize::TypeSize + Eq + Hash, 1404 | V: typesize::TypeSize, 1405 | S: typesize::TypeSize + Clone + BuildHasher, 1406 | { 1407 | fn extra_size(&self) -> usize { 1408 | let shards_extra_size: usize = self 1409 | .shards 1410 | .iter() 1411 | .map(|shard_lock| { 1412 | core::mem::size_of::>>>() 1413 | + shard_lock.read().extra_size() 1414 | }) 1415 | .sum(); 1416 | 1417 | self.hasher.extra_size() + shards_extra_size 1418 | } 1419 | 1420 | typesize::if_typesize_details! { 1421 | fn get_collection_item_count(&self) -> Option { 1422 | Some(self.len()) 1423 | } 1424 | } 1425 | } 1426 | 1427 | #[cfg(test)] 1428 | mod tests { 1429 | use crate::DashMap; 1430 | use std::collections::hash_map::RandomState; 1431 | 1432 | #[test] 1433 | fn test_basic() { 1434 | let dm = DashMap::new(); 1435 | 1436 | dm.insert(0, 0); 1437 | 1438 | assert_eq!(dm.get(&0).unwrap().value(), &0); 1439 | } 1440 | 1441 | #[test] 1442 | fn test_default() { 1443 | let dm: DashMap = DashMap::default(); 1444 | 1445 | dm.insert(0, 0); 1446 | 1447 | assert_eq!(dm.get(&0).unwrap().value(), &0); 1448 | } 1449 | 1450 | #[test] 1451 | fn test_equal() { 1452 | let dm1 = DashMap::new(); 1453 | let dm2 = DashMap::new(); 1454 | assert_eq!(dm1, dm2); 1455 | 1456 | dm1.insert(0, "Hello, world!"); 1457 | assert_ne!(dm1, dm2); 1458 | 1459 | dm1.insert(1, "Goodbye, world!"); 1460 | assert_ne!(dm1, dm2); 1461 | 1462 | dm2.insert(0, "Hello, world!"); 1463 | assert_ne!(dm1, dm2); 1464 | 1465 | dm2.insert(1, "Goodbye, world!"); 1466 | assert_eq!(dm1, dm2); 1467 | } 1468 | 1469 | #[test] 1470 | fn test_multiple_hashes() { 1471 | let dm: DashMap = DashMap::default(); 1472 | 1473 | for i in 0..100 { 1474 | dm.insert(0, i); 1475 | 1476 | dm.insert(i, i); 1477 | } 1478 | 1479 | for i in 1..100 { 1480 | let r = dm.get(&i).unwrap(); 1481 | 1482 | assert_eq!(i, *r.value()); 1483 | 1484 | assert_eq!(i, *r.key()); 1485 | } 1486 | 1487 | let r = dm.get(&0).unwrap(); 1488 | 1489 | assert_eq!(99, *r.value()); 1490 | } 1491 | 1492 | #[test] 1493 | fn test_more_complex_values() { 1494 | #[derive(Hash, PartialEq, Debug, Clone)] 1495 | 1496 | struct T0 { 1497 | s: String, 1498 | u: u8, 1499 | } 1500 | 1501 | let dm = DashMap::new(); 1502 | 1503 | let range = 0..10; 1504 | 1505 | for i in range { 1506 | let t = T0 { 1507 | s: i.to_string(), 1508 | u: i as u8, 1509 | }; 1510 | 1511 | dm.insert(i, t.clone()); 1512 | 1513 | assert_eq!(&t, dm.get(&i).unwrap().value()); 1514 | } 1515 | } 1516 | 1517 | #[test] 1518 | fn test_different_hashers_randomstate() { 1519 | let dm_hm_default: DashMap = 1520 | DashMap::with_hasher(RandomState::new()); 1521 | 1522 | for i in 0..10 { 1523 | dm_hm_default.insert(i, i); 1524 | 1525 | assert_eq!(i, *dm_hm_default.get(&i).unwrap().value()); 1526 | } 1527 | } 1528 | 1529 | #[test] 1530 | fn test_map_view() { 1531 | let dm = DashMap::new(); 1532 | 1533 | let vegetables: [String; 4] = [ 1534 | "Salad".to_string(), 1535 | "Beans".to_string(), 1536 | "Potato".to_string(), 1537 | "Tomato".to_string(), 1538 | ]; 1539 | 1540 | // Give it some values 1541 | dm.insert(0, "Banana".to_string()); 1542 | dm.insert(4, "Pear".to_string()); 1543 | dm.insert(9, "Potato".to_string()); 1544 | dm.insert(12, "Chicken".to_string()); 1545 | 1546 | let potato_vegetableness = dm.view(&9, |_, v| vegetables.contains(v)); 1547 | assert_eq!(potato_vegetableness, Some(true)); 1548 | 1549 | let chicken_vegetableness = dm.view(&12, |_, v| vegetables.contains(v)); 1550 | assert_eq!(chicken_vegetableness, Some(false)); 1551 | 1552 | let not_in_map = dm.view(&30, |_k, _v| false); 1553 | assert_eq!(not_in_map, None); 1554 | } 1555 | 1556 | #[test] 1557 | fn test_try_get() { 1558 | { 1559 | let map = DashMap::new(); 1560 | map.insert("Johnny", 21); 1561 | 1562 | assert_eq!(*map.try_get("Johnny").unwrap(), 21); 1563 | 1564 | let _result1_locking = map.get_mut("Johnny"); 1565 | 1566 | let result2 = map.try_get("Johnny"); 1567 | assert!(result2.is_locked()); 1568 | } 1569 | 1570 | { 1571 | let map = DashMap::new(); 1572 | map.insert("Johnny", 21); 1573 | 1574 | *map.try_get_mut("Johnny").unwrap() += 1; 1575 | assert_eq!(*map.get("Johnny").unwrap(), 22); 1576 | 1577 | let _result1_locking = map.get("Johnny"); 1578 | 1579 | let result2 = map.try_get_mut("Johnny"); 1580 | assert!(result2.is_locked()); 1581 | } 1582 | } 1583 | 1584 | #[test] 1585 | fn test_try_reserve() { 1586 | let mut map: DashMap = DashMap::new(); 1587 | // DashMap is empty and doesn't allocate memory 1588 | assert_eq!(map.capacity(), 0); 1589 | 1590 | map.try_reserve(10).unwrap(); 1591 | 1592 | // And now map can hold at least 10 elements 1593 | assert!(map.capacity() >= 10); 1594 | } 1595 | 1596 | #[test] 1597 | fn test_try_reserve_errors() { 1598 | let mut map: DashMap = DashMap::new(); 1599 | 1600 | match map.try_reserve(usize::MAX) { 1601 | Err(_) => {} 1602 | _ => panic!("should have raised CapacityOverflow error"), 1603 | } 1604 | } 1605 | } 1606 | -------------------------------------------------------------------------------- /src/lock.rs: -------------------------------------------------------------------------------- 1 | use core::sync::atomic::{AtomicUsize, Ordering}; 2 | use parking_lot_core::{ParkToken, SpinWait, UnparkToken}; 3 | 4 | pub type RwLock = lock_api::RwLock; 5 | pub(crate) type RwLockReadGuardDetached<'a> = crate::util::RwLockReadGuardDetached<'a, RawRwLock>; 6 | pub(crate) type RwLockWriteGuardDetached<'a> = crate::util::RwLockWriteGuardDetached<'a, RawRwLock>; 7 | 8 | const READERS_PARKED: usize = 0b0001; 9 | const WRITERS_PARKED: usize = 0b0010; 10 | const ONE_READER: usize = 0b0100; 11 | const ONE_WRITER: usize = !(READERS_PARKED | WRITERS_PARKED); 12 | 13 | pub struct RawRwLock { 14 | state: AtomicUsize, 15 | } 16 | 17 | unsafe impl lock_api::RawRwLock for RawRwLock { 18 | #[allow(clippy::declare_interior_mutable_const)] 19 | const INIT: Self = Self { 20 | state: AtomicUsize::new(0), 21 | }; 22 | 23 | type GuardMarker = lock_api::GuardSend; 24 | 25 | #[inline] 26 | fn try_lock_exclusive(&self) -> bool { 27 | self.state 28 | .compare_exchange(0, ONE_WRITER, Ordering::Acquire, Ordering::Relaxed) 29 | .is_ok() 30 | } 31 | 32 | #[inline] 33 | fn lock_exclusive(&self) { 34 | if self 35 | .state 36 | .compare_exchange_weak(0, ONE_WRITER, Ordering::Acquire, Ordering::Relaxed) 37 | .is_err() 38 | { 39 | self.lock_exclusive_slow(); 40 | } 41 | } 42 | 43 | #[inline] 44 | unsafe fn unlock_exclusive(&self) { 45 | if self 46 | .state 47 | .compare_exchange(ONE_WRITER, 0, Ordering::Release, Ordering::Relaxed) 48 | .is_err() 49 | { 50 | self.unlock_exclusive_slow(); 51 | } 52 | } 53 | 54 | #[inline] 55 | fn try_lock_shared(&self) -> bool { 56 | self.try_lock_shared_fast() || self.try_lock_shared_slow() 57 | } 58 | 59 | #[inline] 60 | fn lock_shared(&self) { 61 | if !self.try_lock_shared_fast() { 62 | self.lock_shared_slow(); 63 | } 64 | } 65 | 66 | #[inline] 67 | unsafe fn unlock_shared(&self) { 68 | let state = self.state.fetch_sub(ONE_READER, Ordering::Release); 69 | 70 | if state == (ONE_READER | WRITERS_PARKED) { 71 | self.unlock_shared_slow(); 72 | } 73 | } 74 | } 75 | 76 | unsafe impl lock_api::RawRwLockDowngrade for RawRwLock { 77 | #[inline] 78 | unsafe fn downgrade(&self) { 79 | let state = self 80 | .state 81 | .fetch_and(ONE_READER | WRITERS_PARKED, Ordering::Release); 82 | if state & READERS_PARKED != 0 { 83 | parking_lot_core::unpark_all((self as *const _ as usize) + 1, UnparkToken(0)); 84 | } 85 | } 86 | } 87 | 88 | impl RawRwLock { 89 | #[cold] 90 | fn lock_exclusive_slow(&self) { 91 | let mut acquire_with = 0; 92 | loop { 93 | let mut spin = SpinWait::new(); 94 | let mut state = self.state.load(Ordering::Relaxed); 95 | 96 | loop { 97 | while state & ONE_WRITER == 0 { 98 | match self.state.compare_exchange_weak( 99 | state, 100 | state | ONE_WRITER | acquire_with, 101 | Ordering::Acquire, 102 | Ordering::Relaxed, 103 | ) { 104 | Ok(_) => return, 105 | Err(e) => state = e, 106 | } 107 | } 108 | 109 | if state & WRITERS_PARKED == 0 { 110 | if spin.spin() { 111 | state = self.state.load(Ordering::Relaxed); 112 | continue; 113 | } 114 | 115 | if let Err(e) = self.state.compare_exchange_weak( 116 | state, 117 | state | WRITERS_PARKED, 118 | Ordering::Relaxed, 119 | Ordering::Relaxed, 120 | ) { 121 | state = e; 122 | continue; 123 | } 124 | } 125 | 126 | let _ = unsafe { 127 | parking_lot_core::park( 128 | self as *const _ as usize, 129 | || { 130 | let state = self.state.load(Ordering::Relaxed); 131 | (state & ONE_WRITER != 0) && (state & WRITERS_PARKED != 0) 132 | }, 133 | || {}, 134 | |_, _| {}, 135 | ParkToken(0), 136 | None, 137 | ) 138 | }; 139 | 140 | acquire_with = WRITERS_PARKED; 141 | break; 142 | } 143 | } 144 | } 145 | 146 | #[cold] 147 | fn unlock_exclusive_slow(&self) { 148 | let state = self.state.load(Ordering::Relaxed); 149 | assert_eq!(state & ONE_WRITER, ONE_WRITER); 150 | 151 | let mut parked = state & (READERS_PARKED | WRITERS_PARKED); 152 | assert_ne!(parked, 0); 153 | 154 | if parked != (READERS_PARKED | WRITERS_PARKED) { 155 | if let Err(new_state) = 156 | self.state 157 | .compare_exchange(state, 0, Ordering::Release, Ordering::Relaxed) 158 | { 159 | assert_eq!(new_state, ONE_WRITER | READERS_PARKED | WRITERS_PARKED); 160 | parked = READERS_PARKED | WRITERS_PARKED; 161 | } 162 | } 163 | 164 | if parked == (READERS_PARKED | WRITERS_PARKED) { 165 | self.state.store(WRITERS_PARKED, Ordering::Release); 166 | parked = READERS_PARKED; 167 | } 168 | 169 | if parked == READERS_PARKED { 170 | return unsafe { 171 | parking_lot_core::unpark_all((self as *const _ as usize) + 1, UnparkToken(0)); 172 | }; 173 | } 174 | 175 | assert_eq!(parked, WRITERS_PARKED); 176 | unsafe { 177 | parking_lot_core::unpark_one(self as *const _ as usize, |_| UnparkToken(0)); 178 | } 179 | } 180 | 181 | #[inline(always)] 182 | fn try_lock_shared_fast(&self) -> bool { 183 | let state = self.state.load(Ordering::Relaxed); 184 | 185 | if let Some(new_state) = state.checked_add(ONE_READER) { 186 | if new_state & ONE_WRITER != ONE_WRITER { 187 | return self 188 | .state 189 | .compare_exchange_weak(state, new_state, Ordering::Acquire, Ordering::Relaxed) 190 | .is_ok(); 191 | } 192 | } 193 | 194 | false 195 | } 196 | 197 | #[cold] 198 | fn try_lock_shared_slow(&self) -> bool { 199 | let mut state = self.state.load(Ordering::Relaxed); 200 | 201 | while let Some(new_state) = state.checked_add(ONE_READER) { 202 | if new_state & ONE_WRITER == ONE_WRITER { 203 | break; 204 | } 205 | 206 | match self.state.compare_exchange_weak( 207 | state, 208 | new_state, 209 | Ordering::Acquire, 210 | Ordering::Relaxed, 211 | ) { 212 | Ok(_) => return true, 213 | Err(e) => state = e, 214 | } 215 | } 216 | 217 | false 218 | } 219 | 220 | #[cold] 221 | fn lock_shared_slow(&self) { 222 | loop { 223 | let mut spin = SpinWait::new(); 224 | let mut state = self.state.load(Ordering::Relaxed); 225 | 226 | loop { 227 | let mut backoff = SpinWait::new(); 228 | while let Some(new_state) = state.checked_add(ONE_READER) { 229 | assert_ne!( 230 | new_state & ONE_WRITER, 231 | ONE_WRITER, 232 | "reader count overflowed", 233 | ); 234 | 235 | if self 236 | .state 237 | .compare_exchange_weak( 238 | state, 239 | new_state, 240 | Ordering::Acquire, 241 | Ordering::Relaxed, 242 | ) 243 | .is_ok() 244 | { 245 | return; 246 | } 247 | 248 | backoff.spin_no_yield(); 249 | state = self.state.load(Ordering::Relaxed); 250 | } 251 | 252 | if state & READERS_PARKED == 0 { 253 | if spin.spin() { 254 | state = self.state.load(Ordering::Relaxed); 255 | continue; 256 | } 257 | 258 | if let Err(e) = self.state.compare_exchange_weak( 259 | state, 260 | state | READERS_PARKED, 261 | Ordering::Relaxed, 262 | Ordering::Relaxed, 263 | ) { 264 | state = e; 265 | continue; 266 | } 267 | } 268 | 269 | let _ = unsafe { 270 | parking_lot_core::park( 271 | (self as *const _ as usize) + 1, 272 | || { 273 | let state = self.state.load(Ordering::Relaxed); 274 | (state & ONE_WRITER == ONE_WRITER) && (state & READERS_PARKED != 0) 275 | }, 276 | || {}, 277 | |_, _| {}, 278 | ParkToken(0), 279 | None, 280 | ) 281 | }; 282 | 283 | break; 284 | } 285 | } 286 | } 287 | 288 | #[cold] 289 | fn unlock_shared_slow(&self) { 290 | if self 291 | .state 292 | .compare_exchange(WRITERS_PARKED, 0, Ordering::Relaxed, Ordering::Relaxed) 293 | .is_ok() 294 | { 295 | unsafe { 296 | parking_lot_core::unpark_one(self as *const _ as usize, |_| UnparkToken(0)); 297 | } 298 | } 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /src/mapref/entry.rs: -------------------------------------------------------------------------------- 1 | use hashbrown::hash_table; 2 | 3 | use super::one::RefMut; 4 | use crate::lock::RwLockWriteGuardDetached; 5 | use core::hash::Hash; 6 | use core::mem; 7 | 8 | pub enum Entry<'a, K, V> { 9 | Occupied(OccupiedEntry<'a, K, V>), 10 | Vacant(VacantEntry<'a, K, V>), 11 | } 12 | 13 | impl<'a, K: Eq + Hash, V> Entry<'a, K, V> { 14 | /// Apply a function to the stored value if it exists. 15 | pub fn and_modify(self, f: impl FnOnce(&mut V)) -> Self { 16 | match self { 17 | Entry::Occupied(mut entry) => { 18 | f(entry.get_mut()); 19 | 20 | Entry::Occupied(entry) 21 | } 22 | 23 | Entry::Vacant(entry) => Entry::Vacant(entry), 24 | } 25 | } 26 | 27 | /// Get the key of the entry. 28 | pub fn key(&self) -> &K { 29 | match *self { 30 | Entry::Occupied(ref entry) => entry.key(), 31 | Entry::Vacant(ref entry) => entry.key(), 32 | } 33 | } 34 | 35 | /// Into the key of the entry. 36 | pub fn into_key(self) -> K { 37 | match self { 38 | Entry::Occupied(entry) => entry.into_key(), 39 | Entry::Vacant(entry) => entry.into_key(), 40 | } 41 | } 42 | 43 | /// Return a mutable reference to the element if it exists, 44 | /// otherwise insert the default and return a mutable reference to that. 45 | pub fn or_default(self) -> RefMut<'a, K, V> 46 | where 47 | V: Default, 48 | { 49 | match self { 50 | Entry::Occupied(entry) => entry.into_ref(), 51 | Entry::Vacant(entry) => entry.insert(V::default()), 52 | } 53 | } 54 | 55 | /// Return a mutable reference to the element if it exists, 56 | /// otherwise a provided value and return a mutable reference to that. 57 | pub fn or_insert(self, value: V) -> RefMut<'a, K, V> { 58 | match self { 59 | Entry::Occupied(entry) => entry.into_ref(), 60 | Entry::Vacant(entry) => entry.insert(value), 61 | } 62 | } 63 | 64 | /// Return a mutable reference to the element if it exists, 65 | /// otherwise insert the result of a provided function and return a mutable reference to that. 66 | pub fn or_insert_with(self, value: impl FnOnce() -> V) -> RefMut<'a, K, V> { 67 | match self { 68 | Entry::Occupied(entry) => entry.into_ref(), 69 | Entry::Vacant(entry) => entry.insert(value()), 70 | } 71 | } 72 | 73 | pub fn or_try_insert_with( 74 | self, 75 | value: impl FnOnce() -> Result, 76 | ) -> Result, E> { 77 | match self { 78 | Entry::Occupied(entry) => Ok(entry.into_ref()), 79 | Entry::Vacant(entry) => Ok(entry.insert(value()?)), 80 | } 81 | } 82 | 83 | /// Sets the value of the entry, and returns a reference to the inserted value. 84 | pub fn insert(self, value: V) -> RefMut<'a, K, V> { 85 | match self { 86 | Entry::Occupied(mut entry) => { 87 | entry.insert(value); 88 | entry.into_ref() 89 | } 90 | Entry::Vacant(entry) => entry.insert(value), 91 | } 92 | } 93 | 94 | /// Sets the value of the entry, and returns an OccupiedEntry. 95 | /// 96 | /// If you are not interested in the occupied entry, 97 | /// consider [`insert`] as it doesn't need to clone the key. 98 | /// 99 | /// [`insert`]: Entry::insert 100 | pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> 101 | where 102 | K: Clone, 103 | { 104 | match self { 105 | Entry::Occupied(mut entry) => { 106 | entry.insert(value); 107 | entry 108 | } 109 | Entry::Vacant(entry) => entry.insert_entry(value), 110 | } 111 | } 112 | } 113 | 114 | pub struct VacantEntry<'a, K, V> { 115 | shard: RwLockWriteGuardDetached<'a>, 116 | key: K, 117 | entry: hash_table::VacantEntry<'a, (K, V)>, 118 | } 119 | 120 | impl<'a, K: Eq + Hash, V> VacantEntry<'a, K, V> { 121 | pub(crate) fn new( 122 | shard: RwLockWriteGuardDetached<'a>, 123 | key: K, 124 | entry: hash_table::VacantEntry<'a, (K, V)>, 125 | ) -> Self { 126 | Self { shard, key, entry } 127 | } 128 | 129 | pub fn insert(self, value: V) -> RefMut<'a, K, V> { 130 | let occupied = self.entry.insert((self.key, value)); 131 | 132 | let (k, v) = occupied.into_mut(); 133 | 134 | RefMut::new(self.shard, k, v) 135 | } 136 | 137 | /// Sets the value of the entry with the VacantEntry’s key, and returns an OccupiedEntry. 138 | pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> 139 | where 140 | K: Clone, 141 | { 142 | let entry = self.entry.insert((self.key.clone(), value)); 143 | OccupiedEntry::new(self.shard, self.key, entry) 144 | } 145 | 146 | pub fn into_key(self) -> K { 147 | self.key 148 | } 149 | 150 | pub fn key(&self) -> &K { 151 | &self.key 152 | } 153 | } 154 | 155 | pub struct OccupiedEntry<'a, K, V> { 156 | shard: RwLockWriteGuardDetached<'a>, 157 | entry: hash_table::OccupiedEntry<'a, (K, V)>, 158 | key: K, 159 | } 160 | 161 | impl<'a, K: Eq + Hash, V> OccupiedEntry<'a, K, V> { 162 | pub(crate) fn new( 163 | shard: RwLockWriteGuardDetached<'a>, 164 | key: K, 165 | entry: hash_table::OccupiedEntry<'a, (K, V)>, 166 | ) -> Self { 167 | Self { shard, entry, key } 168 | } 169 | 170 | pub fn get(&self) -> &V { 171 | &self.entry.get().1 172 | } 173 | 174 | pub fn get_mut(&mut self) -> &mut V { 175 | &mut self.entry.get_mut().1 176 | } 177 | 178 | pub fn insert(&mut self, value: V) -> V { 179 | mem::replace(self.get_mut(), value) 180 | } 181 | 182 | pub fn into_ref(self) -> RefMut<'a, K, V> { 183 | let (k, v) = self.entry.into_mut(); 184 | RefMut::new(self.shard, k, v) 185 | } 186 | 187 | pub fn into_key(self) -> K { 188 | self.key 189 | } 190 | 191 | pub fn key(&self) -> &K { 192 | &self.entry.get().0 193 | } 194 | 195 | pub fn remove(self) -> V { 196 | let ((_k, v), _) = self.entry.remove(); 197 | v 198 | } 199 | 200 | pub fn remove_entry(self) -> (K, V) { 201 | let ((k, v), _) = self.entry.remove(); 202 | (k, v) 203 | } 204 | 205 | pub fn replace_entry(self, value: V) -> (K, V) { 206 | let (k, v) = mem::replace(self.entry.into_mut(), (self.key, value)); 207 | (k, v) 208 | } 209 | } 210 | 211 | #[cfg(test)] 212 | mod tests { 213 | use crate::DashMap; 214 | 215 | use super::*; 216 | 217 | #[test] 218 | fn test_insert_into_vacant() { 219 | let map: DashMap = DashMap::new(); 220 | 221 | let entry = map.entry(1); 222 | 223 | assert!(matches!(entry, Entry::Vacant(_))); 224 | 225 | let val = entry.insert(2); 226 | 227 | assert_eq!(*val, 2); 228 | 229 | drop(val); 230 | 231 | assert_eq!(*map.get(&1).unwrap(), 2); 232 | } 233 | 234 | #[test] 235 | fn test_insert_into_occupied() { 236 | let map: DashMap = DashMap::new(); 237 | 238 | map.insert(1, 1000); 239 | 240 | let entry = map.entry(1); 241 | 242 | assert!(matches!(&entry, Entry::Occupied(entry) if *entry.get() == 1000)); 243 | 244 | let val = entry.insert(2); 245 | 246 | assert_eq!(*val, 2); 247 | 248 | drop(val); 249 | 250 | assert_eq!(*map.get(&1).unwrap(), 2); 251 | } 252 | 253 | #[test] 254 | fn test_insert_entry_into_vacant() { 255 | let map: DashMap = DashMap::new(); 256 | 257 | let entry = map.entry(1); 258 | 259 | assert!(matches!(entry, Entry::Vacant(_))); 260 | 261 | let entry = entry.insert_entry(2); 262 | 263 | assert_eq!(*entry.get(), 2); 264 | 265 | drop(entry); 266 | 267 | assert_eq!(*map.get(&1).unwrap(), 2); 268 | } 269 | 270 | #[test] 271 | fn test_insert_entry_into_occupied() { 272 | let map: DashMap = DashMap::new(); 273 | 274 | map.insert(1, 1000); 275 | 276 | let entry = map.entry(1); 277 | 278 | assert!(matches!(&entry, Entry::Occupied(entry) if *entry.get() == 1000)); 279 | 280 | let entry = entry.insert_entry(2); 281 | 282 | assert_eq!(*entry.get(), 2); 283 | 284 | drop(entry); 285 | 286 | assert_eq!(*map.get(&1).unwrap(), 2); 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /src/mapref/entry_ref.rs: -------------------------------------------------------------------------------- 1 | use hashbrown::hash_table; 2 | 3 | use super::one::RefMut; 4 | use crate::lock::RwLockWriteGuardDetached; 5 | use core::hash::Hash; 6 | use std::mem; 7 | 8 | /// Entry with a borrowed key. 9 | pub enum EntryRef<'a, 'q, K, Q, V> { 10 | Occupied(OccupiedEntryRef<'a, 'q, K, Q, V>), 11 | Vacant(VacantEntryRef<'a, 'q, K, Q, V>), 12 | } 13 | 14 | impl<'a, 'q, K: Eq + Hash, Q, V> EntryRef<'a, 'q, K, Q, V> { 15 | /// Apply a function to the stored value if it exists. 16 | pub fn and_modify(self, f: impl FnOnce(&mut V)) -> Self { 17 | match self { 18 | EntryRef::Occupied(mut entry) => { 19 | f(entry.get_mut()); 20 | 21 | EntryRef::Occupied(entry) 22 | } 23 | 24 | EntryRef::Vacant(entry) => EntryRef::Vacant(entry), 25 | } 26 | } 27 | } 28 | 29 | impl<'a, 'q, K: Eq + Hash + From<&'q Q>, Q, V> EntryRef<'a, 'q, K, Q, V> { 30 | /// Get the key of the entry. 31 | pub fn key(&self) -> &Q { 32 | match *self { 33 | EntryRef::Occupied(ref entry) => entry.key(), 34 | EntryRef::Vacant(ref entry) => entry.key(), 35 | } 36 | } 37 | 38 | /// Into the key of the entry. 39 | pub fn into_key(self) -> K { 40 | match self { 41 | EntryRef::Occupied(entry) => entry.into_key(), 42 | EntryRef::Vacant(entry) => entry.into_key(), 43 | } 44 | } 45 | 46 | /// Return a mutable reference to the element if it exists, 47 | /// otherwise insert the default and return a mutable reference to that. 48 | pub fn or_default(self) -> RefMut<'a, K, V> 49 | where 50 | V: Default, 51 | { 52 | match self { 53 | EntryRef::Occupied(entry) => entry.into_ref(), 54 | EntryRef::Vacant(entry) => entry.insert(V::default()), 55 | } 56 | } 57 | 58 | /// Return a mutable reference to the element if it exists, 59 | /// otherwise a provided value and return a mutable reference to that. 60 | pub fn or_insert(self, value: V) -> RefMut<'a, K, V> { 61 | match self { 62 | EntryRef::Occupied(entry) => entry.into_ref(), 63 | EntryRef::Vacant(entry) => entry.insert(value), 64 | } 65 | } 66 | 67 | /// Return a mutable reference to the element if it exists, 68 | /// otherwise insert the result of a provided function and return a mutable reference to that. 69 | pub fn or_insert_with(self, value: impl FnOnce() -> V) -> RefMut<'a, K, V> { 70 | match self { 71 | EntryRef::Occupied(entry) => entry.into_ref(), 72 | EntryRef::Vacant(entry) => entry.insert(value()), 73 | } 74 | } 75 | 76 | pub fn or_try_insert_with( 77 | self, 78 | value: impl FnOnce() -> Result, 79 | ) -> Result, E> { 80 | match self { 81 | EntryRef::Occupied(entry) => Ok(entry.into_ref()), 82 | EntryRef::Vacant(entry) => Ok(entry.insert(value()?)), 83 | } 84 | } 85 | 86 | /// Sets the value of the entry, and returns a reference to the inserted value. 87 | pub fn insert(self, value: V) -> RefMut<'a, K, V> { 88 | match self { 89 | EntryRef::Occupied(mut entry) => { 90 | entry.insert(value); 91 | entry.into_ref() 92 | } 93 | EntryRef::Vacant(entry) => entry.insert(value), 94 | } 95 | } 96 | 97 | /// Sets the value of the entry, and returns an OccupiedEntryRef. 98 | /// 99 | /// If you are not interested in the occupied entry, 100 | /// consider [`insert`] as it doesn't need to clone the key. 101 | /// 102 | /// [`insert`]: EntryRef::insert 103 | pub fn insert_entry(self, value: V) -> OccupiedEntryRef<'a, 'q, K, Q, V> 104 | where 105 | K: Clone, 106 | { 107 | match self { 108 | EntryRef::Occupied(mut entry) => { 109 | entry.insert(value); 110 | entry 111 | } 112 | EntryRef::Vacant(entry) => entry.insert_entry(value), 113 | } 114 | } 115 | } 116 | 117 | pub struct VacantEntryRef<'a, 'q, K, Q, V> { 118 | shard: RwLockWriteGuardDetached<'a>, 119 | entry: hash_table::VacantEntry<'a, (K, V)>, 120 | key: &'q Q, 121 | } 122 | 123 | impl<'a, 'q, K: Eq + Hash, Q, V> VacantEntryRef<'a, 'q, K, Q, V> { 124 | pub(crate) fn new( 125 | shard: RwLockWriteGuardDetached<'a>, 126 | key: &'q Q, 127 | entry: hash_table::VacantEntry<'a, (K, V)>, 128 | ) -> Self { 129 | Self { shard, entry, key } 130 | } 131 | 132 | pub fn insert(self, value: V) -> RefMut<'a, K, V> 133 | where 134 | K: From<&'q Q>, 135 | { 136 | let k = K::from(self.key); 137 | let occupied = self.entry.insert((k, value)); 138 | let (k, v) = occupied.into_mut(); 139 | 140 | RefMut::new(self.shard, k, v) 141 | } 142 | 143 | /// Sets the value of the entry with the VacantEntryRef’s key, and returns an OccupiedEntry. 144 | pub fn insert_entry(self, value: V) -> OccupiedEntryRef<'a, 'q, K, Q, V> 145 | where 146 | K: From<&'q Q>, 147 | { 148 | let k = K::from(self.key); 149 | let entry = self.entry.insert((k, value)); 150 | OccupiedEntryRef::new(self.shard, self.key, entry) 151 | } 152 | 153 | pub fn into_key(self) -> K 154 | where 155 | K: From<&'q Q>, 156 | { 157 | K::from(self.key) 158 | } 159 | 160 | pub fn key(&self) -> &'q Q { 161 | self.key 162 | } 163 | } 164 | 165 | pub struct OccupiedEntryRef<'a, 'q, K, Q, V> { 166 | shard: RwLockWriteGuardDetached<'a>, 167 | entry: hash_table::OccupiedEntry<'a, (K, V)>, 168 | key: &'q Q, 169 | } 170 | 171 | impl<'a, 'q, K: Eq + Hash, Q, V> OccupiedEntryRef<'a, 'q, K, Q, V> { 172 | pub(crate) fn new( 173 | shard: RwLockWriteGuardDetached<'a>, 174 | key: &'q Q, 175 | entry: hash_table::OccupiedEntry<'a, (K, V)>, 176 | ) -> Self { 177 | Self { shard, entry, key } 178 | } 179 | 180 | pub fn get(&self) -> &V { 181 | &self.entry.get().1 182 | } 183 | 184 | pub fn get_mut(&mut self) -> &mut V { 185 | &mut self.entry.get_mut().1 186 | } 187 | 188 | pub fn insert(&mut self, value: V) -> V { 189 | mem::replace(self.get_mut(), value) 190 | } 191 | 192 | pub fn into_ref(self) -> RefMut<'a, K, V> { 193 | let (k, v) = self.entry.into_mut(); 194 | RefMut::new(self.shard, k, v) 195 | } 196 | 197 | pub fn into_key(self) -> K 198 | where 199 | K: From<&'q Q>, 200 | { 201 | K::from(self.key) 202 | } 203 | 204 | pub fn key(&self) -> &'q Q { 205 | self.key 206 | } 207 | 208 | pub fn remove(self) -> V { 209 | let ((_k, v), _) = self.entry.remove(); 210 | v 211 | } 212 | 213 | pub fn remove_entry(self) -> (K, V) { 214 | let ((k, v), _) = self.entry.remove(); 215 | (k, v) 216 | } 217 | 218 | pub fn replace_entry(self, value: V) -> (K, V) 219 | where 220 | K: From<&'q Q>, 221 | { 222 | let (k, v) = mem::replace(self.entry.into_mut(), (K::from(self.key), value)); 223 | (k, v) 224 | } 225 | } 226 | 227 | #[cfg(test)] 228 | mod tests { 229 | use equivalent::Equivalent; 230 | 231 | use crate::DashMap; 232 | 233 | use super::*; 234 | 235 | #[derive(Hash, PartialEq, Eq, Debug)] 236 | struct K(u32); 237 | impl From<&K> for u32 { 238 | fn from(value: &K) -> Self { 239 | value.0 240 | } 241 | } 242 | impl Equivalent for K { 243 | fn equivalent(&self, key: &u32) -> bool { 244 | self.0 == *key 245 | } 246 | } 247 | 248 | #[test] 249 | fn test_insert_into_vacant() { 250 | let map: DashMap = DashMap::new(); 251 | 252 | let entry = map.entry_ref(&K(1)); 253 | 254 | assert!(matches!(entry, EntryRef::Vacant(_))); 255 | 256 | let val = entry.insert(2); 257 | 258 | assert_eq!(*val, 2); 259 | 260 | drop(val); 261 | 262 | assert_eq!(*map.get(&1).unwrap(), 2); 263 | } 264 | 265 | #[test] 266 | fn test_insert_into_occupied() { 267 | let map: DashMap = DashMap::new(); 268 | 269 | map.insert(1, 1000); 270 | 271 | let entry = map.entry_ref(&K(1)); 272 | 273 | assert!(matches!(&entry, EntryRef::Occupied(entry) if *entry.get() == 1000)); 274 | 275 | let val = entry.insert(2); 276 | 277 | assert_eq!(*val, 2); 278 | 279 | drop(val); 280 | 281 | assert_eq!(*map.get(&1).unwrap(), 2); 282 | } 283 | 284 | #[test] 285 | fn test_insert_entry_into_vacant() { 286 | let map: DashMap = DashMap::new(); 287 | 288 | let entry = map.entry_ref(&K(1)); 289 | 290 | assert!(matches!(entry, EntryRef::Vacant(_))); 291 | 292 | let entry = entry.insert_entry(2); 293 | 294 | assert_eq!(*entry.get(), 2); 295 | 296 | drop(entry); 297 | 298 | assert_eq!(*map.get(&1).unwrap(), 2); 299 | } 300 | 301 | #[test] 302 | fn test_insert_entry_into_occupied() { 303 | let map: DashMap = DashMap::new(); 304 | 305 | map.insert(1, 1000); 306 | 307 | let entry = map.entry_ref(&K(1)); 308 | 309 | assert!(matches!(&entry, EntryRef::Occupied(entry) if *entry.get() == 1000)); 310 | 311 | let entry = entry.insert_entry(2); 312 | 313 | assert_eq!(*entry.get(), 2); 314 | 315 | drop(entry); 316 | 317 | assert_eq!(*map.get(&1).unwrap(), 2); 318 | } 319 | } 320 | -------------------------------------------------------------------------------- /src/mapref/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod entry; 2 | pub mod entry_ref; 3 | pub mod multiple; 4 | pub mod one; 5 | -------------------------------------------------------------------------------- /src/mapref/multiple.rs: -------------------------------------------------------------------------------- 1 | use crate::lock::{RwLockReadGuardDetached, RwLockWriteGuardDetached}; 2 | use core::hash::Hash; 3 | use core::ops::{Deref, DerefMut}; 4 | use std::sync::Arc; 5 | 6 | pub struct RefMulti<'a, K, V> { 7 | _guard: Arc>, 8 | k: &'a K, 9 | v: &'a V, 10 | } 11 | 12 | impl<'a, K: Eq + Hash, V> RefMulti<'a, K, V> { 13 | pub(crate) fn new(guard: Arc>, k: &'a K, v: &'a V) -> Self { 14 | Self { 15 | _guard: guard, 16 | k, 17 | v, 18 | } 19 | } 20 | 21 | pub fn key(&self) -> &K { 22 | self.pair().0 23 | } 24 | 25 | pub fn value(&self) -> &V { 26 | self.pair().1 27 | } 28 | 29 | pub fn pair(&self) -> (&K, &V) { 30 | (self.k, self.v) 31 | } 32 | } 33 | 34 | impl<'a, K: Eq + Hash, V> Deref for RefMulti<'a, K, V> { 35 | type Target = V; 36 | 37 | fn deref(&self) -> &V { 38 | self.value() 39 | } 40 | } 41 | 42 | pub struct RefMutMulti<'a, K, V> { 43 | _guard: Arc>, 44 | k: &'a K, 45 | v: &'a mut V, 46 | } 47 | 48 | impl<'a, K: Eq + Hash, V> RefMutMulti<'a, K, V> { 49 | pub(crate) fn new(guard: Arc>, k: &'a K, v: &'a mut V) -> Self { 50 | Self { 51 | _guard: guard, 52 | k, 53 | v, 54 | } 55 | } 56 | 57 | pub fn key(&self) -> &K { 58 | self.pair().0 59 | } 60 | 61 | pub fn value(&self) -> &V { 62 | self.pair().1 63 | } 64 | 65 | pub fn value_mut(&mut self) -> &mut V { 66 | self.pair_mut().1 67 | } 68 | 69 | pub fn pair(&self) -> (&K, &V) { 70 | (self.k, self.v) 71 | } 72 | 73 | pub fn pair_mut(&mut self) -> (&K, &mut V) { 74 | (self.k, self.v) 75 | } 76 | } 77 | 78 | impl<'a, K: Eq + Hash, V> Deref for RefMutMulti<'a, K, V> { 79 | type Target = V; 80 | 81 | fn deref(&self) -> &V { 82 | self.value() 83 | } 84 | } 85 | 86 | impl<'a, K: Eq + Hash, V> DerefMut for RefMutMulti<'a, K, V> { 87 | fn deref_mut(&mut self) -> &mut V { 88 | self.value_mut() 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/mapref/one.rs: -------------------------------------------------------------------------------- 1 | use crate::lock::{RwLockReadGuardDetached, RwLockWriteGuardDetached}; 2 | use core::hash::Hash; 3 | use core::ops::{Deref, DerefMut}; 4 | use std::fmt::{Debug, Formatter}; 5 | 6 | pub struct Ref<'a, K, V> { 7 | _guard: RwLockReadGuardDetached<'a>, 8 | k: &'a K, 9 | v: &'a V, 10 | } 11 | 12 | impl<'a, K: Eq + Hash, V> Ref<'a, K, V> { 13 | pub(crate) fn new(guard: RwLockReadGuardDetached<'a>, k: &'a K, v: &'a V) -> Self { 14 | Self { 15 | _guard: guard, 16 | k, 17 | v, 18 | } 19 | } 20 | 21 | pub fn key(&self) -> &K { 22 | self.pair().0 23 | } 24 | 25 | pub fn value(&self) -> &V { 26 | self.pair().1 27 | } 28 | 29 | pub fn pair(&self) -> (&K, &V) { 30 | (self.k, self.v) 31 | } 32 | 33 | pub fn map(self, f: F) -> MappedRef<'a, K, T> 34 | where 35 | F: FnOnce(&V) -> &T, 36 | { 37 | MappedRef { 38 | _guard: self._guard, 39 | k: self.k, 40 | v: f(self.v), 41 | } 42 | } 43 | 44 | pub fn try_map(self, f: F) -> Result, Self> 45 | where 46 | F: FnOnce(&V) -> Option<&T>, 47 | { 48 | if let Some(v) = f(self.v) { 49 | Ok(MappedRef { 50 | _guard: self._guard, 51 | k: self.k, 52 | v, 53 | }) 54 | } else { 55 | Err(self) 56 | } 57 | } 58 | } 59 | 60 | impl<'a, K: Eq + Hash + Debug, V: Debug> Debug for Ref<'a, K, V> { 61 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 62 | f.debug_struct("Ref") 63 | .field("k", &self.k) 64 | .field("v", &self.v) 65 | .finish() 66 | } 67 | } 68 | 69 | impl<'a, K: Eq + Hash, V> Deref for Ref<'a, K, V> { 70 | type Target = V; 71 | 72 | fn deref(&self) -> &V { 73 | self.value() 74 | } 75 | } 76 | 77 | pub struct RefMut<'a, K, V> { 78 | guard: RwLockWriteGuardDetached<'a>, 79 | k: &'a K, 80 | v: &'a mut V, 81 | } 82 | 83 | impl<'a, K: Eq + Hash, V> RefMut<'a, K, V> { 84 | pub(crate) fn new(guard: RwLockWriteGuardDetached<'a>, k: &'a K, v: &'a mut V) -> Self { 85 | Self { guard, k, v } 86 | } 87 | 88 | pub fn key(&self) -> &K { 89 | self.pair().0 90 | } 91 | 92 | pub fn value(&self) -> &V { 93 | self.pair().1 94 | } 95 | 96 | pub fn value_mut(&mut self) -> &mut V { 97 | self.pair_mut().1 98 | } 99 | 100 | pub fn pair(&self) -> (&K, &V) { 101 | (self.k, self.v) 102 | } 103 | 104 | pub fn pair_mut(&mut self) -> (&K, &mut V) { 105 | (self.k, self.v) 106 | } 107 | 108 | pub fn downgrade(self) -> Ref<'a, K, V> { 109 | Ref::new( 110 | unsafe { RwLockWriteGuardDetached::downgrade(self.guard) }, 111 | self.k, 112 | self.v, 113 | ) 114 | } 115 | 116 | pub fn map(self, f: F) -> MappedRefMut<'a, K, T> 117 | where 118 | F: FnOnce(&mut V) -> &mut T, 119 | { 120 | MappedRefMut { 121 | _guard: self.guard, 122 | k: self.k, 123 | v: f(&mut *self.v), 124 | } 125 | } 126 | 127 | pub fn try_map(self, f: F) -> Result, Self> 128 | where 129 | F: FnOnce(&mut V) -> Option<&mut T>, 130 | { 131 | let v = match f(unsafe { &mut *(self.v as *mut _) }) { 132 | Some(v) => v, 133 | None => return Err(self), 134 | }; 135 | let guard = self.guard; 136 | let k = self.k; 137 | Ok(MappedRefMut { 138 | _guard: guard, 139 | k, 140 | v, 141 | }) 142 | } 143 | } 144 | 145 | impl<'a, K: Eq + Hash + Debug, V: Debug> Debug for RefMut<'a, K, V> { 146 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 147 | f.debug_struct("RefMut") 148 | .field("k", &self.k) 149 | .field("v", &self.v) 150 | .finish() 151 | } 152 | } 153 | 154 | impl<'a, K: Eq + Hash, V> Deref for RefMut<'a, K, V> { 155 | type Target = V; 156 | 157 | fn deref(&self) -> &V { 158 | self.value() 159 | } 160 | } 161 | 162 | impl<'a, K: Eq + Hash, V> DerefMut for RefMut<'a, K, V> { 163 | fn deref_mut(&mut self) -> &mut V { 164 | self.value_mut() 165 | } 166 | } 167 | 168 | pub struct MappedRef<'a, K, T: ?Sized> { 169 | _guard: RwLockReadGuardDetached<'a>, 170 | k: &'a K, 171 | v: &'a T, 172 | } 173 | 174 | impl<'a, K: Eq + Hash, T: ?Sized> MappedRef<'a, K, T> { 175 | pub fn key(&self) -> &K { 176 | self.pair().0 177 | } 178 | 179 | pub fn value(&self) -> &T { 180 | self.pair().1 181 | } 182 | 183 | pub fn pair(&self) -> (&K, &T) { 184 | (self.k, self.v) 185 | } 186 | 187 | pub fn map(self, f: F) -> MappedRef<'a, K, T2> 188 | where 189 | F: FnOnce(&T) -> &T2, 190 | { 191 | MappedRef { 192 | _guard: self._guard, 193 | k: self.k, 194 | v: f(self.v), 195 | } 196 | } 197 | 198 | pub fn try_map(self, f: F) -> Result, Self> 199 | where 200 | F: FnOnce(&T) -> Option<&T2>, 201 | { 202 | let v = match f(self.v) { 203 | Some(v) => v, 204 | None => return Err(self), 205 | }; 206 | let guard = self._guard; 207 | Ok(MappedRef { 208 | _guard: guard, 209 | k: self.k, 210 | v, 211 | }) 212 | } 213 | } 214 | 215 | impl<'a, K: Eq + Hash + Debug, T: Debug + ?Sized> Debug for MappedRef<'a, K, T> { 216 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 217 | f.debug_struct("MappedRef") 218 | .field("k", &self.k) 219 | .field("v", &self.v) 220 | .finish() 221 | } 222 | } 223 | 224 | impl<'a, K: Eq + Hash, T: ?Sized> Deref for MappedRef<'a, K, T> { 225 | type Target = T; 226 | 227 | fn deref(&self) -> &T { 228 | self.value() 229 | } 230 | } 231 | 232 | impl<'a, K: Eq + Hash, T: std::fmt::Display + ?Sized> std::fmt::Display for MappedRef<'a, K, T> { 233 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 234 | std::fmt::Display::fmt(self.value(), f) 235 | } 236 | } 237 | 238 | impl<'a, K: Eq + Hash, T: ?Sized + AsRef, TDeref: ?Sized> AsRef 239 | for MappedRef<'a, K, T> 240 | { 241 | fn as_ref(&self) -> &TDeref { 242 | self.value().as_ref() 243 | } 244 | } 245 | 246 | pub struct MappedRefMut<'a, K, T: ?Sized> { 247 | _guard: RwLockWriteGuardDetached<'a>, 248 | k: &'a K, 249 | v: &'a mut T, 250 | } 251 | 252 | impl<'a, K: Eq + Hash, T: ?Sized> MappedRefMut<'a, K, T> { 253 | pub fn key(&self) -> &K { 254 | self.pair().0 255 | } 256 | 257 | pub fn value(&self) -> &T { 258 | self.pair().1 259 | } 260 | 261 | pub fn value_mut(&mut self) -> &mut T { 262 | self.pair_mut().1 263 | } 264 | 265 | pub fn pair(&self) -> (&K, &T) { 266 | (self.k, self.v) 267 | } 268 | 269 | pub fn pair_mut(&mut self) -> (&K, &mut T) { 270 | (self.k, self.v) 271 | } 272 | 273 | pub fn map(self, f: F) -> MappedRefMut<'a, K, T2> 274 | where 275 | F: FnOnce(&mut T) -> &mut T2, 276 | { 277 | MappedRefMut { 278 | _guard: self._guard, 279 | k: self.k, 280 | v: f(self.v), 281 | } 282 | } 283 | 284 | pub fn try_map(self, f: F) -> Result, Self> 285 | where 286 | F: FnOnce(&mut T) -> Option<&mut T2>, 287 | { 288 | let v = match f(unsafe { &mut *(self.v as *mut _) }) { 289 | Some(v) => v, 290 | None => return Err(self), 291 | }; 292 | let guard = self._guard; 293 | let k = self.k; 294 | Ok(MappedRefMut { 295 | _guard: guard, 296 | k, 297 | v, 298 | }) 299 | } 300 | } 301 | 302 | impl<'a, K: Eq + Hash + Debug, T: Debug + ?Sized> Debug for MappedRefMut<'a, K, T> { 303 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 304 | f.debug_struct("MappedRefMut") 305 | .field("k", &self.k) 306 | .field("v", &self.v) 307 | .finish() 308 | } 309 | } 310 | 311 | impl<'a, K: Eq + Hash, T: ?Sized> Deref for MappedRefMut<'a, K, T> { 312 | type Target = T; 313 | 314 | fn deref(&self) -> &T { 315 | self.value() 316 | } 317 | } 318 | 319 | impl<'a, K: Eq + Hash, T: ?Sized> DerefMut for MappedRefMut<'a, K, T> { 320 | fn deref_mut(&mut self) -> &mut T { 321 | self.value_mut() 322 | } 323 | } 324 | 325 | #[cfg(test)] 326 | mod tests { 327 | use crate::DashMap; 328 | 329 | #[test] 330 | fn downgrade() { 331 | let data = DashMap::new(); 332 | data.insert("test", "test"); 333 | if let Some(mut w_ref) = data.get_mut("test") { 334 | *w_ref.value_mut() = "test2"; 335 | let r_ref = w_ref.downgrade(); 336 | assert_eq!(*r_ref.value(), "test2"); 337 | }; 338 | } 339 | 340 | #[test] 341 | fn mapped_mut() { 342 | let data = DashMap::new(); 343 | data.insert("test", *b"test"); 344 | if let Some(b_ref) = data.get_mut("test") { 345 | let mut s_ref = b_ref.try_map(|b| std::str::from_utf8_mut(b).ok()).unwrap(); 346 | s_ref.value_mut().make_ascii_uppercase(); 347 | } 348 | 349 | assert_eq!(data.get("test").unwrap().value(), b"TEST"); 350 | } 351 | 352 | #[test] 353 | fn mapped_mut_again() { 354 | let data = DashMap::new(); 355 | data.insert("test", *b"hello world"); 356 | if let Some(b_ref) = data.get_mut("test") { 357 | let s_ref = b_ref.try_map(|b| std::str::from_utf8_mut(b).ok()).unwrap(); 358 | let mut hello_ref = s_ref.try_map(|s| s.get_mut(..5)).unwrap(); 359 | hello_ref.value_mut().make_ascii_uppercase(); 360 | } 361 | 362 | assert_eq!(data.get("test").unwrap().value(), b"HELLO world"); 363 | } 364 | 365 | #[test] 366 | fn mapped_ref() { 367 | let data = DashMap::new(); 368 | data.insert("test", *b"test"); 369 | if let Some(b_ref) = data.get("test") { 370 | let s_ref = b_ref.try_map(|b| std::str::from_utf8(b).ok()).unwrap(); 371 | 372 | assert_eq!(s_ref.value(), "test"); 373 | }; 374 | } 375 | 376 | #[test] 377 | fn mapped_ref_again() { 378 | let data = DashMap::new(); 379 | data.insert("test", *b"hello world"); 380 | if let Some(b_ref) = data.get("test") { 381 | let s_ref = b_ref.try_map(|b| std::str::from_utf8(b).ok()).unwrap(); 382 | let hello_ref = s_ref.try_map(|s| s.get(..5)).unwrap(); 383 | 384 | assert_eq!(hello_ref.value(), "hello"); 385 | }; 386 | } 387 | } 388 | -------------------------------------------------------------------------------- /src/rayon/map.rs: -------------------------------------------------------------------------------- 1 | use crate::lock::{RwLock, RwLockReadGuardDetached, RwLockWriteGuardDetached}; 2 | use crate::mapref::multiple::{RefMulti, RefMutMulti}; 3 | use crate::{DashMap, HashMap}; 4 | use core::hash::{BuildHasher, Hash}; 5 | use crossbeam_utils::CachePadded; 6 | use rayon::iter::plumbing::UnindexedConsumer; 7 | use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; 8 | use std::sync::Arc; 9 | 10 | impl ParallelExtend<(K, V)> for DashMap 11 | where 12 | K: Send + Sync + Eq + Hash, 13 | V: Send + Sync, 14 | S: Send + Sync + Clone + BuildHasher, 15 | { 16 | fn par_extend(&mut self, par_iter: I) 17 | where 18 | I: IntoParallelIterator, 19 | { 20 | (&*self).par_extend(par_iter); 21 | } 22 | } 23 | 24 | // Since we don't actually need mutability, we can implement this on a 25 | // reference, similar to `io::Write for &File`. 26 | impl ParallelExtend<(K, V)> for &'_ DashMap 27 | where 28 | K: Send + Sync + Eq + Hash, 29 | V: Send + Sync, 30 | S: Send + Sync + Clone + BuildHasher, 31 | { 32 | fn par_extend(&mut self, par_iter: I) 33 | where 34 | I: IntoParallelIterator, 35 | { 36 | let &mut map = self; 37 | par_iter.into_par_iter().for_each(move |(key, value)| { 38 | map.insert(key, value); 39 | }); 40 | } 41 | } 42 | 43 | impl FromParallelIterator<(K, V)> for DashMap 44 | where 45 | K: Send + Sync + Eq + Hash, 46 | V: Send + Sync, 47 | S: Send + Sync + Clone + Default + BuildHasher, 48 | { 49 | fn from_par_iter(par_iter: I) -> Self 50 | where 51 | I: IntoParallelIterator, 52 | { 53 | let map = Self::default(); 54 | (&map).par_extend(par_iter); 55 | map 56 | } 57 | } 58 | 59 | // Implementation note: while the shards will iterate in parallel, we flatten 60 | // sequentially within each shard (`flat_map_iter`), because the standard 61 | // `HashMap` only implements `ParallelIterator` by collecting to a `Vec` first. 62 | // There is real parallel support in the `hashbrown/rayon` feature, but we don't 63 | // always use that map. 64 | 65 | impl IntoParallelIterator for DashMap 66 | where 67 | K: Send + Eq + Hash, 68 | V: Send, 69 | S: Send + Clone + BuildHasher, 70 | { 71 | type Iter = OwningIter; 72 | type Item = (K, V); 73 | 74 | fn into_par_iter(self) -> Self::Iter { 75 | OwningIter { 76 | shards: self.shards, 77 | } 78 | } 79 | } 80 | 81 | pub struct OwningIter { 82 | pub(super) shards: Box<[CachePadded>>]>, 83 | } 84 | 85 | impl ParallelIterator for OwningIter 86 | where 87 | K: Send + Eq + Hash, 88 | V: Send, 89 | { 90 | type Item = (K, V); 91 | 92 | fn drive_unindexed(self, consumer: C) -> C::Result 93 | where 94 | C: UnindexedConsumer, 95 | { 96 | Vec::from(self.shards) 97 | .into_par_iter() 98 | .flat_map_iter(|shard| shard.into_inner().into_inner().into_iter()) 99 | .drive_unindexed(consumer) 100 | } 101 | } 102 | 103 | // This impl also enables `IntoParallelRefIterator::par_iter` 104 | impl<'a, K, V, S> IntoParallelIterator for &'a DashMap 105 | where 106 | K: Send + Sync + Eq + Hash, 107 | V: Send + Sync, 108 | S: Send + Sync + Clone + BuildHasher, 109 | { 110 | type Iter = Iter<'a, K, V>; 111 | type Item = RefMulti<'a, K, V>; 112 | 113 | fn into_par_iter(self) -> Self::Iter { 114 | Iter { 115 | shards: &self.shards, 116 | } 117 | } 118 | } 119 | 120 | pub struct Iter<'a, K, V> { 121 | pub(super) shards: &'a [CachePadded>>], 122 | } 123 | 124 | impl<'a, K, V> ParallelIterator for Iter<'a, K, V> 125 | where 126 | K: Send + Sync + Eq + Hash, 127 | V: Send + Sync, 128 | { 129 | type Item = RefMulti<'a, K, V>; 130 | 131 | fn drive_unindexed(self, consumer: C) -> C::Result 132 | where 133 | C: UnindexedConsumer, 134 | { 135 | self.shards 136 | .into_par_iter() 137 | .flat_map_iter(|shard| { 138 | // SAFETY: we keep the guard alive with the shard iterator, 139 | // and with any refs produced by the iterator 140 | let (guard, shard) = unsafe { RwLockReadGuardDetached::detach_from(shard.read()) }; 141 | 142 | let guard = Arc::new(guard); 143 | shard.iter().map(move |(k, v)| { 144 | let guard = Arc::clone(&guard); 145 | RefMulti::new(guard, k, v) 146 | }) 147 | }) 148 | .drive_unindexed(consumer) 149 | } 150 | } 151 | 152 | // This impl also enables `IntoParallelRefMutIterator::par_iter_mut` 153 | impl<'a, K, V> IntoParallelIterator for &'a mut DashMap 154 | where 155 | K: Send + Sync + Eq + Hash, 156 | V: Send + Sync, 157 | { 158 | type Iter = IterMut<'a, K, V>; 159 | type Item = RefMutMulti<'a, K, V>; 160 | 161 | fn into_par_iter(self) -> Self::Iter { 162 | IterMut { 163 | shards: &self.shards, 164 | } 165 | } 166 | } 167 | 168 | impl DashMap 169 | where 170 | K: Send + Sync + Eq + Hash, 171 | V: Send + Sync, 172 | { 173 | // Unlike `IntoParallelRefMutIterator::par_iter_mut`, we only _need_ `&self`. 174 | pub fn par_iter_mut(&self) -> IterMut<'_, K, V> { 175 | IterMut { 176 | shards: &self.shards, 177 | } 178 | } 179 | } 180 | 181 | pub struct IterMut<'a, K, V> { 182 | shards: &'a [CachePadded>>], 183 | } 184 | 185 | impl<'a, K, V> ParallelIterator for IterMut<'a, K, V> 186 | where 187 | K: Send + Sync + Eq + Hash, 188 | V: Send + Sync, 189 | { 190 | type Item = RefMutMulti<'a, K, V>; 191 | 192 | fn drive_unindexed(self, consumer: C) -> C::Result 193 | where 194 | C: UnindexedConsumer, 195 | { 196 | self.shards 197 | .into_par_iter() 198 | .flat_map_iter(|shard| { 199 | // SAFETY: we keep the guard alive with the shard iterator, 200 | // and with any refs produced by the iterator 201 | let (guard, shard) = 202 | unsafe { RwLockWriteGuardDetached::detach_from(shard.write()) }; 203 | 204 | let guard = Arc::new(guard); 205 | shard.iter_mut().map(move |(k, v)| { 206 | let guard = Arc::clone(&guard); 207 | RefMutMulti::new(guard, k, v) 208 | }) 209 | }) 210 | .drive_unindexed(consumer) 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/rayon/read_only.rs: -------------------------------------------------------------------------------- 1 | use crate::mapref::multiple::RefMulti; 2 | use crate::rayon::map::Iter; 3 | use crate::ReadOnlyView; 4 | use core::hash::{BuildHasher, Hash}; 5 | use rayon::iter::IntoParallelIterator; 6 | 7 | impl IntoParallelIterator for ReadOnlyView 8 | where 9 | K: Send + Eq + Hash, 10 | V: Send, 11 | S: Send + Clone + BuildHasher, 12 | { 13 | type Iter = super::map::OwningIter; 14 | type Item = (K, V); 15 | 16 | fn into_par_iter(self) -> Self::Iter { 17 | super::map::OwningIter { 18 | shards: self.map.shards, 19 | } 20 | } 21 | } 22 | 23 | // This impl also enables `IntoParallelRefIterator::par_iter` 24 | impl<'a, K, V, S> IntoParallelIterator for &'a ReadOnlyView 25 | where 26 | K: Send + Sync + Eq + Hash, 27 | V: Send + Sync, 28 | S: Send + Sync + Clone + BuildHasher, 29 | { 30 | type Iter = Iter<'a, K, V>; 31 | type Item = RefMulti<'a, K, V>; 32 | 33 | fn into_par_iter(self) -> Self::Iter { 34 | Iter { 35 | shards: &self.map.shards, 36 | } 37 | } 38 | } 39 | 40 | #[cfg(test)] 41 | mod tests { 42 | use crate::DashMap; 43 | use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; 44 | 45 | fn construct_sample_map() -> DashMap { 46 | let map = DashMap::new(); 47 | 48 | map.insert(1, "one".to_string()); 49 | 50 | map.insert(10, "ten".to_string()); 51 | 52 | map.insert(27, "twenty seven".to_string()); 53 | 54 | map.insert(45, "forty five".to_string()); 55 | 56 | map 57 | } 58 | 59 | #[test] 60 | fn test_par_iter() { 61 | let map = construct_sample_map(); 62 | 63 | let view = map.clone().into_read_only(); 64 | 65 | view.par_iter().for_each(|entry| { 66 | let key = *entry.key(); 67 | 68 | assert!(view.contains_key(&key)); 69 | 70 | let map_entry = map.get(&key).unwrap(); 71 | 72 | assert_eq!(view.get(&key).unwrap(), map_entry.value()); 73 | 74 | let key_value: (&i32, &String) = view.get_key_value(&key).unwrap(); 75 | 76 | assert_eq!(key_value.0, map_entry.key()); 77 | 78 | assert_eq!(key_value.1, map_entry.value()); 79 | }); 80 | } 81 | 82 | #[test] 83 | fn test_into_par_iter() { 84 | let map = construct_sample_map(); 85 | 86 | let view = map.clone().into_read_only(); 87 | 88 | view.into_par_iter().for_each(|(key, value)| { 89 | let map_entry = map.get(&key).unwrap(); 90 | 91 | assert_eq!(&key, map_entry.key()); 92 | 93 | assert_eq!(&value, map_entry.value()); 94 | }); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/rayon/set.rs: -------------------------------------------------------------------------------- 1 | use crate::setref::multiple::RefMulti; 2 | use crate::DashSet; 3 | use core::hash::{BuildHasher, Hash}; 4 | use rayon::iter::plumbing::UnindexedConsumer; 5 | use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; 6 | 7 | impl ParallelExtend for DashSet 8 | where 9 | K: Send + Sync + Eq + Hash, 10 | S: Send + Sync + Clone + BuildHasher, 11 | { 12 | fn par_extend(&mut self, par_iter: I) 13 | where 14 | I: IntoParallelIterator, 15 | { 16 | (&*self).par_extend(par_iter); 17 | } 18 | } 19 | 20 | // Since we don't actually need mutability, we can implement this on a 21 | // reference, similar to `io::Write for &File`. 22 | impl ParallelExtend for &'_ DashSet 23 | where 24 | K: Send + Sync + Eq + Hash, 25 | S: Send + Sync + Clone + BuildHasher, 26 | { 27 | fn par_extend(&mut self, par_iter: I) 28 | where 29 | I: IntoParallelIterator, 30 | { 31 | let &mut set = self; 32 | par_iter.into_par_iter().for_each(move |key| { 33 | set.insert(key); 34 | }); 35 | } 36 | } 37 | 38 | impl FromParallelIterator for DashSet 39 | where 40 | K: Send + Sync + Eq + Hash, 41 | S: Send + Sync + Clone + Default + BuildHasher, 42 | { 43 | fn from_par_iter(par_iter: I) -> Self 44 | where 45 | I: IntoParallelIterator, 46 | { 47 | let set = Self::default(); 48 | (&set).par_extend(par_iter); 49 | set 50 | } 51 | } 52 | 53 | impl IntoParallelIterator for DashSet 54 | where 55 | K: Send + Eq + Hash, 56 | S: Send + Clone + BuildHasher, 57 | { 58 | type Iter = OwningIter; 59 | type Item = K; 60 | 61 | fn into_par_iter(self) -> Self::Iter { 62 | OwningIter { 63 | inner: self.inner.into_par_iter(), 64 | } 65 | } 66 | } 67 | 68 | pub struct OwningIter { 69 | inner: super::map::OwningIter, 70 | } 71 | 72 | impl ParallelIterator for OwningIter 73 | where 74 | K: Send + Eq + Hash, 75 | { 76 | type Item = K; 77 | 78 | fn drive_unindexed(self, consumer: C) -> C::Result 79 | where 80 | C: UnindexedConsumer, 81 | { 82 | self.inner.map(|(k, _)| k).drive_unindexed(consumer) 83 | } 84 | } 85 | 86 | // This impl also enables `IntoParallelRefIterator::par_iter` 87 | impl<'a, K, S> IntoParallelIterator for &'a DashSet 88 | where 89 | K: Send + Sync + Eq + Hash, 90 | S: Send + Sync + Clone + BuildHasher, 91 | { 92 | type Iter = Iter<'a, K>; 93 | type Item = RefMulti<'a, K>; 94 | 95 | fn into_par_iter(self) -> Self::Iter { 96 | Iter { 97 | inner: (&self.inner).into_par_iter(), 98 | } 99 | } 100 | } 101 | 102 | pub struct Iter<'a, K> { 103 | inner: super::map::Iter<'a, K, ()>, 104 | } 105 | 106 | impl<'a, K> ParallelIterator for Iter<'a, K> 107 | where 108 | K: Send + Sync + Eq + Hash, 109 | { 110 | type Item = RefMulti<'a, K>; 111 | 112 | fn drive_unindexed(self, consumer: C) -> C::Result 113 | where 114 | C: UnindexedConsumer, 115 | { 116 | self.inner.map(RefMulti::new).drive_unindexed(consumer) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/read_only.rs: -------------------------------------------------------------------------------- 1 | use crate::lock::RwLock; 2 | use crate::{DashMap, HashMap}; 3 | use cfg_if::cfg_if; 4 | use core::fmt; 5 | use core::hash::{BuildHasher, Hash}; 6 | use crossbeam_utils::CachePadded; 7 | use equivalent::Equivalent; 8 | use std::collections::hash_map::RandomState; 9 | 10 | /// A read-only view into a `DashMap`. Allows to obtain raw references to the stored values. 11 | pub struct ReadOnlyView { 12 | pub(crate) map: DashMap, 13 | } 14 | 15 | impl Clone for ReadOnlyView { 16 | fn clone(&self) -> Self { 17 | Self { 18 | map: self.map.clone(), 19 | } 20 | } 21 | } 22 | 23 | impl fmt::Debug 24 | for ReadOnlyView 25 | { 26 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 27 | self.map.fmt(f) 28 | } 29 | } 30 | 31 | impl ReadOnlyView { 32 | pub(crate) fn new(map: DashMap) -> Self { 33 | Self { map } 34 | } 35 | 36 | /// Consumes this `ReadOnlyView`, returning the underlying `DashMap`. 37 | pub fn into_inner(self) -> DashMap { 38 | self.map 39 | } 40 | } 41 | 42 | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView { 43 | /// Returns the number of elements in the map. 44 | pub fn len(&self) -> usize { 45 | self.map.len() 46 | } 47 | 48 | /// Returns `true` if the map contains no elements. 49 | pub fn is_empty(&self) -> bool { 50 | self.map.is_empty() 51 | } 52 | 53 | /// Returns the number of elements the map can hold without reallocating. 54 | pub fn capacity(&self) -> usize { 55 | self.map.capacity() 56 | } 57 | 58 | /// Returns `true` if the map contains a value for the specified key. 59 | pub fn contains_key(&'a self, key: &Q) -> bool 60 | where 61 | Q: Hash + Equivalent + ?Sized, 62 | { 63 | self.get(key).is_some() 64 | } 65 | 66 | /// Returns a reference to the value corresponding to the key. 67 | pub fn get(&'a self, key: &Q) -> Option<&'a V> 68 | where 69 | Q: Hash + Equivalent + ?Sized, 70 | { 71 | self.get_key_value(key).map(|(_k, v)| v) 72 | } 73 | 74 | /// Returns the key-value pair corresponding to the supplied key. 75 | pub fn get_key_value(&'a self, key: &Q) -> Option<(&'a K, &'a V)> 76 | where 77 | Q: Hash + Equivalent + ?Sized, 78 | { 79 | let hash = self.map.hash_u64(&key); 80 | 81 | let idx = self.map.determine_shard(hash as usize); 82 | 83 | let shard = &self.map.shards[idx]; 84 | let shard = unsafe { &*shard.data_ptr() }; 85 | 86 | shard 87 | .find(hash, |(k, _v)| key.equivalent(k)) 88 | .map(|(k, v)| (k, v)) 89 | } 90 | 91 | /// An iterator visiting all key-value pairs in arbitrary order. The iterator element type is `(&'a K, &'a V)`. 92 | pub fn iter(&'a self) -> impl Iterator + 'a { 93 | self.map 94 | .shards 95 | .iter() 96 | .map(|shard| unsafe { &*shard.data_ptr() }) 97 | .flat_map(|shard| shard.iter()) 98 | .map(|(k, v)| (k, v)) 99 | } 100 | 101 | /// An iterator visiting all keys in arbitrary order. The iterator element type is `&'a K`. 102 | pub fn keys(&'a self) -> impl Iterator + 'a { 103 | self.iter().map(|(k, _v)| k) 104 | } 105 | 106 | /// An iterator visiting all values in arbitrary order. The iterator element type is `&'a V`. 107 | pub fn values(&'a self) -> impl Iterator + 'a { 108 | self.iter().map(|(_k, v)| v) 109 | } 110 | 111 | cfg_if! { 112 | if #[cfg(feature = "raw-api")] { 113 | /// Allows you to peek at the inner shards that store your data. 114 | /// You should probably not use this unless you know what you are doing. 115 | /// 116 | /// Requires the `raw-api` feature to be enabled. 117 | /// 118 | /// # Examples 119 | /// 120 | /// ``` 121 | /// use dashmap::DashMap; 122 | /// 123 | /// let map = DashMap::<(), ()>::new().into_read_only(); 124 | /// println!("Amount of shards: {}", map.shards().len()); 125 | /// ``` 126 | pub fn shards(&self) -> &[CachePadded>>] { 127 | &self.map.shards 128 | } 129 | } else { 130 | #[allow(dead_code)] 131 | pub(crate) fn shards(&self) -> &[CachePadded>>] { 132 | &self.map.shards 133 | } 134 | } 135 | } 136 | } 137 | 138 | #[cfg(test)] 139 | 140 | mod tests { 141 | 142 | use crate::DashMap; 143 | 144 | fn construct_sample_map() -> DashMap { 145 | let map = DashMap::new(); 146 | 147 | map.insert(1, "one".to_string()); 148 | 149 | map.insert(10, "ten".to_string()); 150 | 151 | map.insert(27, "twenty seven".to_string()); 152 | 153 | map.insert(45, "forty five".to_string()); 154 | 155 | map 156 | } 157 | 158 | #[test] 159 | 160 | fn test_properties() { 161 | let map = construct_sample_map(); 162 | 163 | let view = map.clone().into_read_only(); 164 | 165 | assert_eq!(view.is_empty(), map.is_empty()); 166 | 167 | assert_eq!(view.len(), map.len()); 168 | 169 | assert_eq!(view.capacity(), map.capacity()); 170 | 171 | let new_map = view.into_inner(); 172 | 173 | assert_eq!(new_map.is_empty(), map.is_empty()); 174 | 175 | assert_eq!(new_map.len(), map.len()); 176 | 177 | assert_eq!(new_map.capacity(), map.capacity()); 178 | } 179 | 180 | #[test] 181 | 182 | fn test_get() { 183 | let map = construct_sample_map(); 184 | 185 | let view = map.clone().into_read_only(); 186 | 187 | for key in map.iter().map(|entry| *entry.key()) { 188 | assert!(view.contains_key(&key)); 189 | 190 | let map_entry = map.get(&key).unwrap(); 191 | 192 | assert_eq!(view.get(&key).unwrap(), map_entry.value()); 193 | 194 | let key_value: (&i32, &String) = view.get_key_value(&key).unwrap(); 195 | 196 | assert_eq!(key_value.0, map_entry.key()); 197 | 198 | assert_eq!(key_value.1, map_entry.value()); 199 | } 200 | } 201 | 202 | #[test] 203 | 204 | fn test_iters() { 205 | let map = construct_sample_map(); 206 | 207 | let view = map.clone().into_read_only(); 208 | 209 | let mut visited_items = Vec::new(); 210 | 211 | for (key, value) in view.iter() { 212 | map.contains_key(key); 213 | 214 | let map_entry = map.get(key).unwrap(); 215 | 216 | assert_eq!(key, map_entry.key()); 217 | 218 | assert_eq!(value, map_entry.value()); 219 | 220 | visited_items.push((key, value)); 221 | } 222 | 223 | let mut visited_keys = Vec::new(); 224 | 225 | for key in view.keys() { 226 | map.contains_key(key); 227 | 228 | let map_entry = map.get(key).unwrap(); 229 | 230 | assert_eq!(key, map_entry.key()); 231 | 232 | assert_eq!(view.get(key).unwrap(), map_entry.value()); 233 | 234 | visited_keys.push(key); 235 | } 236 | 237 | let mut visited_values = Vec::new(); 238 | 239 | for value in view.values() { 240 | visited_values.push(value); 241 | } 242 | 243 | for entry in map.iter() { 244 | let key = entry.key(); 245 | 246 | let value = entry.value(); 247 | 248 | assert!(visited_keys.contains(&key)); 249 | 250 | assert!(visited_values.contains(&value)); 251 | 252 | assert!(visited_items.contains(&(key, value))); 253 | } 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/serde.rs: -------------------------------------------------------------------------------- 1 | use crate::{mapref, setref, DashMap, DashSet}; 2 | use core::fmt; 3 | use core::hash::{BuildHasher, Hash}; 4 | use core::marker::PhantomData; 5 | use serde::de::{Deserialize, MapAccess, SeqAccess, Visitor}; 6 | use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; 7 | use serde::Deserializer; 8 | 9 | pub struct DashMapVisitor { 10 | marker: PhantomData DashMap>, 11 | } 12 | 13 | impl DashMapVisitor 14 | where 15 | K: Eq + Hash, 16 | S: BuildHasher + Clone, 17 | { 18 | fn new() -> Self { 19 | DashMapVisitor { 20 | marker: PhantomData, 21 | } 22 | } 23 | } 24 | 25 | impl<'de, K, V, S> Visitor<'de> for DashMapVisitor 26 | where 27 | K: Deserialize<'de> + Eq + Hash, 28 | V: Deserialize<'de>, 29 | S: BuildHasher + Clone + Default, 30 | { 31 | type Value = DashMap; 32 | 33 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 34 | formatter.write_str("a DashMap") 35 | } 36 | 37 | fn visit_map(self, mut access: M) -> Result 38 | where 39 | M: MapAccess<'de>, 40 | { 41 | let map = 42 | DashMap::with_capacity_and_hasher(access.size_hint().unwrap_or(0), Default::default()); 43 | 44 | while let Some((key, value)) = access.next_entry()? { 45 | map.insert(key, value); 46 | } 47 | 48 | Ok(map) 49 | } 50 | } 51 | 52 | impl<'de, K, V, S> Deserialize<'de> for DashMap 53 | where 54 | K: Deserialize<'de> + Eq + Hash, 55 | V: Deserialize<'de>, 56 | S: BuildHasher + Clone + Default, 57 | { 58 | fn deserialize(deserializer: D) -> Result 59 | where 60 | D: Deserializer<'de>, 61 | { 62 | deserializer.deserialize_map(DashMapVisitor::::new()) 63 | } 64 | } 65 | 66 | impl Serialize for DashMap 67 | where 68 | K: Serialize + Eq + Hash, 69 | V: Serialize, 70 | H: BuildHasher + Clone, 71 | { 72 | fn serialize(&self, serializer: S) -> Result 73 | where 74 | S: Serializer, 75 | { 76 | let mut map = serializer.serialize_map(Some(self.len()))?; 77 | 78 | for ref_multi in self.iter() { 79 | map.serialize_entry(ref_multi.key(), ref_multi.value())?; 80 | } 81 | 82 | map.end() 83 | } 84 | } 85 | 86 | pub struct DashSetVisitor { 87 | marker: PhantomData DashSet>, 88 | } 89 | 90 | impl DashSetVisitor 91 | where 92 | K: Eq + Hash, 93 | S: BuildHasher + Clone, 94 | { 95 | fn new() -> Self { 96 | DashSetVisitor { 97 | marker: PhantomData, 98 | } 99 | } 100 | } 101 | 102 | impl<'de, K, S> Visitor<'de> for DashSetVisitor 103 | where 104 | K: Deserialize<'de> + Eq + Hash, 105 | S: BuildHasher + Clone + Default, 106 | { 107 | type Value = DashSet; 108 | 109 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 110 | formatter.write_str("a DashSet") 111 | } 112 | 113 | fn visit_seq(self, mut access: M) -> Result 114 | where 115 | M: SeqAccess<'de>, 116 | { 117 | let map = 118 | DashSet::with_capacity_and_hasher(access.size_hint().unwrap_or(0), Default::default()); 119 | 120 | while let Some(key) = access.next_element()? { 121 | map.insert(key); 122 | } 123 | 124 | Ok(map) 125 | } 126 | } 127 | 128 | impl<'de, K, S> Deserialize<'de> for DashSet 129 | where 130 | K: Deserialize<'de> + Eq + Hash, 131 | S: BuildHasher + Clone + Default, 132 | { 133 | fn deserialize(deserializer: D) -> Result 134 | where 135 | D: Deserializer<'de>, 136 | { 137 | deserializer.deserialize_seq(DashSetVisitor::::new()) 138 | } 139 | } 140 | 141 | impl Serialize for DashSet 142 | where 143 | K: Serialize + Eq + Hash, 144 | H: BuildHasher + Clone, 145 | { 146 | fn serialize(&self, serializer: S) -> Result 147 | where 148 | S: Serializer, 149 | { 150 | let mut seq = serializer.serialize_seq(Some(self.len()))?; 151 | 152 | for ref_multi in self.iter() { 153 | seq.serialize_element(ref_multi.key())?; 154 | } 155 | 156 | seq.end() 157 | } 158 | } 159 | 160 | macro_rules! serialize_impl { 161 | () => { 162 | fn serialize(&self, serializer: Ser) -> Result 163 | where 164 | Ser: serde::Serializer, 165 | { 166 | std::ops::Deref::deref(self).serialize(serializer) 167 | } 168 | }; 169 | } 170 | 171 | // Map 172 | impl<'a, K: Eq + Hash, V: Serialize> Serialize for mapref::multiple::RefMulti<'a, K, V> { 173 | serialize_impl! {} 174 | } 175 | 176 | impl<'a, K: Eq + Hash, V: Serialize> Serialize for mapref::multiple::RefMutMulti<'a, K, V> { 177 | serialize_impl! {} 178 | } 179 | 180 | impl<'a, K: Eq + Hash, V: Serialize> Serialize for mapref::one::Ref<'a, K, V> { 181 | serialize_impl! {} 182 | } 183 | 184 | impl<'a, K: Eq + Hash, V: Serialize> Serialize for mapref::one::RefMut<'a, K, V> { 185 | serialize_impl! {} 186 | } 187 | 188 | impl<'a, K: Eq + Hash, T: Serialize> Serialize for mapref::one::MappedRef<'a, K, T> { 189 | serialize_impl! {} 190 | } 191 | 192 | impl<'a, K: Eq + Hash, T: Serialize> Serialize for mapref::one::MappedRefMut<'a, K, T> { 193 | serialize_impl! {} 194 | } 195 | 196 | // Set 197 | impl<'a, V: Hash + Eq + Serialize> Serialize for setref::multiple::RefMulti<'a, V> { 198 | serialize_impl! {} 199 | } 200 | 201 | impl<'a, V: Hash + Eq + Serialize> Serialize for setref::one::Ref<'a, V> { 202 | serialize_impl! {} 203 | } 204 | -------------------------------------------------------------------------------- /src/set.rs: -------------------------------------------------------------------------------- 1 | use crate::iter_set::{Iter, OwningIter}; 2 | #[cfg(feature = "raw-api")] 3 | use crate::lock::RwLock; 4 | use crate::setref::one::Ref; 5 | use crate::DashMap; 6 | #[cfg(feature = "raw-api")] 7 | use crate::HashMap; 8 | use cfg_if::cfg_if; 9 | use core::fmt; 10 | use core::hash::{BuildHasher, Hash}; 11 | use core::iter::FromIterator; 12 | #[cfg(feature = "raw-api")] 13 | use crossbeam_utils::CachePadded; 14 | use equivalent::Equivalent; 15 | use std::collections::hash_map::RandomState; 16 | 17 | /// DashSet is a thin wrapper around [`DashMap`] using `()` as the value type. It uses 18 | /// methods and types which are more convenient to work with on a set. 19 | /// 20 | /// [`DashMap`]: struct.DashMap.html 21 | pub struct DashSet { 22 | pub(crate) inner: DashMap, 23 | } 24 | 25 | impl fmt::Debug for DashSet { 26 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 27 | fmt::Debug::fmt(&self.inner, f) 28 | } 29 | } 30 | 31 | impl Clone for DashSet { 32 | fn clone(&self) -> Self { 33 | Self { 34 | inner: self.inner.clone(), 35 | } 36 | } 37 | 38 | fn clone_from(&mut self, source: &Self) { 39 | self.inner.clone_from(&source.inner) 40 | } 41 | } 42 | 43 | impl Default for DashSet 44 | where 45 | K: Eq + Hash, 46 | S: Default + BuildHasher + Clone, 47 | { 48 | fn default() -> Self { 49 | Self::with_hasher(Default::default()) 50 | } 51 | } 52 | 53 | impl<'a, K: 'a + Eq + Hash> DashSet { 54 | /// Creates a new DashSet with a capacity of 0. 55 | /// 56 | /// # Examples 57 | /// 58 | /// ``` 59 | /// use dashmap::DashSet; 60 | /// 61 | /// let games = DashSet::new(); 62 | /// games.insert("Veloren"); 63 | /// ``` 64 | pub fn new() -> Self { 65 | Self::with_hasher(RandomState::default()) 66 | } 67 | 68 | /// Creates a new DashMap with a specified starting capacity. 69 | /// 70 | /// # Examples 71 | /// 72 | /// ``` 73 | /// use dashmap::DashSet; 74 | /// 75 | /// let numbers = DashSet::with_capacity(2); 76 | /// numbers.insert(2); 77 | /// numbers.insert(8); 78 | /// ``` 79 | pub fn with_capacity(capacity: usize) -> Self { 80 | Self::with_capacity_and_hasher(capacity, RandomState::default()) 81 | } 82 | } 83 | 84 | impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet { 85 | /// Creates a new DashMap with a capacity of 0 and the provided hasher. 86 | /// 87 | /// # Examples 88 | /// 89 | /// ``` 90 | /// use dashmap::DashSet; 91 | /// use std::collections::hash_map::RandomState; 92 | /// 93 | /// let s = RandomState::new(); 94 | /// let games = DashSet::with_hasher(s); 95 | /// games.insert("Veloren"); 96 | /// ``` 97 | pub fn with_hasher(hasher: S) -> Self { 98 | Self::with_capacity_and_hasher(0, hasher) 99 | } 100 | 101 | /// Creates a new DashMap with a specified starting capacity and hasher. 102 | /// 103 | /// # Examples 104 | /// 105 | /// ``` 106 | /// use dashmap::DashSet; 107 | /// use std::collections::hash_map::RandomState; 108 | /// 109 | /// let s = RandomState::new(); 110 | /// let numbers = DashSet::with_capacity_and_hasher(2, s); 111 | /// numbers.insert(2); 112 | /// numbers.insert(8); 113 | /// ``` 114 | pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { 115 | Self { 116 | inner: DashMap::with_capacity_and_hasher(capacity, hasher), 117 | } 118 | } 119 | 120 | /// Hash a given item to produce a usize. 121 | /// Uses the provided or default HashBuilder. 122 | pub fn hash_usize(&self, item: &T) -> usize { 123 | self.inner.hash_usize(item) 124 | } 125 | 126 | cfg_if! { 127 | if #[cfg(feature = "raw-api")] { 128 | /// Allows you to peek at the inner shards that store your data. 129 | /// You should probably not use this unless you know what you are doing. 130 | /// 131 | /// Requires the `raw-api` feature to be enabled. 132 | /// 133 | /// # Examples 134 | /// 135 | /// ``` 136 | /// use dashmap::DashSet; 137 | /// 138 | /// let set = DashSet::<()>::new(); 139 | /// println!("Amount of shards: {}", set.shards().len()); 140 | /// ``` 141 | pub fn shards(&self) -> &[CachePadded>>] { 142 | self.inner.shards() 143 | } 144 | } 145 | } 146 | 147 | cfg_if! { 148 | if #[cfg(feature = "raw-api")] { 149 | /// Finds which shard a certain key is stored in. 150 | /// You should probably not use this unless you know what you are doing. 151 | /// Note that shard selection is dependent on the default or provided HashBuilder. 152 | /// 153 | /// Requires the `raw-api` feature to be enabled. 154 | /// 155 | /// # Examples 156 | /// 157 | /// ``` 158 | /// use dashmap::DashSet; 159 | /// 160 | /// let set = DashSet::new(); 161 | /// set.insert("coca-cola"); 162 | /// println!("coca-cola is stored in shard: {}", set.determine_map("coca-cola")); 163 | /// ``` 164 | pub fn determine_map(&self, key: &Q) -> usize 165 | where 166 | Q: Hash + Equivalent + ?Sized, 167 | { 168 | self.inner.determine_map(key) 169 | } 170 | } 171 | } 172 | 173 | cfg_if! { 174 | if #[cfg(feature = "raw-api")] { 175 | /// Finds which shard a certain hash is stored in. 176 | /// 177 | /// Requires the `raw-api` feature to be enabled. 178 | /// 179 | /// # Examples 180 | /// 181 | /// ``` 182 | /// use dashmap::DashSet; 183 | /// 184 | /// let set: DashSet = DashSet::new(); 185 | /// let key = "key"; 186 | /// let hash = set.hash_usize(&key); 187 | /// println!("hash is stored in shard: {}", set.determine_shard(hash)); 188 | /// ``` 189 | pub fn determine_shard(&self, hash: usize) -> usize { 190 | self.inner.determine_shard(hash) 191 | } 192 | } 193 | } 194 | 195 | /// Inserts a key into the set. Returns true if the key was not already in the set. 196 | /// Does not update the key if it was already present. 197 | /// 198 | /// # Examples 199 | /// 200 | /// ``` 201 | /// use dashmap::DashSet; 202 | /// 203 | /// let set = DashSet::new(); 204 | /// set.insert("I am the key!"); 205 | /// ``` 206 | pub fn insert(&self, key: K) -> bool { 207 | self.inner.insert(key, ()).is_none() 208 | } 209 | 210 | /// Removes an entry from the map, returning the key if it existed in the map. 211 | /// 212 | /// # Examples 213 | /// 214 | /// ``` 215 | /// use dashmap::DashSet; 216 | /// 217 | /// let soccer_team = DashSet::new(); 218 | /// soccer_team.insert("Jack"); 219 | /// assert_eq!(soccer_team.remove("Jack").unwrap(), "Jack"); 220 | /// ``` 221 | pub fn remove(&self, key: &Q) -> Option 222 | where 223 | Q: Hash + Equivalent + ?Sized, 224 | { 225 | self.inner.remove(key).map(|(k, _)| k) 226 | } 227 | 228 | /// Removes an entry from the set, returning the key 229 | /// if the entry existed and the provided conditional function returned true. 230 | /// 231 | /// ``` 232 | /// use dashmap::DashSet; 233 | /// 234 | /// let soccer_team = DashSet::new(); 235 | /// soccer_team.insert("Sam"); 236 | /// soccer_team.remove_if("Sam", |player| player.starts_with("Ja")); 237 | /// assert!(soccer_team.contains("Sam")); 238 | /// ``` 239 | /// ``` 240 | /// use dashmap::DashSet; 241 | /// 242 | /// let soccer_team = DashSet::new(); 243 | /// soccer_team.insert("Sam"); 244 | /// soccer_team.remove_if("Jacob", |player| player.starts_with("Ja")); 245 | /// assert!(!soccer_team.contains("Jacob")); 246 | /// ``` 247 | pub fn remove_if(&self, key: &Q, f: impl FnOnce(&K) -> bool) -> Option 248 | where 249 | Q: Hash + Equivalent + ?Sized, 250 | { 251 | // TODO: Don't create another closure around f 252 | self.inner.remove_if(key, |k, _| f(k)).map(|(k, _)| k) 253 | } 254 | 255 | /// Creates an iterator over a DashMap yielding immutable references. 256 | /// 257 | /// # Examples 258 | /// 259 | /// ``` 260 | /// use dashmap::DashSet; 261 | /// 262 | /// let words = DashSet::new(); 263 | /// words.insert("hello"); 264 | /// assert_eq!(words.iter().count(), 1); 265 | /// ``` 266 | pub fn iter(&'a self) -> Iter<'a, K> { 267 | let iter = self.inner.iter(); 268 | 269 | Iter::new(iter) 270 | } 271 | 272 | /// Get a reference to an entry in the set 273 | /// 274 | /// # Examples 275 | /// 276 | /// ``` 277 | /// use dashmap::DashSet; 278 | /// 279 | /// let youtubers = DashSet::new(); 280 | /// youtubers.insert("Bosnian Bill"); 281 | /// assert_eq!(*youtubers.get("Bosnian Bill").unwrap(), "Bosnian Bill"); 282 | /// ``` 283 | pub fn get(&'a self, key: &Q) -> Option> 284 | where 285 | Q: Hash + Equivalent + ?Sized, 286 | { 287 | self.inner.get(key).map(Ref::new) 288 | } 289 | 290 | /// Remove excess capacity to reduce memory usage. 291 | pub fn shrink_to_fit(&self) { 292 | self.inner.shrink_to_fit() 293 | } 294 | 295 | /// Retain elements that whose predicates return true 296 | /// and discard elements whose predicates return false. 297 | /// 298 | /// # Examples 299 | /// 300 | /// ``` 301 | /// use dashmap::DashSet; 302 | /// 303 | /// let people = DashSet::new(); 304 | /// people.insert("Albin"); 305 | /// people.insert("Jones"); 306 | /// people.insert("Charlie"); 307 | /// people.retain(|name| name.contains('i')); 308 | /// assert_eq!(people.len(), 2); 309 | /// ``` 310 | pub fn retain(&self, mut f: impl FnMut(&K) -> bool) { 311 | self.inner.retain(|k, _| f(k)) 312 | } 313 | 314 | /// Fetches the total number of keys stored in the set. 315 | /// 316 | /// # Examples 317 | /// 318 | /// ``` 319 | /// use dashmap::DashSet; 320 | /// 321 | /// let people = DashSet::new(); 322 | /// people.insert("Albin"); 323 | /// people.insert("Jones"); 324 | /// people.insert("Charlie"); 325 | /// assert_eq!(people.len(), 3); 326 | /// ``` 327 | pub fn len(&self) -> usize { 328 | self.inner.len() 329 | } 330 | 331 | /// Checks if the set is empty or not. 332 | /// 333 | /// # Examples 334 | /// 335 | /// ``` 336 | /// use dashmap::DashSet; 337 | /// 338 | /// let map = DashSet::<()>::new(); 339 | /// assert!(map.is_empty()); 340 | /// ``` 341 | pub fn is_empty(&self) -> bool { 342 | self.inner.is_empty() 343 | } 344 | 345 | /// Removes all keys in the set. 346 | /// 347 | /// # Examples 348 | /// 349 | /// ``` 350 | /// use dashmap::DashSet; 351 | /// 352 | /// let people = DashSet::new(); 353 | /// people.insert("Albin"); 354 | /// assert!(!people.is_empty()); 355 | /// people.clear(); 356 | /// assert!(people.is_empty()); 357 | /// ``` 358 | pub fn clear(&self) { 359 | self.inner.clear() 360 | } 361 | 362 | /// Returns how many keys the set can store without reallocating. 363 | pub fn capacity(&self) -> usize { 364 | self.inner.capacity() 365 | } 366 | 367 | /// Checks if the set contains a specific key. 368 | /// 369 | /// # Examples 370 | /// 371 | /// ``` 372 | /// use dashmap::DashSet; 373 | /// 374 | /// let people = DashSet::new(); 375 | /// people.insert("Dakota Cherries"); 376 | /// assert!(people.contains("Dakota Cherries")); 377 | /// ``` 378 | pub fn contains(&self, key: &Q) -> bool 379 | where 380 | Q: Hash + Equivalent + ?Sized, 381 | { 382 | self.inner.contains_key(key) 383 | } 384 | } 385 | 386 | impl PartialEq for DashSet { 387 | fn eq(&self, other: &Self) -> bool { 388 | self.len() == other.len() && self.iter().all(|r| other.contains(r.key())) 389 | } 390 | } 391 | 392 | impl Eq for DashSet {} 393 | 394 | impl IntoIterator for DashSet { 395 | type Item = K; 396 | 397 | type IntoIter = OwningIter; 398 | 399 | fn into_iter(self) -> Self::IntoIter { 400 | OwningIter::new(self.inner.into_iter()) 401 | } 402 | } 403 | 404 | impl Extend for DashSet { 405 | fn extend>(&mut self, iter: T) { 406 | let iter = iter.into_iter().map(|k| (k, ())); 407 | 408 | self.inner.extend(iter) 409 | } 410 | } 411 | 412 | impl FromIterator for DashSet { 413 | fn from_iter>(iter: I) -> Self { 414 | let mut set = DashSet::default(); 415 | 416 | set.extend(iter); 417 | 418 | set 419 | } 420 | } 421 | 422 | #[cfg(feature = "typesize")] 423 | impl typesize::TypeSize for DashSet 424 | where 425 | K: typesize::TypeSize + Eq + Hash, 426 | S: typesize::TypeSize + Clone + BuildHasher, 427 | { 428 | fn extra_size(&self) -> usize { 429 | self.inner.extra_size() 430 | } 431 | 432 | typesize::if_typesize_details! { 433 | fn get_collection_item_count(&self) -> Option { 434 | Some(self.len()) 435 | } 436 | } 437 | } 438 | 439 | #[cfg(test)] 440 | mod tests { 441 | use crate::DashSet; 442 | 443 | #[test] 444 | fn test_basic() { 445 | let set = DashSet::new(); 446 | 447 | set.insert(0); 448 | 449 | assert_eq!(set.get(&0).as_deref(), Some(&0)); 450 | } 451 | 452 | #[test] 453 | fn test_default() { 454 | let set: DashSet = DashSet::default(); 455 | 456 | set.insert(0); 457 | 458 | assert_eq!(set.get(&0).as_deref(), Some(&0)); 459 | } 460 | 461 | #[test] 462 | fn test_equal() { 463 | let set1 = DashSet::new(); 464 | let set2 = DashSet::new(); 465 | assert_eq!(set1, set2); 466 | 467 | set1.insert("Hello, world!"); 468 | assert_ne!(set1, set2); 469 | 470 | set1.insert("Goodbye, world!"); 471 | assert_ne!(set1, set2); 472 | 473 | set2.insert("Hello, world!"); 474 | assert_ne!(set1, set2); 475 | 476 | set2.insert("Goodbye, world!"); 477 | assert_eq!(set1, set2); 478 | } 479 | 480 | #[test] 481 | fn test_multiple_hashes() { 482 | let set = DashSet::::default(); 483 | 484 | for i in 0..100 { 485 | assert!(set.insert(i)); 486 | } 487 | 488 | for i in 0..100 { 489 | assert!(!set.insert(i)); 490 | } 491 | 492 | for i in 0..100 { 493 | assert_eq!(Some(i), set.remove(&i)); 494 | } 495 | 496 | for i in 0..100 { 497 | assert_eq!(None, set.remove(&i)); 498 | } 499 | } 500 | } 501 | -------------------------------------------------------------------------------- /src/setref/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod multiple; 2 | pub mod one; 3 | -------------------------------------------------------------------------------- /src/setref/multiple.rs: -------------------------------------------------------------------------------- 1 | use crate::mapref; 2 | use core::hash::Hash; 3 | use core::ops::Deref; 4 | 5 | pub struct RefMulti<'a, K> { 6 | inner: mapref::multiple::RefMulti<'a, K, ()>, 7 | } 8 | 9 | impl<'a, K: Eq + Hash> RefMulti<'a, K> { 10 | pub(crate) fn new(inner: mapref::multiple::RefMulti<'a, K, ()>) -> Self { 11 | Self { inner } 12 | } 13 | 14 | pub fn key(&self) -> &K { 15 | self.inner.key() 16 | } 17 | } 18 | 19 | impl<'a, K: Eq + Hash> Deref for RefMulti<'a, K> { 20 | type Target = K; 21 | 22 | fn deref(&self) -> &K { 23 | self.key() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/setref/one.rs: -------------------------------------------------------------------------------- 1 | use crate::mapref; 2 | use core::hash::Hash; 3 | use core::ops::Deref; 4 | 5 | pub struct Ref<'a, K> { 6 | inner: mapref::one::Ref<'a, K, ()>, 7 | } 8 | 9 | impl<'a, K: Eq + Hash> Ref<'a, K> { 10 | pub(crate) fn new(inner: mapref::one::Ref<'a, K, ()>) -> Self { 11 | Self { inner } 12 | } 13 | 14 | pub fn key(&self) -> &K { 15 | self.inner.key() 16 | } 17 | } 18 | 19 | impl<'a, K: Eq + Hash> Deref for Ref<'a, K> { 20 | type Target = K; 21 | 22 | fn deref(&self) -> &K { 23 | self.key() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/try_result.rs: -------------------------------------------------------------------------------- 1 | /// Represents the result of a non-blocking read from a [DashMap](crate::DashMap). 2 | #[derive(Debug)] 3 | pub enum TryResult { 4 | /// The value was present in the map, and the lock for the shard was successfully obtained. 5 | Present(R), 6 | /// The shard wasn't locked, and the value wasn't present in the map. 7 | Absent, 8 | /// The shard was locked. 9 | Locked, 10 | } 11 | 12 | impl TryResult { 13 | /// Returns `true` if the value was present in the map, and the lock for the shard was successfully obtained. 14 | pub fn is_present(&self) -> bool { 15 | matches!(self, TryResult::Present(_)) 16 | } 17 | 18 | /// Returns `true` if the shard wasn't locked, and the value wasn't present in the map. 19 | pub fn is_absent(&self) -> bool { 20 | matches!(self, TryResult::Absent) 21 | } 22 | 23 | /// Returns `true` if the shard was locked. 24 | pub fn is_locked(&self) -> bool { 25 | matches!(self, TryResult::Locked) 26 | } 27 | 28 | /// If `self` is [Present](TryResult::Present), returns the reference to the value in the map. 29 | /// Panics if `self` is not [Present](TryResult::Present). 30 | pub fn unwrap(self) -> R { 31 | match self { 32 | TryResult::Present(r) => r, 33 | TryResult::Locked => panic!("Called unwrap() on TryResult::Locked"), 34 | TryResult::Absent => panic!("Called unwrap() on TryResult::Absent"), 35 | } 36 | } 37 | 38 | /// If `self` is [Present](TryResult::Present), returns the reference to the value in the map. 39 | /// If `self` is not [Present](TryResult::Present), returns `None`. 40 | pub fn try_unwrap(self) -> Option { 41 | match self { 42 | TryResult::Present(r) => Some(r), 43 | _ => None, 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | use core::{mem, ptr}; 2 | use std::{marker::PhantomData, mem::ManuallyDrop}; 3 | 4 | use lock_api::{RawRwLock, RawRwLockDowngrade, RwLockReadGuard, RwLockWriteGuard}; 5 | 6 | pub const fn ptr_size_bits() -> usize { 7 | mem::size_of::() * 8 8 | } 9 | 10 | pub fn map_in_place_2 T>((k, v): (U, &mut T), f: F) { 11 | unsafe { 12 | // # Safety 13 | // 14 | // If the closure panics, we must abort otherwise we could double drop `T` 15 | let promote_panic_to_abort = AbortOnPanic; 16 | 17 | ptr::write(v, f(k, ptr::read(v))); 18 | 19 | // If we made it here, the calling thread could have already have panicked, in which case 20 | // We know that the closure did not panic, so don't bother checking. 21 | std::mem::forget(promote_panic_to_abort); 22 | } 23 | } 24 | 25 | struct AbortOnPanic; 26 | 27 | impl Drop for AbortOnPanic { 28 | fn drop(&mut self) { 29 | if std::thread::panicking() { 30 | std::process::abort() 31 | } 32 | } 33 | } 34 | 35 | /// A [`RwLockReadGuard`], without the data 36 | pub(crate) struct RwLockReadGuardDetached<'a, R: RawRwLock> { 37 | lock: &'a R, 38 | _marker: PhantomData, 39 | } 40 | 41 | impl Drop for RwLockReadGuardDetached<'_, R> { 42 | fn drop(&mut self) { 43 | // Safety: An RwLockReadGuardDetached always holds a shared lock. 44 | unsafe { 45 | self.lock.unlock_shared(); 46 | } 47 | } 48 | } 49 | 50 | /// A [`RwLockWriteGuard`], without the data 51 | pub(crate) struct RwLockWriteGuardDetached<'a, R: RawRwLock> { 52 | lock: &'a R, 53 | _marker: PhantomData, 54 | } 55 | 56 | impl Drop for RwLockWriteGuardDetached<'_, R> { 57 | fn drop(&mut self) { 58 | // Safety: An RwLockWriteGuardDetached always holds an exclusive lock. 59 | unsafe { 60 | self.lock.unlock_exclusive(); 61 | } 62 | } 63 | } 64 | 65 | impl<'a, R: RawRwLock> RwLockReadGuardDetached<'a, R> { 66 | /// Separates the data from the [`RwLockReadGuard`] 67 | /// 68 | /// # Safety 69 | /// 70 | /// The data must not outlive the detached guard 71 | pub(crate) unsafe fn detach_from(guard: RwLockReadGuard<'a, R, T>) -> (Self, &'a T) { 72 | let rwlock = RwLockReadGuard::rwlock(&ManuallyDrop::new(guard)); 73 | 74 | // Safety: There will be no concurrent writes as we are "forgetting" the existing guard, 75 | // with the safety assumption that the caller will not drop the new detached guard early. 76 | let data = unsafe { &*rwlock.data_ptr() }; 77 | let guard = RwLockReadGuardDetached { 78 | // Safety: We are imitating the original RwLockReadGuard. It's the callers 79 | // responsibility to not drop the guard early. 80 | lock: unsafe { rwlock.raw() }, 81 | _marker: PhantomData, 82 | }; 83 | (guard, data) 84 | } 85 | } 86 | 87 | impl<'a, R: RawRwLock> RwLockWriteGuardDetached<'a, R> { 88 | /// Separates the data from the [`RwLockWriteGuard`] 89 | /// 90 | /// # Safety 91 | /// 92 | /// The data must not outlive the detached guard 93 | pub(crate) unsafe fn detach_from(guard: RwLockWriteGuard<'a, R, T>) -> (Self, &'a mut T) { 94 | let rwlock = RwLockWriteGuard::rwlock(&ManuallyDrop::new(guard)); 95 | 96 | // Safety: There will be no concurrent reads/writes as we are "forgetting" the existing guard, 97 | // with the safety assumption that the caller will not drop the new detached guard early. 98 | let data = unsafe { &mut *rwlock.data_ptr() }; 99 | let guard = RwLockWriteGuardDetached { 100 | // Safety: We are imitating the original RwLockWriteGuard. It's the callers 101 | // responsibility to not drop the guard early. 102 | lock: unsafe { rwlock.raw() }, 103 | _marker: PhantomData, 104 | }; 105 | (guard, data) 106 | } 107 | } 108 | 109 | impl<'a, R: RawRwLockDowngrade> RwLockWriteGuardDetached<'a, R> { 110 | /// # Safety 111 | /// 112 | /// The associated data must not mut mutated after downgrading 113 | pub(crate) unsafe fn downgrade(self) -> RwLockReadGuardDetached<'a, R> { 114 | // Do not drop the write guard - otherwise we will trigger a downgrade + unlock_exclusive, 115 | // which is incorrect 116 | let this = ManuallyDrop::new(self); 117 | 118 | // Safety: An RwLockWriteGuardDetached always holds an exclusive lock. 119 | unsafe { this.lock.downgrade() } 120 | RwLockReadGuardDetached { 121 | lock: this.lock, 122 | _marker: this._marker, 123 | } 124 | } 125 | } 126 | --------------------------------------------------------------------------------