Skip to content

Commit cba731c

Browse files
committed
BinaryHeap: implement IterMut
link tracking issue
1 parent 20a6f3a commit cba731c

File tree

4 files changed

+124
-3
lines changed

4 files changed

+124
-3
lines changed

library/alloc/src/collections/binary_heap.rs

+98-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@
144144
#![stable(feature = "rust1", since = "1.0.0")]
145145

146146
use core::fmt;
147-
use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen};
147+
use core::iter::{FromIterator, FusedIterator, InPlaceIterable, Rev, SourceIter, TrustedLen};
148148
use core::mem::{self, swap, ManuallyDrop};
149149
use core::ops::{Deref, DerefMut};
150150
use core::ptr;
@@ -153,6 +153,7 @@ use crate::collections::TryReserveError;
153153
use crate::slice;
154154
use crate::vec::{self, AsVecIntoIter, Vec};
155155

156+
use super::btree::borrow::DormantMutRef;
156157
use super::SpecExtend;
157158

158159
#[cfg(test)]
@@ -819,6 +820,33 @@ impl<T: Ord> BinaryHeap<T> {
819820
// data[0..first_removed] is untouched, so we only need to rebuild the tail:
820821
self.rebuild_tail(first_removed);
821822
}
823+
824+
/// Returns a mutable iterator visiting all values in the underlying vector, in
825+
/// arbitrary order. When `IterMut` is dropped, the binary heap is rebuilt.
826+
///
827+
/// Note: If the `IterMut` value is leaked, the heap may be in an
828+
/// inconsistent state.
829+
///
830+
/// # Examples
831+
///
832+
/// Basic usage:
833+
///
834+
/// ```
835+
/// #![feature(binary_heap_iter_mut)]
836+
/// use std::collections::BinaryHeap;
837+
///
838+
/// let mut heap = BinaryHeap::from([-10, -5, 1, 2, 4, 13]);
839+
///
840+
/// heap.iter_mut().for_each(|x| *x += 1);
841+
///
842+
/// assert_eq!(vec![-9, -4, 2, 3, 5, 14], heap.into_sorted_vec());
843+
/// ```
844+
#[unstable(feature = "binary_heap_iter_mut", issue = "98524")]
845+
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
846+
let (this, dormant) = DormantMutRef::new(self);
847+
let it = this.data.iter_mut().rev(); // reversed to take advantage of `rebuild_tail` on drop
848+
IterMut { iter_mut: ManuallyDrop::new(it), heap: ManuallyDrop::new(dormant) }
849+
}
822850
}
823851

824852
impl<T> BinaryHeap<T> {
@@ -1357,6 +1385,65 @@ impl<T> ExactSizeIterator for Iter<'_, T> {
13571385
#[stable(feature = "fused", since = "1.26.0")]
13581386
impl<T> FusedIterator for Iter<'_, T> {}
13591387

1388+
/// A mutable iterator over the elements of a `BinaryHeap`.
1389+
///
1390+
/// This `struct` is created by [`BinaryHeap::iter_mut()`]. See its
1391+
/// documentation for more.
1392+
///
1393+
/// [`iter_mut`]: BinaryHeap::iter_mut
1394+
#[must_use = "iterators are lazy and do nothing unless consumed"]
1395+
#[unstable(feature = "binary_heap_iter_mut", issue = "98524")]
1396+
pub struct IterMut<'a, T: 'a + Ord> {
1397+
iter_mut: ManuallyDrop<Rev<slice::IterMut<'a, T>>>,
1398+
heap: ManuallyDrop<DormantMutRef<'a, BinaryHeap<T>>>,
1399+
}
1400+
1401+
#[unstable(feature = "binary_heap_iter_mut", issue = "98524")]
1402+
impl<'a, T: Ord> Iterator for IterMut<'a, T> {
1403+
type Item = &'a mut T;
1404+
1405+
#[inline]
1406+
fn next(&mut self) -> Option<&'a mut T> {
1407+
self.iter_mut.next()
1408+
}
1409+
1410+
#[inline]
1411+
fn size_hint(&self) -> (usize, Option<usize>) {
1412+
self.iter_mut.size_hint()
1413+
}
1414+
}
1415+
1416+
#[unstable(feature = "binary_heap_iter_mut", issue = "98524")]
1417+
impl<T: fmt::Debug + Ord> fmt::Debug for IterMut<'_, T> {
1418+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1419+
f.debug_tuple("IterMut").field(&self.iter_mut).finish()
1420+
}
1421+
}
1422+
1423+
#[unstable(feature = "binary_heap_iter_mut", issue = "98524")]
1424+
impl<T: Ord> Drop for IterMut<'_, T> {
1425+
fn drop(&mut self) {
1426+
let remaining = self.iter_mut.len();
1427+
1428+
// Early drop to avoid alias after recovering &mut BinaryHeap
1429+
// SAFETY: we're done using it.
1430+
unsafe { ManuallyDrop::drop(&mut self.iter_mut) };
1431+
1432+
// SAFETY:
1433+
// take: `self.heap` is not used again.
1434+
// awaken: `self.iter_mut` has been dropped and hence no references to the heap remain.
1435+
let heap = unsafe { ManuallyDrop::take(&mut self.heap).awaken() };
1436+
heap.rebuild_tail(remaining);
1437+
}
1438+
}
1439+
1440+
#[unstable(feature = "binary_heap_iter_mut", issue = "98524")]
1441+
impl<T: Ord> ExactSizeIterator for IterMut<'_, T> {
1442+
fn is_empty(&self) -> bool {
1443+
self.iter_mut.is_empty()
1444+
}
1445+
}
1446+
13601447
/// An owning iterator over the elements of a `BinaryHeap`.
13611448
///
13621449
/// This `struct` is created by [`BinaryHeap::into_iter()`]
@@ -1653,6 +1740,16 @@ impl<'a, T> IntoIterator for &'a BinaryHeap<T> {
16531740
}
16541741
}
16551742

1743+
#[stable(feature = "rust1", since = "1.0.0")]
1744+
impl<'a, T: Ord> IntoIterator for &'a mut BinaryHeap<T> {
1745+
type Item = &'a mut T;
1746+
type IntoIter = IterMut<'a, T>;
1747+
1748+
fn into_iter(self) -> IterMut<'a, T> {
1749+
self.iter_mut()
1750+
}
1751+
}
1752+
16561753
#[stable(feature = "rust1", since = "1.0.0")]
16571754
impl<T: Ord> Extend<T> for BinaryHeap<T> {
16581755
#[inline]

library/alloc/src/collections/binary_heap/tests.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,9 @@ fn check_exact_size_iterator<I: ExactSizeIterator>(len: usize, it: I) {
9595

9696
#[test]
9797
fn test_exact_size_iterator() {
98-
let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
98+
let mut heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
9999
check_exact_size_iterator(heap.len(), heap.iter());
100+
check_exact_size_iterator(heap.len(), heap.iter_mut());
100101
check_exact_size_iterator(heap.len(), heap.clone().into_iter());
101102
check_exact_size_iterator(heap.len(), heap.clone().into_iter_sorted());
102103
check_exact_size_iterator(heap.len(), heap.clone().drain());
@@ -122,6 +123,28 @@ fn test_trusted_len() {
122123
check_trusted_len(heap.len(), heap.clone().drain_sorted());
123124
}
124125

126+
#[test]
127+
fn test_iter_mut() {
128+
let mut heap = BinaryHeap::from([5, 9, 3]);
129+
heap.iter_mut().for_each(|e| *e += 1);
130+
assert_eq!(heap.into_vec(), vec![10, 6, 4]);
131+
132+
let mut heap = BinaryHeap::from([5, 9, 3]);
133+
*heap.iter_mut().next().unwrap() -= 10;
134+
assert_eq!(heap.into_vec(), vec![9, 5, -7]);
135+
136+
let mut heap = BinaryHeap::from([5, 9, 3]);
137+
*heap.iter_mut().next().unwrap() += 10;
138+
assert_eq!(heap.into_vec(), vec![13, 5, 9]);
139+
140+
let mut heap = BinaryHeap::from([5, 9, 3]);
141+
*heap.iter_mut().last().unwrap() += 10;
142+
assert_eq!(heap.into_vec(), vec![19, 5, 3]);
143+
144+
let mut heap = BinaryHeap::<i32>::new();
145+
assert_eq!(heap.iter_mut().next(), None);
146+
}
147+
125148
#[test]
126149
fn test_peek_and_pop() {
127150
let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];

library/alloc/src/collections/btree/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
mod append;
2-
mod borrow;
2+
pub(super) mod borrow;
33
mod dedup_sorted_iter;
44
mod fix;
55
pub mod map;

library/alloc/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#![feature(unboxed_closures)]
2424
#![feature(associated_type_bounds)]
2525
#![feature(binary_heap_into_iter_sorted)]
26+
#![feature(binary_heap_iter_mut)]
2627
#![feature(binary_heap_drain_sorted)]
2728
#![feature(slice_ptr_get)]
2829
#![feature(binary_heap_retain)]

0 commit comments

Comments
 (0)