Skip to content

Commit b19ede6

Browse files
Restore Equivalent/Comparable
Renamed OrdComparator to BasicComparator and made compatible with the Equivalent/Comparable traits
1 parent 9e2c8fc commit b19ede6

File tree

8 files changed

+103
-59
lines changed

8 files changed

+103
-59
lines changed

crossbeam-skiplist/src/base.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! A lock-free skip list. See [`SkipList`].
22
3-
use crate::comparator::{Comparator, OrdComparator};
3+
use crate::comparator::{Comparator, BasicComparator};
44

55
use alloc::alloc::{alloc, dealloc, handle_alloc_error, Layout};
66
use core::cmp;
@@ -323,7 +323,7 @@ struct HotData {
323323
// As a further future optimization, if `!mem::needs_drop::<K>() && !mem::needs_drop::<V>()`
324324
// (neither key nor the value have destructors), there's no point in creating a new local
325325
// collector, so we should simply use the global one.
326-
pub struct SkipList<K, V, C = OrdComparator> {
326+
pub struct SkipList<K, V, C = BasicComparator> {
327327
/// The head of the skip list (just a dummy node, not a real entry).
328328
head: Head<K, V>,
329329

@@ -1333,7 +1333,7 @@ impl<K, V, C> IntoIterator for SkipList<K, V, C> {
13331333
/// The lifetimes of the key and value are the same as that of the `Guard`
13341334
/// used when creating the `Entry` (`'g`). This lifetime is also constrained to
13351335
/// not outlive the `SkipList`.
1336-
pub struct Entry<'a: 'g, 'g, K, V, C = OrdComparator> {
1336+
pub struct Entry<'a: 'g, 'g, K, V, C = BasicComparator> {
13371337
parent: &'a SkipList<K, V, C>,
13381338
node: &'g Node<K, V>,
13391339
guard: &'g Guard,
@@ -1476,7 +1476,7 @@ where
14761476
///
14771477
/// You *must* call `release` to free this type, otherwise the node will be
14781478
/// leaked. This is because releasing the entry requires a `Guard`.
1479-
pub struct RefEntry<'a, K, V, C = OrdComparator> {
1479+
pub struct RefEntry<'a, K, V, C = BasicComparator> {
14801480
parent: &'a SkipList<K, V, C>,
14811481
node: &'a Node<K, V>,
14821482
}
@@ -1651,7 +1651,7 @@ where
16511651
}
16521652

16531653
/// An iterator over the entries of a `SkipList`.
1654-
pub struct Iter<'a: 'g, 'g, K, V, C = OrdComparator> {
1654+
pub struct Iter<'a: 'g, 'g, K, V, C = BasicComparator> {
16551655
parent: &'a SkipList<K, V, C>,
16561656
head: Option<&'g Node<K, V>>,
16571657
tail: Option<&'g Node<K, V>>,
@@ -1728,7 +1728,7 @@ where
17281728
}
17291729

17301730
/// An iterator over reference-counted entries of a `SkipList`.
1731-
pub struct RefIter<'a, K, V, C = OrdComparator> {
1731+
pub struct RefIter<'a, K, V, C = BasicComparator> {
17321732
parent: &'a SkipList<K, V, C>,
17331733
head: Option<RefEntry<'a, K, V, C>>,
17341734
tail: Option<RefEntry<'a, K, V, C>>,
@@ -1830,7 +1830,7 @@ impl<'a, K: 'a, V: 'a, C> RefIter<'a, K, V, C> {
18301830
}
18311831

18321832
/// An iterator over a subset of entries of a `SkipList`.
1833-
pub struct Range<'a: 'g, 'g, Q, R, K, V, C = OrdComparator>
1833+
pub struct Range<'a: 'g, 'g, Q, R, K, V, C = BasicComparator>
18341834
where
18351835
C: Comparator<K> + Comparator<K, Q>,
18361836
R: RangeBounds<Q>,
@@ -1946,7 +1946,7 @@ where
19461946
}
19471947

19481948
/// An iterator over reference-counted subset of entries of a `SkipList`.
1949-
pub struct RefRange<'a, Q, R, K, V, C = OrdComparator>
1949+
pub struct RefRange<'a, Q, R, K, V, C = BasicComparator>
19501950
where
19511951
C: Comparator<K> + Comparator<K, Q>,
19521952
R: RangeBounds<Q>,

crossbeam-skiplist/src/comparator.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
use core::{borrow::Borrow, cmp::Ordering};
44

5+
use crate::equivalent::{Comparable, Equivalent};
6+
57
/// Key equality trait.
68
///
79
/// This trait allows for very flexible comparison of objects. You may
@@ -51,30 +53,29 @@ pub trait Comparator<L: ?Sized, R: ?Sized = L>: Equivalator<L, R> {
5153
fn compare(&self, lhs: &L, rhs: &R) -> Ordering;
5254
}
5355

54-
/// This comparator uses the standard library `Borrow` and `Ord` traits to
55-
/// compare values. When used in a data structure, this results in the same
56-
/// behavior as the standard `BTreeMap` interface.
56+
/// This comparator uses the `Equivalent` and `Comparable` traits to perform
57+
/// comparisons, which themselves fall back on the standard library `Borrow`
58+
/// and `Ord` traits. When used in a map, this results in the same behavior as
59+
/// the standard `BTreeMap` interface.
5760
#[derive(Clone, Copy, Debug, Default)]
58-
pub struct OrdComparator;
61+
pub struct BasicComparator;
5962

60-
impl<K: ?Sized, Q: ?Sized> Equivalator<K, Q> for OrdComparator
63+
impl<K: ?Sized, Q: ?Sized> Equivalator<K, Q> for BasicComparator
6164
where
62-
K: Borrow<Q>,
63-
Q: Eq,
65+
K: Equivalent<Q>,
6466
{
6567
#[inline]
6668
fn equivalent(&self, lhs: &K, rhs: &Q) -> bool {
67-
<Q as PartialEq>::eq(lhs.borrow(), rhs)
69+
<K as Equivalent<Q>>::equivalent(lhs, rhs)
6870
}
6971
}
7072

71-
impl<K: ?Sized, Q: ?Sized> Comparator<K, Q> for OrdComparator
73+
impl<K: ?Sized, Q: ?Sized> Comparator<K, Q> for BasicComparator
7274
where
73-
K: Borrow<Q>,
74-
Q: Ord,
75+
K: Comparable<Q>,
7576
{
7677
#[inline]
7778
fn compare(&self, lhs: &K, rhs: &Q) -> Ordering {
78-
Ord::cmp(lhs.borrow(), rhs)
79+
<K as Comparable<Q>>::compare(lhs, rhs)
7980
}
8081
}

crossbeam-skiplist/src/equivalent.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// These traits are based on `equivalent` crate, but `K` and `Q` are flipped to avoid type inference issues:
2+
// https://github.com/indexmap-rs/equivalent/issues/5
3+
4+
//! Traits for key comparison in maps.
5+
6+
use core::{borrow::Borrow, cmp::Ordering};
7+
8+
/// Key equivalence trait.
9+
///
10+
/// This trait allows hash table lookup to be customized. It has one blanket
11+
/// implementation that uses the regular solution with `Borrow` and `Eq`, just
12+
/// like `HashMap` does, so that you can pass `&str` to lookup into a map with
13+
/// `String` keys and so on.
14+
///
15+
/// # Contract
16+
///
17+
/// The implementor **must** hash like `Q`, if it is hashable.
18+
pub trait Equivalent<Q: ?Sized> {
19+
/// Compare self to `key` and return `true` if they are equal.
20+
fn equivalent(&self, key: &Q) -> bool;
21+
}
22+
23+
impl<K: ?Sized, Q: ?Sized> Equivalent<Q> for K
24+
where
25+
K: Borrow<Q>,
26+
Q: Eq,
27+
{
28+
#[inline]
29+
fn equivalent(&self, key: &Q) -> bool {
30+
PartialEq::eq(self.borrow(), key)
31+
}
32+
}
33+
34+
/// Key ordering trait.
35+
///
36+
/// This trait allows ordered map lookup to be customized. It has one blanket
37+
/// implementation that uses the regular solution with `Borrow` and `Ord`, just
38+
/// like `BTreeMap` does, so that you can pass `&str` to lookup into a map with
39+
/// `String` keys and so on.
40+
pub trait Comparable<Q: ?Sized>: Equivalent<Q> {
41+
/// Compare self to `key` and return their ordering.
42+
fn compare(&self, key: &Q) -> Ordering;
43+
}
44+
45+
impl<K: ?Sized, Q: ?Sized> Comparable<Q> for K
46+
where
47+
K: Borrow<Q>,
48+
Q: Ord,
49+
{
50+
#[inline]
51+
fn compare(&self, key: &Q) -> Ordering {
52+
Ord::cmp(self.borrow(), key)
53+
}
54+
}

crossbeam-skiplist/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,4 @@ pub mod set;
260260
pub use crate::{map::SkipMap, set::SkipSet};
261261

262262
pub mod comparator;
263+
pub mod equivalent;

crossbeam-skiplist/src/map.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use std::ptr;
77

88
use crate::{
99
base::{self, try_pin_loop},
10+
comparator::BasicComparator,
1011
comparator::Comparator,
11-
comparator::OrdComparator,
1212
};
1313
use crossbeam_epoch as epoch;
1414

@@ -18,7 +18,7 @@ use crossbeam_epoch as epoch;
1818
/// concurrent access across multiple threads.
1919
///
2020
/// [`BTreeMap`]: std::collections::BTreeMap
21-
pub struct SkipMap<K, V, C = OrdComparator> {
21+
pub struct SkipMap<K, V, C = BasicComparator> {
2222
inner: base::SkipList<K, V, C>,
2323
}
2424

@@ -45,9 +45,9 @@ impl<K, V, C> SkipMap<K, V, C> {
4545
/// # Example
4646
///
4747
/// ```
48-
/// use crossbeam_skiplist::{SkipMap, comparator::OrdComparator};
48+
/// use crossbeam_skiplist::{SkipMap, comparator::BasicComparator};
4949
///
50-
/// let map: SkipMap<i32, &str> = SkipMap::with_comparator(OrdComparator);
50+
/// let map: SkipMap<i32, &str> = SkipMap::with_comparator(BasicComparator);
5151
/// ```
5252
pub fn with_comparator(comparator: C) -> Self {
5353
Self {
@@ -589,7 +589,7 @@ where
589589
}
590590

591591
/// A reference-counted entry in a map.
592-
pub struct Entry<'a, K, V, C = OrdComparator> {
592+
pub struct Entry<'a, K, V, C = BasicComparator> {
593593
inner: ManuallyDrop<base::RefEntry<'a, K, V, C>>,
594594
}
595595

@@ -709,7 +709,7 @@ impl<K, V> fmt::Debug for IntoIter<K, V> {
709709
}
710710

711711
/// An iterator over the entries of a `SkipMap`.
712-
pub struct Iter<'a, K, V, C = OrdComparator> {
712+
pub struct Iter<'a, K, V, C = BasicComparator> {
713713
inner: base::RefIter<'a, K, V, C>,
714714
}
715715

@@ -749,7 +749,7 @@ impl<K, V, C> Drop for Iter<'_, K, V, C> {
749749
}
750750

751751
/// An iterator over a subset of entries of a `SkipMap`.
752-
pub struct Range<'a, Q, R, K, V, C = OrdComparator>
752+
pub struct Range<'a, Q, R, K, V, C = BasicComparator>
753753
where
754754
C: Comparator<K> + Comparator<K, Q>,
755755
R: RangeBounds<Q>,

crossbeam-skiplist/src/set.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::ops::Deref;
55
use std::ops::{Bound, RangeBounds};
66

77
use crate::{
8-
comparator::{Comparator, OrdComparator},
8+
comparator::{BasicComparator, Comparator},
99
map,
1010
};
1111

@@ -15,7 +15,7 @@ use crate::{
1515
/// concurrent access across multiple threads.
1616
///
1717
/// [`BTreeSet`]: std::collections::BTreeSet
18-
pub struct SkipSet<T, C = OrdComparator> {
18+
pub struct SkipSet<T, C = BasicComparator> {
1919
inner: map::SkipMap<T, (), C>,
2020
}
2121

@@ -42,9 +42,9 @@ impl<T, C> SkipSet<T, C> {
4242
/// # Example
4343
///
4444
/// ```
45-
/// use crossbeam_skiplist::{SkipSet, comparator::OrdComparator};
45+
/// use crossbeam_skiplist::{SkipSet, comparator::BasicComparator};
4646
///
47-
/// let map: SkipSet<i32> = SkipSet::with_comparator(OrdComparator);
47+
/// let map: SkipSet<i32> = SkipSet::with_comparator(BasicComparator);
4848
/// ```
4949
pub fn with_comparator(comparator: C) -> Self {
5050
Self {
@@ -469,7 +469,7 @@ where
469469
}
470470

471471
/// A reference-counted entry in a set.
472-
pub struct Entry<'a, T, C = OrdComparator> {
472+
pub struct Entry<'a, T, C = BasicComparator> {
473473
inner: map::Entry<'a, T, (), C>,
474474
}
475475

@@ -574,7 +574,7 @@ impl<T> fmt::Debug for IntoIter<T> {
574574
}
575575

576576
/// An iterator over the entries of a `SkipSet`.
577-
pub struct Iter<'a, T, C = OrdComparator> {
577+
pub struct Iter<'a, T, C = BasicComparator> {
578578
inner: map::Iter<'a, T, (), C>,
579579
}
580580

@@ -605,7 +605,7 @@ impl<T, C> fmt::Debug for Iter<'_, T, C> {
605605
}
606606

607607
/// An iterator over a subset of entries of a `SkipSet`.
608-
pub struct Range<'a, Q, R, T, C = OrdComparator>
608+
pub struct Range<'a, Q, R, T, C = BasicComparator>
609609
where
610610
C: Comparator<T> + Comparator<T, Q>,
611611
R: RangeBounds<Q>,

crossbeam-skiplist/tests/base.rs

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -902,8 +902,8 @@ fn drops() {
902902
}
903903

904904
#[test]
905-
fn comparator() {
906-
use crossbeam_skiplist::comparator::{Comparator, Equivalator};
905+
fn comparable_get() {
906+
use crossbeam_skiplist::equivalent::{Comparable, Equivalent};
907907

908908
#[derive(PartialEq, Eq, PartialOrd, Ord)]
909909
struct Foo {
@@ -916,9 +916,6 @@ fn comparator() {
916916
data: &'a [u8],
917917
}
918918

919-
#[derive(Clone, Copy, Default)]
920-
struct FooComparator;
921-
922919
impl PartialOrd for FooRef<'_> {
923920
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
924921
Some(self.cmp(other))
@@ -938,35 +935,23 @@ fn comparator() {
938935
}
939936
}
940937

941-
impl<'a> Equivalator<Foo> for FooComparator {
942-
fn equivalent(&self, lhs: &Foo, rhs: &Foo) -> bool {
943-
lhs == rhs
944-
}
945-
}
946-
947-
impl<'a> Equivalator<Foo, FooRef<'a>> for FooComparator {
948-
fn equivalent(&self, foo: &Foo, key: &FooRef<'a>) -> bool {
938+
impl<'a> Equivalent<FooRef<'a>> for Foo {
939+
fn equivalent(&self, key: &FooRef<'a>) -> bool {
949940
let a = u64::from_be_bytes(key.data[..8].try_into().unwrap());
950941
let b = u32::from_be_bytes(key.data[8..].try_into().unwrap());
951-
a == foo.a && b == foo.b
942+
a == self.a && b == self.b
952943
}
953944
}
954945

955-
impl<'a> Comparator<Foo> for FooComparator {
956-
fn compare(&self, lhs: &Foo, rhs: &Foo) -> std::cmp::Ordering {
957-
Ord::cmp(lhs, rhs)
958-
}
959-
}
960-
961-
impl<'a> Comparator<Foo, FooRef<'a>> for FooComparator {
962-
fn compare(&self, foo: &Foo, key: &FooRef<'a>) -> std::cmp::Ordering {
946+
impl<'a> Comparable<FooRef<'a>> for Foo {
947+
fn compare(&self, key: &FooRef<'a>) -> std::cmp::Ordering {
963948
let a = u64::from_be_bytes(key.data[..8].try_into().unwrap());
964949
let b = u32::from_be_bytes(key.data[8..].try_into().unwrap());
965-
Foo { a, b }.cmp(foo)
950+
Foo { a, b }.cmp(self)
966951
}
967952
}
968953

969-
let s = SkipList::with_comparator(epoch::default_collector().clone(), FooComparator);
954+
let s = SkipList::new(epoch::default_collector().clone());
970955
let foo = Foo { a: 1, b: 2 };
971956

972957
let g = &epoch::pin();

crossbeam-skiplist/tests/set.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,9 @@ fn comparator() {
766766
assert!(s.contains(b"xy"));
767767
assert!(s.contains(b""));
768768

769-
let elems: Vec<_> = s.into_iter().collect();
769+
let elems: Vec<_> = s.iter().map(|x| &x.value()[..]).collect();
770770
assert_eq!(elems, [&b""[..], b"a", b"ab"]);
771+
772+
s.remove(b"p");
773+
assert!(!s.contains(b"a"));
771774
}

0 commit comments

Comments
 (0)