mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 05:26:47 +00:00
Auto merge of #79895 - Kerollmops:slice-group-by, r=m-ou-se
The return of the GroupBy and GroupByMut iterators on slice According to https://github.com/rust-lang/rfcs/pull/2477#issuecomment-742034372, I am opening this PR again, this time I implemented it in safe Rust only, it is therefore much easier to read and is completely safe. This PR proposes to add two new methods to the slice, the `group_by` and `group_by_mut`. These two methods provide a way to iterate over non-overlapping sub-slices of a base slice that are separated by the predicate given by the user (e.g. `Partial::eq`, `|a, b| a.abs() < b.abs()`). ```rust let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; let mut iter = slice.group_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); assert_eq!(iter.next(), Some(&[3, 3][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); assert_eq!(iter.next(), None); ``` [An RFC](https://github.com/rust-lang/rfcs/pull/2477) was open 2 years ago but wasn't necessary.
This commit is contained in:
commit
b33e234155
@ -139,6 +139,7 @@
|
||||
#![feature(try_trait)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(slice_group_by)]
|
||||
// Allow testing this library
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -110,6 +110,8 @@ pub use core::slice::{Chunks, Windows};
|
||||
pub use core::slice::{ChunksExact, ChunksExactMut};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::slice::{ChunksMut, Split, SplitMut};
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
pub use core::slice::{GroupBy, GroupByMut};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::slice::{Iter, IterMut};
|
||||
#[stable(feature = "rchunks", since = "1.31.0")]
|
||||
|
@ -20,6 +20,7 @@
|
||||
#![feature(iter_map_while)]
|
||||
#![feature(int_bits_const)]
|
||||
#![feature(vecdeque_binary_search)]
|
||||
#![feature(slice_group_by)]
|
||||
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
@ -1898,3 +1898,61 @@ fn subslice_patterns() {
|
||||
m!(&mut v, [..] => ());
|
||||
m!(&mut v, [x, .., y] => c!((x, y), (&mut N, &mut N), (&mut N(0), &mut N(4))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_group_by() {
|
||||
let slice = &[1, 1, 1, 3, 3, 2, 2, 2, 1, 0];
|
||||
|
||||
let mut iter = slice.group_by(|a, b| a == b);
|
||||
assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
|
||||
assert_eq!(iter.next(), Some(&[3, 3][..]));
|
||||
assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
|
||||
assert_eq!(iter.next(), Some(&[1][..]));
|
||||
assert_eq!(iter.next(), Some(&[0][..]));
|
||||
assert_eq!(iter.next(), None);
|
||||
|
||||
let mut iter = slice.group_by(|a, b| a == b);
|
||||
assert_eq!(iter.next_back(), Some(&[0][..]));
|
||||
assert_eq!(iter.next_back(), Some(&[1][..]));
|
||||
assert_eq!(iter.next_back(), Some(&[2, 2, 2][..]));
|
||||
assert_eq!(iter.next_back(), Some(&[3, 3][..]));
|
||||
assert_eq!(iter.next_back(), Some(&[1, 1, 1][..]));
|
||||
assert_eq!(iter.next_back(), None);
|
||||
|
||||
let mut iter = slice.group_by(|a, b| a == b);
|
||||
assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
|
||||
assert_eq!(iter.next_back(), Some(&[0][..]));
|
||||
assert_eq!(iter.next(), Some(&[3, 3][..]));
|
||||
assert_eq!(iter.next_back(), Some(&[1][..]));
|
||||
assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
|
||||
assert_eq!(iter.next_back(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_group_by_mut() {
|
||||
let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2, 1, 0];
|
||||
|
||||
let mut iter = slice.group_by_mut(|a, b| a == b);
|
||||
assert_eq!(iter.next(), Some(&mut [1, 1, 1][..]));
|
||||
assert_eq!(iter.next(), Some(&mut [3, 3][..]));
|
||||
assert_eq!(iter.next(), Some(&mut [2, 2, 2][..]));
|
||||
assert_eq!(iter.next(), Some(&mut [1][..]));
|
||||
assert_eq!(iter.next(), Some(&mut [0][..]));
|
||||
assert_eq!(iter.next(), None);
|
||||
|
||||
let mut iter = slice.group_by_mut(|a, b| a == b);
|
||||
assert_eq!(iter.next_back(), Some(&mut [0][..]));
|
||||
assert_eq!(iter.next_back(), Some(&mut [1][..]));
|
||||
assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..]));
|
||||
assert_eq!(iter.next_back(), Some(&mut [3, 3][..]));
|
||||
assert_eq!(iter.next_back(), Some(&mut [1, 1, 1][..]));
|
||||
assert_eq!(iter.next_back(), None);
|
||||
|
||||
let mut iter = slice.group_by_mut(|a, b| a == b);
|
||||
assert_eq!(iter.next(), Some(&mut [1, 1, 1][..]));
|
||||
assert_eq!(iter.next_back(), Some(&mut [0][..]));
|
||||
assert_eq!(iter.next(), Some(&mut [3, 3][..]));
|
||||
assert_eq!(iter.next_back(), Some(&mut [1][..]));
|
||||
assert_eq!(iter.next(), Some(&mut [2, 2, 2][..]));
|
||||
assert_eq!(iter.next_back(), None);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
// ignore-tidy-filelength
|
||||
//! Definitions of a bunch of iterators for `[T]`.
|
||||
|
||||
#[macro_use] // import iterator! and forward_iterator!
|
||||
@ -2967,3 +2968,176 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over slice in (non-overlapping) chunks separated by a predicate.
|
||||
///
|
||||
/// This struct is created by the [`group_by`] method on [slices].
|
||||
///
|
||||
/// [`group_by`]: ../../std/primitive.slice.html#method.group_by
|
||||
/// [slices]: ../../std/primitive.slice.html
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
pub struct GroupBy<'a, T: 'a, P> {
|
||||
slice: &'a [T],
|
||||
predicate: P,
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
impl<'a, T: 'a, P> GroupBy<'a, T, P> {
|
||||
pub(super) fn new(slice: &'a [T], predicate: P) -> Self {
|
||||
GroupBy { slice, predicate }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P>
|
||||
where
|
||||
P: FnMut(&T, &T) -> bool,
|
||||
{
|
||||
type Item = &'a [T];
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.slice.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let mut len = 1;
|
||||
let mut iter = self.slice.windows(2);
|
||||
while let Some([l, r]) = iter.next() {
|
||||
if (self.predicate)(l, r) { len += 1 } else { break }
|
||||
}
|
||||
let (head, tail) = self.slice.split_at(len);
|
||||
self.slice = tail;
|
||||
Some(head)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
if self.slice.is_empty() { (0, Some(0)) } else { (1, Some(self.slice.len())) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(mut self) -> Option<Self::Item> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P>
|
||||
where
|
||||
P: FnMut(&T, &T) -> bool,
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
if self.slice.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let mut len = 1;
|
||||
let mut iter = self.slice.windows(2);
|
||||
while let Some([l, r]) = iter.next_back() {
|
||||
if (self.predicate)(l, r) { len += 1 } else { break }
|
||||
}
|
||||
let (head, tail) = self.slice.split_at(self.slice.len() - len);
|
||||
self.slice = head;
|
||||
Some(tail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool {}
|
||||
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupBy<'a, T, P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("GroupBy").field("slice", &self.slice).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over slice in (non-overlapping) mutable chunks separated
|
||||
/// by a predicate.
|
||||
///
|
||||
/// This struct is created by the [`group_by_mut`] method on [slices].
|
||||
///
|
||||
/// [`group_by_mut`]: ../../std/primitive.slice.html#method.group_by_mut
|
||||
/// [slices]: ../../std/primitive.slice.html
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
pub struct GroupByMut<'a, T: 'a, P> {
|
||||
slice: &'a mut [T],
|
||||
predicate: P,
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
impl<'a, T: 'a, P> GroupByMut<'a, T, P> {
|
||||
pub(super) fn new(slice: &'a mut [T], predicate: P) -> Self {
|
||||
GroupByMut { slice, predicate }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P>
|
||||
where
|
||||
P: FnMut(&T, &T) -> bool,
|
||||
{
|
||||
type Item = &'a mut [T];
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.slice.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let mut len = 1;
|
||||
let mut iter = self.slice.windows(2);
|
||||
while let Some([l, r]) = iter.next() {
|
||||
if (self.predicate)(l, r) { len += 1 } else { break }
|
||||
}
|
||||
let slice = mem::take(&mut self.slice);
|
||||
let (head, tail) = slice.split_at_mut(len);
|
||||
self.slice = tail;
|
||||
Some(head)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
if self.slice.is_empty() { (0, Some(0)) } else { (1, Some(self.slice.len())) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(mut self) -> Option<Self::Item> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P>
|
||||
where
|
||||
P: FnMut(&T, &T) -> bool,
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
if self.slice.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let mut len = 1;
|
||||
let mut iter = self.slice.windows(2);
|
||||
while let Some([l, r]) = iter.next_back() {
|
||||
if (self.predicate)(l, r) { len += 1 } else { break }
|
||||
}
|
||||
let slice = mem::take(&mut self.slice);
|
||||
let (head, tail) = slice.split_at_mut(slice.len() - len);
|
||||
self.slice = head;
|
||||
Some(tail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
impl<'a, T: 'a, P> FusedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {}
|
||||
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupByMut<'a, T, P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("GroupByMut").field("slice", &self.slice).finish()
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,9 @@ pub use iter::{ArrayChunks, ArrayChunksMut};
|
||||
#[unstable(feature = "array_windows", issue = "75027")]
|
||||
pub use iter::ArrayWindows;
|
||||
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
pub use iter::{GroupBy, GroupByMut};
|
||||
|
||||
#[unstable(feature = "split_inclusive", issue = "72360")]
|
||||
pub use iter::{SplitInclusive, SplitInclusiveMut};
|
||||
|
||||
@ -1208,6 +1211,96 @@ impl<T> [T] {
|
||||
RChunksExactMut::new(self, chunk_size)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the slice producing non-overlapping runs
|
||||
/// of elements using the predicate to separate them.
|
||||
///
|
||||
/// The predicate is called on two elements following themselves,
|
||||
/// it means the predicate is called on `slice[0]` and `slice[1]`
|
||||
/// then on `slice[1]` and `slice[2]` and so on.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_group_by)]
|
||||
///
|
||||
/// let slice = &[1, 1, 1, 3, 3, 2, 2, 2];
|
||||
///
|
||||
/// let mut iter = slice.group_by(|a, b| a == b);
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
|
||||
/// assert_eq!(iter.next(), Some(&[3, 3][..]));
|
||||
/// assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
///
|
||||
/// This method can be used to extract the sorted subslices:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_group_by)]
|
||||
///
|
||||
/// let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4];
|
||||
///
|
||||
/// let mut iter = slice.group_by(|a, b| a <= b);
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..]));
|
||||
/// assert_eq!(iter.next(), Some(&[2, 3][..]));
|
||||
/// assert_eq!(iter.next(), Some(&[2, 3, 4][..]));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
#[inline]
|
||||
pub fn group_by<F>(&self, pred: F) -> GroupBy<'_, T, F>
|
||||
where
|
||||
F: FnMut(&T, &T) -> bool,
|
||||
{
|
||||
GroupBy::new(self, pred)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the slice producing non-overlapping mutable
|
||||
/// runs of elements using the predicate to separate them.
|
||||
///
|
||||
/// The predicate is called on two elements following themselves,
|
||||
/// it means the predicate is called on `slice[0]` and `slice[1]`
|
||||
/// then on `slice[1]` and `slice[2]` and so on.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_group_by)]
|
||||
///
|
||||
/// let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2];
|
||||
///
|
||||
/// let mut iter = slice.group_by_mut(|a, b| a == b);
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(&mut [1, 1, 1][..]));
|
||||
/// assert_eq!(iter.next(), Some(&mut [3, 3][..]));
|
||||
/// assert_eq!(iter.next(), Some(&mut [2, 2, 2][..]));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
///
|
||||
/// This method can be used to extract the sorted subslices:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_group_by)]
|
||||
///
|
||||
/// let slice = &mut [1, 1, 2, 3, 2, 3, 2, 3, 4];
|
||||
///
|
||||
/// let mut iter = slice.group_by_mut(|a, b| a <= b);
|
||||
///
|
||||
/// assert_eq!(iter.next(), Some(&mut [1, 1, 2, 3][..]));
|
||||
/// assert_eq!(iter.next(), Some(&mut [2, 3][..]));
|
||||
/// assert_eq!(iter.next(), Some(&mut [2, 3, 4][..]));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
#[unstable(feature = "slice_group_by", issue = "80552")]
|
||||
#[inline]
|
||||
pub fn group_by_mut<F>(&mut self, pred: F) -> GroupByMut<'_, T, F>
|
||||
where
|
||||
F: FnMut(&T, &T) -> bool,
|
||||
{
|
||||
GroupByMut::new(self, pred)
|
||||
}
|
||||
|
||||
/// Divides one slice into two at an index.
|
||||
///
|
||||
/// The first will contain all indices from `[0, mid)` (excluding
|
||||
|
@ -72,6 +72,7 @@
|
||||
#![feature(nonzero_leading_trailing_zeros)]
|
||||
#![feature(const_option)]
|
||||
#![feature(integer_atomics)]
|
||||
#![feature(slice_group_by)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
extern crate test;
|
||||
|
Loading…
Reference in New Issue
Block a user