diff --git a/src/api/sorting/plugin_sorter.cpp b/src/api/sorting/plugin_sorter.cpp index 22f1a22b..fa31b517 100644 --- a/src/api/sorting/plugin_sorter.cpp +++ b/src/api/sorting/plugin_sorter.cpp @@ -83,6 +83,7 @@ std::vector PluginSorter::Sort(Game& game) { // Clear existing data. graph_.clear(); indexMap_.clear(); + pathsCache_.clear(); AddPluginVertices(game); @@ -264,7 +265,11 @@ void PluginSorter::CheckForCycles() const { } bool PluginSorter::EdgeCreatesCycle(const vertex_t& fromVertex, - const vertex_t& toVertex) const { + const vertex_t& toVertex) { + if (pathsCache_.count(GraphPath(toVertex, fromVertex)) != 0) { + return true; + } + auto start = toVertex; auto end = fromVertex; @@ -288,6 +293,8 @@ bool PluginSorter::EdgeCreatesCycle(const vertex_t& fromVertex, for (auto adjacentV : boost::make_iterator_range(boost::adjacent_vertices(v, graph_))) { if (forwardVisited.count(adjacentV) == 0) { + pathsCache_.insert(GraphPath(start, adjacentV)); + forwardVisited.insert(adjacentV); forwardQueue.push(adjacentV); } @@ -302,6 +309,8 @@ bool PluginSorter::EdgeCreatesCycle(const vertex_t& fromVertex, for (auto adjacentV : boost::make_iterator_range( boost::inv_adjacent_vertices(v, graph_))) { if (reverseVisited.count(adjacentV) == 0) { + pathsCache_.insert(GraphPath(adjacentV, end)); + reverseVisited.insert(adjacentV); reverseQueue.push(adjacentV); } @@ -315,16 +324,21 @@ bool PluginSorter::EdgeCreatesCycle(const vertex_t& fromVertex, void PluginSorter::AddEdge(const vertex_t& fromVertex, const vertex_t& toVertex, EdgeType edgeType) { - if (!boost::edge(fromVertex, toVertex, graph_).second) { - if (logger_) { - logger_->trace("Adding {} edge from \"{}\" to \"{}\".", - describeEdgeType(edgeType), - graph_[fromVertex].GetName(), - graph_[toVertex].GetName()); - } + auto graphPath = GraphPath(fromVertex, toVertex); - boost::add_edge(fromVertex, toVertex, edgeType, graph_); + if (pathsCache_.count(graphPath) != 0) { + return; } + + if (logger_) { + logger_->trace("Adding {} edge from \"{}\" to \"{}\".", + describeEdgeType(edgeType), + graph_[fromVertex].GetName(), + graph_[toVertex].GetName()); + } + + boost::add_edge(fromVertex, toVertex, edgeType, graph_); + pathsCache_.insert(graphPath); } void PluginSorter::AddHardcodedPluginEdges(Game& game) { diff --git a/src/api/sorting/plugin_sorter.h b/src/api/sorting/plugin_sorter.h index 5946a73d..be234679 100644 --- a/src/api/sorting/plugin_sorter.h +++ b/src/api/sorting/plugin_sorter.h @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -51,6 +52,32 @@ typedef boost::associative_property_map> std::string describeEdgeType(EdgeType edgeType); +struct GraphPath { + GraphPath(vertex_t from, vertex_t to) : from(from), to(to) {} + + bool operator==(const GraphPath& rhs) const { + return this->from == rhs.from && this->to == rhs.to; + } + + vertex_t from; + vertex_t to; +}; +} + +namespace std { +template<> +struct hash { + size_t operator()(const loot::GraphPath& graphPath) const { + size_t seed = 0; + boost::hash_combine(seed, graphPath.from); + boost::hash_combine(seed, graphPath.to); + + return seed; + } +}; +} + +namespace loot { class PluginSorter { public: std::vector Sort(Game& game); @@ -58,7 +85,7 @@ public: private: std::optional GetVertexByName(const std::string& name) const; void CheckForCycles() const; - bool EdgeCreatesCycle(const vertex_t& u, const vertex_t& v) const; + bool EdgeCreatesCycle(const vertex_t& u, const vertex_t& v); void AddPluginVertices(Game& game); void AddSpecificEdges(); @@ -76,6 +103,8 @@ private: vertex_map_t vertexIndexMap_; std::shared_ptr logger_; std::unordered_set groups_; + + std::unordered_set pathsCache_; }; }