From cbd255770a9bbda5de8b1d3e2067699cdfc2b81b Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 14 Feb 2021 00:30:51 +0900 Subject: [PATCH 1/2] Add docs for SkipSet and SkipList --- crossbeam-skiplist/src/base.rs | 11 +- crossbeam-skiplist/src/lib.rs | 2 +- crossbeam-skiplist/src/map.rs | 22 ++- crossbeam-skiplist/src/set.rs | 260 +++++++++++++++++++++++++++++++-- 4 files changed, 272 insertions(+), 23 deletions(-) diff --git a/crossbeam-skiplist/src/base.rs b/crossbeam-skiplist/src/base.rs index af5e79182..1ab4f8577 100644 --- a/crossbeam-skiplist/src/base.rs +++ b/crossbeam-skiplist/src/base.rs @@ -1,4 +1,4 @@ -//! TODO: docs +//! A lock-free skip list. See [`SkipList`]. use alloc::alloc::{alloc, dealloc, handle_alloc_error, Layout}; use core::borrow::Borrow; @@ -1551,6 +1551,7 @@ where } } } + /// Moves to the previous entry in the skip list. pub fn move_prev(&mut self, guard: &Guard) -> bool { match self.prev(guard) { @@ -1684,7 +1685,7 @@ impl<'a, K: 'a, V: 'a> RefIter<'a, K, V> where K: Ord, { - /// TODO + /// Advances the iterator and returns the next value. pub fn next(&mut self, guard: &Guard) -> Option> { self.parent.check_guard(guard); self.head = match self.head { @@ -1710,7 +1711,7 @@ where self.head.clone() } - /// TODO + /// Removes and returns an element from the end of the iterator. pub fn next_back(&mut self, guard: &Guard) -> Option> { self.parent.check_guard(guard); self.tail = match self.tail { @@ -1888,7 +1889,7 @@ where R: RangeBounds, Q: Ord + ?Sized, { - /// TODO + /// Advances the iterator and returns the next value. pub fn next(&mut self, guard: &Guard) -> Option> { self.parent.check_guard(guard); self.head = match self.head { @@ -1912,7 +1913,7 @@ where self.head.clone() } - /// TODO: docs + /// Removes and returns an element from the end of the iterator. pub fn next_back(&mut self, guard: &Guard) -> Option> { self.parent.check_guard(guard); self.tail = match self.tail { diff --git a/crossbeam-skiplist/src/lib.rs b/crossbeam-skiplist/src/lib.rs index 68815f26f..13988fa32 100644 --- a/crossbeam-skiplist/src/lib.rs +++ b/crossbeam-skiplist/src/lib.rs @@ -6,7 +6,7 @@ //! multiple threads. //! //! # Concurrent access -//! [`SkipMap`] and [`SkipSet`] implement `Send` and `Sync`, +//! [`SkipMap`] and [`SkipSet`] implement [`Send`] and [`Sync`], //! so they can be shared across threads with ease. //! //! Methods which mutate the map, such as [`insert`], diff --git a/crossbeam-skiplist/src/map.rs b/crossbeam-skiplist/src/map.rs index 7116ce71f..b035d1fc1 100644 --- a/crossbeam-skiplist/src/map.rs +++ b/crossbeam-skiplist/src/map.rs @@ -22,6 +22,14 @@ pub struct SkipMap { impl SkipMap { /// Returns a new, empty map. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipMap; + /// + /// let map: SkipMap = SkipMap::new(); + /// ``` pub fn new() -> SkipMap { SkipMap { inner: base::SkipList::new(epoch::default_collector().clone()), @@ -83,8 +91,8 @@ where /// /// let numbers = SkipMap::new(); /// numbers.insert(5, "five"); + /// assert_eq!(*numbers.front().unwrap().value(), "five"); /// numbers.insert(6, "six"); - /// /// assert_eq!(*numbers.front().unwrap().value(), "five"); /// ``` pub fn front(&self) -> Option> { @@ -103,8 +111,8 @@ where /// /// let numbers = SkipMap::new(); /// numbers.insert(5, "five"); + /// assert_eq!(*numbers.back().unwrap().value(), "five"); /// numbers.insert(6, "six"); - /// /// assert_eq!(*numbers.back().unwrap().value(), "six"); /// ``` pub fn back(&self) -> Option> { @@ -274,9 +282,9 @@ where } } - /// Returns an iterator over a subset of entries in the skip list. + /// Returns an iterator over a subset of entries in the map. /// - /// This iterator returns [`Entry`]s which + /// This iterator returns [`Entry`]s which /// can be used to access keys and their associated values. /// /// # Example @@ -381,7 +389,7 @@ where /// assert_eq!(*numbers.pop_front().unwrap().value(), "twelve"); /// /// // All entries have been removed now. - /// assert!(numbers.pop_front().is_none()); + /// assert!(numbers.is_empty()); /// ``` pub fn pop_front(&self) -> Option> { let guard = &epoch::pin(); @@ -408,7 +416,7 @@ where /// assert_eq!(*numbers.pop_back().unwrap().value(), "six"); /// /// // All entries have been removed now. - /// assert!(numbers.pop_front().is_none()); + /// assert!(numbers.is_empty()); /// ``` pub fn pop_back(&self) -> Option> { let guard = &epoch::pin(); @@ -641,7 +649,7 @@ impl fmt::Debug for Iter<'_, K, V> { } } -/// An iterator over the entries of a `SkipMap`. +/// An iterator over a subset of entries of a `SkipMap`. pub struct Range<'a, Q, R, K, V> where K: Ord + Borrow, diff --git a/crossbeam-skiplist/src/set.rs b/crossbeam-skiplist/src/set.rs index 7ffe477ea..a8d71e49c 100644 --- a/crossbeam-skiplist/src/set.rs +++ b/crossbeam-skiplist/src/set.rs @@ -1,4 +1,4 @@ -//! TODO: docs +//! A set based on a lock-free skip list. See [`SkipSet`]. use std::borrow::Borrow; use std::fmt; @@ -9,12 +9,25 @@ use std::ops::{Bound, RangeBounds}; use crate::map; /// A set based on a lock-free skip list. +/// +/// This is an alternative to [`BTreeSet`] which supports +/// concurrent access across multiple threads. +/// +/// [`BTreeSet`]: std::collections::BTreeSet pub struct SkipSet { inner: map::SkipMap, } impl SkipSet { /// Returns a new, empty set. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set: SkipSet = SkipSet::new(); + /// ``` pub fn new() -> SkipSet { SkipSet { inner: map::SkipMap::new(), @@ -22,6 +35,18 @@ impl SkipSet { } /// Returns `true` if the set is empty. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// assert!(set.is_empty()); + /// + /// set.insert(1); + /// assert!(!set.is_empty()); + /// ``` pub fn is_empty(&self) -> bool { self.inner.is_empty() } @@ -30,6 +55,18 @@ impl SkipSet { /// /// If the set is being concurrently modified, consider the returned number just an /// approximation without any guarantees. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// assert_eq!(set.len(), 0); + /// + /// set.insert(1); + /// assert_eq!(set.len(), 1); + /// ``` pub fn len(&self) -> usize { self.inner.len() } @@ -40,16 +77,50 @@ where T: Ord, { /// Returns the entry with the smallest key. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// set.insert(1); + /// assert_eq!(*set.front().unwrap().value(), 1); + /// set.insert(2); + /// assert_eq!(*set.front().unwrap().value(), 1); + /// ``` pub fn front(&self) -> Option> { self.inner.front().map(Entry::new) } /// Returns the entry with the largest key. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// set.insert(1); + /// assert_eq!(*set.back().unwrap().value(), 1); + /// set.insert(2); + /// assert_eq!(*set.back().unwrap().value(), 2); + /// ``` pub fn back(&self) -> Option> { self.inner.back().map(Entry::new) } /// Returns `true` if the set contains a value for the specified key. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set: SkipSet<_> = (1..=3).collect(); + /// assert!(set.contains(&1)); + /// assert!(!set.contains(&4)); + /// ``` pub fn contains(&self, key: &Q) -> bool where T: Borrow, @@ -59,6 +130,16 @@ where } /// Returns an entry with the specified `key`. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set: SkipSet<_> = (1..=3).collect(); + /// assert_eq!(*set.get(&3).unwrap().value(), 3); + /// assert!(set.get(&4).is_none()); + /// ``` pub fn get(&self, key: &Q) -> Option> where T: Borrow, @@ -70,6 +151,27 @@ where /// Returns an `Entry` pointing to the lowest element whose key is above /// the given bound. If no such element is found then `None` is /// returned. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// use std::ops::Bound::*; + /// + /// let set = SkipSet::new(); + /// set.insert(6); + /// set.insert(7); + /// set.insert(12); + /// + /// let greater_than_five = set.lower_bound(Excluded(&5)).unwrap(); + /// assert_eq!(*greater_than_five.value(), 6); + /// + /// let greater_than_six = set.lower_bound(Excluded(&6)).unwrap(); + /// assert_eq!(*greater_than_six.value(), 7); + /// + /// let greater_than_thirteen = set.lower_bound(Excluded(&13)); + /// assert!(greater_than_thirteen.is_none()); + /// ``` pub fn lower_bound<'a, Q>(&'a self, bound: Bound<&Q>) -> Option> where T: Borrow, @@ -81,6 +183,24 @@ where /// Returns an `Entry` pointing to the highest element whose key is below /// the given bound. If no such element is found then `None` is /// returned. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// use std::ops::Bound::*; + /// + /// let set = SkipSet::new(); + /// set.insert(6); + /// set.insert(7); + /// set.insert(12); + /// + /// let less_than_eight = set.upper_bound(Excluded(&8)).unwrap(); + /// assert_eq!(*less_than_eight.value(), 7); + /// + /// let less_than_six = set.upper_bound(Excluded(&6)); + /// assert!(less_than_six.is_none()); + /// ``` pub fn upper_bound<'a, Q>(&'a self, bound: Bound<&Q>) -> Option> where T: Borrow, @@ -90,18 +210,61 @@ where } /// Finds an entry with the specified key, or inserts a new `key`-`value` pair if none exist. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// let entry = set.get_or_insert(2); + /// assert_eq!(*entry.value(), 2); + /// ``` pub fn get_or_insert(&self, key: T) -> Entry<'_, T> { Entry::new(self.inner.get_or_insert(key, ())) } - /// Returns an iterator over all entries in the map. + /// Returns an iterator over all entries in the set. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// set.insert(6); + /// set.insert(7); + /// set.insert(12); + /// + /// let mut set_iter = set.iter(); + /// assert_eq!(*set_iter.next().unwrap().value(), 6); + /// assert_eq!(*set_iter.next().unwrap().value(), 7); + /// assert_eq!(*set_iter.next().unwrap().value(), 12); + /// assert!(set_iter.next().is_none()); + /// ``` pub fn iter(&self) -> Iter<'_, T> { Iter { inner: self.inner.iter(), } } - /// Returns an iterator over a subset of entries in the skip list. + /// Returns an iterator over a subset of entries in the set. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// set.insert(6); + /// set.insert(7); + /// set.insert(12); + /// + /// let mut set_range = set.range(5..=8); + /// assert_eq!(*set_range.next().unwrap().value(), 6); + /// assert_eq!(*set_range.next().unwrap().value(), 7); + /// assert!(set_range.next().is_none()); + /// ``` pub fn range(&self, range: R) -> Range<'_, Q, R, T> where T: Borrow, @@ -122,11 +285,35 @@ where /// /// If there is an existing entry with this key, it will be removed before inserting the new /// one. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// set.insert(2); + /// assert_eq!(*set.get(&2).unwrap().value(), 2); + /// ``` pub fn insert(&self, key: T) -> Entry<'_, T> { Entry::new(self.inner.insert(key, ())) } /// Removes an entry with the specified key from the set and returns it. + /// + /// The value will not actually be dropped until all references to it have gone + /// out of scope. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// set.insert(2); + /// assert_eq!(*set.remove(&2).unwrap().value(), 2); + /// assert!(set.remove(&2).is_none()); + /// ``` pub fn remove(&self, key: &Q) -> Option> where T: Borrow, @@ -135,17 +322,70 @@ where self.inner.remove(key).map(Entry::new) } - /// Removes an entry from the front of the map. + /// Removes an entry from the front of the set. + /// Returns the removed entry. + /// + /// The value will not actually be dropped until all references to it have gone + /// out of scope. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// set.insert(1); + /// set.insert(2); + /// + /// assert_eq!(*set.pop_front().unwrap().value(), 1); + /// assert_eq!(*set.pop_front().unwrap().value(), 2); + /// + /// // All entries have been removed now. + /// assert!(set.is_empty()); + /// ``` pub fn pop_front(&self) -> Option> { self.inner.pop_front().map(Entry::new) } - /// Removes an entry from the back of the map. + /// Removes an entry from the back of the set. + /// Returns the removed entry. + /// + /// The value will not actually be dropped until all references to it have gone + /// out of scope. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// set.insert(1); + /// set.insert(2); + /// + /// assert_eq!(*set.pop_back().unwrap().value(), 2); + /// assert_eq!(*set.pop_back().unwrap().value(), 1); + /// + /// // All entries have been removed now. + /// assert!(set.is_empty()); + /// ``` pub fn pop_back(&self) -> Option> { self.inner.pop_back().map(Entry::new) } /// Iterates over the set and removes every entry. + /// + /// # Example + /// + /// ``` + /// use crossbeam_skiplist::SkipSet; + /// + /// let set = SkipSet::new(); + /// set.insert(1); + /// set.insert(2); + /// + /// set.clear(); + /// assert!(set.is_empty()); + /// ``` pub fn clear(&self) { self.inner.clear(); } @@ -205,7 +445,7 @@ where } } -/// TODO +/// A reference-counted entry in a set. pub struct Entry<'a, T> { inner: map::Entry<'a, T, ()>, } @@ -215,7 +455,7 @@ impl<'a, T> Entry<'a, T> { Entry { inner } } - /// Returns a reference to the key. + /// Returns a reference to the value. pub fn value(&self) -> &T { self.inner.key() } @@ -230,12 +470,12 @@ impl<'a, T> Entry<'a, T> where T: Ord, { - /// TODO + /// Moves to the next entry in the set. pub fn move_next(&mut self) -> bool { self.inner.move_next() } - /// TODO + /// Moves to the previous entry in the set. pub fn move_prev(&mut self) -> bool { self.inner.move_prev() } @@ -340,7 +580,7 @@ impl fmt::Debug for Iter<'_, T> { } } -/// An iterator over the entries of a `SkipMap`. +/// An iterator over a subset of entries of a `SkipSet`. pub struct Range<'a, Q, R, T> where T: Ord + Borrow, From 82a173f997f3cdf507d24dc301af80291e92e70d Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 14 Feb 2021 04:47:34 +0900 Subject: [PATCH 2/2] Update SkipSet docs to use deref --- crossbeam-skiplist/src/set.rs | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/crossbeam-skiplist/src/set.rs b/crossbeam-skiplist/src/set.rs index a8d71e49c..cc4083472 100644 --- a/crossbeam-skiplist/src/set.rs +++ b/crossbeam-skiplist/src/set.rs @@ -85,9 +85,9 @@ where /// /// let set = SkipSet::new(); /// set.insert(1); - /// assert_eq!(*set.front().unwrap().value(), 1); + /// assert_eq!(*set.front().unwrap(), 1); /// set.insert(2); - /// assert_eq!(*set.front().unwrap().value(), 1); + /// assert_eq!(*set.front().unwrap(), 1); /// ``` pub fn front(&self) -> Option> { self.inner.front().map(Entry::new) @@ -102,9 +102,9 @@ where /// /// let set = SkipSet::new(); /// set.insert(1); - /// assert_eq!(*set.back().unwrap().value(), 1); + /// assert_eq!(*set.back().unwrap(), 1); /// set.insert(2); - /// assert_eq!(*set.back().unwrap().value(), 2); + /// assert_eq!(*set.back().unwrap(), 2); /// ``` pub fn back(&self) -> Option> { self.inner.back().map(Entry::new) @@ -137,7 +137,7 @@ where /// use crossbeam_skiplist::SkipSet; /// /// let set: SkipSet<_> = (1..=3).collect(); - /// assert_eq!(*set.get(&3).unwrap().value(), 3); + /// assert_eq!(*set.get(&3).unwrap(), 3); /// assert!(set.get(&4).is_none()); /// ``` pub fn get(&self, key: &Q) -> Option> @@ -164,10 +164,10 @@ where /// set.insert(12); /// /// let greater_than_five = set.lower_bound(Excluded(&5)).unwrap(); - /// assert_eq!(*greater_than_five.value(), 6); + /// assert_eq!(*greater_than_five, 6); /// /// let greater_than_six = set.lower_bound(Excluded(&6)).unwrap(); - /// assert_eq!(*greater_than_six.value(), 7); + /// assert_eq!(*greater_than_six, 7); /// /// let greater_than_thirteen = set.lower_bound(Excluded(&13)); /// assert!(greater_than_thirteen.is_none()); @@ -196,7 +196,7 @@ where /// set.insert(12); /// /// let less_than_eight = set.upper_bound(Excluded(&8)).unwrap(); - /// assert_eq!(*less_than_eight.value(), 7); + /// assert_eq!(*less_than_eight, 7); /// /// let less_than_six = set.upper_bound(Excluded(&6)); /// assert!(less_than_six.is_none()); @@ -218,7 +218,7 @@ where /// /// let set = SkipSet::new(); /// let entry = set.get_or_insert(2); - /// assert_eq!(*entry.value(), 2); + /// assert_eq!(*entry, 2); /// ``` pub fn get_or_insert(&self, key: T) -> Entry<'_, T> { Entry::new(self.inner.get_or_insert(key, ())) @@ -237,9 +237,9 @@ where /// set.insert(12); /// /// let mut set_iter = set.iter(); - /// assert_eq!(*set_iter.next().unwrap().value(), 6); - /// assert_eq!(*set_iter.next().unwrap().value(), 7); - /// assert_eq!(*set_iter.next().unwrap().value(), 12); + /// assert_eq!(*set_iter.next().unwrap(), 6); + /// assert_eq!(*set_iter.next().unwrap(), 7); + /// assert_eq!(*set_iter.next().unwrap(), 12); /// assert!(set_iter.next().is_none()); /// ``` pub fn iter(&self) -> Iter<'_, T> { @@ -261,8 +261,8 @@ where /// set.insert(12); /// /// let mut set_range = set.range(5..=8); - /// assert_eq!(*set_range.next().unwrap().value(), 6); - /// assert_eq!(*set_range.next().unwrap().value(), 7); + /// assert_eq!(*set_range.next().unwrap(), 6); + /// assert_eq!(*set_range.next().unwrap(), 7); /// assert!(set_range.next().is_none()); /// ``` pub fn range(&self, range: R) -> Range<'_, Q, R, T> @@ -293,7 +293,7 @@ where /// /// let set = SkipSet::new(); /// set.insert(2); - /// assert_eq!(*set.get(&2).unwrap().value(), 2); + /// assert_eq!(*set.get(&2).unwrap(), 2); /// ``` pub fn insert(&self, key: T) -> Entry<'_, T> { Entry::new(self.inner.insert(key, ())) @@ -311,7 +311,7 @@ where /// /// let set = SkipSet::new(); /// set.insert(2); - /// assert_eq!(*set.remove(&2).unwrap().value(), 2); + /// assert_eq!(*set.remove(&2).unwrap(), 2); /// assert!(set.remove(&2).is_none()); /// ``` pub fn remove(&self, key: &Q) -> Option> @@ -337,8 +337,8 @@ where /// set.insert(1); /// set.insert(2); /// - /// assert_eq!(*set.pop_front().unwrap().value(), 1); - /// assert_eq!(*set.pop_front().unwrap().value(), 2); + /// assert_eq!(*set.pop_front().unwrap(), 1); + /// assert_eq!(*set.pop_front().unwrap(), 2); /// /// // All entries have been removed now. /// assert!(set.is_empty()); @@ -362,8 +362,8 @@ where /// set.insert(1); /// set.insert(2); /// - /// assert_eq!(*set.pop_back().unwrap().value(), 2); - /// assert_eq!(*set.pop_back().unwrap().value(), 1); + /// assert_eq!(*set.pop_back().unwrap(), 2); + /// assert_eq!(*set.pop_back().unwrap(), 1); /// /// // All entries have been removed now. /// assert!(set.is_empty());