From a891f6edfeb4d7b061a215ba160fca0e4804ffd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 10:16:29 +0100 Subject: [PATCH 01/14] Introduce the GroupBy and GroupByMut Iterators --- library/alloc/src/lib.rs | 1 + library/alloc/src/slice.rs | 2 + library/alloc/tests/lib.rs | 1 + library/alloc/tests/slice.rs | 27 +++++ library/core/src/slice/iter.rs | 180 +++++++++++++++++++++++++++++++++ library/core/src/slice/mod.rs | 68 +++++++++++++ library/core/tests/lib.rs | 1 + 7 files changed, 280 insertions(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3ac34c9ae28af..34102d9c4036a 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -140,6 +140,7 @@ #![feature(try_trait)] #![feature(type_alias_impl_trait)] #![feature(associated_type_bounds)] +#![feature(slice_group_by)] // Allow testing this library #[cfg(test)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 064700fc72c95..bfa317ffd73c8 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -118,6 +118,8 @@ pub use core::slice::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut}; +#[unstable(feature = "slice_group_by", issue = "0")] +pub use core::slice::{GroupBy, GroupByMut}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index b7cc03f8eb999..268153242c778 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -21,6 +21,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}; diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index a4f0fb415fb3c..e2fdb5a6b5a73 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1898,3 +1898,30 @@ 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]; + + let mut iter = slice.group_by(|a, b| a == b); + + assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + + assert_eq!(iter.remaining(), &[3, 3, 2, 2, 2]); + + assert_eq!(iter.next(), Some(&[3, 3][..])); + assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next(), None); +} + +#[test] +fn test_group_by_rev() { + let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; + + let mut iter = slice.group_by(|a, b| a == b); + + 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); +} diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index e373936a6c74d..917997f902aec 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2967,3 +2967,183 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { false } } + +macro_rules! group_by { + (struct $name:ident, $elem:ty, $mkslice:ident) => { + #[unstable(feature = "slice_group_by", issue = "0")] + impl<'a, T: 'a, P> $name<'a, T, P> { + #[inline] + fn is_empty(&self) -> bool { + self.ptr == self.end + } + + #[inline] + fn remaining_len(&self) -> usize { + unsafe { self.end.offset_from(self.ptr) as usize } + } + } + + #[unstable(feature = "slice_group_by", issue = "0")] + impl<'a, T: 'a, P> Iterator for $name<'a, T, P> + where P: FnMut(&T, &T) -> bool, + { + type Item = $elem; + + fn next(&mut self) -> Option { + // we use an unsafe block to avoid bounds checking here. + // this is safe because the only thing we do here is to get + // two elements at `ptr` and `ptr + 1`, bounds checking is done by hand. + unsafe { + if self.is_empty() { return None } + + let mut i = 0; + let mut ptr = self.ptr; + + // we need to get *two* contiguous elements so we check that: + // - the first element is at the `end - 1` position because + // - the second one will be read from `ptr + 1` that must + // be lower or equal to `end` + while ptr != self.end.sub(1) { + let a = &*ptr; + ptr = ptr.add(1); + let b = &*ptr; + + i += 1; + + if !(self.predicate)(a, b) { + let slice = $mkslice(self.ptr, i); + self.ptr = ptr; + return Some(slice) + } + } + + // `i` is either `0` or the slice `length - 1` because either: + // - we have not entered the loop and so `i` is equal to `0` + // the slice length is necessarily `1` because we ensure it is not empty + // - we have entered the loop and we have not early returned + // so `i` is equal to the slice `length - 1` + let slice = $mkslice(self.ptr, i + 1); + self.ptr = self.end; + Some(slice) + } + } + + fn size_hint(&self) -> (usize, Option) { + if self.is_empty() { return (0, Some(0)) } + let len = self.remaining_len(); + (1, Some(len)) + } + + fn last(mut self) -> Option { + self.next_back() + } + } + + #[unstable(feature = "slice_group_by", issue = "0")] + impl<'a, T: 'a, P> DoubleEndedIterator for $name<'a, T, P> + where P: FnMut(&T, &T) -> bool, + { + fn next_back(&mut self) -> Option { + // during the loop we retrieve two elements at `ptr` and `ptr - 1`. + unsafe { + if self.is_empty() { return None } + + let mut i = 0; + // we ensure that the first element that will be read + // is not under `end` because `end` is out of bound. + let mut ptr = self.end.sub(1); + + while ptr != self.ptr { + // we first get `a` that is at the left of `ptr` + // then `b` that is under the `ptr` position. + let a = &*ptr.sub(1); + let b = &*ptr; + + i += 1; + + if !(self.predicate)(a, b) { + // the slice to return starts at the `ptr` position + // and `i` is the length of it. + let slice = $mkslice(ptr, i); + + // because `end` is always an invalid bound + // we use `ptr` as `end` for the future call to `next`. + self.end = ptr; + return Some(slice) + } + + ptr = ptr.sub(1); + } + + let slice = $mkslice(self.ptr, i + 1); + self.ptr = self.end; + Some(slice) + } + } + } + + #[unstable(feature = "slice_group_by", issue = "0")] + impl<'a, T: 'a, P> FusedIterator for $name<'a, T, P> + where P: FnMut(&T, &T) -> bool, + { } + } +} + +/// 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 = "0")] +#[derive(Debug)] // FIXME implement Debug to be more user friendly +pub struct GroupBy<'a, T: 'a, P> { + ptr: *const T, + end: *const T, + predicate: P, + _phantom: marker::PhantomData<&'a T>, +} + +#[unstable(feature = "slice_group_by", issue = "0")] +impl<'a, T: 'a, P> GroupBy<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ + /// Returns the remainder of the original slice that is going to be + /// returned by the iterator. + pub fn remaining(&self) -> &[T] { + let len = self.remaining_len(); + unsafe { from_raw_parts(self.ptr, len) } + } +} + +group_by!{ struct GroupBy, &'a [T], from_raw_parts } + +/// 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 = "0")] +#[derive(Debug)] // FIXME implement Debug to be more user friendly +pub struct GroupByMut<'a, T: 'a, P> { + ptr: *mut T, + end: *mut T, + predicate: P, + _phantom: marker::PhantomData<&'a T>, +} + +#[unstable(feature = "slice_group_by", issue = "0")] +impl<'a, T: 'a, P> GroupByMut<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ + /// Returns the remainder of the original slice that is going to be + /// returned by the iterator. + pub fn into_remaining(self) -> &'a mut [T] { + let len = self.remaining_len(); + unsafe { from_raw_parts_mut(self.ptr, len) } + } +} + +group_by!{ struct GroupByMut, &'a mut [T], from_raw_parts_mut } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 44fe2ca88596f..e366baa34c665 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1207,6 +1207,74 @@ impl [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); + /// ``` + #[unstable(feature = "slice_group_by", issue = "0")] + #[inline] + pub fn group_by(&self, pred: F) -> GroupBy + where F: FnMut(&T, &T) -> bool + { + GroupBy { + ptr: self.as_ptr(), + end: unsafe { self.as_ptr().add(self.len()) }, + predicate: pred, + _phantom: marker::PhantomData, + } + } + + /// 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); + /// ``` + #[unstable(feature = "slice_group_by", issue = "0")] + #[inline] + pub fn group_by_mut(&mut self, pred: F) -> GroupByMut + where F: FnMut(&T, &T) -> bool + { + GroupByMut { + ptr: self.as_mut_ptr(), + end: unsafe { self.as_mut_ptr().add(self.len()) }, + predicate: pred, + _phantom: marker::PhantomData, + } + } + /// Divides one slice into two at an index. /// /// The first will contain all indices from `[0, mid)` (excluding diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 106c9fe5da3e6..1199fa4abbce9 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -65,6 +65,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; From 1c55a73b750bcae1bbf05cbafbd36bce8bd993fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:17:41 +0100 Subject: [PATCH 02/14] Implement it with only safe code --- library/alloc/tests/slice.rs | 39 ++++-- library/core/src/slice/iter.rs | 238 ++++++++++++++------------------- library/core/src/slice/mod.rs | 14 +- 3 files changed, 128 insertions(+), 163 deletions(-) diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index e2fdb5a6b5a73..8f03a9240e280 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1904,24 +1904,43 @@ fn test_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.remaining(), &[3, 3, 2, 2, 2]); - assert_eq!(iter.next(), Some(&[3, 3][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); assert_eq!(iter.next(), None); -} - -#[test] -fn test_group_by_rev() { - let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; let mut iter = slice.group_by(|a, b| a == b); - 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(&[2, 2, 2][..])); + assert_eq!(iter.next(), Some(&[3, 3][..])); + assert_eq!(iter.next_back(), None); +} + +#[test] +fn test_group_by_mut() { + 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); + + let mut iter = slice.group_by_mut(|a, b| a == b); + 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 [2, 2, 2][..])); + assert_eq!(iter.next(), Some(&mut [3, 3][..])); + assert_eq!(iter.next_back(), None); } diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 917997f902aec..8f52fa852ba9d 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2968,127 +2968,6 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { } } -macro_rules! group_by { - (struct $name:ident, $elem:ty, $mkslice:ident) => { - #[unstable(feature = "slice_group_by", issue = "0")] - impl<'a, T: 'a, P> $name<'a, T, P> { - #[inline] - fn is_empty(&self) -> bool { - self.ptr == self.end - } - - #[inline] - fn remaining_len(&self) -> usize { - unsafe { self.end.offset_from(self.ptr) as usize } - } - } - - #[unstable(feature = "slice_group_by", issue = "0")] - impl<'a, T: 'a, P> Iterator for $name<'a, T, P> - where P: FnMut(&T, &T) -> bool, - { - type Item = $elem; - - fn next(&mut self) -> Option { - // we use an unsafe block to avoid bounds checking here. - // this is safe because the only thing we do here is to get - // two elements at `ptr` and `ptr + 1`, bounds checking is done by hand. - unsafe { - if self.is_empty() { return None } - - let mut i = 0; - let mut ptr = self.ptr; - - // we need to get *two* contiguous elements so we check that: - // - the first element is at the `end - 1` position because - // - the second one will be read from `ptr + 1` that must - // be lower or equal to `end` - while ptr != self.end.sub(1) { - let a = &*ptr; - ptr = ptr.add(1); - let b = &*ptr; - - i += 1; - - if !(self.predicate)(a, b) { - let slice = $mkslice(self.ptr, i); - self.ptr = ptr; - return Some(slice) - } - } - - // `i` is either `0` or the slice `length - 1` because either: - // - we have not entered the loop and so `i` is equal to `0` - // the slice length is necessarily `1` because we ensure it is not empty - // - we have entered the loop and we have not early returned - // so `i` is equal to the slice `length - 1` - let slice = $mkslice(self.ptr, i + 1); - self.ptr = self.end; - Some(slice) - } - } - - fn size_hint(&self) -> (usize, Option) { - if self.is_empty() { return (0, Some(0)) } - let len = self.remaining_len(); - (1, Some(len)) - } - - fn last(mut self) -> Option { - self.next_back() - } - } - - #[unstable(feature = "slice_group_by", issue = "0")] - impl<'a, T: 'a, P> DoubleEndedIterator for $name<'a, T, P> - where P: FnMut(&T, &T) -> bool, - { - fn next_back(&mut self) -> Option { - // during the loop we retrieve two elements at `ptr` and `ptr - 1`. - unsafe { - if self.is_empty() { return None } - - let mut i = 0; - // we ensure that the first element that will be read - // is not under `end` because `end` is out of bound. - let mut ptr = self.end.sub(1); - - while ptr != self.ptr { - // we first get `a` that is at the left of `ptr` - // then `b` that is under the `ptr` position. - let a = &*ptr.sub(1); - let b = &*ptr; - - i += 1; - - if !(self.predicate)(a, b) { - // the slice to return starts at the `ptr` position - // and `i` is the length of it. - let slice = $mkslice(ptr, i); - - // because `end` is always an invalid bound - // we use `ptr` as `end` for the future call to `next`. - self.end = ptr; - return Some(slice) - } - - ptr = ptr.sub(1); - } - - let slice = $mkslice(self.ptr, i + 1); - self.ptr = self.end; - Some(slice) - } - } - } - - #[unstable(feature = "slice_group_by", issue = "0")] - impl<'a, T: 'a, P> FusedIterator for $name<'a, T, P> - where P: FnMut(&T, &T) -> bool, - { } - } -} - /// An iterator over slice in (non-overlapping) chunks separated by a predicate. /// /// This struct is created by the [`group_by`] method on [slices]. @@ -3098,25 +2977,65 @@ macro_rules! group_by { #[unstable(feature = "slice_group_by", issue = "0")] #[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupBy<'a, T: 'a, P> { - ptr: *const T, - end: *const T, + slice: &'a [T], predicate: P, - _phantom: marker::PhantomData<&'a T>, } #[unstable(feature = "slice_group_by", issue = "0")] -impl<'a, T: 'a, P> GroupBy<'a, T, P> +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 = "0")] +impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { - /// Returns the remainder of the original slice that is going to be - /// returned by the iterator. - pub fn remaining(&self) -> &[T] { - let len = self.remaining_len(); - unsafe { from_raw_parts(self.ptr, len) } + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option { + 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) + } } } -group_by!{ struct GroupBy, &'a [T], from_raw_parts } +#[unstable(feature = "slice_group_by", issue = "0")] +impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option { + 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 = "0")] +impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ } /// An iterator over slice in (non-overlapping) mutable chunks separated /// by a predicate. @@ -3128,22 +3047,59 @@ group_by!{ struct GroupBy, &'a [T], from_raw_parts } #[unstable(feature = "slice_group_by", issue = "0")] #[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupByMut<'a, T: 'a, P> { - ptr: *mut T, - end: *mut T, + slice: &'a mut [T], predicate: P, - _phantom: marker::PhantomData<&'a T>, } #[unstable(feature = "slice_group_by", issue = "0")] -impl<'a, T: 'a, P> GroupByMut<'a, T, P> +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 = "0")] +impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { - /// Returns the remainder of the original slice that is going to be - /// returned by the iterator. - pub fn into_remaining(self) -> &'a mut [T] { - let len = self.remaining_len(); - unsafe { from_raw_parts_mut(self.ptr, len) } + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option { + 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) + } } } -group_by!{ struct GroupByMut, &'a mut [T], from_raw_parts_mut } +#[unstable(feature = "slice_group_by", issue = "0")] +impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P> +where P: FnMut(&T, &T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option { + 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) + } + } +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e366baa34c665..2e304cc5d2ea4 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1233,12 +1233,7 @@ impl [T] { pub fn group_by(&self, pred: F) -> GroupBy where F: FnMut(&T, &T) -> bool { - GroupBy { - ptr: self.as_ptr(), - end: unsafe { self.as_ptr().add(self.len()) }, - predicate: pred, - _phantom: marker::PhantomData, - } + GroupBy::new(self, pred) } /// Returns an iterator over the slice producing non-overlapping mutable @@ -1267,12 +1262,7 @@ impl [T] { pub fn group_by_mut(&mut self, pred: F) -> GroupByMut where F: FnMut(&T, &T) -> bool { - GroupByMut { - ptr: self.as_mut_ptr(), - end: unsafe { self.as_mut_ptr().add(self.len()) }, - predicate: pred, - _phantom: marker::PhantomData, - } + GroupByMut::new(self, pred) } /// Divides one slice into two at an index. From e16eaeaa11c4119543bfcb5e61f74fcde780727a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:22:20 +0100 Subject: [PATCH 03/14] Implement size_hint on the GroupBy and GroupByMut Iterators --- library/core/src/slice/iter.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 8f52fa852ba9d..730009568dd32 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3009,6 +3009,15 @@ where P: FnMut(&T, &T) -> bool, Some(head) } } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.slice.is_empty() { + (0, Some(0)) + } else { + (1, Some(self.slice.len())) + } + } } #[unstable(feature = "slice_group_by", issue = "0")] @@ -3080,6 +3089,15 @@ where P: FnMut(&T, &T) -> bool, Some(head) } } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.slice.is_empty() { + (0, Some(0)) + } else { + (1, Some(self.slice.len())) + } + } } #[unstable(feature = "slice_group_by", issue = "0")] From 005912fce87700c5aee6185701e9c2aea3f216d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:22:29 +0100 Subject: [PATCH 04/14] Implement last on the GroupBy and GroupByMut Iterators --- library/core/src/slice/iter.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 730009568dd32..90afd00f21db1 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3018,6 +3018,11 @@ where P: FnMut(&T, &T) -> bool, (1, Some(self.slice.len())) } } + + #[inline] + fn last(self) -> Option { + self.next_back() + } } #[unstable(feature = "slice_group_by", issue = "0")] @@ -3098,6 +3103,11 @@ where P: FnMut(&T, &T) -> bool, (1, Some(self.slice.len())) } } + + #[inline] + fn last(self) -> Option { + self.next_back() + } } #[unstable(feature = "slice_group_by", issue = "0")] From 1b406afe23c17467f43a5c1bd83b4af1d55d08d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:37:40 +0100 Subject: [PATCH 05/14] Use none as the issue instead of 0 --- library/alloc/src/slice.rs | 2 +- library/core/src/slice/iter.rs | 18 +++++++++--------- library/core/src/slice/mod.rs | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index bfa317ffd73c8..5f92dfe539fb4 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -118,7 +118,7 @@ pub use core::slice::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut}; -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] pub use core::slice::{GroupBy, GroupByMut}; //////////////////////////////////////////////////////////////////////////////// diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 90afd00f21db1..9053376bdf24f 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2974,21 +2974,21 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { /// /// [`group_by`]: ../../std/primitive.slice.html#method.group_by /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] #[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupBy<'a, T: 'a, P> { slice: &'a [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] 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 = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3025,7 +3025,7 @@ where P: FnMut(&T, &T) -> bool, } } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3046,7 +3046,7 @@ where P: FnMut(&T, &T) -> bool, } } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool, { } @@ -3058,21 +3058,21 @@ where P: FnMut(&T, &T) -> bool, /// /// [`group_by_mut`]: ../../std/primitive.slice.html#method.group_by_mut /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] #[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupByMut<'a, T: 'a, P> { slice: &'a mut [T], predicate: P, } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] 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 = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { @@ -3110,7 +3110,7 @@ where P: FnMut(&T, &T) -> bool, } } -#[unstable(feature = "slice_group_by", issue = "0")] +#[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 2e304cc5d2ea4..40f480fa85be3 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1228,7 +1228,7 @@ impl [T] { /// assert_eq!(iter.next(), Some(&[2, 2, 2][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "0")] + #[unstable(feature = "slice_group_by", issue = "none")] #[inline] pub fn group_by(&self, pred: F) -> GroupBy where F: FnMut(&T, &T) -> bool @@ -1257,7 +1257,7 @@ impl [T] { /// assert_eq!(iter.next(), Some(&mut [2, 2, 2][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "0")] + #[unstable(feature = "slice_group_by", issue = "none")] #[inline] pub fn group_by_mut(&mut self, pred: F) -> GroupByMut where F: FnMut(&T, &T) -> bool From 0ebf8e13f096c5e68f1e436c8f039642e90c8a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:41:43 +0100 Subject: [PATCH 06/14] Import the GroupBy and GroupByMut in the slice module --- library/core/src/slice/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 40f480fa85be3..9d51a4779cff3 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -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 = "none")] +pub use iter::{GroupBy, GroupByMut}; + #[unstable(feature = "split_inclusive", issue = "72360")] pub use iter::{SplitInclusive, SplitInclusiveMut}; From 6a5a60048d98e0d0c545703ff5a9ba39beef49a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:47:15 +0100 Subject: [PATCH 07/14] Indicate the anonymous lifetime of the GroupBy and GroupByMut --- library/core/src/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 9d51a4779cff3..218cd2c25a293 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1233,7 +1233,7 @@ impl [T] { /// ``` #[unstable(feature = "slice_group_by", issue = "none")] #[inline] - pub fn group_by(&self, pred: F) -> GroupBy + pub fn group_by(&self, pred: F) -> GroupBy<'_, T, F> where F: FnMut(&T, &T) -> bool { GroupBy::new(self, pred) @@ -1262,7 +1262,7 @@ impl [T] { /// ``` #[unstable(feature = "slice_group_by", issue = "none")] #[inline] - pub fn group_by_mut(&mut self, pred: F) -> GroupByMut + pub fn group_by_mut(&mut self, pred: F) -> GroupByMut<'_, T, F> where F: FnMut(&T, &T) -> bool { GroupByMut::new(self, pred) From 5190fe4979f90b2912aed5a2cf9b77e3dcfb1a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 11:58:52 +0100 Subject: [PATCH 08/14] Mark the Iterator last self parameter as mut --- library/core/src/slice/iter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 9053376bdf24f..71106c66f125a 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3020,7 +3020,7 @@ where P: FnMut(&T, &T) -> bool, } #[inline] - fn last(self) -> Option { + fn last(mut self) -> Option { self.next_back() } } @@ -3105,7 +3105,7 @@ where P: FnMut(&T, &T) -> bool, } #[inline] - fn last(self) -> Option { + fn last(mut self) -> Option { self.next_back() } } From 9940c47885df3d6873aab9a78a7725cb41e8d957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 13:42:31 +0100 Subject: [PATCH 09/14] Update the slice GroupBy/Mut test --- library/alloc/tests/slice.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 8f03a9240e280..777c10b1bf740 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1901,15 +1901,19 @@ fn subslice_patterns() { #[test] fn test_group_by() { - let slice = &[1, 1, 1, 3, 3, 2, 2, 2]; + 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][..])); @@ -1917,22 +1921,28 @@ fn test_group_by() { let mut iter = slice.group_by(|a, b| a == b); assert_eq!(iter.next(), Some(&[1, 1, 1][..])); - assert_eq!(iter.next_back(), Some(&[2, 2, 2][..])); + 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]; + 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][..])); @@ -1940,7 +1950,9 @@ fn test_group_by_mut() { 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 [2, 2, 2][..])); + 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); } From 45693b43a5e779545cf6c6af909ab5c27d94e4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 18:36:07 +0100 Subject: [PATCH 10/14] Mute the file-length error --- library/core/src/slice/iter.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 71106c66f125a..a10ebacf5fb0c 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength //! Definitions of a bunch of iterators for `[T]`. #[macro_use] // import iterator! and forward_iterator! From 7952ea5a04aa34dc5441a47f7d4d227193c8fdf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 19:10:09 +0100 Subject: [PATCH 11/14] Fix the fmt issues --- library/alloc/src/slice.rs | 4 ++-- library/core/src/slice/iter.rs | 31 ++++++++++++++----------------- library/core/src/slice/mod.rs | 6 ++++-- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 5f92dfe539fb4..72da781da3cc4 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -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 = "none")] +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")] @@ -118,8 +120,6 @@ pub use core::slice::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut}; -#[unstable(feature = "slice_group_by", issue = "none")] -pub use core::slice::{GroupBy, GroupByMut}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index a10ebacf5fb0c..423cbd113501b 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2991,7 +2991,8 @@ impl<'a, T: 'a, P> GroupBy<'a, T, P> { #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P> -where P: FnMut(&T, &T) -> bool, +where + P: FnMut(&T, &T) -> bool, { type Item = &'a [T]; @@ -3013,11 +3014,7 @@ where P: FnMut(&T, &T) -> bool, #[inline] fn size_hint(&self) -> (usize, Option) { - if self.slice.is_empty() { - (0, Some(0)) - } else { - (1, Some(self.slice.len())) - } + if self.slice.is_empty() { (0, Some(0)) } else { (1, Some(self.slice.len())) } } #[inline] @@ -3028,7 +3025,8 @@ where P: FnMut(&T, &T) -> bool, #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P> -where P: FnMut(&T, &T) -> bool, +where + P: FnMut(&T, &T) -> bool, { #[inline] fn next_back(&mut self) -> Option { @@ -3048,9 +3046,7 @@ where P: FnMut(&T, &T) -> bool, } #[unstable(feature = "slice_group_by", issue = "none")] -impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> -where P: FnMut(&T, &T) -> bool, -{ } +impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} /// An iterator over slice in (non-overlapping) mutable chunks separated /// by a predicate. @@ -3075,7 +3071,8 @@ impl<'a, T: 'a, P> GroupByMut<'a, T, P> { #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P> -where P: FnMut(&T, &T) -> bool, +where + P: FnMut(&T, &T) -> bool, { type Item = &'a mut [T]; @@ -3098,11 +3095,7 @@ where P: FnMut(&T, &T) -> bool, #[inline] fn size_hint(&self) -> (usize, Option) { - if self.slice.is_empty() { - (0, Some(0)) - } else { - (1, Some(self.slice.len())) - } + if self.slice.is_empty() { (0, Some(0)) } else { (1, Some(self.slice.len())) } } #[inline] @@ -3113,7 +3106,8 @@ where P: FnMut(&T, &T) -> bool, #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P> -where P: FnMut(&T, &T) -> bool, +where + P: FnMut(&T, &T) -> bool, { #[inline] fn next_back(&mut self) -> Option { @@ -3132,3 +3126,6 @@ where P: FnMut(&T, &T) -> bool, } } } + +#[unstable(feature = "slice_group_by", issue = "none")] +impl<'a, T: 'a, P> FusedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 218cd2c25a293..648cf88b7ef79 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1234,7 +1234,8 @@ impl [T] { #[unstable(feature = "slice_group_by", issue = "none")] #[inline] pub fn group_by(&self, pred: F) -> GroupBy<'_, T, F> - where F: FnMut(&T, &T) -> bool + where + F: FnMut(&T, &T) -> bool, { GroupBy::new(self, pred) } @@ -1263,7 +1264,8 @@ impl [T] { #[unstable(feature = "slice_group_by", issue = "none")] #[inline] pub fn group_by_mut(&mut self, pred: F) -> GroupByMut<'_, T, F> - where F: FnMut(&T, &T) -> bool + where + F: FnMut(&T, &T) -> bool, { GroupByMut::new(self, pred) } From b2a7076b10d69ede61092a62a9d5245f5077d184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 10 Dec 2020 19:13:34 +0100 Subject: [PATCH 12/14] Implement a user friendly Debug on GroupBy and GroupByMut --- library/core/src/slice/iter.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 423cbd113501b..6bb9cf99402ee 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2976,7 +2976,6 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { /// [`group_by`]: ../../std/primitive.slice.html#method.group_by /// [slices]: ../../std/primitive.slice.html #[unstable(feature = "slice_group_by", issue = "none")] -#[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupBy<'a, T: 'a, P> { slice: &'a [T], predicate: P, @@ -3048,6 +3047,13 @@ where #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[unstable(feature = "slice_group_by", issue = "none")] +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. /// @@ -3056,7 +3062,6 @@ impl<'a, T: 'a, P> FusedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> /// [`group_by_mut`]: ../../std/primitive.slice.html#method.group_by_mut /// [slices]: ../../std/primitive.slice.html #[unstable(feature = "slice_group_by", issue = "none")] -#[derive(Debug)] // FIXME implement Debug to be more user friendly pub struct GroupByMut<'a, T: 'a, P> { slice: &'a mut [T], predicate: P, @@ -3129,3 +3134,10 @@ where #[unstable(feature = "slice_group_by", issue = "none")] impl<'a, T: 'a, P> FusedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {} + +#[unstable(feature = "slice_group_by", issue = "none")] +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() + } +} From a2d55d70c4c6ef24e114a48864c9483ed92687f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 31 Dec 2020 11:57:40 +0100 Subject: [PATCH 13/14] Add an extra example to the two methods --- library/core/src/slice/mod.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 648cf88b7ef79..b4dd057eef0f5 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1231,6 +1231,21 @@ impl [T] { /// 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 = "none")] #[inline] pub fn group_by(&self, pred: F) -> GroupBy<'_, T, F> @@ -1261,6 +1276,21 @@ impl [T] { /// 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 = "none")] #[inline] pub fn group_by_mut(&mut self, pred: F) -> GroupByMut<'_, T, F> From 8b53be660444d736bb6a6e1c6ba42c8180c968e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 31 Dec 2020 12:13:03 +0100 Subject: [PATCH 14/14] Replace the tracking issue for the slice_group_by feature --- library/alloc/src/slice.rs | 2 +- library/core/src/slice/iter.rs | 24 ++++++++++++------------ library/core/src/slice/mod.rs | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 72da781da3cc4..cb015b949305c 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -110,7 +110,7 @@ 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 = "none")] +#[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}; diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 6bb9cf99402ee..a367b4737dbac 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2975,20 +2975,20 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { /// /// [`group_by`]: ../../std/primitive.slice.html#method.group_by /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "slice_group_by", issue = "none")] +#[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 = "none")] +#[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 = "none")] +#[unstable(feature = "slice_group_by", issue = "80552")] impl<'a, T: 'a, P> Iterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool, @@ -3022,7 +3022,7 @@ where } } -#[unstable(feature = "slice_group_by", issue = "none")] +#[unstable(feature = "slice_group_by", issue = "80552")] impl<'a, T: 'a, P> DoubleEndedIterator for GroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool, @@ -3044,10 +3044,10 @@ where } } -#[unstable(feature = "slice_group_by", issue = "none")] +#[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 = "none")] +#[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() @@ -3061,20 +3061,20 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for GroupBy<'a, T, P> { /// /// [`group_by_mut`]: ../../std/primitive.slice.html#method.group_by_mut /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "slice_group_by", issue = "none")] +#[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 = "none")] +#[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 = "none")] +#[unstable(feature = "slice_group_by", issue = "80552")] impl<'a, T: 'a, P> Iterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, @@ -3109,7 +3109,7 @@ where } } -#[unstable(feature = "slice_group_by", issue = "none")] +#[unstable(feature = "slice_group_by", issue = "80552")] impl<'a, T: 'a, P> DoubleEndedIterator for GroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool, @@ -3132,10 +3132,10 @@ where } } -#[unstable(feature = "slice_group_by", issue = "none")] +#[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 = "none")] +#[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() diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index b4dd057eef0f5..b1332a3f7bc8b 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -57,7 +57,7 @@ pub use iter::{ArrayChunks, ArrayChunksMut}; #[unstable(feature = "array_windows", issue = "75027")] pub use iter::ArrayWindows; -#[unstable(feature = "slice_group_by", issue = "none")] +#[unstable(feature = "slice_group_by", issue = "80552")] pub use iter::{GroupBy, GroupByMut}; #[unstable(feature = "split_inclusive", issue = "72360")] @@ -1246,7 +1246,7 @@ impl [T] { /// assert_eq!(iter.next(), Some(&[2, 3, 4][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "none")] + #[unstable(feature = "slice_group_by", issue = "80552")] #[inline] pub fn group_by(&self, pred: F) -> GroupBy<'_, T, F> where @@ -1291,7 +1291,7 @@ impl [T] { /// assert_eq!(iter.next(), Some(&mut [2, 3, 4][..])); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "slice_group_by", issue = "none")] + #[unstable(feature = "slice_group_by", issue = "80552")] #[inline] pub fn group_by_mut(&mut self, pred: F) -> GroupByMut<'_, T, F> where