Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a struct HashMapRef which holds a reference and guard #45

Merged
merged 8 commits into from
Jan 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,15 @@
#![warn(rust_2018_idioms)]

mod map;
mod map_ref;
mod node;
mod raw;

/// Iterator types.
pub mod iter;

pub use map::HashMap;
pub use map_ref::HashMapRef;

/// Default hasher for [`HashMap`].
pub type DefaultHashBuilder = ahash::RandomState;
Expand Down
22 changes: 15 additions & 7 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1587,7 +1587,7 @@ where
{
self.check_guard(guard);
// removed selected keys
for (k, v) in self.iter(&guard) {
for (k, v) in self.iter(guard) {
if !f(k, v) {
let old_value: Shared<'_, V> = Shared::from(v as *const V);
self.replace_node(k, None, Some(old_value), guard);
Expand All @@ -1607,7 +1607,7 @@ where
{
self.check_guard(guard);
// removed selected keys
for (k, v) in self.iter(&guard) {
for (k, v) in self.iter(guard) {
if !f(k, v) {
self.replace_node(k, None, None, guard);
}
Expand Down Expand Up @@ -1674,6 +1674,18 @@ where
pub fn is_empty(&self) -> bool {
self.len() == 0
}

pub(crate) fn guarded_eq(&self, other: &Self, our_guard: &Guard, their_guard: &Guard) -> bool
where
V: PartialEq,
{
if self.len() != other.len() {
return false;
}

self.iter(our_guard)
.all(|(key, value)| other.get(key, their_guard).map_or(false, |v| *value == *v))
}
}

impl<K, V, S> PartialEq for HashMap<K, V, S>
Expand All @@ -1686,11 +1698,7 @@ where
if self.len() != other.len() {
return false;
}

let our_guard = self.collector.register().pin();
let their_guard = other.collector.register().pin();
self.iter(&our_guard)
.all(|(key, value)| other.get(key, &their_guard).map_or(false, |v| *value == *v))
self.guarded_eq(other, &self.guard(), &other.guard())
}
}

Expand Down
272 changes: 272 additions & 0 deletions src/map_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
use crate::iter::*;
use crate::HashMap;
use crossbeam_epoch::Guard;
use std::borrow::Borrow;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};
use std::ops::{Deref, Index};

/// A reference to a [`HashMap`], constructed with [`HashMap::pin`] or [`HashMap::with_guard`].
///
/// The current thread will be pinned for the duration of this reference.
cuviper marked this conversation as resolved.
Show resolved Hide resolved
/// Keep in mind that this prevents the collection of garbage generated by the map.
pub struct HashMapRef<'map, K: 'static, V: 'static, S = crate::DefaultHashBuilder> {
map: &'map HashMap<K, V, S>,
guard: GuardRef<'map>,
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
}

enum GuardRef<'g> {
Owned(Guard),
Ref(&'g Guard),
}

impl Deref for GuardRef<'_> {
type Target = Guard;

#[inline]
fn deref(&self) -> &Guard {
match *self {
GuardRef::Owned(ref guard) | GuardRef::Ref(&ref guard) => guard,
}
}
}

impl<K, V, S> HashMap<K, V, S>
where
K: Sync + Send + Clone + Hash + Eq,
V: Sync + Send,
S: BuildHasher,
{
/// Get a reference to this map with the current thread pinned.
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
///
/// Keep in mind that for as long as you hold onto this, you are preventing the collection of
/// garbage generated by the map.
pub fn pin(&self) -> HashMapRef<'_, K, V, S> {
HashMapRef {
guard: GuardRef::Owned(self.guard()),
map: &self,
}
}

/// Get a reference to this map with the given guard.
pub fn with_guard<'g>(&'g self, guard: &'g Guard) -> HashMapRef<'g, K, V, S> {
HashMapRef {
map: &self,
guard: GuardRef::Ref(guard),
}
}
}

impl<K, V, S> HashMapRef<'_, K, V, S>
where
K: Sync + Send + Clone + Hash + Eq,
V: Sync + Send,
S: BuildHasher,
{
/// Tests if `key` is a key in this table.
/// See also [`HashMap::contains_key`].
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.map.contains_key(key, &self.guard)
}

/// Returns the value to which `key` is mapped.
/// See also [`HashMap::get`].
pub fn get<'g, Q>(&'g self, key: &Q) -> Option<&'g V>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.map.get(key, &self.guard)
}

/// Returns the key-value pair corresponding to `key`.
/// See also [`HashMap::get_key_value`].
pub fn get_key_value<'g, Q>(&'g self, key: &Q) -> Option<(&'g K, &'g V)>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.map.get_key_value(key, &self.guard)
}

/// Maps `key` to `value` in this table.
/// See also [`HashMap::insert`].
pub fn insert<'g>(&'g self, key: K, value: V) -> Option<&'g V> {
self.map.insert(key, value, &self.guard)
}

/// If the value for the specified `key` is present, attempts to
/// compute a new mapping given the key and its current mapped value.
/// See also [`HashMap::compute_if_present`].
pub fn compute_if_present<'g, Q, F>(&'g self, key: &Q, remapping_function: F) -> Option<&'g V>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
F: FnOnce(&K, &V) -> Option<V>,
{
self.map
.compute_if_present(key, remapping_function, &self.guard)
}

/// Tries to reserve capacity for at least additional more elements.
/// See also [`HashMap::reserve`].
pub fn reserve(&self, additional: usize) {
self.map.reserve(additional, &self.guard)
}

/// Removes the key (and its corresponding value) from this map.
/// See also [`HashMap::remove`].
pub fn remove<'g, Q>(&'g self, key: &Q) -> Option<&'g V>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.map.remove(key, &self.guard)
}

/// Retains only the elements specified by the predicate.
/// See also [`HashMap::retain`].
pub fn retain<F>(&self, f: F)
where
F: FnMut(&K, &V) -> bool,
{
self.map.retain(f, &self.guard);
}

/// Retains only the elements specified by the predicate.
/// See also [`HashMap::retain_force`].
pub fn retain_force<F>(&self, f: F)
where
F: FnMut(&K, &V) -> bool,
{
self.map.retain_force(f, &self.guard);
}

/// An iterator visiting all key-value pairs in arbitrary order.
/// The iterator element type is `(&'g K, &'g V)`.
/// See also [`HashMap::iter`].
pub fn iter<'g>(&'g self) -> Iter<'g, K, V> {
self.map.iter(&self.guard)
}

/// An iterator visiting all keys in arbitrary order.
/// The iterator element type is `&'g K`.
/// See also [`HashMap::keys`].
pub fn keys<'g>(&'g self) -> Keys<'g, K, V> {
self.map.keys(&self.guard)
}

/// An iterator visiting all values in arbitrary order.
/// The iterator element type is `&'g V`.
/// See also [`HashMap::values`].
pub fn values<'g>(&'g self) -> Values<'g, K, V> {
self.map.values(&self.guard)
}

/// Returns the number of entries in the map.
/// See also [`HashMap::len`].
pub fn len(&self) -> usize {
self.map.len()
}

/// Returns `true` if the map is empty. Otherwise returns `false`.
/// See also [`HashMap::is_empty`].
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
}

impl<'g, K, V, S> IntoIterator for &'g HashMapRef<'_, K, V, S>
where
K: Sync + Send + Clone + Hash + Eq,
V: Sync + Send,
S: BuildHasher,
{
type IntoIter = Iter<'g, K, V>;
type Item = (&'g K, &'g V);

fn into_iter(self) -> Self::IntoIter {
self.map.iter(&self.guard)
}
}

impl<K, V, S> Debug for HashMapRef<'_, K, V, S>
where
K: Sync + Send + Clone + Hash + Eq + Debug,
V: Sync + Send + Debug,
S: BuildHasher,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self).finish()
}
}

impl<K, V, S> Clone for HashMapRef<'_, K, V, S>
where
K: Sync + Send + Clone + Hash + Eq,
V: Sync + Send,
S: BuildHasher,
{
fn clone(&self) -> Self {
self.map.pin()
}
}

impl<K, V, S> PartialEq for HashMapRef<'_, K, V, S>
where
K: Sync + Send + Clone + Hash + Eq,
V: Sync + Send + PartialEq,
S: BuildHasher,
{
fn eq(&self, other: &Self) -> bool {
self.map.guarded_eq(&other.map, &self.guard, &other.guard)
}
}

impl<K, V, S> PartialEq<HashMap<K, V, S>> for HashMapRef<'_, K, V, S>
where
K: Sync + Send + Clone + Hash + Eq,
V: Sync + Send + PartialEq,
S: BuildHasher,
{
fn eq(&self, other: &HashMap<K, V, S>) -> bool {
self.map.guarded_eq(&other, &self.guard, &other.guard())
}
}

impl<K, V, S> PartialEq<HashMapRef<'_, K, V, S>> for HashMap<K, V, S>
where
K: Sync + Send + Clone + Hash + Eq,
V: Sync + Send + PartialEq,
S: BuildHasher,
{
fn eq(&self, other: &HashMapRef<'_, K, V, S>) -> bool {
self.guarded_eq(&other.map, &self.guard(), &other.guard)
}
}

impl<K, V, S> Eq for HashMapRef<'_, K, V, S>
where
K: Sync + Send + Clone + Hash + Eq,
V: Sync + Send + Eq,
S: BuildHasher,
{
}

impl<K, Q, V, S> Index<&'_ Q> for HashMapRef<'_, K, V, S>
where
K: Sync + Send + Clone + Hash + Eq + Borrow<Q>,
Q: ?Sized + Hash + Eq,
V: Sync + Send,
S: BuildHasher,
{
type Output = V;

fn index(&self, key: &Q) -> &V {
self.get(key).expect("no entry found for key")
}
}
Loading