Auto merge of #73565 - matthewjasper:core-min-spec, r=nagisa

Use min_specialization in libcore

Getting `TrustedRandomAccess` to work is the main interesting thing here.

- `get_unchecked` is now an unstable, hidden method on `Iterator`
- The contract for `TrustedRandomAccess` is made clearer in documentation
- Fixed a bug where `Debug` would create aliasing references when using the specialized zip impl
- Added tests for the side effects of `next_back` and `nth`.

closes #68536
This commit is contained in:
bors 2020-08-20 23:05:31 +00:00
commit d9d4d39612
8 changed files with 487 additions and 200 deletions

View File

@ -1,7 +1,7 @@
use crate::intrinsics;
use crate::iter::{
DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedRandomAccess,
};
use crate::iter::adapters::zip::try_get_unchecked;
use crate::iter::TrustedRandomAccess;
use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator};
use crate::ops::Try;
/// An iterator that yields `None` forever after the underlying iterator
@ -114,6 +114,19 @@ where
{
FuseImpl::find(self, predicate)
}
#[inline]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item
where
Self: TrustedRandomAccess,
{
match self.iter {
// SAFETY: the caller must uphold the contract for `Iterator::get_unchecked`.
Some(ref mut iter) => unsafe { try_get_unchecked(iter, idx) },
// SAFETY: the caller asserts there is an item at `i`, so we're not exhausted.
None => unsafe { intrinsics::unreachable() },
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -172,19 +185,12 @@ where
}
}
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccess for Fuse<I>
where
I: TrustedRandomAccess,
{
unsafe fn get_unchecked(&mut self, i: usize) -> I::Item {
match self.iter {
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
Some(ref mut iter) => unsafe { iter.get_unchecked(i) },
// SAFETY: the caller asserts there is an item at `i`, so we're not exhausted.
None => unsafe { intrinsics::unreachable() },
}
}
fn may_have_side_effect() -> bool {
I::may_have_side_effect()
}

View File

@ -15,6 +15,7 @@ pub use self::chain::Chain;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::flatten::{FlatMap, Flatten};
pub use self::fuse::Fuse;
use self::zip::try_get_unchecked;
pub(crate) use self::zip::TrustedRandomAccess;
pub use self::zip::Zip;
@ -213,6 +214,15 @@ where
fn count(self) -> usize {
self.it.count()
}
unsafe fn get_unchecked(&mut self, idx: usize) -> T
where
Self: TrustedRandomAccess,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::get_unchecked`.
*unsafe { try_get_unchecked(&mut self.it, idx) }
}
}
#[stable(feature = "iter_copied", since = "1.36.0")]
@ -266,16 +276,11 @@ where
}
#[doc(hidden)]
unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Copied<I>
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccess for Copied<I>
where
I: TrustedRandomAccess<Item = &'a T>,
T: Copy,
I: TrustedRandomAccess,
{
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
unsafe { *self.it.get_unchecked(i) }
}
#[inline]
fn may_have_side_effect() -> bool {
I::may_have_side_effect()
@ -344,6 +349,15 @@ where
{
self.it.map(T::clone).fold(init, f)
}
unsafe fn get_unchecked(&mut self, idx: usize) -> T
where
Self: TrustedRandomAccess,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::get_unchecked`.
unsafe { try_get_unchecked(&mut self.it, idx).clone() }
}
}
#[stable(feature = "iter_cloned", since = "1.1.0")]
@ -397,36 +411,14 @@ where
}
#[doc(hidden)]
unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccess for Cloned<I>
where
I: TrustedRandomAccess<Item = &'a T>,
T: Clone,
I: TrustedRandomAccess,
{
default unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
unsafe { self.it.get_unchecked(i) }.clone()
}
#[inline]
default fn may_have_side_effect() -> bool {
true
}
}
#[doc(hidden)]
unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
where
I: TrustedRandomAccess<Item = &'a T>,
T: Copy,
{
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
unsafe { *self.it.get_unchecked(i) }
}
#[inline]
fn may_have_side_effect() -> bool {
I::may_have_side_effect()
true
}
}
@ -872,6 +864,15 @@ where
{
self.iter.fold(init, map_fold(self.f, g))
}
unsafe fn get_unchecked(&mut self, idx: usize) -> B
where
Self: TrustedRandomAccess,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::get_unchecked`.
unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -927,15 +928,11 @@ where
}
#[doc(hidden)]
unsafe impl<B, I, F> TrustedRandomAccess for Map<I, F>
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I, F> TrustedRandomAccess for Map<I, F>
where
I: TrustedRandomAccess,
F: FnMut(I::Item) -> B,
{
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
(self.f)(unsafe { self.iter.get_unchecked(i) })
}
#[inline]
fn may_have_side_effect() -> bool {
true
@ -1306,6 +1303,16 @@ where
self.iter.fold(init, enumerate(self.count, fold))
}
unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
where
Self: TrustedRandomAccess,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::get_unchecked`.
let value = unsafe { try_get_unchecked(&mut self.iter, idx) };
(Add::add(self.count, idx), value)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -1391,15 +1398,11 @@ where
}
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<I> TrustedRandomAccess for Enumerate<I>
where
I: TrustedRandomAccess,
{
unsafe fn get_unchecked(&mut self, i: usize) -> (usize, I::Item) {
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
(self.count + i, unsafe { self.iter.get_unchecked(i) })
}
fn may_have_side_effect() -> bool {
I::may_have_side_effect()
}

View File

@ -1,4 +1,5 @@
use crate::cmp;
use crate::fmt::{self, Debug};
use super::super::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedLen};
@ -9,7 +10,7 @@ use super::super::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterat
///
/// [`zip`]: trait.Iterator.html#method.zip
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[derive(Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Zip<A, B> {
@ -56,6 +57,16 @@ where
fn nth(&mut self, n: usize) -> Option<Self::Item> {
ZipImpl::nth(self, n)
}
#[inline]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item
where
Self: TrustedRandomAccess,
{
// SAFETY: `ZipImpl::get_unchecked` has same safety requirements as
// `Iterator::get_unchecked`.
unsafe { ZipImpl::get_unchecked(self, idx) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -82,6 +93,10 @@ trait ZipImpl<A, B> {
where
A: DoubleEndedIterator + ExactSizeIterator,
B: DoubleEndedIterator + ExactSizeIterator;
// This has the same safety requirements as `Iterator::get_unchecked`
unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
where
Self: Iterator + TrustedRandomAccess;
}
// General Zip impl
@ -156,16 +171,23 @@ where
(lower, upper)
}
default unsafe fn get_unchecked(&mut self, _idx: usize) -> <Self as Iterator>::Item
where
Self: TrustedRandomAccess,
{
unreachable!("Always specialized");
}
}
#[doc(hidden)]
impl<A, B> ZipImpl<A, B> for Zip<A, B>
where
A: TrustedRandomAccess,
B: TrustedRandomAccess,
A: TrustedRandomAccess + Iterator,
B: TrustedRandomAccess + Iterator,
{
fn new(a: A, b: B) -> Self {
let len = cmp::min(a.len(), b.len());
let len = cmp::min(a.size(), b.size());
Zip { a, b, index: 0, len }
}
@ -176,7 +198,7 @@ where
self.index += 1;
// SAFETY: `i` is smaller than `self.len`, thus smaller than `self.a.len()` and `self.b.len()`
unsafe { Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) }
} else if A::may_have_side_effect() && self.index < self.a.len() {
} else if A::may_have_side_effect() && self.index < self.a.size() {
// match the base implementation's potential side effects
// SAFETY: we just checked that `self.index` < `self.a.len()`
unsafe {
@ -227,20 +249,26 @@ where
A: DoubleEndedIterator + ExactSizeIterator,
B: DoubleEndedIterator + ExactSizeIterator,
{
// Adjust a, b to equal length
if A::may_have_side_effect() {
let sz = self.a.len();
if sz > self.len {
for _ in 0..sz - cmp::max(self.len, self.index) {
self.a.next_back();
let a_side_effect = A::may_have_side_effect();
let b_side_effect = B::may_have_side_effect();
if a_side_effect || b_side_effect {
let sz_a = self.a.size();
let sz_b = self.b.size();
// Adjust a, b to equal length, make sure that only the first call
// of `next_back` does this, otherwise we will break the restriction
// on calls to `self.next_back()` after calling `get_unchecked()`.
if sz_a != sz_b {
let sz_a = self.a.size();
if a_side_effect && sz_a > self.len {
for _ in 0..sz_a - cmp::max(self.len, self.index) {
self.a.next_back();
}
}
}
}
if B::may_have_side_effect() {
let sz = self.b.len();
if sz > self.len {
for _ in 0..sz - self.len {
self.b.next_back();
let sz_b = self.b.size();
if b_side_effect && sz_b > self.len {
for _ in 0..sz_b - self.len {
self.b.next_back();
}
}
}
}
@ -254,6 +282,13 @@ where
None
}
}
#[inline]
unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item {
// SAFETY: the caller must uphold the contract for
// `Iterator::get_unchecked`.
unsafe { (self.a.get_unchecked(idx), self.b.get_unchecked(idx)) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -265,16 +300,12 @@ where
}
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
where
A: TrustedRandomAccess,
B: TrustedRandomAccess,
{
unsafe fn get_unchecked(&mut self, i: usize) -> (A::Item, B::Item) {
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
unsafe { (self.a.get_unchecked(i), self.b.get_unchecked(i)) }
}
fn may_have_side_effect() -> bool {
A::may_have_side_effect() || B::may_have_side_effect()
}
@ -296,19 +327,109 @@ where
{
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Debug, B: Debug> Debug for Zip<A, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ZipFmt::fmt(self, f)
}
}
trait ZipFmt<A, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
}
impl<A: Debug, B: Debug> ZipFmt<A, B> for Zip<A, B> {
default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Zip").field("a", &self.a).field("b", &self.b).finish()
}
}
impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B> for Zip<A, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// It's *not safe* to call fmt on the contained iterators, since once
// we start iterating they're in strange, potentially unsafe, states.
f.debug_struct("Zip").finish()
}
}
/// An iterator whose items are random-accessible efficiently
///
/// # Safety
///
/// The iterator's .len() and size_hint() must be exact.
/// `.len()` must be cheap to call.
/// The iterator's `size_hint` must be exact and cheap to call.
///
/// .get_unchecked() must return distinct mutable references for distinct
/// indices (if applicable), and must return a valid reference if index is in
/// 0..self.len().
pub(crate) unsafe trait TrustedRandomAccess: ExactSizeIterator {
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item;
/// `size` may not be overridden.
///
/// `<Self as Iterator>::get_unchecked` must be safe to call provided the
/// following conditions are met.
///
/// 1. `0 <= idx` and `idx < self.size()`.
/// 2. If `self: !Clone`, then `get_unchecked` is never called with the same
/// index on `self` more than once.
/// 3. After `self.get_unchecked(idx)` has been called then `next_back` will
/// only be called at most `self.size() - idx - 1` times.
/// 4. After `get_unchecked` is called, then only the following methods will be
/// called on `self`:
/// * `std::clone::Clone::clone`
/// * `std::iter::Iterator::size_hint()`
/// * `std::iter::Iterator::next_back()`
/// * `std::iter::Iterator::get_unchecked()`
/// * `std::iter::TrustedRandomAccess::size()`
///
/// Further, given that these conditions are met, it must guarantee that:
///
/// * It does not change the value returned from `size_hint`
/// * It must be safe to call the methods listed above on `self` after calling
/// `get_unchecked`, assuming that the required traits are implemented.
/// * It must also be safe to drop `self` after calling `get_unchecked`.
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
#[rustc_specialization_trait]
pub unsafe trait TrustedRandomAccess: Sized {
// Convenience method.
fn size(&self) -> usize
where
Self: Iterator,
{
self.size_hint().0
}
/// Returns `true` if getting an iterator element may have
/// side effects. Remember to take inner iterators into account.
fn may_have_side_effect() -> bool;
}
/// Like `Iterator::get_unchecked`, but doesn't require the compiler to
/// know that `U: TrustedRandomAccess`.
///
/// ## Safety
///
/// Same requirements calling `get_unchecked` directly.
#[doc(hidden)]
pub(in crate::iter::adapters) unsafe fn try_get_unchecked<I>(it: &mut I, idx: usize) -> I::Item
where
I: Iterator,
{
// SAFETY: the caller must uphold the contract for
// `Iterator::get_unchecked`.
unsafe { it.try_get_unchecked(idx) }
}
unsafe trait SpecTrustedRandomAccess: Iterator {
/// If `Self: TrustedRandomAccess`, it must be safe to call a
/// `Iterator::get_unchecked(self, index)`.
unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item;
}
unsafe impl<I: Iterator> SpecTrustedRandomAccess for I {
default unsafe fn try_get_unchecked(&mut self, _: usize) -> Self::Item {
panic!("Should only be called on TrustedRandomAccess iterators");
}
}
unsafe impl<I: Iterator + TrustedRandomAccess> SpecTrustedRandomAccess for I {
unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item {
// SAFETY: the caller must uphold the contract for
// `Iterator::get_unchecked`.
unsafe { self.get_unchecked(index) }
}
}

View File

@ -6,6 +6,7 @@ use crate::cmp::{self, Ordering};
use crate::ops::{Add, Try};
use super::super::LoopState;
use super::super::TrustedRandomAccess;
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
use super::super::{FlatMap, Flatten};
use super::super::{FromIterator, Product, Sum, Zip};
@ -3245,6 +3246,17 @@ pub trait Iterator {
{
self.map(f).is_sorted()
}
/// See [TrustedRandomAccess]
#[inline]
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe fn get_unchecked(&mut self, _idx: usize) -> Self::Item
where
Self: TrustedRandomAccess,
{
unreachable!("Always specialized");
}
}
#[stable(feature = "rust1", since = "1.0.0")]

View File

@ -118,7 +118,7 @@
#![feature(repr_simd, platform_intrinsics)]
#![feature(rustc_attrs)]
#![feature(simd_ffi)]
#![feature(specialization)]
#![feature(min_specialization)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(stmt_expr_attributes)]

View File

@ -3647,21 +3647,21 @@ macro_rules! iterator {
struct $name:ident -> $ptr:ty,
$elem:ty,
$raw_mut:tt,
{$( $mut_:tt )*},
{$( $mut_:tt )?},
{$($extra:tt)*}
) => {
// Returns the first element and moves the start of the iterator forwards by 1.
// Greatly improves performance compared to an inlined function. The iterator
// must not be empty.
macro_rules! next_unchecked {
($self: ident) => {& $( $mut_ )* *$self.post_inc_start(1)}
($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)}
}
// Returns the last element and moves the end of the iterator backwards by 1.
// Greatly improves performance compared to an inlined function. The iterator
// must not be empty.
macro_rules! next_back_unchecked {
($self: ident) => {& $( $mut_ )* *$self.pre_dec_end(1)}
($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)}
}
// Shrinks the iterator when T is a ZST, by moving the end of the iterator
@ -3921,6 +3921,21 @@ macro_rules! iterator {
None
}
#[doc(hidden)]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
// SAFETY: the caller must guarantee that `i` is in bounds of
// the underlying slice, so `i` cannot overflow an `isize`, and
// the returned references is guaranteed to refer to an element
// of the slice and thus guaranteed to be valid.
//
// Also note that the caller also guarantees that we're never
// called with the same index again, and that no other methods
// that will access this subslice are called, so it is valid
// for the returned reference to be mutable in the case of
// `IterMut`
unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) }
}
$($extra)*
}
@ -5005,6 +5020,15 @@ impl<'a, T> Iterator for Windows<'a, T> {
Some(&self.v[start..])
}
}
#[doc(hidden)]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
// SAFETY: since the caller guarantees that `i` is in bounds,
// which means that `i` cannot overflow an `isize`, and the
// slice created by `from_raw_parts` is a subslice of `self.v`
// thus is guaranteed to be valid for the lifetime `'a` of `self.v`.
unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -5044,14 +5068,8 @@ unsafe impl<T> TrustedLen for Windows<'_, T> {}
impl<T> FusedIterator for Windows<'_, T> {}
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] {
// SAFETY: since the caller guarantees that `i` is in bounds,
// which means that `i` cannot overflow an `isize`, and the
// slice created by `from_raw_parts` is a subslice of `self.v`
// thus is guaranteed to be valid for the lifetime `'a` of `self.v`.
unsafe { from_raw_parts(self.v.as_ptr().add(i), self.size) }
}
fn may_have_side_effect() -> bool {
false
}
@ -5141,6 +5159,23 @@ impl<'a, T> Iterator for Chunks<'a, T> {
Some(&self.v[start..])
}
}
#[doc(hidden)]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
let start = idx * self.chunk_size;
let end = match start.checked_add(self.chunk_size) {
None => self.v.len(),
Some(end) => cmp::min(end, self.v.len()),
};
// SAFETY: the caller guarantees that `i` is in bounds,
// which means that `start` must be in bounds of the
// underlying `self.v` slice, and we made sure that `end`
// is also in bounds of `self.v`. Thus, `start` cannot overflow
// an `isize`, and the slice constructed by `from_raw_parts`
// is a subslice of `self.v` which is guaranteed to be valid
// for the lifetime `'a` of `self.v`.
unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -5187,22 +5222,8 @@ unsafe impl<T> TrustedLen for Chunks<'_, T> {}
impl<T> FusedIterator for Chunks<'_, T> {}
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] {
let start = i * self.chunk_size;
let end = match start.checked_add(self.chunk_size) {
None => self.v.len(),
Some(end) => cmp::min(end, self.v.len()),
};
// SAFETY: the caller guarantees that `i` is in bounds,
// which means that `start` must be in bounds of the
// underlying `self.v` slice, and we made sure that `end`
// is also in bounds of `self.v`. Thus, `start` cannot overflow
// an `isize`, and the slice constructed by `from_raw_parts`
// is a subslice of `self.v` which is guaranteed to be valid
// for the lifetime `'a` of `self.v`.
unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
}
fn may_have_side_effect() -> bool {
false
}
@ -5287,6 +5308,22 @@ impl<'a, T> Iterator for ChunksMut<'a, T> {
Some(&mut self.v[start..])
}
}
#[doc(hidden)]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
let start = idx * self.chunk_size;
let end = match start.checked_add(self.chunk_size) {
None => self.v.len(),
Some(end) => cmp::min(end, self.v.len()),
};
// SAFETY: see comments for `Chunks::get_unchecked`.
//
// Also note that the caller also guarantees that we're never called
// with the same index again, and that no other methods that will
// access this subslice are called, so it is valid for the returned
// slice to be mutable.
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -5336,16 +5373,8 @@ unsafe impl<T> TrustedLen for ChunksMut<'_, T> {}
impl<T> FusedIterator for ChunksMut<'_, T> {}
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] {
let start = i * self.chunk_size;
let end = match start.checked_add(self.chunk_size) {
None => self.v.len(),
Some(end) => cmp::min(end, self.v.len()),
};
// SAFETY: see comments for `Chunks::get_unchecked`.
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
}
fn may_have_side_effect() -> bool {
false
}
@ -5432,6 +5461,13 @@ impl<'a, T> Iterator for ChunksExact<'a, T> {
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
#[doc(hidden)]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
let start = idx * self.chunk_size;
// SAFETY: mostly identical to `Chunks::get_unchecked`.
unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
}
}
#[stable(feature = "chunks_exact", since = "1.31.0")]
@ -5477,13 +5513,8 @@ unsafe impl<T> TrustedLen for ChunksExact<'_, T> {}
impl<T> FusedIterator for ChunksExact<'_, T> {}
#[doc(hidden)]
#[stable(feature = "chunks_exact", since = "1.31.0")]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] {
let start = i * self.chunk_size;
// SAFETY: mostly identical to `Chunks::get_unchecked`.
unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
}
fn may_have_side_effect() -> bool {
false
}
@ -5564,6 +5595,13 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> {
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
#[doc(hidden)]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
let start = idx * self.chunk_size;
// SAFETY: see comments for `ChunksMut::get_unchecked`.
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
}
}
#[stable(feature = "chunks_exact", since = "1.31.0")]
@ -5612,13 +5650,8 @@ unsafe impl<T> TrustedLen for ChunksExactMut<'_, T> {}
impl<T> FusedIterator for ChunksExactMut<'_, T> {}
#[doc(hidden)]
#[stable(feature = "chunks_exact", since = "1.31.0")]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] {
let start = i * self.chunk_size;
// SAFETY: see comments for `ChunksExactMut::get_unchecked`.
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
}
fn may_have_side_effect() -> bool {
false
}
@ -5689,6 +5722,12 @@ impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> {
fn last(self) -> Option<Self::Item> {
self.iter.last()
}
unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] {
// SAFETY: The safety guarantees of `get_unchecked` are transferred to
// the caller.
unsafe { self.iter.get_unchecked(i) }
}
}
#[unstable(feature = "array_chunks", issue = "74985")]
@ -5720,11 +5759,6 @@ impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {}
#[doc(hidden)]
#[unstable(feature = "array_chunks", issue = "74985")]
unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] {
// SAFETY: The safety guarantees of `get_unchecked` are transferred to
// the caller.
unsafe { self.iter.get_unchecked(i) }
}
fn may_have_side_effect() -> bool {
false
}
@ -5817,6 +5851,17 @@ impl<'a, T> Iterator for RChunks<'a, T> {
Some(&self.v[0..end])
}
}
#[doc(hidden)]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
let end = self.v.len() - idx * self.chunk_size;
let start = match end.checked_sub(self.chunk_size) {
None => 0,
Some(start) => start,
};
// SAFETY: mostly identical to `Chunks::get_unchecked`.
unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
}
}
#[stable(feature = "rchunks", since = "1.31.0")]
@ -5862,17 +5907,8 @@ unsafe impl<T> TrustedLen for RChunks<'_, T> {}
impl<T> FusedIterator for RChunks<'_, T> {}
#[doc(hidden)]
#[stable(feature = "rchunks", since = "1.31.0")]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] {
let end = self.v.len() - i * self.chunk_size;
let start = match end.checked_sub(self.chunk_size) {
None => 0,
Some(start) => start,
};
// SAFETY: mostly identical to `Chunks::get_unchecked`.
unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
}
fn may_have_side_effect() -> bool {
false
}
@ -5961,6 +5997,17 @@ impl<'a, T> Iterator for RChunksMut<'a, T> {
Some(&mut self.v[0..end])
}
}
#[doc(hidden)]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
let end = self.v.len() - idx * self.chunk_size;
let start = match end.checked_sub(self.chunk_size) {
None => 0,
Some(start) => start,
};
// SAFETY: see comments for `RChunks::get_unchecked` and `ChunksMut::get_unchecked`
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
}
}
#[stable(feature = "rchunks", since = "1.31.0")]
@ -6008,17 +6055,8 @@ unsafe impl<T> TrustedLen for RChunksMut<'_, T> {}
impl<T> FusedIterator for RChunksMut<'_, T> {}
#[doc(hidden)]
#[stable(feature = "rchunks", since = "1.31.0")]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] {
let end = self.v.len() - i * self.chunk_size;
let start = match end.checked_sub(self.chunk_size) {
None => 0,
Some(start) => start,
};
// SAFETY: see comments for `RChunks::get_unchecked`.
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
}
fn may_have_side_effect() -> bool {
false
}
@ -6105,6 +6143,15 @@ impl<'a, T> Iterator for RChunksExact<'a, T> {
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
#[doc(hidden)]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
let end = self.v.len() - idx * self.chunk_size;
let start = end - self.chunk_size;
// SAFETY:
// SAFETY: mostmy identical to `Chunks::get_unchecked`.
unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
}
}
#[stable(feature = "rchunks", since = "1.31.0")]
@ -6153,14 +6200,8 @@ unsafe impl<T> TrustedLen for RChunksExact<'_, T> {}
impl<T> FusedIterator for RChunksExact<'_, T> {}
#[doc(hidden)]
#[stable(feature = "rchunks", since = "1.31.0")]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] {
let end = self.v.len() - i * self.chunk_size;
let start = end - self.chunk_size;
// SAFETY: mostmy identical to `Chunks::get_unchecked`.
unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
}
fn may_have_side_effect() -> bool {
false
}
@ -6243,6 +6284,14 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> {
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
#[doc(hidden)]
unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
let end = self.v.len() - idx * self.chunk_size;
let start = end - self.chunk_size;
// SAFETY: see comments for `RChunksMut::get_unchecked`.
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
}
}
#[stable(feature = "rchunks", since = "1.31.0")]
@ -6293,14 +6342,8 @@ unsafe impl<T> TrustedLen for RChunksExactMut<'_, T> {}
impl<T> FusedIterator for RChunksExactMut<'_, T> {}
#[doc(hidden)]
#[stable(feature = "rchunks", since = "1.31.0")]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] {
let end = self.v.len() - i * self.chunk_size;
let start = end - self.chunk_size;
// SAFETY: see comments for `RChunksExact::get_unchecked`.
unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
}
fn may_have_side_effect() -> bool {
false
}
@ -6543,18 +6586,20 @@ where
}
// Use an equal-pointer optimization when types are `Eq`
impl<A> SlicePartialEq<A> for [A]
// We can't make `A` and `B` the same type because `min_specialization` won't
// allow it.
impl<A, B> SlicePartialEq<B> for [A]
where
A: PartialEq<A> + Eq,
A: MarkerEq<B>,
{
default fn equal(&self, other: &[A]) -> bool {
default fn equal(&self, other: &[B]) -> bool {
if self.len() != other.len() {
return false;
}
// While performance would suffer if `guaranteed_eq` just returned `false`
// for all arguments, correctness and return value of this function are not affected.
if self.as_ptr().guaranteed_eq(other.as_ptr()) {
if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
return true;
}
@ -6563,18 +6608,18 @@ where
}
// Use memcmp for bytewise equality when the types allow
impl<A> SlicePartialEq<A> for [A]
impl<A, B> SlicePartialEq<B> for [A]
where
A: PartialEq<A> + BytewiseEquality,
A: BytewiseEquality<B>,
{
fn equal(&self, other: &[A]) -> bool {
fn equal(&self, other: &[B]) -> bool {
if self.len() != other.len() {
return false;
}
// While performance would suffer if `guaranteed_eq` just returned `false`
// for all arguments, correctness and return value of this function are not affected.
if self.as_ptr().guaranteed_eq(other.as_ptr()) {
if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
return true;
}
// SAFETY: `self` and `other` are references and are thus guaranteed to be valid.
@ -6631,6 +6676,7 @@ impl<A: AlwaysApplicableOrd> SlicePartialOrd for A {
}
}
#[rustc_specialization_trait]
trait AlwaysApplicableOrd: SliceOrd + Ord {}
macro_rules! always_applicable_ord {
@ -6695,15 +6741,22 @@ impl SliceOrd for u8 {
}
}
// Hack to allow specializing on `Eq` even though `Eq` has a method.
#[rustc_unsafe_specialization_marker]
trait MarkerEq<T>: PartialEq<T> {}
impl<T: Eq> MarkerEq<T> for T {}
#[doc(hidden)]
/// Trait implemented for types that can be compared for equality using
/// their bytewise representation
trait BytewiseEquality: Eq + Copy {}
#[rustc_specialization_trait]
trait BytewiseEquality<T>: MarkerEq<T> + Copy {}
macro_rules! impl_marker_for {
($traitname:ident, $($ty:ty)*) => {
$(
impl $traitname for $ty { }
impl $traitname<$ty> for $ty { }
)*
}
}
@ -6712,25 +6765,16 @@ impl_marker_for!(BytewiseEquality,
u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool);
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a T {
// SAFETY: the caller must guarantee that `i` is in bounds
// of the underlying slice, so `i` cannot overflow an `isize`,
// and the returned references is guaranteed to refer to an element
// of the slice and thus guaranteed to be valid.
unsafe { &*self.ptr.as_ptr().add(i) }
}
fn may_have_side_effect() -> bool {
false
}
}
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T {
// SAFETY: see comments for `Iter::get_unchecked`.
unsafe { &mut *self.ptr.as_ptr().add(i) }
}
fn may_have_side_effect() -> bool {
false
}

View File

@ -13,8 +13,9 @@ use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
use crate::char;
use crate::fmt::{self, Write};
use crate::iter::TrustedRandomAccess;
use crate::iter::{Chain, FlatMap, Flatten};
use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen, TrustedRandomAccess};
use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen};
use crate::mem;
use crate::ops::Try;
use crate::option;
@ -819,6 +820,13 @@ impl Iterator for Bytes<'_> {
{
self.0.rposition(predicate)
}
#[inline]
unsafe fn get_unchecked(&mut self, idx: usize) -> u8 {
// SAFETY: the caller must uphold the safety contract
// for `Iterator::get_unchecked`.
unsafe { self.0.get_unchecked(idx) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -862,12 +870,8 @@ impl FusedIterator for Bytes<'_> {}
unsafe impl TrustedLen for Bytes<'_> {}
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl TrustedRandomAccess for Bytes<'_> {
unsafe fn get_unchecked(&mut self, i: usize) -> u8 {
// SAFETY: the caller must uphold the safety contract
// for `TrustedRandomAccess::get_unchecked`.
unsafe { self.0.get_unchecked(i) }
}
fn may_have_side_effect() -> bool {
false
}

View File

@ -304,6 +304,103 @@ fn test_zip_nth_side_effects() {
assert_eq!(b, vec![200, 300, 400, 500, 600]);
}
#[test]
fn test_zip_next_back_side_effects() {
let mut a = Vec::new();
let mut b = Vec::new();
let mut iter = [1, 2, 3, 4, 5, 6]
.iter()
.cloned()
.map(|n| {
a.push(n);
n * 10
})
.zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
b.push(n * 100);
n * 1000
}));
// The second iterator is one item longer, so `next_back` is called on it
// one more time.
assert_eq!(iter.next_back(), Some((60, 7000)));
assert_eq!(iter.next_back(), Some((50, 6000)));
assert_eq!(iter.next_back(), Some((40, 5000)));
assert_eq!(iter.next_back(), Some((30, 4000)));
assert_eq!(a, vec![6, 5, 4, 3]);
assert_eq!(b, vec![800, 700, 600, 500, 400]);
}
#[test]
fn test_zip_nth_back_side_effects() {
let mut a = Vec::new();
let mut b = Vec::new();
let value = [1, 2, 3, 4, 5, 6]
.iter()
.cloned()
.map(|n| {
a.push(n);
n * 10
})
.zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
b.push(n * 100);
n * 1000
}))
.nth_back(3);
assert_eq!(value, Some((30, 4000)));
assert_eq!(a, vec![6, 5, 4, 3]);
assert_eq!(b, vec![800, 700, 600, 500, 400]);
}
#[test]
fn test_zip_next_back_side_effects_exhausted() {
let mut a = Vec::new();
let mut b = Vec::new();
let mut iter = [1, 2, 3, 4, 5, 6]
.iter()
.cloned()
.map(|n| {
a.push(n);
n * 10
})
.zip([2, 3, 4].iter().cloned().map(|n| {
b.push(n * 100);
n * 1000
}));
iter.next();
iter.next();
iter.next();
iter.next();
assert_eq!(iter.next_back(), None);
assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
assert_eq!(b, vec![200, 300, 400]);
}
#[test]
fn test_zip_nth_back_side_effects_exhausted() {
let mut a = Vec::new();
let mut b = Vec::new();
let mut iter = [1, 2, 3, 4, 5, 6]
.iter()
.cloned()
.map(|n| {
a.push(n);
n * 10
})
.zip([2, 3, 4].iter().cloned().map(|n| {
b.push(n * 100);
n * 1000
}));
iter.next();
iter.next();
iter.next();
iter.next();
assert_eq!(iter.nth_back(0), None);
assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
assert_eq!(b, vec![200, 300, 400]);
}
#[test]
fn test_iterator_step_by() {
// Identity