mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-12 11:37:42 +00:00
Convert actions storage to unordered_map
Enhance action lookup efficiency by switching from a vector to an unordered_map, allowing faster access by action ID.
This commit is contained in:
@@ -75,18 +75,14 @@ void ActionRegistry::upsert(std::shared_ptr<AppAction> action)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
seed_state(*action);
|
seed_state(*action);
|
||||||
auto existing = std::find_if(m_actions.begin(), m_actions.end(),
|
std::string id = action->id;
|
||||||
[&](const auto& current) { return current->id == action->id; });
|
m_actions.insert_or_assign(std::move(id), std::move(action));
|
||||||
if (existing == m_actions.end())
|
|
||||||
m_actions.push_back(std::move(action));
|
|
||||||
else
|
|
||||||
*existing = std::move(action);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActionRegistry::remove(const std::string& id)
|
void ActionRegistry::remove(const std::string& id)
|
||||||
{
|
{
|
||||||
assert(wxThread::IsMain());
|
assert(wxThread::IsMain());
|
||||||
erase_id(id);
|
m_actions.erase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActionRegistry::seed_state(AppAction& a) const
|
void ActionRegistry::seed_state(AppAction& a) const
|
||||||
@@ -110,8 +106,8 @@ void ActionRegistry::seed_state(AppAction& a) const
|
|||||||
const AppAction* ActionRegistry::by_id(const std::string& id) const
|
const AppAction* ActionRegistry::by_id(const std::string& id) const
|
||||||
{
|
{
|
||||||
assert(wxThread::IsMain());
|
assert(wxThread::IsMain());
|
||||||
auto it = std::find_if(m_actions.begin(), m_actions.end(), [&](const auto& a) { return a->id == id; });
|
auto it = m_actions.find(id);
|
||||||
return it == m_actions.end() ? nullptr : it->get();
|
return it == m_actions.end() ? nullptr : it->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
AppAction* ActionRegistry::find(const std::string& id)
|
AppAction* ActionRegistry::find(const std::string& id)
|
||||||
@@ -119,25 +115,18 @@ AppAction* ActionRegistry::find(const std::string& id)
|
|||||||
return const_cast<AppAction*>(by_id(id));
|
return const_cast<AppAction*>(by_id(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActionRegistry::erase_id(const std::string& id)
|
|
||||||
{
|
|
||||||
m_actions.erase(std::remove_if(m_actions.begin(), m_actions.end(),
|
|
||||||
[&](const auto& a) { return a->id == id; }),
|
|
||||||
m_actions.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- dispatch + write-through ----------------------------------------------
|
// ---- dispatch + write-through ----------------------------------------------
|
||||||
|
|
||||||
AppActionRunResult ActionRegistry::run(const std::string& id)
|
AppActionRunResult ActionRegistry::run(const std::string& id)
|
||||||
{
|
{
|
||||||
assert(wxThread::IsMain());
|
assert(wxThread::IsMain());
|
||||||
auto it = std::find_if(m_actions.begin(), m_actions.end(), [&](const auto& e) { return e->id == id; });
|
auto it = m_actions.find(id);
|
||||||
if (it == m_actions.end())
|
if (it == m_actions.end())
|
||||||
return {}; // default Info, empty message
|
return {}; // default Info, empty message
|
||||||
// why: hold a shared_ptr keep-alive, never a bare vector element. A runner may pump
|
// why: hold a shared_ptr keep-alive, never a bare map entry. A runner may pump a
|
||||||
// a nested event loop; a queued source refresh can erase this action from m_actions,
|
// nested event loop; a queued source refresh can erase the entry while the
|
||||||
// while the keep-alive preserves the object until run returns.
|
// keep-alive preserves the action until run returns.
|
||||||
std::shared_ptr<AppAction> keep = *it;
|
std::shared_ptr<AppAction> keep = it->second;
|
||||||
AppActionRunResult o = keep->run();
|
AppActionRunResult o = keep->run();
|
||||||
if (o.level == AppActionRunResult::Level::Busy)
|
if (o.level == AppActionRunResult::Level::Busy)
|
||||||
return o;
|
return o;
|
||||||
@@ -210,16 +199,20 @@ nlohmann::json ActionRegistry::snapshot() const
|
|||||||
assert(wxThread::IsMain());
|
assert(wxThread::IsMain());
|
||||||
std::vector<const AppAction*> sorted;
|
std::vector<const AppAction*> sorted;
|
||||||
sorted.reserve(m_actions.size());
|
sorted.reserve(m_actions.size());
|
||||||
for (const auto& a : m_actions)
|
for (const auto& entry : m_actions)
|
||||||
sorted.push_back(a.get());
|
sorted.push_back(entry.second.get());
|
||||||
|
|
||||||
const long long now = (long long) std::time(nullptr);
|
const long long now = (long long) std::time(nullptr);
|
||||||
std::stable_sort(sorted.begin(), sorted.end(), [&](const AppAction* a, const AppAction* b) {
|
std::sort(sorted.begin(), sorted.end(), [&](const AppAction* a, const AppAction* b) {
|
||||||
double sa = frecency_score(a->count, a->last, now);
|
double sa = frecency_score(a->count, a->last, now);
|
||||||
double sb = frecency_score(b->count, b->last, now);
|
double sb = frecency_score(b->count, b->last, now);
|
||||||
if (sa != sb)
|
if (sa != sb)
|
||||||
return sa > sb;
|
return sa > sb;
|
||||||
return a->title < b->title; // ties alphabetical
|
if (a->title != b->title)
|
||||||
|
return a->title < b->title;
|
||||||
|
if (a->source != b->source)
|
||||||
|
return a->source < b->source;
|
||||||
|
return a->id < b->id;
|
||||||
});
|
});
|
||||||
|
|
||||||
nlohmann::json actions = nlohmann::json::array();
|
nlohmann::json actions = nlohmann::json::array();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -81,7 +82,6 @@ public:
|
|||||||
void remove(const std::string& id);
|
void remove(const std::string& id);
|
||||||
|
|
||||||
// Always-clean read surface. UI thread only.
|
// Always-clean read surface. UI thread only.
|
||||||
const std::vector<std::shared_ptr<AppAction>>& all() const { assert(wxThread::IsMain()); return m_actions; }
|
|
||||||
const AppAction* by_id(const std::string& id) const;
|
const AppAction* by_id(const std::string& id) const;
|
||||||
|
|
||||||
// Dispatch + write-through (registry is the only thing that touches AppConfig).
|
// Dispatch + write-through (registry is the only thing that touches AppConfig).
|
||||||
@@ -99,15 +99,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
void seed_state(AppAction& a) const; // favourite/stats from config
|
void seed_state(AppAction& a) const; // favourite/stats from config
|
||||||
AppAction* find(const std::string& id);
|
AppAction* find(const std::string& id);
|
||||||
void erase_id(const std::string& id);
|
|
||||||
|
|
||||||
// why: vector storage favors the popup path, which snapshots by iterating, sorting, and
|
|
||||||
// serializing small action sets. Id lookups are event-driven and initialization is startup-only, so
|
|
||||||
// a persistent map would add hashing/allocation cost without helping render.
|
|
||||||
// shared_ptr: AppAction is abstract (stored by pointer), and run() takes a keep-alive
|
|
||||||
// copy so a queued source refresh cannot erase the object mid-run.
|
|
||||||
std::vector<std::unique_ptr<IActionSource>> m_sources;
|
std::vector<std::unique_ptr<IActionSource>> m_sources;
|
||||||
std::vector<std::shared_ptr<AppAction>> m_actions; // UI-thread confined; no lock
|
std::unordered_map<std::string, std::shared_ptr<AppAction>> m_actions; // UI-thread confined; no lock
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace Slic3r::GUI
|
}} // namespace Slic3r::GUI
|
||||||
|
|||||||
Reference in New Issue
Block a user