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

Finish fixing #17 #78

Merged
merged 15 commits into from
Mar 27, 2020
Merged
Show file tree
Hide file tree
Changes from 5 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
20 changes: 20 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,19 +213,23 @@
intra_doc_link_resolution_failure
)]
#![warn(rust_2018_idioms)]
use crossbeam_epoch::Guard;
use std::ops::Deref;

mod map;
mod map_ref;
mod node;
mod raw;
mod set;
mod set_ref;

/// Iterator types.
pub mod iter;

pub use map::{HashMap, TryInsertError};
pub use map_ref::HashMapRef;
pub use set::HashSet;
pub use set_ref::HashSetRef;

/// Default hasher for [`HashMap`].
pub type DefaultHashBuilder = ahash::RandomState;
Expand All @@ -234,3 +238,19 @@ pub type DefaultHashBuilder = ahash::RandomState;
pub mod epoch {
pub use crossbeam_epoch::{pin, Guard};
}

pub(crate) 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,
}
}
}
20 changes: 2 additions & 18 deletions src/map_ref.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::iter::*;
use crate::{HashMap, TryInsertError};
use crate::{GuardRef, HashMap, TryInsertError};
use crossbeam_epoch::Guard;
use std::borrow::Borrow;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};
use std::ops::{Deref, Index};
use std::ops::Index;

/// A reference to a [`HashMap`], constructed with [`HashMap::pin`] or [`HashMap::with_guard`].
///
Expand All @@ -15,22 +15,6 @@ pub struct HashMapRef<'map, K, V, S = crate::DefaultHashBuilder> {
guard: GuardRef<'map>,
}

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> {
/// Get a reference to this map with the current thread pinned.
///
Expand Down
60 changes: 60 additions & 0 deletions src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,10 @@ where
{
self.map.get_key_value(value, guard).map(|(k, _)| k)
}

pub(crate) fn guarded_eq(&self, other: &Self, our_guard: &Guard, their_guard: &Guard) -> bool {
self.map.guarded_eq(&other.map, our_guard, their_guard)
}
}

impl<T, S> HashSet<T, S>
Expand Down Expand Up @@ -367,6 +371,62 @@ where
{
self.map.remove_entry(value, guard).map(|(k, _)| k)
}

/// Retains only the elements specified by the predicate.
///
/// In other words, remove all elements `e` such that `f(&e)` returns `false`.
///
/// # Examples
///
/// ```
/// use flurry::HashSet;
///
/// let set = HashSet::new();
///
/// for i in 0..8 {
/// set.pin().insert(i);
/// }
/// set.pin().retain(|&e| e % 2 == 0);
/// assert_eq!(set.pin().len(), 4);
/// ```
#[inline]
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
pub fn retain<F>(&self, mut f: F, guard: &Guard)
where
F: FnMut(&T) -> bool,
{
self.map.retain(|value, ()| f(value), guard)
}
}

impl<T, S> HashSet<T, S>
where
T: Clone,
{
/// Clears the set, removing all elements.
///
/// # Examples
///
/// ```
/// use flurry::HashSet;
///
/// let set = HashSet::new();
///
/// set.pin().insert("a");
/// set.pin().clear();
/// assert!(set.pin().is_empty());
/// ```
#[inline]
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
pub fn clear(&self, guard: &Guard) {
self.map.clear(guard)
}

/// Tries to reserve capacity for at least `additional` more elements to
/// be inserted in the `HashSet`. The collection may reserve more space to
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
/// avoid frequent reallocations.
#[inline]
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
pub fn reserve(&self, additional: usize, guard: &Guard) {
self.map.reserve(additional, guard)
}
}

impl<T, S> PartialEq for HashSet<T, S>
Expand Down
208 changes: 208 additions & 0 deletions src/set_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
use crate::iter::*;
use crate::{GuardRef, HashSet};
use crossbeam_epoch::Guard;
use std::borrow::Borrow;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};

/// A reference to a [`HashSet`], constructed with [`HashSet::pin`] or [`HashSet::with_guard`].
///
/// The current thread will be pinned for the duration of this reference.
/// Keep in mind that this prevents the collection of garbage generated by the set.
pub struct HashSetRef<'set, T, S = crate::DefaultHashBuilder> {
set: &'set HashSet<T, S>,
guard: GuardRef<'set>,
}

impl<T, S> HashSet<T, S> {
/// Get a reference to this set with the current thread pinned.
///
/// Keep in mind that for as long as you hold onto this, you are preventing the collection of
/// garbage generated by the set.
pub fn pin(&self) -> HashSetRef<'_, T, S> {
HashSetRef {
guard: GuardRef::Owned(self.guard()),
set: &self,
}
}

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

impl<T, S> HashSetRef<'_, T, S> {
/// An iterator visiting all elements in arbitrary order.
/// The iterator item type is `&'g T`.
/// See also [`HashSet::iter`].
pub fn iter(&self) -> Keys<'_, T, ()> {
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
self.set.iter(&self.guard)
}

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

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

impl<T, S> HashSetRef<'_, T, S>
where
T: Clone,
{
/// Tries to reserve capacity for at least `additional` more elements.
/// See also [`HashSet::reserve`].
pub fn reserve(&self, additional: usize) {
self.set.reserve(additional, &self.guard)
}

/// Removes all elements from this set.
/// See also [`HashSet::clear`].
pub fn clear(&self) {
self.set.clear(&self.guard);
}
}

impl<T, S> HashSetRef<'_, T, S>
where
T: Hash + Eq,
S: BuildHasher,
{
/// Tests if `value` is an element of this set.
/// See also [`HashSet::contains`].
pub fn contains<Q>(&self, value: &Q) -> bool
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
where
T: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.set.contains(value, &self.guard)
}

/// Returns a reference to the value in the set, if any, that is equal to the given value.
///
/// See also [`HashSet::get`].
#[inline]
pub fn get<'g, Q>(&'g self, value: &Q) -> Option<&'g T>
where
T: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.set.get(value, &self.guard)
}
}

impl<T, S> HashSetRef<'_, T, S>
where
T: 'static + Sync + Send + Clone + Hash + Eq,
S: BuildHasher,
{
/// Inserts an element into the set.
///
/// See also [`HashSet::insert`].
pub fn insert(&self, value: T) -> bool {
self.set.insert(value, &self.guard)
}

/// Removes the element from this set.
///
/// See also [`HashSet::remove`].
pub fn remove<'g, Q>(&'g self, value: &Q) -> bool
where
T: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.set.remove(value, &self.guard)
}

/// Removes and returns the value in the set, if any, that is equal to the given one.
///
/// See also [`HashSet::take`].
pub fn take<Q>(&self, value: &Q) -> Option<&'_ T>
where
T: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.set.take(value, &self.guard)
}

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

impl<'g, T, S> IntoIterator for &'g HashSetRef<'_, T, S> {
type IntoIter = Keys<'g, T, ()>;
type Item = &'g T;

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

impl<T, S> Debug for HashSetRef<'_, T, S>
where
T: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_set().entries(self).finish()
}
}

impl<T, S> Clone for HashSetRef<'_, T, S> {
fn clone(&self) -> Self {
self.set.pin()
}
}

impl<T, S> PartialEq for HashSetRef<'_, T, S>
where
T: Hash + Eq,
S: BuildHasher,
{
fn eq(&self, other: &Self) -> bool {
self.set == other.set
}
}

impl<T, S> PartialEq<HashSet<T, S>> for HashSetRef<'_, T, S>
where
T: Hash + Eq,
S: BuildHasher,
{
fn eq(&self, other: &HashSet<T, S>) -> bool {
self.set.guarded_eq(&other, &self.guard, &other.guard())
}
}

impl<T, S> PartialEq<HashSetRef<'_, T, S>> for HashSet<T, S>
where
T: Hash + Eq,
S: BuildHasher,
{
fn eq(&self, other: &HashSetRef<'_, T, S>) -> bool {
self.guarded_eq(&other.set, &self.guard(), &other.guard)
}
}

impl<T, S> Eq for HashSetRef<'_, T, S>
where
T: Hash + Eq,
S: BuildHasher,
{
}