| use crate::lock::RwLock; |
| use crate::t::Map; |
| use crate::{DashMap, HashMap}; |
| use cfg_if::cfg_if; |
| use core::borrow::Borrow; |
| use core::fmt; |
| use core::hash::{BuildHasher, Hash}; |
| use std::collections::hash_map::RandomState; |
| |
| /// A read-only view into a `DashMap`. Allows to obtain raw references to the stored values. |
| pub struct ReadOnlyView<K, V, S = RandomState> { |
| pub(crate) map: DashMap<K, V, S>, |
| } |
| |
| impl<K: Eq + Hash + Clone, V: Clone, S: Clone> Clone for ReadOnlyView<K, V, S> { |
| fn clone(&self) -> Self { |
| Self { |
| map: self.map.clone(), |
| } |
| } |
| } |
| |
| impl<K: Eq + Hash + fmt::Debug, V: fmt::Debug, S: BuildHasher + Clone> fmt::Debug |
| for ReadOnlyView<K, V, S> |
| { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| self.map.fmt(f) |
| } |
| } |
| |
| impl<K, V, S> ReadOnlyView<K, V, S> { |
| pub(crate) fn new(map: DashMap<K, V, S>) -> Self { |
| Self { map } |
| } |
| |
| /// Consumes this `ReadOnlyView`, returning the underlying `DashMap`. |
| pub fn into_inner(self) -> DashMap<K, V, S> { |
| self.map |
| } |
| } |
| |
| impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S> { |
| /// Returns the number of elements in the map. |
| pub fn len(&self) -> usize { |
| self.map.len() |
| } |
| |
| /// Returns `true` if the map contains no elements. |
| pub fn is_empty(&self) -> bool { |
| self.map.is_empty() |
| } |
| |
| /// Returns the number of elements the map can hold without reallocating. |
| pub fn capacity(&self) -> usize { |
| self.map.capacity() |
| } |
| |
| /// Returns `true` if the map contains a value for the specified key. |
| pub fn contains_key<Q>(&'a self, key: &Q) -> bool |
| where |
| K: Borrow<Q>, |
| Q: Hash + Eq + ?Sized, |
| { |
| let hash = self.map.hash_usize(&key); |
| |
| let idx = self.map.determine_shard(hash); |
| |
| let shard = unsafe { self.map._get_read_shard(idx) }; |
| |
| shard.contains_key(key) |
| } |
| |
| /// Returns a reference to the value corresponding to the key. |
| pub fn get<Q>(&'a self, key: &Q) -> Option<&'a V> |
| where |
| K: Borrow<Q>, |
| Q: Hash + Eq + ?Sized, |
| { |
| let hash = self.map.hash_usize(&key); |
| |
| let idx = self.map.determine_shard(hash); |
| |
| let shard = unsafe { self.map._get_read_shard(idx) }; |
| |
| shard.get(key).map(|v| v.get()) |
| } |
| |
| /// Returns the key-value pair corresponding to the supplied key. |
| pub fn get_key_value<Q>(&'a self, key: &Q) -> Option<(&'a K, &'a V)> |
| where |
| K: Borrow<Q>, |
| Q: Hash + Eq + ?Sized, |
| { |
| let hash = self.map.hash_usize(&key); |
| |
| let idx = self.map.determine_shard(hash); |
| |
| let shard = unsafe { self.map._get_read_shard(idx) }; |
| |
| shard.get_key_value(key).map(|(k, v)| (k, v.get())) |
| } |
| |
| fn shard_read_iter(&'a self) -> impl Iterator<Item = &'a HashMap<K, V, S>> + 'a { |
| (0..self.map._shard_count()) |
| .map(move |shard_i| unsafe { self.map._get_read_shard(shard_i) }) |
| } |
| |
| /// An iterator visiting all key-value pairs in arbitrary order. The iterator element type is `(&'a K, &'a V)`. |
| pub fn iter(&'a self) -> impl Iterator<Item = (&'a K, &'a V)> + 'a { |
| self.shard_read_iter() |
| .flat_map(|shard| shard.iter()) |
| .map(|(k, v)| (k, v.get())) |
| } |
| |
| /// An iterator visiting all keys in arbitrary order. The iterator element type is `&'a K`. |
| pub fn keys(&'a self) -> impl Iterator<Item = &'a K> + 'a { |
| self.shard_read_iter().flat_map(|shard| shard.keys()) |
| } |
| |
| /// An iterator visiting all values in arbitrary order. The iterator element type is `&'a V`. |
| pub fn values(&'a self) -> impl Iterator<Item = &'a V> + 'a { |
| self.shard_read_iter() |
| .flat_map(|shard| shard.values()) |
| .map(|v| v.get()) |
| } |
| |
| cfg_if! { |
| if #[cfg(feature = "raw-api")] { |
| /// Allows you to peek at the inner shards that store your data. |
| /// You should probably not use this unless you know what you are doing. |
| /// |
| /// Requires the `raw-api` feature to be enabled. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashMap; |
| /// |
| /// let map = DashMap::<(), ()>::new().into_read_only(); |
| /// println!("Amount of shards: {}", map.shards().len()); |
| /// ``` |
| pub fn shards(&self) -> &[RwLock<HashMap<K, V, S>>] { |
| &self.map.shards |
| } |
| } else { |
| #[allow(dead_code)] |
| pub(crate) fn shards(&self) -> &[RwLock<HashMap<K, V, S>>] { |
| &self.map.shards |
| } |
| } |
| } |
| } |
| |
| #[cfg(test)] |
| |
| mod tests { |
| |
| use crate::DashMap; |
| |
| fn construct_sample_map() -> DashMap<i32, String> { |
| let map = DashMap::new(); |
| |
| map.insert(1, "one".to_string()); |
| |
| map.insert(10, "ten".to_string()); |
| |
| map.insert(27, "twenty seven".to_string()); |
| |
| map.insert(45, "forty five".to_string()); |
| |
| map |
| } |
| |
| #[test] |
| |
| fn test_properties() { |
| let map = construct_sample_map(); |
| |
| let view = map.clone().into_read_only(); |
| |
| assert_eq!(view.is_empty(), map.is_empty()); |
| |
| assert_eq!(view.len(), map.len()); |
| |
| assert_eq!(view.capacity(), map.capacity()); |
| |
| let new_map = view.into_inner(); |
| |
| assert_eq!(new_map.is_empty(), map.is_empty()); |
| |
| assert_eq!(new_map.len(), map.len()); |
| |
| assert_eq!(new_map.capacity(), map.capacity()); |
| } |
| |
| #[test] |
| |
| fn test_get() { |
| let map = construct_sample_map(); |
| |
| let view = map.clone().into_read_only(); |
| |
| for key in map.iter().map(|entry| *entry.key()) { |
| assert!(view.contains_key(&key)); |
| |
| let map_entry = map.get(&key).unwrap(); |
| |
| assert_eq!(view.get(&key).unwrap(), map_entry.value()); |
| |
| let key_value: (&i32, &String) = view.get_key_value(&key).unwrap(); |
| |
| assert_eq!(key_value.0, map_entry.key()); |
| |
| assert_eq!(key_value.1, map_entry.value()); |
| } |
| } |
| |
| #[test] |
| |
| fn test_iters() { |
| let map = construct_sample_map(); |
| |
| let view = map.clone().into_read_only(); |
| |
| let mut visited_items = Vec::new(); |
| |
| for (key, value) in view.iter() { |
| map.contains_key(key); |
| |
| let map_entry = map.get(key).unwrap(); |
| |
| assert_eq!(key, map_entry.key()); |
| |
| assert_eq!(value, map_entry.value()); |
| |
| visited_items.push((key, value)); |
| } |
| |
| let mut visited_keys = Vec::new(); |
| |
| for key in view.keys() { |
| map.contains_key(key); |
| |
| let map_entry = map.get(key).unwrap(); |
| |
| assert_eq!(key, map_entry.key()); |
| |
| assert_eq!(view.get(key).unwrap(), map_entry.value()); |
| |
| visited_keys.push(key); |
| } |
| |
| let mut visited_values = Vec::new(); |
| |
| for value in view.values() { |
| visited_values.push(value); |
| } |
| |
| for entry in map.iter() { |
| let key = entry.key(); |
| |
| let value = entry.value(); |
| |
| assert!(visited_keys.contains(&key)); |
| |
| assert!(visited_values.contains(&value)); |
| |
| assert!(visited_items.contains(&(key, value))); |
| } |
| } |
| } |