Skip to content

Commit a54ddfb

Browse files
committed
core: Unroll the loop in the slice iterator search methods
Introduce a helper method .search_while() that generalizes internal iteration (Iterator's all, find, position, fold and so on). The compiler does not unroll loops with conditional exits; we can do this manually instead to improve the performance of for example Iterator::find and Iterator::position when used on the slice iterators. The unrolling is patterned on libstdc++'s implementation of std::find_if.
1 parent 7611e42 commit a54ddfb

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

src/libcore/slice.rs

+118
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,64 @@ macro_rules! iterator {
852852
fn last(mut self) -> Option<$elem> {
853853
self.next_back()
854854
}
855+
856+
fn all<F>(&mut self, mut predicate: F) -> bool
857+
where F: FnMut(Self::Item) -> bool,
858+
{
859+
self.search_while(true, move |elt| {
860+
if predicate(elt) {
861+
SearchWhile::Continue
862+
} else {
863+
SearchWhile::Done(false)
864+
}
865+
})
866+
}
867+
868+
fn any<F>(&mut self, mut predicate: F) -> bool
869+
where F: FnMut(Self::Item) -> bool,
870+
{
871+
!self.all(move |elt| !predicate(elt))
872+
}
873+
874+
fn find<F>(&mut self, mut predicate: F) -> Option<Self::Item>
875+
where F: FnMut(&Self::Item) -> bool,
876+
{
877+
self.search_while(None, move |elt| {
878+
if predicate(&elt) {
879+
SearchWhile::Done(Some(elt))
880+
} else {
881+
SearchWhile::Continue
882+
}
883+
})
884+
}
885+
886+
fn position<F>(&mut self, mut predicate: F) -> Option<usize>
887+
where F: FnMut(Self::Item) -> bool,
888+
{
889+
let mut index = 0;
890+
self.search_while(None, move |elt| {
891+
if predicate(elt) {
892+
SearchWhile::Done(Some(index))
893+
} else {
894+
index += 1;
895+
SearchWhile::Continue
896+
}
897+
})
898+
}
899+
900+
fn rposition<F>(&mut self, mut predicate: F) -> Option<usize>
901+
where F: FnMut(Self::Item) -> bool,
902+
{
903+
let mut index = self.len();
904+
self.rsearch_while(None, move |elt| {
905+
index -= 1;
906+
if predicate(elt) {
907+
SearchWhile::Done(Some(index))
908+
} else {
909+
SearchWhile::Continue
910+
}
911+
})
912+
}
855913
}
856914

857915
#[stable(feature = "rust1", since = "1.0.0")]
@@ -872,6 +930,48 @@ macro_rules! iterator {
872930
}
873931
}
874932
}
933+
934+
// search_while is a generalization of the internal iteration methods.
935+
impl<'a, T> $name<'a, T> {
936+
// search through the iterator's element using the closure `g`.
937+
// if no element was found, return `default`.
938+
fn search_while<Acc, G>(&mut self, default: Acc, mut g: G) -> Acc
939+
where Self: Sized,
940+
G: FnMut($elem) -> SearchWhile<Acc>
941+
{
942+
// manual unrolling is needed when there are conditional exits from the loop
943+
unsafe {
944+
while ptrdistance(self.ptr, self.end) >= 4 {
945+
search_while!(g($mkref!(self.ptr.post_inc())));
946+
search_while!(g($mkref!(self.ptr.post_inc())));
947+
search_while!(g($mkref!(self.ptr.post_inc())));
948+
search_while!(g($mkref!(self.ptr.post_inc())));
949+
}
950+
while self.ptr != self.end {
951+
search_while!(g($mkref!(self.ptr.post_inc())));
952+
}
953+
}
954+
default
955+
}
956+
957+
fn rsearch_while<Acc, G>(&mut self, default: Acc, mut g: G) -> Acc
958+
where Self: Sized,
959+
G: FnMut($elem) -> SearchWhile<Acc>
960+
{
961+
unsafe {
962+
while ptrdistance(self.ptr, self.end) >= 4 {
963+
search_while!(g($mkref!(self.end.pre_dec())));
964+
search_while!(g($mkref!(self.end.pre_dec())));
965+
search_while!(g($mkref!(self.end.pre_dec())));
966+
search_while!(g($mkref!(self.end.pre_dec())));
967+
}
968+
while self.ptr != self.end {
969+
search_while!(g($mkref!(self.end.pre_dec())));
970+
}
971+
}
972+
default
973+
}
974+
}
875975
}
876976
}
877977

@@ -903,6 +1003,24 @@ macro_rules! make_mut_slice {
9031003
}}
9041004
}
9051005

1006+
// An enum used for controlling the execution of `.search_while()`.
1007+
enum SearchWhile<T> {
1008+
// Continue searching
1009+
Continue,
1010+
// Fold is complete and will return this value
1011+
Done(T),
1012+
}
1013+
1014+
// helper macro for search while's control flow
1015+
macro_rules! search_while {
1016+
($e:expr) => {
1017+
match $e {
1018+
SearchWhile::Continue => { }
1019+
SearchWhile::Done(done) => return done,
1020+
}
1021+
}
1022+
}
1023+
9061024
/// Immutable slice iterator
9071025
///
9081026
/// This struct is created by the [`iter`] method on [slices].

0 commit comments

Comments
 (0)