Introduce the GroupBy and GroupByMut Iterators

上级 e413d89a
......@@ -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)]
......
......@@ -118,6 +118,8 @@
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
......
......@@ -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};
......
......@@ -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);
}
......@@ -2967,3 +2967,183 @@ fn may_have_side_effect() -> bool {
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<Self::Item> {
// 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<usize>) {
if self.is_empty() { return (0, Some(0)) }
let len = self.remaining_len();
(1, Some(len))
}
fn last(mut self) -> Option<Self::Item> {
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<Self::Item> {
// 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 }
......@@ -1207,6 +1207,74 @@ pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, 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<F>(&self, pred: F) -> GroupBy<T, F>
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<F>(&mut self, pred: F) -> GroupByMut<T, F>
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
......
......@@ -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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册