Skip to content

Commit e8f0fb1

Browse files
authored
Rollup merge of #72166 - nnethercote:simpler-slice-Iterator-methods, r=cuviper
Simpler slice `Iterator` methods These reduce the amount of LLVM IR generated, helping compile times. r? @cuviper
2 parents 9dd7ad3 + 3b10858 commit e8f0fb1

File tree

2 files changed

+106
-18
lines changed

2 files changed

+106
-18
lines changed

src/libcore/iter/traits/iterator.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ pub trait Iterator {
333333
#[inline]
334334
#[stable(feature = "rust1", since = "1.0.0")]
335335
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
336-
for x in self {
336+
while let Some(x) = self.next() {
337337
if n == 0 {
338338
return Some(x);
339339
}

src/libcore/slice/mod.rs

+105-17
Original file line numberDiff line numberDiff line change
@@ -3179,6 +3179,7 @@ macro_rules! is_empty {
31793179
$self.ptr.as_ptr() as *const T == $self.end
31803180
};
31813181
}
3182+
31823183
// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
31833184
// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
31843185
macro_rules! len {
@@ -3347,40 +3348,127 @@ macro_rules! iterator {
33473348
self.next_back()
33483349
}
33493350

3351+
// We override the default implementation, which uses `try_fold`,
3352+
// because this simple implementation generates less LLVM IR and is
3353+
// faster to compile.
3354+
#[inline]
3355+
fn for_each<F>(mut self, mut f: F)
3356+
where
3357+
Self: Sized,
3358+
F: FnMut(Self::Item),
3359+
{
3360+
while let Some(x) = self.next() {
3361+
f(x);
3362+
}
3363+
}
3364+
3365+
// We override the default implementation, which uses `try_fold`,
3366+
// because this simple implementation generates less LLVM IR and is
3367+
// faster to compile.
3368+
#[inline]
3369+
fn all<F>(&mut self, mut f: F) -> bool
3370+
where
3371+
Self: Sized,
3372+
F: FnMut(Self::Item) -> bool,
3373+
{
3374+
while let Some(x) = self.next() {
3375+
if !f(x) {
3376+
return false;
3377+
}
3378+
}
3379+
true
3380+
}
3381+
3382+
// We override the default implementation, which uses `try_fold`,
3383+
// because this simple implementation generates less LLVM IR and is
3384+
// faster to compile.
3385+
#[inline]
3386+
fn any<F>(&mut self, mut f: F) -> bool
3387+
where
3388+
Self: Sized,
3389+
F: FnMut(Self::Item) -> bool,
3390+
{
3391+
while let Some(x) = self.next() {
3392+
if f(x) {
3393+
return true;
3394+
}
3395+
}
3396+
false
3397+
}
3398+
3399+
// We override the default implementation, which uses `try_fold`,
3400+
// because this simple implementation generates less LLVM IR and is
3401+
// faster to compile.
3402+
#[inline]
3403+
fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
3404+
where
3405+
Self: Sized,
3406+
P: FnMut(&Self::Item) -> bool,
3407+
{
3408+
while let Some(x) = self.next() {
3409+
if predicate(&x) {
3410+
return Some(x);
3411+
}
3412+
}
3413+
None
3414+
}
3415+
3416+
// We override the default implementation, which uses `try_fold`,
3417+
// because this simple implementation generates less LLVM IR and is
3418+
// faster to compile.
3419+
#[inline]
3420+
fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
3421+
where
3422+
Self: Sized,
3423+
F: FnMut(Self::Item) -> Option<B>,
3424+
{
3425+
while let Some(x) = self.next() {
3426+
if let Some(y) = f(x) {
3427+
return Some(y);
3428+
}
3429+
}
3430+
None
3431+
}
3432+
3433+
// We override the default implementation, which uses `try_fold`,
3434+
// because this simple implementation generates less LLVM IR and is
3435+
// faster to compile. Also, the `assume` avoids a bounds check.
33503436
#[inline]
33513437
#[rustc_inherit_overflow_checks]
33523438
fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
33533439
Self: Sized,
33543440
P: FnMut(Self::Item) -> bool,
33553441
{
3356-
// The addition might panic on overflow.
33573442
let n = len!(self);
3358-
self.try_fold(0, move |i, x| {
3359-
if predicate(x) { Err(i) }
3360-
else { Ok(i + 1) }
3361-
}).err()
3362-
.map(|i| {
3443+
let mut i = 0;
3444+
while let Some(x) = self.next() {
3445+
if predicate(x) {
33633446
unsafe { assume(i < n) };
3364-
i
3365-
})
3447+
return Some(i);
3448+
}
3449+
i += 1;
3450+
}
3451+
None
33663452
}
33673453

3454+
// We override the default implementation, which uses `try_fold`,
3455+
// because this simple implementation generates less LLVM IR and is
3456+
// faster to compile. Also, the `assume` avoids a bounds check.
33683457
#[inline]
33693458
fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
33703459
P: FnMut(Self::Item) -> bool,
33713460
Self: Sized + ExactSizeIterator + DoubleEndedIterator
33723461
{
3373-
// No need for an overflow check here, because `ExactSizeIterator`
33743462
let n = len!(self);
3375-
self.try_rfold(n, move |i, x| {
3376-
let i = i - 1;
3377-
if predicate(x) { Err(i) }
3378-
else { Ok(i) }
3379-
}).err()
3380-
.map(|i| {
3463+
let mut i = n;
3464+
while let Some(x) = self.next_back() {
3465+
i -= 1;
3466+
if predicate(x) {
33813467
unsafe { assume(i < n) };
3382-
i
3383-
})
3468+
return Some(i);
3469+
}
3470+
}
3471+
None
33843472
}
33853473

33863474
$($extra)*

0 commit comments

Comments
 (0)