Skip to content

Commit ed70e16

Browse files
committed
Merge pull request #210 from rust-lang-nursery/extend-from-slice
Fixes a performance bug in bytes::Regex::replace.
2 parents 767f939 + 6770e23 commit ed70e16

File tree

3 files changed

+25
-9
lines changed

3 files changed

+25
-9
lines changed

examples/shootout-regex-dna-bytes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::thread;
1414
macro_rules! regex { ($re:expr) => { ::regex::bytes::Regex::new($re).unwrap() } }
1515

1616
fn main() {
17-
let mut seq = Vec::with_capacity(50 * (1 << 20));
17+
let mut seq = Vec::with_capacity(51 * (1 << 20));
1818
io::stdin().read_to_end(&mut seq).unwrap();
1919
let ilen = seq.len();
2020

examples/shootout-regex-dna.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::thread;
1414
macro_rules! regex { ($re:expr) => { ::regex::Regex::new($re).unwrap() } }
1515

1616
fn main() {
17-
let mut seq = String::with_capacity(50 * (1 << 20));
17+
let mut seq = String::with_capacity(51 * (1 << 20));
1818
io::stdin().read_to_string(&mut seq).unwrap();
1919
let ilen = seq.len();
2020

src/re_bytes.rs

+23-7
Original file line numberDiff line numberDiff line change
@@ -445,11 +445,11 @@ impl Regex {
445445
if limit > 0 && i >= limit {
446446
break
447447
}
448-
new.extend(&text[last_match..s]);
449-
new.extend(&*rep);
448+
extend_from_slice(&mut new, &text[last_match..s]);
449+
extend_from_slice(&mut new, &*rep);
450450
last_match = e;
451451
}
452-
new.extend(&text[last_match..]);
452+
extend_from_slice(&mut new, &text[last_match..]);
453453
return new;
454454
}
455455

@@ -463,11 +463,11 @@ impl Regex {
463463
}
464464
// unwrap on 0 is OK because captures only reports matches
465465
let (s, e) = cap.pos(0).unwrap();
466-
new.extend(&text[last_match..s]);
466+
extend_from_slice(&mut new, &text[last_match..s]);
467467
rep.replace_append(&cap, &mut new);
468468
last_match = e;
469469
}
470-
new.extend(&text[last_match..]);
470+
extend_from_slice(&mut new, &text[last_match..]);
471471
new
472472
}
473473

@@ -928,7 +928,7 @@ impl<'a> Replacer for &'a [u8] {
928928

929929
impl<F> Replacer for F where F: FnMut(&Captures) -> Vec<u8> {
930930
fn replace_append(&mut self, caps: &Captures, dst: &mut Vec<u8>) {
931-
dst.extend((*self)(caps))
931+
extend_from_slice(dst, &(*self)(caps));
932932
}
933933
}
934934

@@ -944,10 +944,26 @@ pub struct NoExpand<'r>(pub &'r [u8]);
944944

945945
impl<'a> Replacer for NoExpand<'a> {
946946
fn replace_append(&mut self, _: &Captures, dst: &mut Vec<u8>) {
947-
dst.extend(self.0)
947+
extend_from_slice(dst, self.0);
948948
}
949949

950950
fn no_expansion<'r>(&'r mut self) -> Option<Cow<'r, [u8]>> {
951951
Some(Cow::Borrowed(self.0))
952952
}
953953
}
954+
955+
/// This hopefully has the same performance characteristics as
956+
/// Vec::extend_from_slice (which was introduced in Rust 1.6), but works on
957+
/// Rust 1.3.
958+
///
959+
/// N.B. Remove this once we do a semver bump. At that point, we'll bump
960+
/// required Rust version to at least 1.6.
961+
fn extend_from_slice(dst: &mut Vec<u8>, src: &[u8]) {
962+
dst.reserve(src.len());
963+
let dst_len = dst.len();
964+
unsafe { dst.set_len(dst_len + src.len()); }
965+
let mut dst = &mut dst[dst_len..dst_len + src.len()];
966+
for i in 0..src.len() {
967+
dst[i] = src[i];
968+
}
969+
}

0 commit comments

Comments
 (0)