Skip to content

Commit 480e23f

Browse files
authored
Small perf improvement for wilcard matching (#22)
- Initialize vector with pattern size - Avoid use of macros and use a helper function instead
1 parent 7d619b8 commit 480e23f

File tree

1 file changed

+40
-44
lines changed

1 file changed

+40
-44
lines changed

src/wildcard.rs

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -79,67 +79,63 @@ pub(crate) fn tokenize(s: &str, lowercase: bool) -> Vec<WildcardToken> {
7979
result
8080
}
8181

82-
macro_rules! match_tokens {
83-
($haystack_iterator:expr, $tokens:expr) => {{
84-
let mut starmode = false;
85-
let mut haystack_iterator = $haystack_iterator.peekable();
86-
87-
'outer: for (i, token) in $tokens.iter().enumerate() {
88-
let is_last_token = i == $tokens.len() - 1;
89-
match token {
90-
WildcardToken::QuestionMark => {
91-
if haystack_iterator.next().is_none() {
92-
return false;
93-
}
82+
fn match_tokens(haystack_iterator: impl Iterator<Item = char>, tokens: &[WildcardToken]) -> bool {
83+
let mut starmode = false;
84+
let mut haystack_iterator = haystack_iterator.peekable();
85+
86+
'outer: for (i, token) in tokens.iter().enumerate() {
87+
let is_last_token = i == tokens.len() - 1;
88+
match token {
89+
WildcardToken::QuestionMark => {
90+
if haystack_iterator.next().is_none() {
91+
return false;
9492
}
95-
WildcardToken::Pattern(p) if starmode => {
96-
starmode = false;
97-
let mut buffer: Vec<char> = vec![];
98-
99-
while let Some(haystack_char) = haystack_iterator.next() {
100-
buffer.push(haystack_char);
93+
}
94+
WildcardToken::Pattern(p) if starmode => {
95+
starmode = false;
96+
let mut buffer = Vec::with_capacity(p.len());
10197

102-
if buffer.len() > p.len() {
103-
buffer.remove(0);
104-
}
98+
while let Some(haystack_char) = haystack_iterator.next() {
99+
if buffer.len() == p.len() {
100+
buffer.remove(0);
101+
}
102+
buffer.push(haystack_char);
105103

106-
// Loop till a match is found
107-
// If we process the last token, make sure we loop till the end of the haystack
108-
if buffer == *p && (!is_last_token || haystack_iterator.peek().is_none()) {
109-
continue 'outer;
110-
}
104+
// Loop till a match is found
105+
// If we process the last token, make sure we loop till the end of the haystack
106+
if buffer == *p && (!is_last_token || haystack_iterator.peek().is_none()) {
107+
continue 'outer;
111108
}
112-
return false;
113109
}
114-
WildcardToken::Pattern(p) => {
115-
for c in p {
116-
if let Some(haystack_char) = haystack_iterator.next() {
117-
if *c != haystack_char {
118-
return false;
119-
}
120-
} else {
110+
return false;
111+
}
112+
WildcardToken::Pattern(p) => {
113+
for c in p {
114+
if let Some(haystack_char) = haystack_iterator.next() {
115+
if *c != haystack_char {
121116
return false;
122117
}
118+
} else {
119+
return false;
123120
}
124121
}
125-
WildcardToken::Star => {
126-
if is_last_token {
127-
return true;
128-
}
129-
starmode = true;
122+
}
123+
WildcardToken::Star => {
124+
if is_last_token {
125+
return true;
130126
}
127+
starmode = true;
131128
}
132129
}
130+
}
133131

134-
haystack_iterator.peek().is_none()
135-
}};
132+
haystack_iterator.peek().is_none()
136133
}
137-
138134
pub(crate) fn match_tokenized(tokens: &[WildcardToken], haystack: &str, lowercase: bool) -> bool {
139135
if lowercase {
140-
match_tokens!(haystack.chars().flat_map(|c| c.to_lowercase()), tokens)
136+
match_tokens(haystack.chars().flat_map(|c| c.to_lowercase()), tokens)
141137
} else {
142-
match_tokens!(haystack.chars(), tokens)
138+
match_tokens(haystack.chars(), tokens)
143139
}
144140
}
145141

0 commit comments

Comments
 (0)