perf(history): group transaction rows by txid once per change
The History tab built a txid-to-indices map twice when its inputs changed, once for the summary-card totals and once for the display list, each a full pass over every transaction with string-keyed hashing. - The rows are now grouped by txid a single time whenever the transaction list changes, into an index-only structure (first/next chains with no string copies), and both the summary pass and the display pass reuse it. A sort-combo change re-sorts without regrouping. Adds a pure, unit-testable groupByTxid helper in transactions_tab_helpers.h. Tests: the chains match a reference map over a random id stream, and the empty and single-row cases. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
// DragonX Wallet - ImGui Edition
|
||||
// Copyright 2024-2026 The Hush Developers
|
||||
// Released under the GPLv3
|
||||
#pragma once
|
||||
// Pure helpers behind the History tab (no ImGui), so they can be unit-tested.
|
||||
#include "../../data/wallet_state.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace dragonx {
|
||||
namespace ui {
|
||||
namespace history {
|
||||
|
||||
// Rows of one txid chained in ascending index order. first[i] = lowest index sharing tx i's txid;
|
||||
// next[i] = next higher index with the same txid, or -1. Holds indices only (no string copies, no
|
||||
// pointers into the list), so it stays valid for as long as the list is unchanged (same tx_revision).
|
||||
struct TxidGroups {
|
||||
std::vector<int> first;
|
||||
std::vector<int> next;
|
||||
bool hasSiblings(std::size_t i) const { return next[static_cast<std::size_t>(first[i])] >= 0; }
|
||||
};
|
||||
|
||||
inline TxidGroups groupByTxid(const std::vector<TransactionInfo>& txs)
|
||||
{
|
||||
TxidGroups g;
|
||||
const std::size_t n = txs.size();
|
||||
g.first.assign(n, -1);
|
||||
g.next.assign(n, -1);
|
||||
std::unordered_map<std::string_view, int> last; // txid (view into txs) -> last index seen
|
||||
last.reserve(n);
|
||||
for (std::size_t i = 0; i < n; ++i) {
|
||||
auto ins = last.try_emplace(std::string_view(txs[i].txid), static_cast<int>(i));
|
||||
if (ins.second) {
|
||||
g.first[i] = static_cast<int>(i);
|
||||
} else {
|
||||
g.first[i] = g.first[static_cast<std::size_t>(ins.first->second)];
|
||||
g.next[static_cast<std::size_t>(ins.first->second)] = static_cast<int>(i);
|
||||
ins.first->second = static_cast<int>(i);
|
||||
}
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
} // namespace history
|
||||
} // namespace ui
|
||||
} // namespace dragonx
|
||||
Reference in New Issue
Block a user