Skip to content

Commit 676be36

Browse files
committed
perf: Optimize sort_worker_results for cached key lookup (fn and ordering) - review comment
1 parent f1553f4 commit 676be36

1 file changed

Lines changed: 39 additions & 31 deletions

File tree

src/walk.rs

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::path::PathBuf;
66
use std::sync::atomic::{AtomicBool, Ordering};
77
use std::sync::{Arc, Mutex, MutexGuard};
88
use std::thread;
9-
use std::time::{Duration, Instant};
9+
use std::time::{Duration, Instant, SystemTime};
1010

1111
use anyhow::{Result, anyhow};
1212
use crossbeam_channel::{Receiver, RecvTimeoutError, SendError, Sender, bounded};
@@ -675,37 +675,45 @@ impl WorkerState {
675675
}
676676

677677
fn sort_worker_results(results: &mut [WorkerResult], sort_key: SortKey) {
678-
results.sort_by(|a, b| {
679-
// Errors sort to the end; two errors are considered equal.
680-
let (a, b) = match (a, b) {
681-
(WorkerResult::Entry(a), WorkerResult::Entry(b)) => (a, b),
682-
(WorkerResult::Error(_), WorkerResult::Entry(_)) => {
683-
return std::cmp::Ordering::Greater;
684-
}
685-
(WorkerResult::Entry(_), WorkerResult::Error(_)) => {
686-
return std::cmp::Ordering::Less;
687-
}
688-
(WorkerResult::Error(_), WorkerResult::Error(_)) => {
689-
return std::cmp::Ordering::Equal;
690-
}
691-
};
678+
// Build the key extractor once, based on sort_key.
679+
// Returns None for errors, pushing them to the end naturally via Ord on Option.
680+
let key_fn: Box<dyn Fn(&WorkerResult) -> Option<SortKeyValue>> = match sort_key {
681+
SortKey::Path => Box::new(|r| match r {
682+
WorkerResult::Entry(e) => Some(SortKeyValue::Path(e.path().to_path_buf())),
683+
WorkerResult::Error(_) => None,
684+
}),
685+
SortKey::Size => Box::new(|r| match r {
686+
WorkerResult::Entry(e) => Some(SortKeyValue::Size(
687+
e.metadata().map(|m| m.len()).unwrap_or(0),
688+
)),
689+
WorkerResult::Error(_) => None,
690+
}),
691+
SortKey::Created => Box::new(|r| match r {
692+
WorkerResult::Entry(e) => Some(SortKeyValue::Time(
693+
e.metadata().and_then(|m| m.created().ok()),
694+
)),
695+
WorkerResult::Error(_) => None,
696+
}),
697+
SortKey::Modified => Box::new(|r| match r {
698+
WorkerResult::Entry(e) => Some(SortKeyValue::Time(
699+
e.metadata().and_then(|m| m.modified().ok()),
700+
)),
701+
WorkerResult::Error(_) => None,
702+
}),
703+
};
704+
705+
// Use sort_by_cached_key to avoid recomputing the key for each comparison.
706+
results.sort_by_cached_key(|r| key_fn(r));
707+
}
692708

693-
match sort_key {
694-
SortKey::Path => a.path().cmp(b.path()),
695-
SortKey::Size => {
696-
let size = |e: &DirEntry| e.metadata().map(|m| m.len()).unwrap_or(0);
697-
size(a).cmp(&size(b))
698-
}
699-
SortKey::Created => {
700-
let time = |e: &DirEntry| e.metadata().and_then(|m| m.created().ok());
701-
time(a).cmp(&time(b))
702-
}
703-
SortKey::Modified => {
704-
let time = |e: &DirEntry| e.metadata().and_then(|m| m.modified().ok());
705-
time(a).cmp(&time(b))
706-
}
707-
}
708-
});
709+
/// Comparable key values, one variant per SortKey.
710+
/// None sorts last via Option<T: Ord>'s natural ordering (None > Some).
711+
/// Only like enum variants will be compared (e.g., Path < Size will never be compared).
712+
#[derive(Eq, PartialEq, Ord, PartialOrd)]
713+
enum SortKeyValue {
714+
Path(PathBuf),
715+
Size(u64),
716+
Time(Option<SystemTime>),
709717
}
710718

711719
fn search_str_for_entry<'a>(

0 commit comments

Comments
 (0)