上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