Skip to content

Commit

Permalink
String::remove_matches O(n^2) -> O(n)
Browse files Browse the repository at this point in the history
Copy only non-matching bytes.
  • Loading branch information
tamird committed Jun 6, 2021
1 parent 38013e7 commit 977903b
Showing 1 changed file with 38 additions and 15 deletions.
53 changes: 38 additions & 15 deletions library/alloc/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1290,26 +1290,49 @@ impl String {
{
use core::str::pattern::Searcher;

let matches: Vec<_> = {
let rejections = {
let mut searcher = pat.into_searcher(self);
from_fn(|| searcher.next_match()).collect()
// Per Searcher::next:
//
// A Match result needs to contain the whole matched pattern,
// however Reject results may be split up into arbitrary many
// adjacent fragments. Both ranges may have zero length.
//
// In practice the implementation of Searcher::next_match tends to
// be more efficient, so we use it here and do some work to invert
// matches into rejections since that's what we want to copy below.
let mut front = 0;
let rejections: Vec<_> = from_fn(|| {
let (start, end) = searcher.next_match()?;
let prev_front = front;
front = end;
Some((prev_front, start))
})
.collect();
rejections.into_iter().chain(core::iter::once((front, self.len())))
};

let len = self.len();
let mut shrunk_by = 0;
let mut len = 0;
let ptr = self.vec.as_mut_ptr();

for (start, end) in rejections {
let count = end - start;
if start != len {
// SAFETY: per Searcher::next:
//
// The stream of Match and Reject values up to a Done will
// contain index ranges that are adjacent, non-overlapping,
// covering the whole haystack, and laying on utf8
// boundaries.
unsafe {
ptr::copy(ptr.add(start), ptr.add(len), count);
}
}
len += count;
}

// SAFETY: start and end will be on utf8 byte boundaries per
// the Searcher docs
unsafe {
for (start, end) in matches {
ptr::copy(
self.vec.as_mut_ptr().add(end - shrunk_by),
self.vec.as_mut_ptr().add(start - shrunk_by),
len - end,
);
shrunk_by += end - start;
}
self.vec.set_len(len - shrunk_by);
self.vec.set_len(len);
}
}

Expand Down

0 comments on commit 977903b

Please sign in to comment.