-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tracking issue for BinaryHeap
sorted iterator methods
#59278
Comments
Isn't |
@clarfon No, because getting the largest |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Hi, I've implemented both API in the local rust tree. Any ideas? Currently proposed API
|
Both owning and borrowing versions are useful. I can't return a version that borrows from a local variable, but I can return the version that moves it. That said, I agree that (I'm not worried about discoverability here; people have presumably been taught about the difference in things like |
@sekineh nope, not currently working on a PR |
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 )
BinaryHeap
owned iterators should yield items in heap orderBinaryHeap
sorted iterator methods
I've updated the issue to reflect that this now tracks the features implemented in #65091. |
@KodrAus (not sure if you're the right person to ping for this) This should probably get |
I kind of feel like in-order iteration should be the default for a heap. I was surprised to learn that the |
Also the destructor of |
How about renaming?
Would such a renaming even need a deprecation warning? |
I almost ran headlong into the underlying issue. I agree that it is unintuitive that results don't come out sorted. Additionally, if iteration order is arbitrary, reversing the order with Whether |
Leak amplification for peek_mut() to ensure BinaryHeap's invariant is always met In the libs-api team's discussion around rust-lang#104210, some of the team had hesitations around exposing malformed BinaryHeaps of an element type whose Ord and Drop impls are trusted, and which does not contain interior mutability. For example in the context of this kind of code: ```rust use std::collections::BinaryHeap; use std::ops::Range; use std::slice; fn main() { let slice = &mut ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; let cut_points = BinaryHeap::from(vec![4, 2, 7]); println!("{:?}", chop(slice, cut_points)); } // This is a souped up slice::split_at_mut to split in arbitrary many places. // // usize's Ord impl is trusted, so 1 single bounds check guarantees all those // output slices are non-overlapping and in-bounds fn chop<T>(slice: &mut [T], mut cut_points: BinaryHeap<usize>) -> Vec<&mut [T]> { let mut vec = Vec::with_capacity(cut_points.len() + 1); let max = match cut_points.pop() { Some(max) => max, None => { vec.push(slice); return vec; } }; assert!(max <= slice.len()); let len = slice.len(); let ptr: *mut T = slice.as_mut_ptr(); let get_unchecked_mut = unsafe { |range: Range<usize>| &mut *slice::from_raw_parts_mut(ptr.add(range.start), range.len()) }; vec.push(get_unchecked_mut(max..len)); let mut end = max; while let Some(start) = cut_points.pop() { vec.push(get_unchecked_mut(start..end)); end = start; } vec.push(get_unchecked_mut(0..end)); vec } ``` ```console [['7', '8', '9'], ['4', '5', '6'], ['2', '3'], ['0', '1']] ``` In the current BinaryHeap API, `peek_mut()` is the only thing that makes the above function unsound. ```rust let slice = &mut ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; let mut cut_points = BinaryHeap::from(vec![4, 2, 7]); { let mut max = cut_points.peek_mut().unwrap(); *max = 0; std::mem::forget(max); } println!("{:?}", chop(slice, cut_points)); ``` ```console [['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], [], ['2', '3'], ['0', '1']] ``` Or worse: ```rust let slice = &mut ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; let mut cut_points = BinaryHeap::from(vec![100, 100]); { let mut max = cut_points.peek_mut().unwrap(); *max = 0; std::mem::forget(max); } println!("{:?}", chop(slice, cut_points)); ``` ```console [['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], [], ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\u{1}', '\0', '?', '翾', '?', '翾', '\0', '\0', '?', '翾', '?', '翾', '?', '啿', '?', '啿', '?', '啿', '?', '啿', '?', '啿', '?', '翾', '\0', '\0', '', '啿', '\u{5}', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\u{8}', '\0', '`@',` '\0', '\u{1}', '\0', '?', '翾', '?', '翾', '?', '翾', ' thread 'main' panicked at 'index out of bounds: the len is 33 but the index is 33', library/core/src/unicode/unicode_data.rs:319:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ``` --- This PR makes `peek_mut()` use leak amplification (https://doc.rust-lang.org/1.66.0/nomicon/leaking.html#drain) to preserve the heap's invariant even in the situation that `PeekMut` gets leaked. I'll also follow up in the tracking issue of unstable `drain_sorted()` (rust-lang#59278) and `retain()` (rust-lang#71503).
I feel it odd that the return value of |
Copying my thoughts from #76234 (comment): My personal conclusions:
So I'd be tempted to "solve" this issue by adding I don't know if libs-api would be interested in the whole new collection type, though... |
This tracks the stabilization of
BinaryHeap::into_iter_sorted
(binary_heap_into_iter_sorted
) andBinaryHeap::drain_sorted
(binary_heap_drain_sorted
) implemented in #65091.EDIT much later:
into_sorted_vec
) need to be addressed before a future attempt to stabilize.Original feature request:
Currently, both
BinaryHeap::into_iter
andBinaryHeap::drain
yield the heap elements in an arbitrary order. This seems counter-intuitive given the nature of a heap. Sadly, we can't simply change their behavior behind the scenes, as we would have to remove the implementation ofDoubleEndedIterator
. Should we perhaps addinto_ordered_iter
anddrain_ordered
? The implementation is pretty straightforward so I'd be happy to submit a PR.The text was updated successfully, but these errors were encountered: