mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Improve performance of checking if an edge would cause a cycle
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include "plugin_sorter.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <queue>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/graph/breadth_first_search.hpp>
|
||||
@@ -48,8 +49,6 @@ typedef boost::graph_traits<PluginGraph>::vertex_iterator vertex_it;
|
||||
typedef boost::graph_traits<PluginGraph>::edge_descriptor edge_t;
|
||||
typedef boost::graph_traits<PluginGraph>::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<string> 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<std::string> 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<vertex_t> forwardQueue;
|
||||
std::queue<vertex_t> reverseQueue;
|
||||
std::unordered_set<vertex_t> forwardVisited;
|
||||
std::unordered_set<vertex_t> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
namespace loot {
|
||||
typedef boost::adjacency_list<boost::listS,
|
||||
boost::listS,
|
||||
boost::directedS,
|
||||
boost::bidirectionalS,
|
||||
PluginSortingData>
|
||||
PluginGraph;
|
||||
typedef boost::graph_traits<PluginGraph>::vertex_descriptor vertex_t;
|
||||
|
||||
Reference in New Issue
Block a user