Tune RepeatWith::try_fold and Take::for_each and Vec::extend_trusted
This commit is contained in:
parent
a8954f1f6a
commit
9d68a1a74c
@ -2874,13 +2874,12 @@ fn extend_trusted(&mut self, iterator: impl iter::TrustedLen<Item = T>) {
|
|||||||
);
|
);
|
||||||
self.reserve(additional);
|
self.reserve(additional);
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut ptr = self.as_mut_ptr().add(self.len());
|
let ptr = self.as_mut_ptr();
|
||||||
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
||||||
iterator.for_each(move |element| {
|
iterator.for_each(move |element| {
|
||||||
ptr::write(ptr, element);
|
ptr::write(ptr.add(local_len.current_len()), element);
|
||||||
ptr = ptr.add(1);
|
// Since the loop executes user code which can panic we have to update
|
||||||
// Since the loop executes user code which can panic we have to bump the pointer
|
// the length every step to correctly drop what we've written.
|
||||||
// after each step.
|
|
||||||
// NB can't overflow since we would have had to alloc the address space
|
// NB can't overflow since we would have had to alloc the address space
|
||||||
local_len.increment_len(1);
|
local_len.increment_len(1);
|
||||||
});
|
});
|
||||||
|
@ -18,6 +18,11 @@ pub(super) fn new(len: &'a mut usize) -> Self {
|
|||||||
pub(super) fn increment_len(&mut self, increment: usize) {
|
pub(super) fn increment_len(&mut self, increment: usize) {
|
||||||
self.local_len += increment;
|
self.local_len += increment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn current_len(&self) -> usize {
|
||||||
|
self.local_len
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for SetLenOnDrop<'_> {
|
impl Drop for SetLenOnDrop<'_> {
|
||||||
|
@ -75,7 +75,6 @@ fn size_hint(&self) -> (usize, Option<usize>) {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
|
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
|
||||||
where
|
where
|
||||||
Self: Sized,
|
|
||||||
Fold: FnMut(Acc, Self::Item) -> R,
|
Fold: FnMut(Acc, Self::Item) -> R,
|
||||||
R: Try<Output = Acc>,
|
R: Try<Output = Acc>,
|
||||||
{
|
{
|
||||||
@ -100,6 +99,26 @@ fn check<'a, T, Acc, R: Try<Output = Acc>>(
|
|||||||
|
|
||||||
impl_fold_via_try_fold! { fold -> try_fold }
|
impl_fold_via_try_fold! { fold -> try_fold }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn for_each<F: FnMut(Self::Item)>(mut self, f: F) {
|
||||||
|
// The default implementation would use a unit accumulator, so we can
|
||||||
|
// avoid a stateful closure by folding over the remaining number
|
||||||
|
// of items we wish to return instead.
|
||||||
|
fn check<'a, Item>(
|
||||||
|
mut action: impl FnMut(Item) + 'a,
|
||||||
|
) -> impl FnMut(usize, Item) -> Option<usize> + 'a {
|
||||||
|
move |more, x| {
|
||||||
|
action(x);
|
||||||
|
more.checked_sub(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let remaining = self.n;
|
||||||
|
if remaining > 0 {
|
||||||
|
self.iter.try_fold(remaining - 1, check(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_inherit_overflow_checks]
|
#[rustc_inherit_overflow_checks]
|
||||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::iter::{FusedIterator, TrustedLen};
|
use crate::iter::{FusedIterator, TrustedLen};
|
||||||
|
use crate::ops::Try;
|
||||||
|
|
||||||
/// Creates a new iterator that repeats elements of type `A` endlessly by
|
/// Creates a new iterator that repeats elements of type `A` endlessly by
|
||||||
/// applying the provided closure, the repeater, `F: FnMut() -> A`.
|
/// applying the provided closure, the repeater, `F: FnMut() -> A`.
|
||||||
@ -89,6 +90,22 @@ fn next(&mut self) -> Option<A> {
|
|||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
(usize::MAX, None)
|
(usize::MAX, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
|
||||||
|
where
|
||||||
|
Fold: FnMut(Acc, Self::Item) -> R,
|
||||||
|
R: Try<Output = Acc>,
|
||||||
|
{
|
||||||
|
// This override isn't strictly needed, but avoids the need to optimize
|
||||||
|
// away the `next`-always-returns-`Some` and emphasizes that the `?`
|
||||||
|
// is the only way to exit the loop.
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let item = (self.repeater)();
|
||||||
|
init = fold(init, item)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
|
#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
|
||||||
|
@ -146,3 +146,23 @@ fn test_take_try_folds() {
|
|||||||
assert_eq!(iter.try_for_each(Err), Err(2));
|
assert_eq!(iter.try_for_each(Err), Err(2));
|
||||||
assert_eq!(iter.try_for_each(Err), Ok(()));
|
assert_eq!(iter.try_for_each(Err), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_byref_take_consumed_items() {
|
||||||
|
let mut inner = 10..90;
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
inner.by_ref().take(0).for_each(|_| count += 1);
|
||||||
|
assert_eq!(count, 0);
|
||||||
|
assert_eq!(inner, 10..90);
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
inner.by_ref().take(10).for_each(|_| count += 1);
|
||||||
|
assert_eq!(count, 10);
|
||||||
|
assert_eq!(inner, 20..90);
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
inner.by_ref().take(100).for_each(|_| count += 1);
|
||||||
|
assert_eq!(count, 70);
|
||||||
|
assert_eq!(inner, 90..90);
|
||||||
|
}
|
||||||
|
@ -11,3 +11,10 @@ pub fn repeat_take_collect() -> Vec<u8> {
|
|||||||
// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{[0-9]+}}, i8 42, i{{[0-9]+}} 100000, i1 false)
|
// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{[0-9]+}}, i8 42, i{{[0-9]+}} 100000, i1 false)
|
||||||
iter::repeat(42).take(100000).collect()
|
iter::repeat(42).take(100000).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @repeat_with_take_collect
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn repeat_with_take_collect() -> Vec<u8> {
|
||||||
|
// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{[0-9]+}}, i8 13, i{{[0-9]+}} 12345, i1 false)
|
||||||
|
iter::repeat_with(|| 13).take(12345).collect()
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user