impl: optimize replacen loop

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
This commit is contained in:
Jonas Berlin
2022-11-28 20:37:22 +02:00
committed by GitHub
parent 9d91f47dd1
commit e3b21e91f1
3 changed files with 30 additions and 12 deletions
+6 -6
View File
@@ -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);
@@ -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)
+6 -6
View File
@@ -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);
@@ -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)
+18
View File
@@ -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")
);
}