From c7be27f744abd8cecd66d75d5dc45fda5c75fbe6 Mon Sep 17 00:00:00 2001 From: Ken Micklas Date: Thu, 1 Aug 2024 19:47:28 +0100 Subject: [PATCH] Introduce `Cursor`/`CursorMut`/`CursorMutKey` thrichotomy for `BTreeSet` like map API --- alloc/src/collections/btree/set.rs | 210 ++++++++++++++++++++++++++--- 1 file changed, 194 insertions(+), 16 deletions(-) diff --git a/alloc/src/collections/btree/set.rs b/alloc/src/collections/btree/set.rs index 47b7e56ddf050..86401714639c0 100644 --- a/alloc/src/collections/btree/set.rs +++ b/alloc/src/collections/btree/set.rs @@ -1249,25 +1249,25 @@ impl BTreeSet { /// /// let mut set = BTreeSet::from([1, 2, 3, 4]); /// - /// let mut cursor = unsafe { set.lower_bound_mut(Bound::Included(&2)) }; + /// let mut cursor = set.lower_bound_mut(Bound::Included(&2)); /// assert_eq!(cursor.peek_prev(), Some(&mut 1)); /// assert_eq!(cursor.peek_next(), Some(&mut 2)); /// - /// let mut cursor = unsafe { set.lower_bound_mut(Bound::Excluded(&2)) }; + /// let mut cursor = set.lower_bound_mut(Bound::Excluded(&2)); /// assert_eq!(cursor.peek_prev(), Some(&mut 2)); /// assert_eq!(cursor.peek_next(), Some(&mut 3)); /// - /// let mut cursor = unsafe { set.lower_bound_mut(Bound::Unbounded) }; + /// let mut cursor = set.lower_bound_mut(Bound::Unbounded); /// assert_eq!(cursor.peek_prev(), None); /// assert_eq!(cursor.peek_next(), Some(&mut 1)); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub unsafe fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> + pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> where T: Borrow + Ord, Q: Ord, { - CursorMut { inner: unsafe { self.map.lower_bound_mut(bound).with_mutable_key() } } + CursorMut { inner: self.map.lower_bound_mut(bound) } } /// Returns a [`Cursor`] pointing at the gap after the greatest element @@ -1353,7 +1353,7 @@ impl BTreeSet { T: Borrow + Ord, Q: Ord, { - CursorMut { inner: unsafe { self.map.upper_bound_mut(bound).with_mutable_key() } } + CursorMut { inner: self.map.upper_bound_mut(bound) } } } @@ -2010,6 +2010,31 @@ impl Debug for Cursor<'_, K> { } } +/// A cursor over a `BTreeSet` with editing operations. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can +/// safely mutate the set during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying map. This means +/// cursors cannot yield multiple elements at once. +/// +/// Cursors always point to a gap between two elements in the set, and can +/// operate on the two immediately adjacent elements. +/// +/// A `CursorMut` is created with the [`BTreeSet::lower_bound_mut`] and [`BTreeSet::upper_bound_mut`] +/// methods. +#[unstable(feature = "btree_cursors", issue = "107540")] +pub struct CursorMut<'a, K: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A = Global> +{ + inner: super::map::CursorMut<'a, K, SetValZST, A>, +} + +#[unstable(feature = "btree_cursors", issue = "107540")] +impl Debug for CursorMut<'_, K, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("CursorMut") + } +} + /// A cursor over a `BTreeSet` with editing operations, and which allows /// mutating elements. /// @@ -2021,8 +2046,8 @@ impl Debug for Cursor<'_, K> { /// Cursors always point to a gap between two elements in the set, and can /// operate on the two immediately adjacent elements. /// -/// A `CursorMut` is created with the [`BTreeSet::lower_bound_mut`] and -/// [`BTreeSet::upper_bound_mut`] methods. +/// A `CursorMutKey` is created from a [`CursorMut`] with the +/// [`CursorMut::with_mutable_key`] method. /// /// # Safety /// @@ -2032,15 +2057,18 @@ impl Debug for Cursor<'_, K> { /// * The newly inserted element must be unique in the tree. /// * All elements in the tree must remain in sorted order. #[unstable(feature = "btree_cursors", issue = "107540")] -pub struct CursorMut<'a, K: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A = Global> -{ +pub struct CursorMutKey< + 'a, + K: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A = Global, +> { inner: super::map::CursorMutKey<'a, K, SetValZST, A>, } #[unstable(feature = "btree_cursors", issue = "107540")] -impl Debug for CursorMut<'_, K, A> { +impl Debug for CursorMutKey<'_, K, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("CursorMut") + f.write_str("CursorMutKey") } } @@ -2089,7 +2117,7 @@ impl<'a, T, A> CursorMut<'a, T, A> { /// If the cursor is already at the end of the set then `None` is returned /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn next(&mut self) -> Option<&mut T> { + pub fn next(&mut self) -> Option<&T> { self.inner.next().map(|(k, _)| k) } @@ -2099,7 +2127,7 @@ impl<'a, T, A> CursorMut<'a, T, A> { /// If the cursor is already at the start of the set then `None` is returned /// and the cursor is not moved. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn prev(&mut self) -> Option<&mut T> { + pub fn prev(&mut self) -> Option<&T> { self.inner.prev().map(|(k, _)| k) } @@ -2107,7 +2135,7 @@ impl<'a, T, A> CursorMut<'a, T, A> { /// /// If the cursor is at the end of the set then `None` is returned. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn peek_next(&mut self) -> Option<&mut T> { + pub fn peek_next(&mut self) -> Option<&T> { self.inner.peek_next().map(|(k, _)| k) } @@ -2115,7 +2143,7 @@ impl<'a, T, A> CursorMut<'a, T, A> { /// /// If the cursor is at the start of the set then `None` is returned. #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn peek_prev(&mut self) -> Option<&mut T> { + pub fn peek_prev(&mut self) -> Option<&T> { self.inner.peek_prev().map(|(k, _)| k) } @@ -2129,6 +2157,70 @@ impl<'a, T, A> CursorMut<'a, T, A> { pub fn as_cursor(&self) -> Cursor<'_, T> { Cursor { inner: self.inner.as_cursor() } } + + /// Converts the cursor into a [`CursorMutKey`], which allows mutating + /// elements in the tree. + /// + /// # Safety + /// + /// Since this cursor allows mutating elements, you must ensure that the + /// `BTreeSet` invariants are maintained. Specifically: + /// + /// * The newly inserted element must be unique in the tree. + /// * All elements in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn with_mutable_key(self) -> CursorMutKey<'a, T, A> { + CursorMutKey { inner: unsafe { self.inner.with_mutable_key() } } + } +} + +impl<'a, T, A> CursorMutKey<'a, T, A> { + /// Advances the cursor to the next gap, returning the element that it + /// moved over. + /// + /// If the cursor is already at the end of the set then `None` is returned + /// and the cursor is not moved. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn next(&mut self) -> Option<&mut T> { + self.inner.next().map(|(k, _)| k) + } + + /// Advances the cursor to the previous gap, returning the element that it + /// moved over. + /// + /// If the cursor is already at the start of the set then `None` is returned + /// and the cursor is not moved. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn prev(&mut self) -> Option<&mut T> { + self.inner.prev().map(|(k, _)| k) + } + + /// Returns a reference to the next element without moving the cursor. + /// + /// If the cursor is at the end of the set then `None` is returned + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_next(&mut self) -> Option<&mut T> { + self.inner.peek_next().map(|(k, _)| k) + } + + /// Returns a reference to the previous element without moving the cursor. + /// + /// If the cursor is at the start of the set then `None` is returned. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn peek_prev(&mut self) -> Option<&mut T> { + self.inner.peek_prev().map(|(k, _)| k) + } + + /// Returns a read-only cursor pointing to the same location as the + /// `CursorMutKey`. + /// + /// The lifetime of the returned `Cursor` is bound to that of the + /// `CursorMutKey`, which means it cannot outlive the `CursorMutKey` and that the + /// `CursorMutKey` is frozen for the lifetime of the `Cursor`. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn as_cursor(&self) -> Cursor<'_, T> { + Cursor { inner: self.inner.as_cursor() } + } } impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> { @@ -2217,6 +2309,92 @@ impl<'a, T: Ord, A: Allocator + Clone> CursorMut<'a, T, A> { } } +impl<'a, T: Ord, A: Allocator + Clone> CursorMutKey<'a, T, A> { + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. + /// + /// # Safety + /// + /// You must ensure that the `BTreeSet` invariants are maintained. + /// Specifically: + /// + /// * The key of the newly inserted element must be unique in the tree. + /// * All elements in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_after_unchecked(&mut self, value: T) { + unsafe { self.inner.insert_after_unchecked(value, SetValZST) } + } + + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. + /// + /// # Safety + /// + /// You must ensure that the `BTreeSet` invariants are maintained. + /// Specifically: + /// + /// * The newly inserted element must be unique in the tree. + /// * All elements in the tree must remain in sorted order. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub unsafe fn insert_before_unchecked(&mut self, value: T) { + unsafe { self.inner.insert_before_unchecked(value, SetValZST) } + } + + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap before the + /// newly inserted element. + /// + /// If the inserted element is not greater than the element before the + /// cursor (if any), or if it not less than the element after the cursor (if + /// any), then an [`UnorderedKeyError`] is returned since this would + /// invalidate the [`Ord`] invariant between the elements of the set. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_after(&mut self, value: T) -> Result<(), UnorderedKeyError> { + self.inner.insert_after(value, SetValZST) + } + + /// Inserts a new element into the set in the gap that the + /// cursor is currently pointing to. + /// + /// After the insertion the cursor will be pointing at the gap after the + /// newly inserted element. + /// + /// If the inserted element is not greater than the element before the + /// cursor (if any), or if it not less than the element after the cursor (if + /// any), then an [`UnorderedKeyError`] is returned since this would + /// invalidate the [`Ord`] invariant between the elements of the set. + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn insert_before(&mut self, value: T) -> Result<(), UnorderedKeyError> { + self.inner.insert_before(value, SetValZST) + } + + /// Removes the next element from the `BTreeSet`. + /// + /// The element that was removed is returned. The cursor position is + /// unchanged (before the removed element). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_next(&mut self) -> Option { + self.inner.remove_next().map(|(k, _)| k) + } + + /// Removes the precending element from the `BTreeSet`. + /// + /// The element that was removed is returned. The cursor position is + /// unchanged (after the removed element). + #[unstable(feature = "btree_cursors", issue = "107540")] + pub fn remove_prev(&mut self) -> Option { + self.inner.remove_prev().map(|(k, _)| k) + } +} + #[unstable(feature = "btree_cursors", issue = "107540")] pub use super::map::UnorderedKeyError;