From 1263e20bae345ca8521c792d98237d8eabae6e6e Mon Sep 17 00:00:00 2001 From: Crementif <26669564+Crementif@users.noreply.github.com> Date: Sat, 16 May 2026 14:08:48 +0200 Subject: [PATCH] debugger: make symbol list virtualized --- src/gui/wxgui/debugger/SymbolCtrl.cpp | 98 ++++++++++++--------------- src/gui/wxgui/debugger/SymbolCtrl.h | 15 ++-- 2 files changed, 50 insertions(+), 63 deletions(-) diff --git a/src/gui/wxgui/debugger/SymbolCtrl.cpp b/src/gui/wxgui/debugger/SymbolCtrl.cpp index 77f55529..533b259e 100644 --- a/src/gui/wxgui/debugger/SymbolCtrl.cpp +++ b/src/gui/wxgui/debugger/SymbolCtrl.cpp @@ -38,13 +38,12 @@ SymbolListCtrl::SymbolListCtrl(wxWindow* parent, const wxWindowID& id, const wxP m_list_filter.Clear(); OnGameLoaded(); - - SetItemCount(m_data.size()); } void SymbolListCtrl::OnGameLoaded() { m_data.clear(); + m_visible_items.clear(); const auto symbol_map = rplSymbolStorage_lockSymbolMap(); for (auto const& [address, symbol_info] : symbol_map) { @@ -56,48 +55,30 @@ void SymbolListCtrl::OnGameLoaded() wxString searchNameWX = libNameWX + symbolNameWX; searchNameWX.MakeLower(); - auto new_entry = m_data.try_emplace( - symbol_info->address, - symbolNameWX, + m_data.try_emplace( + address, + symbolNameWX, libNameWX, - searchNameWX, - false + searchNameWX ); - - if (m_list_filter.IsEmpty()) - new_entry.first->second.visible = true; - else if (new_entry.first->second.searchName.Contains(m_list_filter)) - new_entry.first->second.visible = true; } rplSymbolStorage_unlockSymbolMap(); - SetItemCount(m_data.size()); - if (m_data.size() > 0) - RefreshItems(GetTopItem(), std::min(m_data.size() - 1, GetTopItem() + GetCountPerPage() + 1)); + RebuildVisibleItems(); } wxString SymbolListCtrl::OnGetItemText(long item, long column) const { - if (item >= GetItemCount()) + if (item < 0 || item >= static_cast(m_visible_items.size())) return wxEmptyString; - long visible_idx = 0; - for (const auto& [address, symbol] : m_data) - { - if (!symbol.visible) - continue; - - if (item == visible_idx) - { - if (column == ColumnName) - return wxString(symbol.name); - if (column == ColumnAddress) - return wxString::Format("%08x", address); - if (column == ColumnModule) - return wxString(symbol.libName); - } - visible_idx++; - } + const auto& [address, symbol] = *m_visible_items[item]; + if (column == ColumnName) + return symbol.name; + if (column == ColumnAddress) + return wxString::Format("%08x", address); + if (column == ColumnModule) + return symbol.libName; return wxEmptyString; } @@ -106,10 +87,9 @@ wxString SymbolListCtrl::OnGetItemText(long item, long column) const void SymbolListCtrl::OnLeftDClick(wxListEvent& event) { long selected = GetFirstSelected(); - if (selected == wxNOT_FOUND) + if (selected == wxNOT_FOUND || selected >= static_cast(m_visible_items.size())) return; - const auto text = GetItemText(selected, ColumnAddress); - const auto address = std::stoul(text.ToStdString(), nullptr, 16); + const auto address = m_visible_items[selected]->first; if (address == 0) return; debugger_jumpToAddressInDisasm(address); @@ -118,10 +98,9 @@ void SymbolListCtrl::OnLeftDClick(wxListEvent& event) void SymbolListCtrl::OnRightClick(wxListEvent& event) { long selected = GetFirstSelected(); - if (selected == wxNOT_FOUND) + if (selected == wxNOT_FOUND || selected >= static_cast(m_visible_items.size())) return; - auto text = GetItemText(selected, ColumnAddress); - text = "0x" + text; + auto text = wxString::Format("0x%08x", m_visible_items[selected]->first); #if BOOST_OS_WINDOWS if (OpenClipboard(nullptr)) { @@ -140,24 +119,31 @@ void SymbolListCtrl::OnRightClick(wxListEvent& event) #endif } +void SymbolListCtrl::RebuildVisibleItems() +{ + m_visible_items.clear(); + m_visible_items.reserve(m_data.size()); + const bool has_filter = !m_list_filter.IsEmpty(); + for (auto it = m_data.cbegin(); it != m_data.cend(); ++it) + { + if (has_filter && !it->second.searchName.Contains(m_list_filter)) + continue; + + m_visible_items.emplace_back(it); + } + + SetItemCount(static_cast(m_visible_items.size())); + if (!m_visible_items.empty()) + { + const auto top_item = std::min(GetTopItem(), static_cast(m_visible_items.size() - 1)); + RefreshItems(top_item, std::min(static_cast(m_visible_items.size() - 1), top_item + GetCountPerPage() + 1)); + } + else + Refresh(); +} + void SymbolListCtrl::ChangeListFilter(wxString filter) { m_list_filter = filter.MakeLower(); - - size_t visible_entries = m_data.size(); - for (auto& [address, symbol] : m_data) - { - if (m_list_filter.IsEmpty()) - symbol.visible = true; - else if (symbol.searchName.Contains(m_list_filter)) - symbol.visible = true; - else - { - visible_entries--; - symbol.visible = false; - } - } - SetItemCount(visible_entries); - if (visible_entries > 0) - RefreshItems(GetTopItem(), std::min(visible_entries - 1, GetTopItem() + GetCountPerPage() + 1)); + RebuildVisibleItems(); } diff --git a/src/gui/wxgui/debugger/SymbolCtrl.h b/src/gui/wxgui/debugger/SymbolCtrl.h index cb592ee7..938361c0 100644 --- a/src/gui/wxgui/debugger/SymbolCtrl.h +++ b/src/gui/wxgui/debugger/SymbolCtrl.h @@ -10,22 +10,23 @@ public: void ChangeListFilter(wxString filter); - private: +private: struct SymbolItem { - SymbolItem() = default; - SymbolItem(wxString name, wxString libName, wxString searchName, bool visible) : name(name), libName(libName), searchName(searchName), visible(visible) {} - + SymbolItem() = default; + SymbolItem(const wxString& name, const wxString& libName, const wxString& searchName) : name(name), libName(libName), searchName(searchName) {} wxString name; wxString libName; wxString searchName; - bool visible; }; + using SymbolMap = std::map; - std::map m_data; + SymbolMap m_data; wxString m_list_filter; + std::vector m_visible_items; - wxString OnGetItemText(long item, long column) const; + wxString OnGetItemText(long item, long column) const override; + void RebuildVisibleItems(); void OnLeftDClick(wxListEvent& event); void OnRightClick(wxListEvent& event); };