Skip to content

Commit 0f8df80

Browse files
committed
auto merge of #18056 : TeXitoi/rust/shootout-reverse-complement-improvement, r=alexcrichton
This is some improvement as asked and discused here: http://www.reddit.com/r/rust/comments/2j2ij3/benchmark_improvement_reverse_compliment/ Before: ``` real 0m0.396s user 0m0.280s sys 0m0.112s ``` after: ``` real 0m0.293s user 0m0.216s sys 0m0.076s ``` best C version: ``` real 0m0.135s user 0m0.132s sys 0m0.060s ``` Another possibility will be to add a `DoubleEndedIterator::next_two_side()` with a deffault implementation, and specialising it for slices, and use it here (`MutableSlice::reverse()` can then become safe). This benchmark will then be safe. What do you think?
2 parents 3dec727 + 1a6f1eb commit 0f8df80

File tree

1 file changed

+46
-12
lines changed

1 file changed

+46
-12
lines changed

src/test/bench/shootout-reverse-complement.rs

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -96,21 +96,55 @@ fn main() {
9696
}
9797

9898
// reverse complement, as
99-
// seq.reverse(); for c in seq.iter_mut() {*c = complements[*c]}
99+
// seq.reverse(); for c in seq.iter_mut() { *c = complements[*c] }
100100
// but faster:
101-
let mut it = seq.iter_mut();
102-
loop {
103-
match (it.next(), it.next_back()) {
104-
(Some(front), Some(back)) => {
105-
let tmp = complements[*front as uint];
106-
*front = complements[*back as uint];
107-
*back = tmp;
108-
}
109-
(Some(last), None) => *last = complements[*last as uint], // last element
110-
_ => break // vector exhausted.
111-
}
101+
for (front, back) in two_side_iter(seq) {
102+
let tmp = complements[*front as uint];
103+
*front = complements[*back as uint];
104+
*back = tmp;
105+
}
106+
if seq.len() % 2 == 1 {
107+
let middle = &mut seq[seq.len() / 2];
108+
*middle = complements[*middle as uint];
112109
}
113110
}
114111

115112
stdout().write(data.as_slice()).unwrap();
116113
}
114+
115+
pub struct TwoSideIter<'a, T: 'a> {
116+
first: *mut T,
117+
last: *mut T,
118+
marker: std::kinds::marker::ContravariantLifetime<'a>,
119+
marker2: std::kinds::marker::NoCopy
120+
}
121+
122+
pub fn two_side_iter<'a, T>(slice: &'a mut [T]) -> TwoSideIter<'a, T> {
123+
let len = slice.len();
124+
let first = slice.as_mut_ptr();
125+
let last = if len == 0 {
126+
first
127+
} else {
128+
unsafe { first.offset(len as int - 1) }
129+
};
130+
131+
TwoSideIter {
132+
first: first,
133+
last: last,
134+
marker: std::kinds::marker::ContravariantLifetime,
135+
marker2: std::kinds::marker::NoCopy
136+
}
137+
}
138+
139+
impl<'a, T> Iterator<(&'a mut T, &'a mut T)> for TwoSideIter<'a, T> {
140+
fn next(&mut self) -> Option<(&'a mut T, &'a mut T)> {
141+
if self.first < self.last {
142+
let result = unsafe { (&mut *self.first, &mut *self.last) };
143+
self.first = unsafe { self.first.offset(1) };
144+
self.last = unsafe { self.last.offset(-1) };
145+
Some(result)
146+
} else {
147+
None
148+
}
149+
}
150+
}

0 commit comments

Comments
 (0)