Skip to content

Commit aa4e57c

Browse files
committed
Auto merge of #65091 - sekineh:into-iter-sorted, r=KodrAus
Implement ordered/sorted iterators on BinaryHeap as per #59278 I've implemented the ordered version of iterator on BinaryHeap as per #59278. # Added methods: * `.into_iter_sorted()` * like `.into_iter()`; but returns elements in heap order * `.drain_sorted()` * like `.drain()`; but returns elements in heap order * It's a bit _lazy_; elements are removed on drop. (Edit: it’s similar to vec::Drain) For `DrainSorted` struct, I implemented `Drop` trait following @scottmcm 's [suggestion](#59278 (comment)) # ~TODO~ DONE * ~I think I need to add more tests other than doctest.~ # **Notes:** * we renamed `_ordered` to `_sorted`, because the latter is more common in rust libs. (as suggested by @KodrAus )
2 parents 92df638 + 95442ae commit aa4e57c

File tree

3 files changed

+204
-5
lines changed

3 files changed

+204
-5
lines changed

Diff for: src/liballoc/collections/binary_heap.rs

+129-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@
146146
#![stable(feature = "rust1", since = "1.0.0")]
147147

148148
use core::ops::{Deref, DerefMut};
149-
use core::iter::{FromIterator, FusedIterator};
149+
use core::iter::{FromIterator, FusedIterator, TrustedLen};
150150
use core::mem::{swap, size_of, ManuallyDrop};
151151
use core::ptr;
152152
use core::fmt;
@@ -648,6 +648,36 @@ impl<T: Ord> BinaryHeap<T> {
648648
self.extend(other.drain());
649649
}
650650
}
651+
652+
/// Returns an iterator which retrieves elements in heap order.
653+
/// The retrieved elements are removed from the original heap.
654+
/// The remaining elements will be removed on drop in heap order.
655+
///
656+
/// Note:
657+
/// * `.drain_sorted()` is O(n lg n); much slower than `.drain()`.
658+
/// You should use the latter for most cases.
659+
///
660+
/// # Examples
661+
///
662+
/// Basic usage:
663+
///
664+
/// ```
665+
/// #![feature(binary_heap_drain_sorted)]
666+
/// use std::collections::BinaryHeap;
667+
///
668+
/// let mut heap = BinaryHeap::from(vec![1, 2, 3, 4, 5]);
669+
/// assert_eq!(heap.len(), 5);
670+
///
671+
/// drop(heap.drain_sorted()); // removes all elements in heap order
672+
/// assert_eq!(heap.len(), 0);
673+
/// ```
674+
#[inline]
675+
#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
676+
pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> {
677+
DrainSorted {
678+
inner: self,
679+
}
680+
}
651681
}
652682

653683
impl<T> BinaryHeap<T> {
@@ -672,6 +702,27 @@ impl<T> BinaryHeap<T> {
672702
Iter { iter: self.data.iter() }
673703
}
674704

705+
/// Returns an iterator which retrieves elements in heap order.
706+
/// This method consumes the original heap.
707+
///
708+
/// # Examples
709+
///
710+
/// Basic usage:
711+
///
712+
/// ```
713+
/// #![feature(binary_heap_into_iter_sorted)]
714+
/// use std::collections::BinaryHeap;
715+
/// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5]);
716+
///
717+
/// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), vec![5, 4]);
718+
/// ```
719+
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
720+
pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
721+
IntoIterSorted {
722+
inner: self,
723+
}
724+
}
725+
675726
/// Returns the greatest item in the binary heap, or `None` if it is empty.
676727
///
677728
/// # Examples
@@ -1115,6 +1166,37 @@ impl<T> ExactSizeIterator for IntoIter<T> {
11151166
#[stable(feature = "fused", since = "1.26.0")]
11161167
impl<T> FusedIterator for IntoIter<T> {}
11171168

1169+
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
1170+
#[derive(Clone, Debug)]
1171+
pub struct IntoIterSorted<T> {
1172+
inner: BinaryHeap<T>,
1173+
}
1174+
1175+
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
1176+
impl<T: Ord> Iterator for IntoIterSorted<T> {
1177+
type Item = T;
1178+
1179+
#[inline]
1180+
fn next(&mut self) -> Option<T> {
1181+
self.inner.pop()
1182+
}
1183+
1184+
#[inline]
1185+
fn size_hint(&self) -> (usize, Option<usize>) {
1186+
let exact = self.inner.len();
1187+
(exact, Some(exact))
1188+
}
1189+
}
1190+
1191+
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
1192+
impl<T: Ord> ExactSizeIterator for IntoIterSorted<T> {}
1193+
1194+
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
1195+
impl<T: Ord> FusedIterator for IntoIterSorted<T> {}
1196+
1197+
#[unstable(feature = "trusted_len", issue = "37572")]
1198+
unsafe impl<T: Ord> TrustedLen for IntoIterSorted<T> {}
1199+
11181200
/// A draining iterator over the elements of a `BinaryHeap`.
11191201
///
11201202
/// This `struct` is created by the [`drain`] method on [`BinaryHeap`]. See its
@@ -1161,6 +1243,52 @@ impl<T> ExactSizeIterator for Drain<'_, T> {
11611243
#[stable(feature = "fused", since = "1.26.0")]
11621244
impl<T> FusedIterator for Drain<'_, T> {}
11631245

1246+
/// A draining iterator over the elements of a `BinaryHeap`.
1247+
///
1248+
/// This `struct` is created by the [`drain_sorted`] method on [`BinaryHeap`]. See its
1249+
/// documentation for more.
1250+
///
1251+
/// [`drain_sorted`]: struct.BinaryHeap.html#method.drain_sorted
1252+
/// [`BinaryHeap`]: struct.BinaryHeap.html
1253+
#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
1254+
#[derive(Debug)]
1255+
pub struct DrainSorted<'a, T: Ord> {
1256+
inner: &'a mut BinaryHeap<T>,
1257+
}
1258+
1259+
#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
1260+
impl<'a, T: Ord> Drop for DrainSorted<'a, T> {
1261+
/// Removes heap elements in heap order.
1262+
fn drop(&mut self) {
1263+
while let Some(_) = self.inner.pop() {}
1264+
}
1265+
}
1266+
1267+
#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
1268+
impl<T: Ord> Iterator for DrainSorted<'_, T> {
1269+
type Item = T;
1270+
1271+
#[inline]
1272+
fn next(&mut self) -> Option<T> {
1273+
self.inner.pop()
1274+
}
1275+
1276+
#[inline]
1277+
fn size_hint(&self) -> (usize, Option<usize>) {
1278+
let exact = self.inner.len();
1279+
(exact, Some(exact))
1280+
}
1281+
}
1282+
1283+
#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
1284+
impl<T: Ord> ExactSizeIterator for DrainSorted<'_, T> { }
1285+
1286+
#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
1287+
impl<T: Ord> FusedIterator for DrainSorted<'_, T> {}
1288+
1289+
#[unstable(feature = "trusted_len", issue = "37572")]
1290+
unsafe impl<T: Ord> TrustedLen for DrainSorted<'_, T> {}
1291+
11641292
#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
11651293
impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
11661294
/// Converts a `Vec<T>` into a `BinaryHeap<T>`.

Diff for: src/liballoc/tests/binary_heap.rs

+73-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::BinaryHeap;
22
use std::collections::binary_heap::{Drain, PeekMut};
3+
use std::iter::TrustedLen;
34

45
#[test]
56
fn test_iterator() {
@@ -14,7 +15,7 @@ fn test_iterator() {
1415
}
1516

1617
#[test]
17-
fn test_iterator_reverse() {
18+
fn test_iter_rev_cloned_collect() {
1819
let data = vec![5, 9, 3];
1920
let iterout = vec![3, 5, 9];
2021
let pq = BinaryHeap::from(data);
@@ -24,7 +25,7 @@ fn test_iterator_reverse() {
2425
}
2526

2627
#[test]
27-
fn test_move_iter() {
28+
fn test_into_iter_collect() {
2829
let data = vec![5, 9, 3];
2930
let iterout = vec![9, 5, 3];
3031
let pq = BinaryHeap::from(data);
@@ -34,7 +35,7 @@ fn test_move_iter() {
3435
}
3536

3637
#[test]
37-
fn test_move_iter_size_hint() {
38+
fn test_into_iter_size_hint() {
3839
let data = vec![5, 9];
3940
let pq = BinaryHeap::from(data);
4041

@@ -51,7 +52,7 @@ fn test_move_iter_size_hint() {
5152
}
5253

5354
#[test]
54-
fn test_move_iter_reverse() {
55+
fn test_into_iter_rev_collect() {
5556
let data = vec![5, 9, 3];
5657
let iterout = vec![3, 5, 9];
5758
let pq = BinaryHeap::from(data);
@@ -60,6 +61,65 @@ fn test_move_iter_reverse() {
6061
assert_eq!(v, iterout);
6162
}
6263

64+
#[test]
65+
fn test_into_iter_sorted_collect() {
66+
let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
67+
let it = heap.into_iter_sorted();
68+
let sorted = it.collect::<Vec<_>>();
69+
assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
70+
}
71+
72+
#[test]
73+
fn test_drain_sorted_collect() {
74+
let mut heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
75+
let it = heap.drain_sorted();
76+
let sorted = it.collect::<Vec<_>>();
77+
assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
78+
}
79+
80+
fn check_exact_size_iterator<I: ExactSizeIterator>(len: usize, it: I) {
81+
let mut it = it;
82+
83+
for i in 0..it.len() {
84+
let (lower, upper) = it.size_hint();
85+
assert_eq!(Some(lower), upper);
86+
assert_eq!(lower, len - i);
87+
assert_eq!(it.len(), len - i);
88+
it.next();
89+
}
90+
assert_eq!(it.len(), 0);
91+
assert!(it.is_empty());
92+
}
93+
94+
#[test]
95+
fn test_exact_size_iterator() {
96+
let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
97+
check_exact_size_iterator(heap.len(), heap.iter());
98+
check_exact_size_iterator(heap.len(), heap.clone().into_iter());
99+
check_exact_size_iterator(heap.len(), heap.clone().into_iter_sorted());
100+
check_exact_size_iterator(heap.len(), heap.clone().drain());
101+
check_exact_size_iterator(heap.len(), heap.clone().drain_sorted());
102+
}
103+
104+
fn check_trusted_len<I: TrustedLen>(len: usize, it: I) {
105+
let mut it = it;
106+
for i in 0..len {
107+
let (lower, upper) = it.size_hint();
108+
if upper.is_some() {
109+
assert_eq!(Some(lower), upper);
110+
assert_eq!(lower, len - i);
111+
}
112+
it.next();
113+
}
114+
}
115+
116+
#[test]
117+
fn test_trusted_len() {
118+
let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
119+
check_trusted_len(heap.len(), heap.clone().into_iter_sorted());
120+
check_trusted_len(heap.len(), heap.clone().drain_sorted());
121+
}
122+
63123
#[test]
64124
fn test_peek_and_pop() {
65125
let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
@@ -206,6 +266,15 @@ fn test_drain() {
206266
assert!(q.is_empty());
207267
}
208268

269+
#[test]
270+
fn test_drain_sorted() {
271+
let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
272+
273+
assert_eq!(q.drain_sorted().take(5).collect::<Vec<_>>(), vec![9, 8, 7, 6, 5]);
274+
275+
assert!(q.is_empty());
276+
}
277+
209278
#[test]
210279
fn test_extend_ref() {
211280
let mut a = BinaryHeap::new();

Diff for: src/liballoc/tests/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#![feature(try_reserve)]
99
#![feature(unboxed_closures)]
1010
#![feature(associated_type_bounds)]
11+
#![feature(binary_heap_into_iter_sorted)]
12+
#![feature(binary_heap_drain_sorted)]
1113

1214
use std::hash::{Hash, Hasher};
1315
use std::collections::hash_map::DefaultHasher;

0 commit comments

Comments
 (0)