mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Refactor CycleDetector to be generic across graphs
This commit is contained in:
@@ -71,47 +71,6 @@ typedef boost::adjacency_list<boost::vecS,
|
||||
typedef boost::graph_traits<GroupGraph>::vertex_descriptor vertex_t;
|
||||
typedef boost::graph_traits<GroupGraph>::edge_descriptor edge_t;
|
||||
|
||||
class CycleDetector : public boost::dfs_visitor<> {
|
||||
public:
|
||||
void tree_edge(edge_t edge, const GroupGraph& graph) {
|
||||
auto source = boost::source(edge, graph);
|
||||
|
||||
auto vertex = Vertex(graph[source].GetName(), graph[edge]);
|
||||
|
||||
// Check if the plugin already exists in the recorded trail.
|
||||
auto it = find_if(begin(trail), end(trail), [&](const Vertex& v) {
|
||||
return v.GetName() == graph[source].GetName();
|
||||
});
|
||||
|
||||
if (it != end(trail)) {
|
||||
// Erase everything from this position onwards, as it doesn't
|
||||
// contribute to a forward-cycle.
|
||||
trail.erase(it, end(trail));
|
||||
}
|
||||
|
||||
trail.push_back(vertex);
|
||||
}
|
||||
|
||||
void back_edge(edge_t edge, const GroupGraph& graph) {
|
||||
auto source = boost::source(edge, graph);
|
||||
auto target = boost::target(edge, graph);
|
||||
|
||||
auto vertex = Vertex(graph[source].GetName(), graph[edge]);
|
||||
trail.push_back(vertex);
|
||||
|
||||
auto it = find_if(begin(trail), end(trail), [&](const Vertex& v) {
|
||||
return v.GetName() == graph[target].GetName();
|
||||
});
|
||||
|
||||
if (it != trail.end()) {
|
||||
throw CyclicInteractionError(std::vector<Vertex>(it, trail.end()));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Vertex> trail;
|
||||
};
|
||||
|
||||
class AfterGroupsVisitor : public boost::dfs_visitor<> {
|
||||
public:
|
||||
AfterGroupsVisitor(std::unordered_set<std::string>& visitedGroups) :
|
||||
@@ -209,7 +168,7 @@ GetTransitiveAfterGroups(const std::unordered_set<Group>& masterlistGroups,
|
||||
if (logger) {
|
||||
logger->trace("Checking for cycles in the group graph");
|
||||
}
|
||||
boost::depth_first_search(graph, boost::visitor(CycleDetector()));
|
||||
boost::depth_first_search(graph, boost::visitor(CycleDetector<GroupGraph>()));
|
||||
|
||||
std::unordered_map<std::string, std::unordered_set<std::string>>
|
||||
transitiveAfterGroups;
|
||||
|
||||
@@ -28,7 +28,12 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/depth_first_search.hpp>
|
||||
|
||||
#include "loot/exception/cyclic_interaction_error.h"
|
||||
#include "loot/metadata/group.h"
|
||||
|
||||
namespace loot {
|
||||
@@ -36,5 +41,47 @@ namespace loot {
|
||||
std::unordered_map<std::string, std::unordered_set<std::string>>
|
||||
GetTransitiveAfterGroups(const std::unordered_set<Group>& masterlistGroups,
|
||||
const std::unordered_set<Group>& userGroups);
|
||||
|
||||
template<typename G>
|
||||
class CycleDetector : public boost::dfs_visitor<> {
|
||||
public:
|
||||
void tree_edge(typename boost::graph_traits<G>::edge_descriptor edge, const G& graph) {
|
||||
auto source = boost::source(edge, graph);
|
||||
|
||||
auto vertex = Vertex(graph[source].GetName(), graph[edge]);
|
||||
|
||||
// Check if the vertex already exists in the recorded trail.
|
||||
auto it = find_if(begin(trail), end(trail), [&](const Vertex& v) {
|
||||
return v.GetName() == graph[source].GetName();
|
||||
});
|
||||
|
||||
if (it != end(trail)) {
|
||||
// Erase everything from this position onwards, as it doesn't
|
||||
// contribute to a forward-cycle.
|
||||
trail.erase(it, end(trail));
|
||||
}
|
||||
|
||||
trail.push_back(vertex);
|
||||
}
|
||||
|
||||
void back_edge(typename boost::graph_traits<G>::edge_descriptor edge, const G& graph) {
|
||||
auto source = boost::source(edge, graph);
|
||||
auto target = boost::target(edge, graph);
|
||||
|
||||
auto vertex = Vertex(graph[source].GetName(), graph[edge]);
|
||||
trail.push_back(vertex);
|
||||
|
||||
auto it = find_if(begin(trail), end(trail), [&](const Vertex& v) {
|
||||
return v.GetName() == graph[target].GetName();
|
||||
});
|
||||
|
||||
if (it != trail.end()) {
|
||||
throw CyclicInteractionError(std::vector<Vertex>(it, trail.end()));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Vertex> trail;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -49,47 +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 CycleDetector : public boost::dfs_visitor<> {
|
||||
public:
|
||||
void tree_edge(edge_t edge, const PluginGraph& graph) {
|
||||
const vertex_t source = boost::source(edge, graph);
|
||||
|
||||
auto vertex = Vertex(graph[source].GetName(), graph[edge]);
|
||||
|
||||
// Check if the plugin already exists in the recorded trail.
|
||||
auto it = find_if(begin(trail), end(trail), [&](const Vertex& v) {
|
||||
return v.GetName() == graph[source].GetName();
|
||||
});
|
||||
|
||||
if (it != end(trail)) {
|
||||
// Erase everything from this position onwards, as it doesn't
|
||||
// contribute to a forward-cycle.
|
||||
trail.erase(it, end(trail));
|
||||
}
|
||||
|
||||
trail.push_back(vertex);
|
||||
}
|
||||
|
||||
void back_edge(edge_t edge, const PluginGraph& graph) {
|
||||
vertex_t source = boost::source(edge, graph);
|
||||
vertex_t target = boost::target(edge, graph);
|
||||
|
||||
auto vertex = Vertex(graph[source].GetName(), graph[edge]);
|
||||
trail.push_back(vertex);
|
||||
|
||||
auto it = find_if(begin(trail), end(trail), [&](const Vertex& v) {
|
||||
return v.GetName() == graph[target].GetName();
|
||||
});
|
||||
|
||||
if (it != trail.end()) {
|
||||
throw CyclicInteractionError(std::vector<Vertex>(it, trail.end()));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
vector<Vertex> trail;
|
||||
};
|
||||
|
||||
std::vector<std::string> PluginSorter::Sort(Game& game) {
|
||||
logger_ = getLogger();
|
||||
|
||||
@@ -297,7 +256,7 @@ bool PluginSorter::GetVertexByName(const std::string& name,
|
||||
|
||||
void PluginSorter::CheckForCycles() const {
|
||||
boost::depth_first_search(
|
||||
graph_, visitor(CycleDetector()).vertex_index_map(vertexIndexMap_));
|
||||
graph_, visitor(CycleDetector<PluginGraph>()).vertex_index_map(vertexIndexMap_));
|
||||
}
|
||||
|
||||
bool PluginSorter::EdgeCreatesCycle(const vertex_t& fromVertex,
|
||||
|
||||
Reference in New Issue
Block a user