- Notifications
You must be signed in to change notification settings - Fork 14k
Add slice::sort_by_cached_key as a memoised sort_by_key #48639
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
Changes from 1 commit
ea6a1bd 670e69e b8452cc 9fbee35 21fde09 7dcfc07 bdcc6f9 f41a26f b430cba ca3bed0 9896b38 81edd17 785e3c3 eca1e18 9c7b69e File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| | @@ -102,6 +102,7 @@ use core::mem::size_of; | |
| use core::mem; | ||
| use core::ptr; | ||
| use core::slice as core_slice; | ||
| use core::{u8, u16, u32}; | ||
| | ||
| use borrow::{Borrow, BorrowMut, ToOwned}; | ||
| use boxed::Box; | ||
| | @@ -1329,19 +1330,31 @@ impl<T> [T] { | |
| pub fn sort_by_key<K, F>(&mut self, f: F) | ||
| where F: FnMut(&T) -> K, K: Ord | ||
| { | ||
| let mut indices: Vec<_> = self.iter().map(f).enumerate().map(|(i, k)| (k, i)).collect(); | ||
| // The elements of `indices` are unique, as they are indexed, so any sort will be stable | ||
| // with respect to the original slice. We use `sort_unstable` here because it requires less | ||
| // memory allocation. | ||
| indices.sort_unstable(); | ||
| for i in 0..self.len() { | ||
| let mut index = indices[i].1; | ||
| while index < i { | ||
| index = indices[index].1; | ||
| } | ||
| indices[i].1 = index; | ||
| self.swap(i, index); | ||
| // Helper macro for indexing our vector by the smallest possible type, to reduce allocation. | ||
| macro_rules! sort_by_key { | ||
| ($t:ty, $slice:ident, $f:ident) => ({ | ||
| let mut indices: Vec<_> = | ||
| $slice.iter().map($f).enumerate().map(|(i, k)| (k, i as $t)).collect(); | ||
| // The elements of `indices` are unique, as they are indexed, so any sort will be | ||
| // stable with respect to the original slice. We use `sort_unstable` here because it | ||
| // requires less memory allocation. | ||
| indices.sort_unstable(); | ||
| for i in 0..$slice.len() { | ||
| ||
| let mut index = indices[i].1; | ||
| while (index as usize) < i { | ||
| index = indices[index as usize].1; | ||
| } | ||
| indices[i].1 = index; | ||
| $slice.swap(i, index as usize); | ||
| } | ||
| }) | ||
| } | ||
| ||
| | ||
| let len = self.len(); | ||
| if len <= ( u8::MAX as usize) { return sort_by_key!( u8, self, f) } | ||
| if len <= (u16::MAX as usize) { return sort_by_key!(u16, self, f) } | ||
| if len <= (u32::MAX as usize) { return sort_by_key!(u32, self, f) } | ||
| sort_by_key!(usize, self, f) | ||
| ||
| } | ||
| | ||
| /// Sorts the slice, but may not preserve the order of equal elements. | ||
| | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to be able to use
SmallVechere and save an allocation when sorting short slices.Just a suggestion, though. Maybe leave that for a future PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good idea; I might leave that for a future PR though, yeah.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than pulling in a full crate (which is mostly about encapsulating stuff in a single type that can be moved as a unit), you can reproduce that functionality with a couple of stack variables. Something like:
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Just a caveat, that's the gist of it and the array code needs to take more precautions to be safe.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bluss Oh, do you mean panic-safe? Yes, I forgot about that, the array should be inside a
ManuallyDrop.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And use
ptr::writeor the equivalent with a ManuallyDrop around each element, that's the two things I could spot.