perf(ui): dedupe time-ago + allocation-free case-insensitive filter (audit #1-3)
Per-frame hot paths in the immediate-mode UI were allocating needlessly:
- Address filtering in the balance tab rebuilt a std::string filter per address AND
containsIgnoreCase() lower-cased two fresh copies per call — ~6×N allocations/frame
on large wallets. New util::containsIgnoreCase(string_view, string_view) is
allocation-free, and the filter is now built once outside the loop.
- Four duplicated "time ago" implementations (balance_tab_helpers, balance_recent_tx,
send_tab, transactions_tab) are consolidated into util::formatTimeAgo (localized long
form) + util::formatTimeAgoShort (compact "5s ago"), preserving each call site's exact
display style. Both use snprintf, no per-row string concatenation.
- The send-tab address-suggestion scan (a walk over the whole tx list) is memoized on the
typed text + tx count, so it no longer recomputes every frame while the user pauses.
New src/util/text_format.{h,cpp}; the two existing containsIgnoreCase/timeAgo definitions
now delegate to it. Added to both the app and test targets (test target also gains i18n.cpp,
which text_format's localized path needs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include "../../config/version.h"
|
||||
#include "../../embedded/IconsMaterialDesign.h"
|
||||
#include "../../util/i18n.h"
|
||||
#include "../../util/text_format.h"
|
||||
#include "../material/colors.h"
|
||||
#include "../material/type.h"
|
||||
|
||||
@@ -22,26 +23,15 @@ std::string TrId(const char* trKey, const char* id)
|
||||
return value;
|
||||
}
|
||||
|
||||
// Thin wrappers over the shared, allocation-free helpers (kept for existing call sites).
|
||||
bool containsIgnoreCase(const std::string& value, const std::string& search)
|
||||
{
|
||||
if (search.empty()) return true;
|
||||
std::string haystack = value;
|
||||
std::string needle = search;
|
||||
std::transform(haystack.begin(), haystack.end(), haystack.begin(), ::tolower);
|
||||
std::transform(needle.begin(), needle.end(), needle.begin(), ::tolower);
|
||||
return haystack.find(needle) != std::string::npos;
|
||||
return util::containsIgnoreCase(value, search);
|
||||
}
|
||||
|
||||
std::string timeAgo(int64_t timestamp)
|
||||
{
|
||||
if (timestamp <= 0) return "";
|
||||
int64_t now = static_cast<int64_t>(std::time(nullptr));
|
||||
int64_t diff = now - timestamp;
|
||||
if (diff < 0) diff = 0;
|
||||
if (diff < 60) return std::to_string(diff) + "s ago";
|
||||
if (diff < 3600) return std::to_string(diff / 60) + "m ago";
|
||||
if (diff < 86400) return std::to_string(diff / 3600) + "h ago";
|
||||
return std::to_string(diff / 86400) + "d ago";
|
||||
return util::formatTimeAgoShort(timestamp);
|
||||
}
|
||||
|
||||
std::string truncateAddress(const std::string& address, int maxLen)
|
||||
|
||||
Reference in New Issue
Block a user