Skip to content

Commit adc1665

Browse files
daniel-thomclaude
andcommitted
Cache parsed timestamps in TUI Completion/Elapsed sorts
Switch the Completion (Results) and Elapsed (Running) sort arms from sort_by comparators that re-parse RFC3339 timestamps O(n log n) times to sort_by_cached_key, parsing each row once. None-last ordering and the existing sort directions are preserved, matching the name-sort pattern already used in apply_*_sort. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent f9c8b04 commit adc1665

1 file changed

Lines changed: 19 additions & 38 deletions

File tree

src/tui/app.rs

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,24 +1521,15 @@ impl App {
15211521
.results
15221522
.sort_by_key(|r| std::cmp::Reverse(r.return_code)),
15231523
ResultsSort::ReturnAsc => self.results.sort_by_key(|r| r.return_code),
1524-
ResultsSort::CompletionDesc => {
1525-
self.results
1526-
.sort_by(|a, b| match (completion_secs(a), completion_secs(b)) {
1527-
(Some(x), Some(y)) => y.cmp(&x),
1528-
(Some(_), None) => std::cmp::Ordering::Less,
1529-
(None, Some(_)) => std::cmp::Ordering::Greater,
1530-
(None, None) => std::cmp::Ordering::Equal,
1531-
});
1532-
}
1533-
ResultsSort::CompletionAsc => {
1534-
self.results
1535-
.sort_by(|a, b| match (completion_secs(a), completion_secs(b)) {
1536-
(Some(x), Some(y)) => x.cmp(&y),
1537-
(Some(_), None) => std::cmp::Ordering::Less,
1538-
(None, Some(_)) => std::cmp::Ordering::Greater,
1539-
(None, None) => std::cmp::Ordering::Equal,
1540-
});
1541-
}
1524+
// Cache the parsed timestamp per row; unparseable times sort last.
1525+
ResultsSort::CompletionDesc => self.results.sort_by_cached_key(|r| {
1526+
let secs = completion_secs(r);
1527+
(secs.is_none(), std::cmp::Reverse(secs.unwrap_or(0)))
1528+
}),
1529+
ResultsSort::CompletionAsc => self.results.sort_by_cached_key(|r| {
1530+
let secs = completion_secs(r);
1531+
(secs.is_none(), secs.unwrap_or(0))
1532+
}),
15421533
ResultsSort::PeakMemoryDesc => {
15431534
self.results
15441535
.sort_by(|a, b| match (a.peak_memory_bytes, b.peak_memory_bytes) {
@@ -1746,26 +1737,16 @@ impl App {
17461737
RunningSort::NameAsc => self
17471738
.running
17481739
.sort_by_cached_key(|j| j.job_name.to_lowercase()),
1749-
// Longest-running first: earliest start_time first. Unparseable
1750-
// start times sort last.
1751-
RunningSort::ElapsedDesc => {
1752-
self.running
1753-
.sort_by(|a, b| match (start_secs(a), start_secs(b)) {
1754-
(Some(x), Some(y)) => x.cmp(&y),
1755-
(Some(_), None) => std::cmp::Ordering::Less,
1756-
(None, Some(_)) => std::cmp::Ordering::Greater,
1757-
(None, None) => std::cmp::Ordering::Equal,
1758-
})
1759-
}
1760-
RunningSort::ElapsedAsc => {
1761-
self.running
1762-
.sort_by(|a, b| match (start_secs(a), start_secs(b)) {
1763-
(Some(x), Some(y)) => y.cmp(&x),
1764-
(Some(_), None) => std::cmp::Ordering::Less,
1765-
(None, Some(_)) => std::cmp::Ordering::Greater,
1766-
(None, None) => std::cmp::Ordering::Equal,
1767-
})
1768-
}
1740+
// Longest-running first: earliest start_time first. The parsed
1741+
// start time is cached per row; unparseable start times sort last.
1742+
RunningSort::ElapsedDesc => self.running.sort_by_cached_key(|j| {
1743+
let secs = start_secs(j);
1744+
(secs.is_none(), secs.unwrap_or(0))
1745+
}),
1746+
RunningSort::ElapsedAsc => self.running.sort_by_cached_key(|j| {
1747+
let secs = start_secs(j);
1748+
(secs.is_none(), std::cmp::Reverse(secs.unwrap_or(0)))
1749+
}),
17691750
}
17701751
}
17711752

0 commit comments

Comments
 (0)