]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #47333 - arthurprs:iter-position-bounds-check, r=dtolnay
authorkennytm <kennytm@gmail.com>
Wed, 17 Jan 2018 17:57:13 +0000 (01:57 +0800)
committerGitHub <noreply@github.com>
Wed, 17 Jan 2018 17:57:13 +0000 (01:57 +0800)
Optimize slice.{r}position result bounds check

Second attempt of https://github.com/rust-lang/rust/pull/45501
Fixes https://github.com/rust-lang/rust/issues/45964

Demo: https://godbolt.org/g/N4mBHp

1  2 
src/libcore/slice/mod.rs
src/libcore/tests/slice.rs

diff --combined src/libcore/slice/mod.rs
index 48e82666d35151cafa566bf965cddd874cb8b283,d088d4e663496991f74ef840efe66faa528b8e43..5bf7301434771512d26f8e59bf20081f78f63a12
@@@ -104,9 -104,6 +104,9 @@@ pub trait SliceExt 
      #[stable(feature = "core", since = "1.6.0")]
      fn chunks(&self, size: usize) -> Chunks<Self::Item>;
  
 +    #[unstable(feature = "exact_chunks", issue = "47115")]
 +    fn exact_chunks(&self, size: usize) -> ExactChunks<Self::Item>;
 +
      #[stable(feature = "core", since = "1.6.0")]
      fn get<I>(&self, index: I) -> Option<&I::Output>
          where I: SliceIndex<Self>;
      #[stable(feature = "core", since = "1.6.0")]
      fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<Self::Item>;
  
 +    #[unstable(feature = "exact_chunks", issue = "47115")]
 +    fn exact_chunks_mut(&mut self, size: usize) -> ExactChunksMut<Self::Item>;
 +
      #[stable(feature = "core", since = "1.6.0")]
      fn swap(&mut self, a: usize, b: usize);
  
@@@ -362,14 -356,6 +362,14 @@@ impl<T> SliceExt for [T] 
          Chunks { v: self, chunk_size: chunk_size }
      }
  
 +    #[inline]
 +    fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
 +        assert!(chunk_size != 0);
 +        let rem = self.len() % chunk_size;
 +        let len = self.len() - rem;
 +        ExactChunks { v: &self[..len], chunk_size: chunk_size}
 +    }
 +
      #[inline]
      fn get<I>(&self, index: I) -> Option<&I::Output>
          where I: SliceIndex<[T]>
          ChunksMut { v: self, chunk_size: chunk_size }
      }
  
 +    #[inline]
 +    fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
 +        assert!(chunk_size != 0);
 +        let rem = self.len() % chunk_size;
 +        let len = self.len() - rem;
 +        ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size}
 +    }
 +
      #[inline]
      fn swap(&mut self, a: usize, b: usize) {
          unsafe {
@@@ -1237,6 -1215,43 +1237,43 @@@ macro_rules! iterator 
                  }
                  accum
              }
+             #[inline]
+             #[rustc_inherit_overflow_checks]
+             fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
+                 Self: Sized,
+                 P: FnMut(Self::Item) -> bool,
+             {
+                 // The addition might panic on overflow
+                 let n = self.len();
+                 self.try_fold(0, move |i, x| {
+                     if predicate(x) { Err(i) }
+                     else { Ok(i + 1) }
+                 }).err()
+                     .map(|i| {
+                         unsafe { assume(i < n) };
+                         i
+                     })
+             }
+             #[inline]
+             fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
+                 P: FnMut(Self::Item) -> bool,
+                 Self: Sized + ExactSizeIterator + DoubleEndedIterator
+             {
+                 // No need for an overflow check here, because `ExactSizeIterator`
+                 // implies that the number of elements fits into a `usize`.
+                 let n = self.len();
+                 self.try_rfold(n, move |i, x| {
+                     let i = i - 1;
+                     if predicate(x) { Err(i) }
+                     else { Ok(i) }
+                 }).err()
+                     .map(|i| {
+                         unsafe { assume(i < n) };
+                         i
+                     })
+             }
          }
  
          #[stable(feature = "rust1", since = "1.0.0")]
@@@ -2400,209 -2415,6 +2437,209 @@@ unsafe impl<'a, T> TrustedRandomAccess 
      fn may_have_side_effect() -> bool { false }
  }
  
 +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
 +/// time).
 +///
 +/// When the slice len is not evenly divided by the chunk size, the last
 +/// up to `chunk_size-1` elements will be omitted.
 +///
 +/// This struct is created by the [`exact_chunks`] method on [slices].
 +///
 +/// [`exact_chunks`]: ../../std/primitive.slice.html#method.exact_chunks
 +/// [slices]: ../../std/primitive.slice.html
 +#[derive(Debug)]
 +#[unstable(feature = "exact_chunks", issue = "47115")]
 +pub struct ExactChunks<'a, T:'a> {
 +    v: &'a [T],
 +    chunk_size: usize
 +}
 +
 +// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
 +#[unstable(feature = "exact_chunks", issue = "47115")]
 +impl<'a, T> Clone for ExactChunks<'a, T> {
 +    fn clone(&self) -> ExactChunks<'a, T> {
 +        ExactChunks {
 +            v: self.v,
 +            chunk_size: self.chunk_size,
 +        }
 +    }
 +}
 +
 +#[unstable(feature = "exact_chunks", issue = "47115")]
 +impl<'a, T> Iterator for ExactChunks<'a, T> {
 +    type Item = &'a [T];
 +
 +    #[inline]
 +    fn next(&mut self) -> Option<&'a [T]> {
 +        if self.v.len() < self.chunk_size {
 +            None
 +        } else {
 +            let (fst, snd) = self.v.split_at(self.chunk_size);
 +            self.v = snd;
 +            Some(fst)
 +        }
 +    }
 +
 +    #[inline]
 +    fn size_hint(&self) -> (usize, Option<usize>) {
 +        let n = self.v.len() / self.chunk_size;
 +        (n, Some(n))
 +    }
 +
 +    #[inline]
 +    fn count(self) -> usize {
 +        self.len()
 +    }
 +
 +    #[inline]
 +    fn nth(&mut self, n: usize) -> Option<Self::Item> {
 +        let (start, overflow) = n.overflowing_mul(self.chunk_size);
 +        if start >= self.v.len() || overflow {
 +            self.v = &[];
 +            None
 +        } else {
 +            let (_, snd) = self.v.split_at(start);
 +            self.v = snd;
 +            self.next()
 +        }
 +    }
 +
 +    #[inline]
 +    fn last(mut self) -> Option<Self::Item> {
 +        self.next_back()
 +    }
 +}
 +
 +#[unstable(feature = "exact_chunks", issue = "47115")]
 +impl<'a, T> DoubleEndedIterator for ExactChunks<'a, T> {
 +    #[inline]
 +    fn next_back(&mut self) -> Option<&'a [T]> {
 +        if self.v.len() < self.chunk_size {
 +            None
 +        } else {
 +            let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size);
 +            self.v = fst;
 +            Some(snd)
 +        }
 +    }
 +}
 +
 +#[unstable(feature = "exact_chunks", issue = "47115")]
 +impl<'a, T> ExactSizeIterator for ExactChunks<'a, T> {
 +    fn is_empty(&self) -> bool {
 +        self.v.is_empty()
 +    }
 +}
 +
 +#[unstable(feature = "fused", issue = "35602")]
 +impl<'a, T> FusedIterator for ExactChunks<'a, T> {}
 +
 +#[doc(hidden)]
 +unsafe impl<'a, T> TrustedRandomAccess for ExactChunks<'a, T> {
 +    unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] {
 +        let start = i * self.chunk_size;
 +        from_raw_parts(self.v.as_ptr().offset(start as isize), self.chunk_size)
 +    }
 +    fn may_have_side_effect() -> bool { false }
 +}
 +
 +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
 +/// elements at a time). When the slice len is not evenly divided by the chunk
 +/// size, the last up to `chunk_size-1` elements will be omitted.
 +///
 +/// This struct is created by the [`exact_chunks_mut`] method on [slices].
 +///
 +/// [`exact_chunks_mut`]: ../../std/primitive.slice.html#method.exact_chunks_mut
 +/// [slices]: ../../std/primitive.slice.html
 +#[derive(Debug)]
 +#[unstable(feature = "exact_chunks", issue = "47115")]
 +pub struct ExactChunksMut<'a, T:'a> {
 +    v: &'a mut [T],
 +    chunk_size: usize
 +}
 +
 +#[unstable(feature = "exact_chunks", issue = "47115")]
 +impl<'a, T> Iterator for ExactChunksMut<'a, T> {
 +    type Item = &'a mut [T];
 +
 +    #[inline]
 +    fn next(&mut self) -> Option<&'a mut [T]> {
 +        if self.v.len() < self.chunk_size {
 +            None
 +        } else {
 +            let tmp = mem::replace(&mut self.v, &mut []);
 +            let (head, tail) = tmp.split_at_mut(self.chunk_size);
 +            self.v = tail;
 +            Some(head)
 +        }
 +    }
 +
 +    #[inline]
 +    fn size_hint(&self) -> (usize, Option<usize>) {
 +        let n = self.v.len() / self.chunk_size;
 +        (n, Some(n))
 +    }
 +
 +    #[inline]
 +    fn count(self) -> usize {
 +        self.len()
 +    }
 +
 +    #[inline]
 +    fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
 +        let (start, overflow) = n.overflowing_mul(self.chunk_size);
 +        if start >= self.v.len() || overflow {
 +            self.v = &mut [];
 +            None
 +        } else {
 +            let tmp = mem::replace(&mut self.v, &mut []);
 +            let (_, snd) = tmp.split_at_mut(start);
 +            self.v = snd;
 +            self.next()
 +        }
 +    }
 +
 +    #[inline]
 +    fn last(mut self) -> Option<Self::Item> {
 +        self.next_back()
 +    }
 +}
 +
 +#[unstable(feature = "exact_chunks", issue = "47115")]
 +impl<'a, T> DoubleEndedIterator for ExactChunksMut<'a, T> {
 +    #[inline]
 +    fn next_back(&mut self) -> Option<&'a mut [T]> {
 +        if self.v.len() < self.chunk_size {
 +            None
 +        } else {
 +            let tmp = mem::replace(&mut self.v, &mut []);
 +            let tmp_len = tmp.len();
 +            let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
 +            self.v = head;
 +            Some(tail)
 +        }
 +    }
 +}
 +
 +#[unstable(feature = "exact_chunks", issue = "47115")]
 +impl<'a, T> ExactSizeIterator for ExactChunksMut<'a, T> {
 +    fn is_empty(&self) -> bool {
 +        self.v.is_empty()
 +    }
 +}
 +
 +#[unstable(feature = "fused", issue = "35602")]
 +impl<'a, T> FusedIterator for ExactChunksMut<'a, T> {}
 +
 +#[doc(hidden)]
 +unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> {
 +    unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] {
 +        let start = i * self.chunk_size;
 +        from_raw_parts_mut(self.v.as_mut_ptr().offset(start as isize), self.chunk_size)
 +    }
 +    fn may_have_side_effect() -> bool { false }
 +}
 +
  //
  // Free functions
  //
index f7a4a71e5cfda4909700cd455c5b762d6a3965cd,d6bff43bc72925b1f20838376636f57cb1e23464..13740b958025171b2875d9b9e9c57947716d8842
  
  use core::result::Result::{Ok, Err};
  
+ #[test]
+ fn test_position() {
+     let b = [1, 2, 3, 5, 5];
+     assert!(b.iter().position(|&v| v == 9) == None);
+     assert!(b.iter().position(|&v| v == 5) == Some(3));
+     assert!(b.iter().position(|&v| v == 3) == Some(2));
+     assert!(b.iter().position(|&v| v == 0) == None);
+ }
+ #[test]
+ fn test_rposition() {
+     let b = [1, 2, 3, 5, 5];
+     assert!(b.iter().rposition(|&v| v == 9) == None);
+     assert!(b.iter().rposition(|&v| v == 5) == Some(4));
+     assert!(b.iter().rposition(|&v| v == 3) == Some(2));
+     assert!(b.iter().rposition(|&v| v == 0) == None);
+ }
  #[test]
  fn test_binary_search() {
      let b: [i32; 0] = [];
@@@ -117,12 -136,12 +136,12 @@@ fn test_chunks_count() 
  fn test_chunks_nth() {
      let v: &[i32] = &[0, 1, 2, 3, 4, 5];
      let mut c = v.chunks(2);
 -    assert_eq!(c.nth(1).unwrap()[1], 3);
 -    assert_eq!(c.next().unwrap()[0], 4);
 +    assert_eq!(c.nth(1).unwrap(), &[2, 3]);
 +    assert_eq!(c.next().unwrap(), &[4, 5]);
  
      let v2: &[i32] = &[0, 1, 2, 3, 4];
      let mut c2 = v2.chunks(3);
 -    assert_eq!(c2.nth(1).unwrap()[1], 4);
 +    assert_eq!(c2.nth(1).unwrap(), &[3, 4]);
      assert_eq!(c2.next(), None);
  }
  
@@@ -168,12 -187,12 +187,12 @@@ fn test_chunks_mut_count() 
  fn test_chunks_mut_nth() {
      let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
      let mut c = v.chunks_mut(2);
 -    assert_eq!(c.nth(1).unwrap()[1], 3);
 -    assert_eq!(c.next().unwrap()[0], 4);
 +    assert_eq!(c.nth(1).unwrap(), &[2, 3]);
 +    assert_eq!(c.next().unwrap(), &[4, 5]);
  
      let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
      let mut c2 = v2.chunks_mut(3);
 -    assert_eq!(c2.nth(1).unwrap()[1], 4);
 +    assert_eq!(c2.nth(1).unwrap(), &[3, 4]);
      assert_eq!(c2.next(), None);
  }
  
  fn test_chunks_mut_last() {
      let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
      let c = v.chunks_mut(2);
 -    assert_eq!(c.last().unwrap()[1], 5);
 +    assert_eq!(c.last().unwrap(), &[4, 5]);
  
      let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
      let c2 = v2.chunks_mut(2);
 -    assert_eq!(c2.last().unwrap()[0], 4);
 +    assert_eq!(c2.last().unwrap(), &[4]);
  }
  
  #[test]
@@@ -202,110 -221,6 +221,110 @@@ fn test_chunks_mut_zip() 
      assert_eq!(v1, [13, 14, 19, 20, 14]);
  }
  
 +#[test]
 +fn test_exact_chunks_count() {
 +    let v: &[i32] = &[0, 1, 2, 3, 4, 5];
 +    let c = v.exact_chunks(3);
 +    assert_eq!(c.count(), 2);
 +
 +    let v2: &[i32] = &[0, 1, 2, 3, 4];
 +    let c2 = v2.exact_chunks(2);
 +    assert_eq!(c2.count(), 2);
 +
 +    let v3: &[i32] = &[];
 +    let c3 = v3.exact_chunks(2);
 +    assert_eq!(c3.count(), 0);
 +}
 +
 +#[test]
 +fn test_exact_chunks_nth() {
 +    let v: &[i32] = &[0, 1, 2, 3, 4, 5];
 +    let mut c = v.exact_chunks(2);
 +    assert_eq!(c.nth(1).unwrap(), &[2, 3]);
 +    assert_eq!(c.next().unwrap(), &[4, 5]);
 +
 +    let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
 +    let mut c2 = v2.exact_chunks(3);
 +    assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
 +    assert_eq!(c2.next(), None);
 +}
 +
 +#[test]
 +fn test_exact_chunks_last() {
 +    let v: &[i32] = &[0, 1, 2, 3, 4, 5];
 +    let c = v.exact_chunks(2);
 +    assert_eq!(c.last().unwrap(), &[4, 5]);
 +
 +    let v2: &[i32] = &[0, 1, 2, 3, 4];
 +    let c2 = v2.exact_chunks(2);
 +    assert_eq!(c2.last().unwrap(), &[2, 3]);
 +}
 +
 +#[test]
 +fn test_exact_chunks_zip() {
 +    let v1: &[i32] = &[0, 1, 2, 3, 4];
 +    let v2: &[i32] = &[6, 7, 8, 9, 10];
 +
 +    let res = v1.exact_chunks(2)
 +        .zip(v2.exact_chunks(2))
 +        .map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
 +        .collect::<Vec<_>>();
 +    assert_eq!(res, vec![14, 22]);
 +}
 +
 +#[test]
 +fn test_exact_chunks_mut_count() {
 +    let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
 +    let c = v.exact_chunks_mut(3);
 +    assert_eq!(c.count(), 2);
 +
 +    let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
 +    let c2 = v2.exact_chunks_mut(2);
 +    assert_eq!(c2.count(), 2);
 +
 +    let v3: &mut [i32] = &mut [];
 +    let c3 = v3.exact_chunks_mut(2);
 +    assert_eq!(c3.count(), 0);
 +}
 +
 +#[test]
 +fn test_exact_chunks_mut_nth() {
 +    let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
 +    let mut c = v.exact_chunks_mut(2);
 +    assert_eq!(c.nth(1).unwrap(), &[2, 3]);
 +    assert_eq!(c.next().unwrap(), &[4, 5]);
 +
 +    let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
 +    let mut c2 = v2.exact_chunks_mut(3);
 +    assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
 +    assert_eq!(c2.next(), None);
 +}
 +
 +#[test]
 +fn test_exact_chunks_mut_last() {
 +    let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
 +    let c = v.exact_chunks_mut(2);
 +    assert_eq!(c.last().unwrap(), &[4, 5]);
 +
 +    let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
 +    let c2 = v2.exact_chunks_mut(2);
 +    assert_eq!(c2.last().unwrap(), &[2, 3]);
 +}
 +
 +#[test]
 +fn test_exact_chunks_mut_zip() {
 +    let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
 +    let v2: &[i32] = &[6, 7, 8, 9, 10];
 +
 +    for (a, b) in v1.exact_chunks_mut(2).zip(v2.exact_chunks(2)) {
 +        let sum = b.iter().sum::<i32>();
 +        for v in a {
 +            *v += sum;
 +        }
 +    }
 +    assert_eq!(v1, [13, 14, 19, 20, 4]);
 +}
 +
  #[test]
  fn test_windows_count() {
      let v: &[i32] = &[0, 1, 2, 3, 4, 5];