-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Add take_...
functions to slices
#62282
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 all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,7 +31,7 @@ use crate::isize; | |
use crate::iter::*; | ||
use crate::marker::{self, Copy, Send, Sized, Sync}; | ||
use crate::mem; | ||
use crate::ops::{self, FnMut, Range}; | ||
use crate::ops::{self, Bound, FnMut, OneSidedRange, Range}; | ||
use crate::option::Option; | ||
use crate::option::Option::{None, Some}; | ||
use crate::ptr::{self, NonNull}; | ||
|
@@ -53,6 +53,24 @@ mod sort; | |
// Extension traits | ||
// | ||
|
||
/// Calculates the direction and split point of a one-sided range. | ||
/// | ||
/// Helper for `take` and `take_mut` which returns a boolean | ||
/// indicating whether the front of the split is being taken | ||
/// (as opposed to the back), as well as a number indicating the | ||
/// index at which to split. Returns `None` if the split index would | ||
/// overflow `usize`. | ||
#[inline] | ||
fn take_split_point(range: impl OneSidedRange<usize>) -> Option<(bool, usize)> { | ||
Some(match (range.start_bound(), range.end_bound()) { | ||
(Bound::Unbounded, Bound::Excluded(i)) => (true, *i), | ||
(Bound::Unbounded, Bound::Included(i)) => (true, i.checked_add(1)?), | ||
(Bound::Excluded(i), Bound::Unbounded) => (false, i.checked_add(1)?), | ||
(Bound::Included(i), Bound::Unbounded) => (false, *i), | ||
_ => unreachable!(), | ||
}) | ||
} | ||
|
||
#[lang = "slice"] | ||
#[cfg(not(test))] | ||
impl<T> [T] { | ||
|
@@ -2639,6 +2657,227 @@ impl<T> [T] { | |
{ | ||
self.iter().is_sorted_by_key(f) | ||
} | ||
|
||
/// Removes and returns the portion of the slice specified by `range`. | ||
/// | ||
/// If the provided `range` starts or ends outside of the slice, | ||
/// `None` is returned and the slice is not modified. | ||
/// | ||
/// # Examples | ||
/// | ||
/// Taking the first three items from a slice (via `..3`): | ||
/// | ||
/// ``` | ||
/// #![feature(slice_take)] | ||
/// | ||
/// let mut slice: &[_] = &['a', 'b', 'c', 'd']; | ||
/// let mut first_three = slice.take(..3).unwrap(); | ||
/// | ||
/// assert_eq!(slice, &['d']); | ||
/// assert_eq!(first_three, &['a', 'b', 'c']); | ||
/// ``` | ||
/// | ||
/// Taking the tail of a slice starting at index two (via `2..`): | ||
/// | ||
/// ``` | ||
/// #![feature(slice_take)] | ||
/// | ||
/// let mut slice: &[_] = &['a', 'b', 'c', 'd']; | ||
/// let mut tail = slice.take(2..).unwrap(); | ||
/// | ||
/// assert_eq!(slice, &['a', 'b']); | ||
/// assert_eq!(tail, &['c', 'd']); | ||
/// ``` | ||
/// | ||
/// Getting `None` when `range` starts or ends outside of the slice: | ||
/// | ||
/// ``` | ||
/// #![feature(slice_take)] | ||
/// | ||
/// let mut slice: &[_] = &['a', 'b', 'c', 'd']; | ||
/// | ||
/// assert_eq!(None, slice.take(5..)); | ||
/// assert_eq!(None, slice.take(..5)); | ||
/// assert_eq!(None, slice.take(..=4)); | ||
/// let expected: &[char] = &['a', 'b', 'c', 'd']; | ||
/// assert_eq!(Some(expected), slice.take(..4)); | ||
/// ``` | ||
#[inline] | ||
#[unstable(feature = "slice_take", issue = "62280")] | ||
pub fn take<'a, R: OneSidedRange<usize>>(self: &mut &'a Self, range: R) -> Option<&'a Self> { | ||
let (taking_front, split_index) = take_split_point(range)?; | ||
if split_index > self.len() { | ||
return None; | ||
} | ||
let original = crate::mem::take(self); | ||
let (front, back) = original.split_at(split_index); | ||
if taking_front { | ||
*self = back; | ||
Some(front) | ||
} else { | ||
*self = front; | ||
Some(back) | ||
} | ||
} | ||
|
||
/// Removes and returns the portion of the mutable slice specified by `range`. | ||
/// | ||
/// If the provided `range` starts or ends outside of the slice, | ||
/// `None` is returned and the slice is not modified. | ||
/// | ||
/// # Examples | ||
/// | ||
/// Taking the first three items from a slice (via `..3`): | ||
/// | ||
/// ``` | ||
/// #![feature(slice_take)] | ||
/// | ||
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; | ||
/// let mut first_three = slice.take_mut(..3).unwrap(); | ||
/// | ||
/// assert_eq!(slice, &mut ['d']); | ||
/// assert_eq!(first_three, &mut ['a', 'b', 'c']); | ||
/// ``` | ||
/// | ||
/// Taking the tail of a slice starting at index two (via `2..`): | ||
/// | ||
/// ``` | ||
/// #![feature(slice_take)] | ||
/// | ||
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; | ||
/// let mut tail = slice.take_mut(2..).unwrap(); | ||
/// | ||
/// assert_eq!(slice, &mut ['a', 'b']); | ||
/// assert_eq!(tail, &mut ['c', 'd']); | ||
/// ``` | ||
cramertj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// | ||
/// Getting `None` when `range` starts or ends outside of the slice: | ||
/// | ||
/// ``` | ||
/// #![feature(slice_take)] | ||
/// | ||
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; | ||
/// | ||
/// assert_eq!(None, slice.take_mut(5..)); | ||
/// assert_eq!(None, slice.take_mut(..5)); | ||
/// assert_eq!(None, slice.take_mut(..=4)); | ||
/// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd']; | ||
/// assert_eq!(Some(expected), slice.take_mut(..4)); | ||
/// ``` | ||
#[inline] | ||
#[unstable(feature = "slice_take", issue = "62280")] | ||
pub fn take_mut<'a, R: OneSidedRange<usize>>( | ||
self: &mut &'a mut Self, | ||
range: R, | ||
) -> Option<&'a mut Self> { | ||
let (taking_front, split_index) = take_split_point(range)?; | ||
if split_index > self.len() { | ||
return None; | ||
} | ||
let original = crate::mem::take(self); | ||
let (front, back) = original.split_at_mut(split_index); | ||
if taking_front { | ||
*self = back; | ||
Some(front) | ||
} else { | ||
*self = front; | ||
Some(back) | ||
} | ||
} | ||
|
||
/// Takes the first element out of the slice. | ||
/// | ||
/// Returns a reference pointing to the first element of the old slice. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no such thing as an old slice, given there is not really a new slice either. |
||
/// | ||
/// Returns `None` if the slice is empty. | ||
Comment on lines
+2788
to
+2792
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we want to adopt the formulation from the
This would also resolve @nox's remark. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a little confused about how to phrase this, because I want to make it clear that the element itself is staying in place, and the only thing being manipulated is what the slice refers to. That is, "Removes and returns the first element from the slice." sounds to me like it's taking an element out from the backing memory, which isn't the case. WDYT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, you're right, it's a bit misleading. I don't have a good idea, but maybe something like:
or
or
In all cases, the first "
And if we change the |
||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// #![feature(slice_take)] | ||
/// | ||
/// let mut slice: &[_] = &['a', 'b', 'c']; | ||
/// let first = slice.take_first().unwrap(); | ||
/// | ||
/// assert_eq!(slice, &['b', 'c']); | ||
/// assert_eq!(first, &'a'); | ||
/// ``` | ||
#[inline] | ||
#[unstable(feature = "slice_take", issue = "62280")] | ||
pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> { | ||
self.take(..=0).map(|res| &res[0]) | ||
} | ||
|
||
/// Takes the first element out of the mutable slice. | ||
/// | ||
/// Returns a mutable reference pointing to the first element of the old slice. | ||
/// | ||
/// Returns `None` if the slice is empty. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// #![feature(slice_take)] | ||
/// | ||
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; | ||
/// let first = slice.take_first_mut().unwrap(); | ||
/// *first = 'd'; | ||
/// | ||
/// assert_eq!(slice, &['b', 'c']); | ||
/// assert_eq!(first, &'d'); | ||
/// ``` | ||
#[inline] | ||
#[unstable(feature = "slice_take", issue = "62280")] | ||
pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { | ||
self.take_mut(..=0).map(|res| &mut res[0]) | ||
} | ||
|
||
/// Takes the last element out of the slice. | ||
/// | ||
/// Returns a reference pointing to the last element of the old slice. | ||
/// | ||
/// Returns `None` if the slice is empty. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// #![feature(slice_take)] | ||
/// | ||
/// let mut slice: &[_] = &['a', 'b', 'c']; | ||
/// let last = slice.take_last().unwrap(); | ||
/// | ||
/// assert_eq!(slice, &['a', 'b']); | ||
/// assert_eq!(last, &'c'); | ||
/// ``` | ||
#[inline] | ||
#[unstable(feature = "slice_take", issue = "62280")] | ||
pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> { | ||
self.take((self.len() - 1)..).map(|res| &res[0]) | ||
} | ||
|
||
/// Takes the last element out of the mutable slice. | ||
/// | ||
/// Returns a mutable reference pointing to the last element of the old slice. | ||
/// | ||
/// Returns `None` if the slice is empty. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// #![feature(slice_take)] | ||
/// | ||
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; | ||
/// let last = slice.take_last_mut().unwrap(); | ||
/// *last = 'd'; | ||
/// | ||
/// assert_eq!(slice, &['a', 'b']); | ||
/// assert_eq!(last, &'d'); | ||
/// ``` | ||
#[inline] | ||
#[unstable(feature = "slice_take", issue = "62280")] | ||
pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { | ||
self.take_mut((self.len() - 1)..).map(|res| &mut res[0]) | ||
} | ||
} | ||
|
||
#[lang = "slice_u8"] | ||
|
Uh oh!
There was an error while loading. Please reload this page.