上Shepmaster的最终解决方案,这显著开销降低(由倍〜1.5)的改进,是
fn foo(line: &str, pattern: &str) -> bool {
let pattern_len = pattern.chars().count();
let starts = line.char_indices().map(|(i, _)| i);
let mut ends = line.char_indices().map(|(i, _)| i);
// Itertools::dropping
if pattern_len != 0 { ends.nth(pattern_len - 1); }
for (start, end) in starts.zip(ends.chain(Some(line.len()))) {
let bar = &line[start..end];
if bar == pattern { return true }
}
false
}
这就是说,从GitHub的页面代码是有点奇怪。例如,您尝试处理不同长度的打开和关闭标签与wordier版本的
let length = cmp::max(comment.len(), comment_end.len());
但你的支票,然后
if window.contains(comment)
可能引发多次!
更好的办法是迭代缩小的切片。在小例子,这将是
fn foo(line: &str, pattern: &str) -> bool {
let mut chars = line.chars();
loop {
let bar = chars.as_str();
if bar.starts_with(pattern) { return true }
if chars.next().is_none() { break }
}
false
}
(请注意,这由〜1.5的另一个因素再次结束了再次提高了性能。)
,并在更大的例子,这会是这样的
let mut is_in_comments = 0u64;
let start = match line.find(comment) {
Some(start) => start,
None => return false,
};
let end = match line.rfind(comment_end) {
Some(end) => end,
None => return true,
};
let mut chars = line[start..end + comment_end.len()].chars();
loop {
let window = chars.as_str();
if window.starts_with(comment) {
if nested {
is_in_comments += 1;
} else {
is_in_comments = 1;
}
} else if window.starts_with(comment_end) {
is_in_comments = is_in_comments.saturating_sub(1);
}
if chars.next().is_none() { break }
}
请注意,这仍然会计算重叠,因此/*/
可能会计为开头/*
,紧接着是关闭*/
。
要清楚,您的性能测试已将所包含代码的特定部分的性能问题隔离开来了吗? – Shepmaster
在我的机器上,调用方法(固定编译并使用基本相等检查代替注释)需要4.7秒,其中'line'是100MiB的“a”,后跟一个“b”,“match”是“ab “(这一次包括构建该字符串的时间)。你在寻找什么样的时间/表现? – Shepmaster
@Shepmaster固定。而实际的非MWE是https://github.com/Aaronepower/tokei/blob/master/src/lib/utils/fs.rs#L18,我已经通过对巨大的源代码树(例如Linux )。 – Aaronepower