Skip to content

Commit

Permalink
impl: optimize replacen loop
Browse files Browse the repository at this point in the history
The previous implementation didn't bail out of the replace
loop when the limit was reached until one more than the
total number of 'find' operations had completed. By moving
the limit check to the end of the loop body, we execute only
the number of 'find' operations that is necessary, instead of
one extra.

This optimization only applies to 'replacen' calls with a limit
not equal to '0'. That includes 'replace' but not 'replace_all'.

PR #930
  • Loading branch information
xkr47 committed Nov 28, 2022
1 parent f871a8e commit ac2d0e1
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 12 deletions.
12 changes: 6 additions & 6 deletions src/re_bytes.rs
Expand Up @@ -496,12 +496,12 @@ impl Regex {
let mut new = Vec::with_capacity(text.len());
let mut last_match = 0;
for (i, m) in it {
if limit > 0 && i >= limit {
break;
}
new.extend_from_slice(&text[last_match..m.start()]);
new.extend_from_slice(&rep);
last_match = m.end();
if limit > 0 && i >= limit - 1 {
break;
}
}
new.extend_from_slice(&text[last_match..]);
return Cow::Owned(new);
Expand All @@ -516,14 +516,14 @@ impl Regex {
let mut new = Vec::with_capacity(text.len());
let mut last_match = 0;
for (i, cap) in it {
if limit > 0 && i >= limit {
break;
}
// unwrap on 0 is OK because captures only reports matches
let m = cap.get(0).unwrap();
new.extend_from_slice(&text[last_match..m.start()]);
rep.replace_append(&cap, &mut new);
last_match = m.end();
if limit > 0 && i >= limit - 1 {
break;
}
}
new.extend_from_slice(&text[last_match..]);
Cow::Owned(new)
Expand Down
12 changes: 6 additions & 6 deletions src/re_unicode.rs
Expand Up @@ -554,12 +554,12 @@ impl Regex {
let mut new = String::with_capacity(text.len());
let mut last_match = 0;
for (i, m) in it {
if limit > 0 && i >= limit {
break;
}
new.push_str(&text[last_match..m.start()]);
new.push_str(&rep);
last_match = m.end();
if limit > 0 && i >= limit - 1 {
break;
}
}
new.push_str(&text[last_match..]);
return Cow::Owned(new);
Expand All @@ -574,14 +574,14 @@ impl Regex {
let mut new = String::with_capacity(text.len());
let mut last_match = 0;
for (i, cap) in it {
if limit > 0 && i >= limit {
break;
}
// unwrap on 0 is OK because captures only reports matches
let m = cap.get(0).unwrap();
new.push_str(&text[last_match..m.start()]);
rep.replace_append(&cap, &mut new);
last_match = m.end();
if limit > 0 && i >= limit - 1 {
break;
}
}
new.push_str(&text[last_match..]);
Cow::Owned(new)
Expand Down
18 changes: 18 additions & 0 deletions tests/replace.rs
Expand Up @@ -228,3 +228,21 @@ replace!(
bytes!(&std::borrow::Cow::<'_, [u8]>::Owned(vec![b'Z'])),
"age: Z6"
);

#[test]
fn replacen_no_captures() {
let re = regex!(r"[0-9]");
assert_eq!(
re.replacen(text!("age: 1234"), 2, t!("Z")),
text!("age: ZZ34")
);
}

#[test]
fn replacen_with_captures() {
let re = regex!(r"([0-9])");
assert_eq!(
re.replacen(text!("age: 1234"), 2, t!("${1}Z")),
text!("age: 1Z2Z34")
);
}

0 comments on commit ac2d0e1

Please sign in to comment.