Skip to content

Commit 81601cd

Browse files
authored
Auto merge of #37306 - bluss:trusted-len, r=alexcrichton
Add Iterator trait TrustedLen to enable better FromIterator / Extend This trait attempts to improve FromIterator / Extend code by enabling it to trust the iterator to produce an exact number of elements, which means that reallocation needs to happen only once and is moved out of the loop. `TrustedLen` differs from `ExactSizeIterator` in that it attempts to include _more_ iterators by allowing for the case that the iterator's len does not fit in `usize`. Consumers must check for this case (for example they could panic, since they can't allocate a collection of that size). For example, chain can be TrustedLen and all numerical ranges can be TrustedLen. All they need to do is to report an exact size if it fits in `usize`, and `None` as the upper bound otherwise. The trait describes its contract like this: ``` An iterator that reports an accurate length using size_hint. The iterator reports a size hint where it is either exact (lower bound is equal to upper bound), or the upper bound is `None`. The upper bound must only be `None` if the actual iterator length is larger than `usize::MAX`. The iterator must produce exactly the number of elements it reported. This trait must only be implemented when the contract is upheld. Consumers of this trait must inspect `.size_hint()`’s upper bound. ``` Fixes #37232
2 parents ccfc38f + f0e6b90 commit 81601cd

File tree

8 files changed

+146
-60
lines changed

8 files changed

+146
-60
lines changed

src/libcollections/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#![feature(specialization)]
5151
#![feature(staged_api)]
5252
#![feature(step_by)]
53+
#![feature(trusted_len)]
5354
#![feature(unicode)]
5455
#![feature(unique)]
5556
#![cfg_attr(test, feature(rand, test))]

src/libcollections/vec.rs

+43-57
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,14 @@ use core::cmp::Ordering;
7575
use core::fmt;
7676
use core::hash::{self, Hash};
7777
use core::intrinsics::{arith_offset, assume};
78-
use core::iter::{FromIterator, FusedIterator};
78+
use core::iter::{FromIterator, FusedIterator, TrustedLen};
7979
use core::mem;
8080
use core::ops::{Index, IndexMut};
8181
use core::ops;
8282
use core::ptr;
8383
use core::ptr::Shared;
8484
use core::slice;
8585

86-
use super::SpecExtend;
8786
use super::range::RangeArgument;
8887

8988
/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
@@ -1245,26 +1244,7 @@ impl<T: Clone> Vec<T> {
12451244
/// ```
12461245
#[stable(feature = "vec_extend_from_slice", since = "1.6.0")]
12471246
pub fn extend_from_slice(&mut self, other: &[T]) {
1248-
self.reserve(other.len());
1249-
1250-
// Unsafe code so this can be optimised to a memcpy (or something
1251-
// similarly fast) when T is Copy. LLVM is easily confused, so any
1252-
// extra operations during the loop can prevent this optimisation.
1253-
unsafe {
1254-
let len = self.len();
1255-
let ptr = self.get_unchecked_mut(len) as *mut T;
1256-
// Use SetLenOnDrop to work around bug where compiler
1257-
// may not realize the store through `ptr` trough self.set_len()
1258-
// don't alias.
1259-
let mut local_len = SetLenOnDrop::new(&mut self.len);
1260-
1261-
for i in 0..other.len() {
1262-
ptr::write(ptr.offset(i as isize), other.get_unchecked(i).clone());
1263-
local_len.increment_len(1);
1264-
}
1265-
1266-
// len set by scope guard
1267-
}
1247+
self.extend(other.iter().cloned())
12681248
}
12691249
}
12701250

@@ -1606,19 +1586,25 @@ impl<'a, T> IntoIterator for &'a mut Vec<T> {
16061586
impl<T> Extend<T> for Vec<T> {
16071587
#[inline]
16081588
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1609-
<Self as SpecExtend<I>>::spec_extend(self, iter);
1589+
self.extend_desugared(iter.into_iter())
16101590
}
16111591
}
16121592

1613-
impl<I: IntoIterator> SpecExtend<I> for Vec<I::Item> {
1614-
default fn spec_extend(&mut self, iter: I) {
1615-
self.extend_desugared(iter.into_iter())
1616-
}
1593+
trait IsTrustedLen : Iterator {
1594+
fn trusted_len(&self) -> Option<usize> { None }
16171595
}
1596+
impl<I> IsTrustedLen for I where I: Iterator { }
16181597

1619-
impl<T> SpecExtend<Vec<T>> for Vec<T> {
1620-
fn spec_extend(&mut self, ref mut other: Vec<T>) {
1621-
self.append(other);
1598+
impl<I> IsTrustedLen for I where I: TrustedLen
1599+
{
1600+
fn trusted_len(&self) -> Option<usize> {
1601+
let (low, high) = self.size_hint();
1602+
if let Some(high_value) = high {
1603+
debug_assert_eq!(low, high_value,
1604+
"TrustedLen iterator's size hint is not exact: {:?}",
1605+
(low, high));
1606+
}
1607+
high
16221608
}
16231609
}
16241610

@@ -1629,16 +1615,30 @@ impl<T> Vec<T> {
16291615
// for item in iterator {
16301616
// self.push(item);
16311617
// }
1632-
while let Some(element) = iterator.next() {
1633-
let len = self.len();
1634-
if len == self.capacity() {
1635-
let (lower, _) = iterator.size_hint();
1636-
self.reserve(lower.saturating_add(1));
1637-
}
1618+
if let Some(additional) = iterator.trusted_len() {
1619+
self.reserve(additional);
16381620
unsafe {
1639-
ptr::write(self.get_unchecked_mut(len), element);
1640-
// NB can't overflow since we would have had to alloc the address space
1641-
self.set_len(len + 1);
1621+
let mut ptr = self.as_mut_ptr().offset(self.len() as isize);
1622+
let mut local_len = SetLenOnDrop::new(&mut self.len);
1623+
for element in iterator {
1624+
ptr::write(ptr, element);
1625+
ptr = ptr.offset(1);
1626+
// NB can't overflow since we would have had to alloc the address space
1627+
local_len.increment_len(1);
1628+
}
1629+
}
1630+
} else {
1631+
while let Some(element) = iterator.next() {
1632+
let len = self.len();
1633+
if len == self.capacity() {
1634+
let (lower, _) = iterator.size_hint();
1635+
self.reserve(lower.saturating_add(1));
1636+
}
1637+
unsafe {
1638+
ptr::write(self.get_unchecked_mut(len), element);
1639+
// NB can't overflow since we would have had to alloc the address space
1640+
self.set_len(len + 1);
1641+
}
16421642
}
16431643
}
16441644
}
@@ -1647,24 +1647,7 @@ impl<T> Vec<T> {
16471647
#[stable(feature = "extend_ref", since = "1.2.0")]
16481648
impl<'a, T: 'a + Copy> Extend<&'a T> for Vec<T> {
16491649
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
1650-
<I as SpecExtendVec<T>>::extend_vec(iter, self);
1651-
}
1652-
}
1653-
1654-
// helper trait for specialization of Vec's Extend impl
1655-
trait SpecExtendVec<T> {
1656-
fn extend_vec(self, vec: &mut Vec<T>);
1657-
}
1658-
1659-
impl <'a, T: 'a + Copy, I: IntoIterator<Item=&'a T>> SpecExtendVec<T> for I {
1660-
default fn extend_vec(self, vec: &mut Vec<T>) {
1661-
vec.extend(self.into_iter().cloned());
1662-
}
1663-
}
1664-
1665-
impl<'a, T: Copy> SpecExtendVec<T> for &'a [T] {
1666-
fn extend_vec(self, vec: &mut Vec<T>) {
1667-
vec.extend_from_slice(self);
1650+
self.extend(iter.into_iter().map(|&x| x))
16681651
}
16691652
}
16701653

@@ -1988,6 +1971,9 @@ impl<T> ExactSizeIterator for IntoIter<T> {}
19881971
#[unstable(feature = "fused", issue = "35602")]
19891972
impl<T> FusedIterator for IntoIter<T> {}
19901973

1974+
#[unstable(feature = "trusted_len", issue = "37572")]
1975+
unsafe impl<T> TrustedLen for IntoIter<T> {}
1976+
19911977
#[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
19921978
impl<T: Clone> Clone for IntoIter<T> {
19931979
fn clone(&self) -> IntoIter<T> {

src/libcore/iter/mod.rs

+33
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,8 @@ pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend};
328328
pub use self::traits::{ExactSizeIterator, Sum, Product};
329329
#[unstable(feature = "fused", issue = "35602")]
330330
pub use self::traits::FusedIterator;
331+
#[unstable(feature = "trusted_len", issue = "37572")]
332+
pub use self::traits::TrustedLen;
331333

332334
mod iterator;
333335
mod range;
@@ -372,6 +374,10 @@ impl<I> ExactSizeIterator for Rev<I>
372374
impl<I> FusedIterator for Rev<I>
373375
where I: FusedIterator + DoubleEndedIterator {}
374376

377+
#[unstable(feature = "trusted_len", issue = "37572")]
378+
unsafe impl<I> TrustedLen for Rev<I>
379+
where I: TrustedLen + DoubleEndedIterator {}
380+
375381
/// An iterator that clones the elements of an underlying iterator.
376382
///
377383
/// This `struct` is created by the [`cloned()`] method on [`Iterator`]. See its
@@ -438,6 +444,12 @@ unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
438444
fn may_have_side_effect() -> bool { true }
439445
}
440446

447+
#[unstable(feature = "trusted_len", issue = "37572")]
448+
unsafe impl<'a, I, T: 'a> TrustedLen for Cloned<I>
449+
where I: TrustedLen<Item=&'a T>,
450+
T: Clone
451+
{}
452+
441453
/// An iterator that repeats endlessly.
442454
///
443455
/// This `struct` is created by the [`cycle()`] method on [`Iterator`]. See its
@@ -667,6 +679,11 @@ impl<A, B> FusedIterator for Chain<A, B>
667679
B: FusedIterator<Item=A::Item>,
668680
{}
669681

682+
#[unstable(feature = "trusted_len", issue = "37572")]
683+
unsafe impl<A, B> TrustedLen for Chain<A, B>
684+
where A: TrustedLen, B: TrustedLen<Item=A::Item>,
685+
{}
686+
670687
/// An iterator that iterates two other iterators simultaneously.
671688
///
672689
/// This `struct` is created by the [`zip()`] method on [`Iterator`]. See its
@@ -884,6 +901,11 @@ unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
884901
impl<A, B> FusedIterator for Zip<A, B>
885902
where A: FusedIterator, B: FusedIterator, {}
886903

904+
#[unstable(feature = "trusted_len", issue = "37572")]
905+
unsafe impl<A, B> TrustedLen for Zip<A, B>
906+
where A: TrustedLen, B: TrustedLen,
907+
{}
908+
887909
/// An iterator that maps the values of `iter` with `f`.
888910
///
889911
/// This `struct` is created by the [`map()`] method on [`Iterator`]. See its
@@ -991,6 +1013,11 @@ impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F>
9911013
impl<B, I: FusedIterator, F> FusedIterator for Map<I, F>
9921014
where F: FnMut(I::Item) -> B {}
9931015

1016+
#[unstable(feature = "trusted_len", issue = "37572")]
1017+
unsafe impl<B, I, F> TrustedLen for Map<I, F>
1018+
where I: TrustedLen,
1019+
F: FnMut(I::Item) -> B {}
1020+
9941021
#[doc(hidden)]
9951022
unsafe impl<B, I, F> TrustedRandomAccess for Map<I, F>
9961023
where I: TrustedRandomAccess,
@@ -1227,6 +1254,12 @@ unsafe impl<I> TrustedRandomAccess for Enumerate<I>
12271254
#[unstable(feature = "fused", issue = "35602")]
12281255
impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {}
12291256

1257+
#[unstable(feature = "trusted_len", issue = "37572")]
1258+
unsafe impl<I> TrustedLen for Enumerate<I>
1259+
where I: TrustedLen,
1260+
{}
1261+
1262+
12301263
/// An iterator with a `peek()` that returns an optional reference to the next
12311264
/// element.
12321265
///

src/libcore/iter/range.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use mem;
1212
use ops::{self, Add, Sub};
1313
use usize;
1414

15-
use super::FusedIterator;
15+
use super::{FusedIterator, TrustedLen};
1616

1717
/// Objects that can be stepped over in both directions.
1818
///
@@ -480,6 +480,22 @@ macro_rules! range_incl_exact_iter_impl {
480480
)*)
481481
}
482482

483+
macro_rules! range_trusted_len_impl {
484+
($($t:ty)*) => ($(
485+
#[unstable(feature = "trusted_len", issue = "37572")]
486+
unsafe impl TrustedLen for ops::Range<$t> { }
487+
)*)
488+
}
489+
490+
macro_rules! range_incl_trusted_len_impl {
491+
($($t:ty)*) => ($(
492+
#[unstable(feature = "inclusive_range",
493+
reason = "recently added, follows RFC",
494+
issue = "28237")]
495+
unsafe impl TrustedLen for ops::RangeInclusive<$t> { }
496+
)*)
497+
}
498+
483499
#[stable(feature = "rust1", since = "1.0.0")]
484500
impl<A: Step> Iterator for ops::Range<A> where
485501
for<'a> &'a A: Add<&'a A, Output = A>
@@ -513,6 +529,13 @@ impl<A: Step> Iterator for ops::Range<A> where
513529
range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
514530
range_incl_exact_iter_impl!(u8 u16 i8 i16);
515531

532+
// These macros generate `TrustedLen` impls.
533+
//
534+
// They need to guarantee that .size_hint() is either exact, or that
535+
// the upper bound is None when it does not fit the type limits.
536+
range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
537+
range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
538+
516539
#[stable(feature = "rust1", since = "1.0.0")]
517540
impl<A: Step + Clone> DoubleEndedIterator for ops::Range<A> where
518541
for<'a> &'a A: Add<&'a A, Output = A>,

src/libcore/iter/traits.rs

+19
Original file line numberDiff line numberDiff line change
@@ -665,3 +665,22 @@ pub trait FusedIterator: Iterator {}
665665

666666
#[unstable(feature = "fused", issue = "35602")]
667667
impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {}
668+
669+
/// An iterator that reports an accurate length using size_hint.
670+
///
671+
/// The iterator reports a size hint where it is either exact
672+
/// (lower bound is equal to upper bound), or the upper bound is `None`.
673+
/// The upper bound must only be `None` if the actual iterator length is
674+
/// larger than `usize::MAX`.
675+
///
676+
/// The iterator must produce exactly the number of elements it reported.
677+
///
678+
/// # Safety
679+
///
680+
/// This trait must only be implemented when the contract is upheld.
681+
/// Consumers of this trait must inspect `.size_hint()`’s upper bound.
682+
#[unstable(feature = "trusted_len", issue = "37572")]
683+
pub unsafe trait TrustedLen : Iterator {}
684+
685+
#[unstable(feature = "trusted_len", issue = "37572")]
686+
unsafe impl<'a, I: TrustedLen + ?Sized> TrustedLen for &'a mut I {}

src/libcore/option.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@
145145
146146
#![stable(feature = "rust1", since = "1.0.0")]
147147

148-
use iter::{FromIterator, FusedIterator};
148+
use iter::{FromIterator, FusedIterator, TrustedLen};
149149
use mem;
150150

151151
// Note that this is not a lang item per se, but it has a hidden dependency on
@@ -803,6 +803,7 @@ impl<A> DoubleEndedIterator for Item<A> {
803803

804804
impl<A> ExactSizeIterator for Item<A> {}
805805
impl<A> FusedIterator for Item<A> {}
806+
unsafe impl<A> TrustedLen for Item<A> {}
806807

807808
/// An iterator over a reference of the contained item in an [`Option`].
808809
///
@@ -833,6 +834,9 @@ impl<'a, A> ExactSizeIterator for Iter<'a, A> {}
833834
#[unstable(feature = "fused", issue = "35602")]
834835
impl<'a, A> FusedIterator for Iter<'a, A> {}
835836

837+
#[unstable(feature = "trusted_len", issue = "37572")]
838+
unsafe impl<'a, A> TrustedLen for Iter<'a, A> {}
839+
836840
#[stable(feature = "rust1", since = "1.0.0")]
837841
impl<'a, A> Clone for Iter<'a, A> {
838842
fn clone(&self) -> Iter<'a, A> {
@@ -868,6 +872,8 @@ impl<'a, A> ExactSizeIterator for IterMut<'a, A> {}
868872

869873
#[unstable(feature = "fused", issue = "35602")]
870874
impl<'a, A> FusedIterator for IterMut<'a, A> {}
875+
#[unstable(feature = "trusted_len", issue = "37572")]
876+
unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {}
871877

872878
/// An iterator over the item contained inside an [`Option`].
873879
///
@@ -898,6 +904,9 @@ impl<A> ExactSizeIterator for IntoIter<A> {}
898904
#[unstable(feature = "fused", issue = "35602")]
899905
impl<A> FusedIterator for IntoIter<A> {}
900906

907+
#[unstable(feature = "trusted_len", issue = "37572")]
908+
unsafe impl<A> TrustedLen for IntoIter<A> {}
909+
901910
/////////////////////////////////////////////////////////////////////////////
902911
// FromIterator
903912
/////////////////////////////////////////////////////////////////////////////

src/libcore/result.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@
249249
#![stable(feature = "rust1", since = "1.0.0")]
250250

251251
use fmt;
252-
use iter::{FromIterator, FusedIterator};
252+
use iter::{FromIterator, FusedIterator, TrustedLen};
253253

254254
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
255255
///
@@ -924,6 +924,9 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
924924
#[unstable(feature = "fused", issue = "35602")]
925925
impl<'a, T> FusedIterator for Iter<'a, T> {}
926926

927+
#[unstable(feature = "trusted_len", issue = "37572")]
928+
unsafe impl<'a, A> TrustedLen for Iter<'a, A> {}
929+
927930
#[stable(feature = "rust1", since = "1.0.0")]
928931
impl<'a, T> Clone for Iter<'a, T> {
929932
fn clone(&self) -> Iter<'a, T> { Iter { inner: self.inner } }
@@ -962,6 +965,9 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
962965
#[unstable(feature = "fused", issue = "35602")]
963966
impl<'a, T> FusedIterator for IterMut<'a, T> {}
964967

968+
#[unstable(feature = "trusted_len", issue = "37572")]
969+
unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {}
970+
965971
/// An iterator over the value in a [`Ok`] variant of a [`Result`]. This struct is
966972
/// created by the [`into_iter`] method on [`Result`][`Result`] (provided by
967973
/// the [`IntoIterator`] trait).
@@ -999,6 +1005,9 @@ impl<T> ExactSizeIterator for IntoIter<T> {}
9991005
#[unstable(feature = "fused", issue = "35602")]
10001006
impl<T> FusedIterator for IntoIter<T> {}
10011007

1008+
#[unstable(feature = "trusted_len", issue = "37572")]
1009+
unsafe impl<A> TrustedLen for IntoIter<A> {}
1010+
10021011
/////////////////////////////////////////////////////////////////////////////
10031012
// FromIterator
10041013
/////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)