Skip to content

Commit

Permalink
Fix TwoWaySearcher to work when used with periodic needles.
Browse files Browse the repository at this point in the history
There is a check in TwoWaySearcher::new to determine whether the needle
is periodic. This is needed because during searching when a match fails,
we cannot advance the position by the entire length of the needle when
it is periodic, but can only advance by the length of the period.

The reason "bananas".contains("nana") (and similar searches) were
returning false was because the periodicity check was wrong.

Closes #16589
  • Loading branch information
nham committed Aug 20, 2014
1 parent 3f5d0b5 commit 9419e92
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/libcore/str.rs
Expand Up @@ -419,6 +419,8 @@ struct TwoWaySearcher {
memory: uint
}

// This is the Two-Way search algorithm, which was introduced in the paper:
// Crochemore, M., Perrin, D., 1991, Two-way string-matching, Journal of the ACM 38(3):651-675.
impl TwoWaySearcher {
fn new(needle: &[u8]) -> TwoWaySearcher {
let (critPos1, period1) = TwoWaySearcher::maximal_suffix(needle, false);
Expand All @@ -437,7 +439,10 @@ impl TwoWaySearcher {
let byteset = needle.iter()
.fold(0, |a, &b| (1 << ((b & 0x3f) as uint)) | a);

if needle.slice_to(critPos) == needle.slice_from(needle.len() - critPos) {
// Check if the needle is periodic. If so, during searching when we
// find a mismatch, we must only advance the position by the length
// of the period, not the length of the entire needle
if needle.slice_to(critPos) == needle.slice(period, period + critPos) {
TwoWaySearcher {
critPos: critPos,
period: period,
Expand Down
20 changes: 20 additions & 0 deletions src/libcoretest/str.rs
Expand Up @@ -8,7 +8,27 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn check_contains_all_substrings(s: &str) {
assert!(s.contains(""));
for i in range(0, s.len()) {
for j in range(i+1, s.len() + 1) {
assert!(s.contains(s.slice(i, j)));
}
}
}

#[test]
fn strslice_issue_16589() {
assert!("bananas".contains("nana"));

// prior to the fix for #16589, x.contains("abcdabcd") returned false
// test all substrings for good measure
check_contains_all_substrings("012345678901234567890123456789bcdabcdabcd");
}


#[test]
fn test_strslice_contains() {
let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'";
check_contains_all_substrings(x);
}

0 comments on commit 9419e92

Please sign in to comment.