Skip to content

Commit

Permalink
Make map generic over lock type
Browse files Browse the repository at this point in the history
This is necessary since there is no particular lock implementation that
"makes sense" on `no_std`. This patch changes all types to be generic
over any lock type that implements `lock_api::RawMutex`, and defaults to
`parking_lot::RawMutex` on `std`.

Note that this patch forks the struct definition for `HashMap` into one
for `std` (which has a default for `L`) and one for `no_std` (which does
not). This is fine since any code written _without_ the `std` feature
_will_ compile with the `std` feature enabled (`indexmap` does the same;
the reverse is not true). We _could_ introduce an intermediate private
struct to avoid repeating the definition, but it would require writing
`self.inner` all over the place, which would be sad. This seemed
marginally cleaner.

Also, this diff makes me want implied bounds a lot:
rust-lang/rust#44491
  • Loading branch information
jonhoo committed Jan 30, 2020
1 parent 7b32a16 commit adb58e0
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 86 deletions.
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ maintenance = { status = "experimental" }

[features]
sanitize = ['crossbeam-epoch/sanitize']
std = ["crossbeam-epoch/std", "num_cpus"]
std = ["crossbeam-epoch/std", "num_cpus", "parking_lot"]
default = ["std"]

[dependencies]
parking_lot = "0.10"
lock_api = "0.3.3"

[dependencies.parking_lot]
version = "0.10"
optional = true

[dependencies.num_cpus]
version = "1.12.0"
Expand Down
36 changes: 27 additions & 9 deletions src/iter/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ use crossbeam_epoch::Guard;
///
/// See [`HashMap::iter`](crate::HashMap::iter) for details.
#[derive(Debug)]
pub struct Iter<'g, K, V> {
pub(crate) node_iter: NodeIter<'g, K, V>,
pub struct Iter<'g, K, V, L>
where
L: lock_api::RawMutex,
{
pub(crate) node_iter: NodeIter<'g, K, V, L>,
pub(crate) guard: &'g Guard,
}

impl<'g, K, V> Iterator for Iter<'g, K, V> {
impl<'g, K, V, L> Iterator for Iter<'g, K, V, L>
where
L: lock_api::RawMutex,
{
type Item = (&'g K, &'g V);
fn next(&mut self) -> Option<Self::Item> {
let node = self.node_iter.next()?;
Expand All @@ -26,11 +32,17 @@ impl<'g, K, V> Iterator for Iter<'g, K, V> {
///
/// See [`HashMap::keys`](crate::HashMap::keys) for details.
#[derive(Debug)]
pub struct Keys<'g, K, V> {
pub(crate) node_iter: NodeIter<'g, K, V>,
pub struct Keys<'g, K, V, L>
where
L: lock_api::RawMutex,
{
pub(crate) node_iter: NodeIter<'g, K, V, L>,
}

impl<'g, K, V> Iterator for Keys<'g, K, V> {
impl<'g, K, V, L> Iterator for Keys<'g, K, V, L>
where
L: lock_api::RawMutex,
{
type Item = &'g K;
fn next(&mut self) -> Option<Self::Item> {
let node = self.node_iter.next()?;
Expand All @@ -42,12 +54,18 @@ impl<'g, K, V> Iterator for Keys<'g, K, V> {
///
/// See [`HashMap::values`](crate::HashMap::values) for details.
#[derive(Debug)]
pub struct Values<'g, K, V> {
pub(crate) node_iter: NodeIter<'g, K, V>,
pub struct Values<'g, K, V, L>
where
L: lock_api::RawMutex,
{
pub(crate) node_iter: NodeIter<'g, K, V, L>,
pub(crate) guard: &'g Guard,
}

impl<'g, K, V> Iterator for Values<'g, K, V> {
impl<'g, K, V, L> Iterator for Values<'g, K, V, L>
where
L: lock_api::RawMutex,
{
type Item = &'g V;
fn next(&mut self) -> Option<Self::Item> {
let node = self.node_iter.next()?;
Expand Down
40 changes: 26 additions & 14 deletions src/iter/traverser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@ use core::sync::atomic::Ordering;
use crossbeam_epoch::{Guard, Shared};

#[derive(Debug)]
pub(crate) struct NodeIter<'g, K, V> {
pub(crate) struct NodeIter<'g, K, V, L>
where
L: lock_api::RawMutex,
{
/// Current table; update if resized
table: Option<&'g Table<K, V>>,
table: Option<&'g Table<K, V, L>>,

stack: Option<Box<TableStack<'g, K, V>>>,
spare: Option<Box<TableStack<'g, K, V>>>,
stack: Option<Box<TableStack<'g, K, V, L>>>,
spare: Option<Box<TableStack<'g, K, V, L>>>,

/// The last bin entry iterated over
prev: Option<&'g Node<K, V>>,
prev: Option<&'g Node<K, V, L>>,

/// Index of bin to use next
index: usize,
Expand All @@ -34,8 +37,11 @@ pub(crate) struct NodeIter<'g, K, V> {
guard: &'g Guard,
}

impl<'g, K, V> NodeIter<'g, K, V> {
pub(crate) fn new(table: Shared<'g, Table<K, V>>, guard: &'g Guard) -> Self {
impl<'g, K, V, L> NodeIter<'g, K, V, L>
where
L: lock_api::RawMutex,
{
pub(crate) fn new(table: Shared<'g, Table<K, V, L>>, guard: &'g Guard) -> Self {
let (table, len) = if table.is_null() {
(None, 0)
} else {
Expand All @@ -58,7 +64,7 @@ impl<'g, K, V> NodeIter<'g, K, V> {
}
}

fn push_state(&mut self, t: &'g Table<K, V>, i: usize, n: usize) {
fn push_state(&mut self, t: &'g Table<K, V, L>, i: usize, n: usize) {
let mut s = self.spare.take();
if let Some(ref mut s) = s {
self.spare = s.next.take();
Expand Down Expand Up @@ -114,8 +120,11 @@ impl<'g, K, V> NodeIter<'g, K, V> {
}
}

impl<'g, K, V> Iterator for NodeIter<'g, K, V> {
type Item = &'g Node<K, V>;
impl<'g, K, V, L> Iterator for NodeIter<'g, K, V, L>
where
L: lock_api::RawMutex,
{
type Item = &'g Node<K, V, L>;
fn next(&mut self) -> Option<Self::Item> {
let mut e = None;
if let Some(prev) = self.prev {
Expand Down Expand Up @@ -182,19 +191,22 @@ impl<'g, K, V> Iterator for NodeIter<'g, K, V> {
}

#[derive(Debug)]
struct TableStack<'g, K, V> {
struct TableStack<'g, K, V, L>
where
L: lock_api::RawMutex,
{
length: usize,
index: usize,
table: &'g Table<K, V>,
next: Option<Box<TableStack<'g, K, V>>>,
table: &'g Table<K, V, L>,
next: Option<Box<TableStack<'g, K, V, L>>>,
}

#[cfg(test)]
mod tests {
use super::*;
use crate::raw::Table;
use crossbeam_epoch::{self as epoch, Atomic, Owned};
use parking_lot::Mutex;
use lock_api::Mutex;

#[test]
fn iter_new() {
Expand Down
Loading

0 comments on commit adb58e0

Please sign in to comment.