diff --git a/src/api/sorting/plugin_sorter.cpp b/src/api/sorting/plugin_sorter.cpp index d57d2a68..c3891626 100644 --- a/src/api/sorting/plugin_sorter.cpp +++ b/src/api/sorting/plugin_sorter.cpp @@ -25,6 +25,7 @@ #include "plugin_sorter.h" #include +#include #include #include @@ -48,8 +49,6 @@ typedef boost::graph_traits::vertex_iterator vertex_it; typedef boost::graph_traits::edge_descriptor edge_t; typedef boost::graph_traits::edge_iterator edge_it; -class PathFoundException : public std::exception {}; - class CycleDetector : public boost::dfs_visitor<> { public: void tree_edge(edge_t edge, const PluginGraph& graph) { @@ -88,19 +87,6 @@ private: list trail; }; -class PathDetector : public boost::bfs_visitor<> { -public: - PathDetector(vertex_t vertex) : target(vertex) {} - - inline void discover_vertex(vertex_t vertex, const PluginGraph& graph) { - if (vertex == target) - throw PathFoundException(); - } - -private: - vertex_t target; -}; - std::vector PluginSorter::Sort(Game& game) { logger_ = getLogger(); @@ -306,14 +292,48 @@ void PluginSorter::CheckForCycles() const { bool PluginSorter::EdgeCreatesCycle(const vertex_t& fromVertex, const vertex_t& toVertex) const { - try { - boost::breadth_first_search( - graph_, - toVertex, - visitor(PathDetector(fromVertex)).vertex_index_map(vertexIndexMap_)); - } catch (PathFoundException&) { - return true; + auto start = toVertex; + auto end = fromVertex; + + std::queue forwardQueue; + std::queue reverseQueue; + std::unordered_set forwardVisited; + std::unordered_set reverseVisited; + + forwardQueue.push(start); + forwardVisited.insert(start); + reverseQueue.push(end); + reverseVisited.insert(end); + + while (!forwardQueue.empty() && !reverseQueue.empty()) { + if (!forwardQueue.empty()) { + auto v = forwardQueue.front(); + forwardQueue.pop(); + if (v == end || reverseVisited.count(v) > 0) { + return true; + } + for (auto adjacentV : boost::make_iterator_range(boost::adjacent_vertices(v, graph_))) { + if (forwardVisited.count(adjacentV) == 0) { + forwardVisited.insert(adjacentV); + forwardQueue.push(adjacentV); + } + } + } + if (!reverseQueue.empty()) { + auto v = reverseQueue.front(); + reverseQueue.pop(); + if (v == start || forwardVisited.count(v) > 0) { + return true; + } + for (auto adjacentV : boost::make_iterator_range(boost::inv_adjacent_vertices(v, graph_))) { + if (reverseVisited.count(adjacentV) == 0) { + reverseVisited.insert(adjacentV); + reverseQueue.push(adjacentV); + } + } + } } + return false; } diff --git a/src/api/sorting/plugin_sorter.h b/src/api/sorting/plugin_sorter.h index 29b8624e..46ab51cd 100644 --- a/src/api/sorting/plugin_sorter.h +++ b/src/api/sorting/plugin_sorter.h @@ -40,7 +40,7 @@ namespace loot { typedef boost::adjacency_list PluginGraph; typedef boost::graph_traits::vertex_descriptor vertex_t;