diff --git a/src/backend/graph.cpp b/src/backend/graph.cpp index 63e92015..7b40e1c9 100644 --- a/src/backend/graph.cpp +++ b/src/backend/graph.cpp @@ -163,4 +163,104 @@ namespace boss { boss::cycle_detector vis; boost::depth_first_search(graph, visitor(vis).vertex_index_map(v_index_map)); } + + void AddNonOverlapEdges(PluginGraph& graph) { + //First find the position of the first non-master. + boss::vertex_it vitFirstNonMaster, vit, vitend; + for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) { + if (!graph[*vit]->IsMaster()) { + vitFirstNonMaster = vit; + break; + } + } + + //Now add edges for all relationships that aren't overlaps. + for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) { + vertex_t parentVertex; + + BOOST_LOG_TRIVIAL(trace) << "Adding non-overlap in-edges to vertex for \"" << graph[*vit]->Name() << "\"."; + + if (graph[*vit]->IsMaster()) { + BOOST_LOG_TRIVIAL(trace) << "Adding out-edges for non-master plugins."; + + for (boss::vertex_it vit2 = vitFirstNonMaster; vit2 != vitend; ++vit2) { + BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[*vit]->Name() << "\" to \"" << graph[*vit2]->Name() << "\"."; + + if (!boost::edge(*vit, *vit2, graph).second) //To avoid duplicates (helps visualisation). + boost::add_edge(*vit, *vit2, graph); + } + } + + BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for masters."; + vector strVec(graph[*vit]->Masters()); + for (vector::const_iterator it=strVec.begin(), itend=strVec.end(); it != itend; ++it) { + if (boss::GetVertexByName(graph, *it, parentVertex) && + !boost::edge(parentVertex, *vit, graph).second) { + + BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\"."; + + boost::add_edge(parentVertex, *vit, graph); + } + } + BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for requirements."; + set fileset(graph[*vit]->Reqs()); + for (set::const_iterator it=fileset.begin(), itend=fileset.end(); it != itend; ++it) { + if (boss::IsPlugin(it->Name()) && + boss::GetVertexByName(graph, it->Name(), parentVertex) && + !boost::edge(parentVertex, *vit, graph).second) { + + BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\"."; + + boost::add_edge(parentVertex, *vit, graph); + } + } + + BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for 'load after's."; + fileset = graph[*vit]->LoadAfter(); + for (set::const_iterator it=fileset.begin(), itend=fileset.end(); it != itend; ++it) { + if (boss::IsPlugin(it->Name()) && + boss::GetVertexByName(graph, it->Name(), parentVertex) && + !boost::edge(parentVertex, *vit, graph).second) { + + BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\"."; + + boost::add_edge(parentVertex, *vit, graph); + } + } + } + } + + void AddOverlapEdges(PluginGraph& graph, const boost::unordered_map< std::string, std::vector >& overlapMap) { + boss::vertex_it vit, vitend; + + for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) { + vertex_t parentVertex; + + BOOST_LOG_TRIVIAL(trace) << "Adding overlap in-edges to vertex for \"" << graph[*vit]->Name() << "\"."; + + + //Now add any overlaps, except where an edge already exists between the two plugins, going the other way, since overlap-based edges have the lowest priority and are not a candidate for causing cyclic loop errors. + boost::unordered_map< string, vector >::const_iterator overlapIt = overlapMap.find(graph[*vit]->Name()); + if (overlapIt != overlapMap.end()) { + for (vector::const_iterator it=overlapIt->second.begin(), itend=overlapIt->second.end(); it != itend; ++it) { + if (boss::GetVertexByName(graph, *it, parentVertex) && + !boost::edge(*vit, parentVertex, graph).second && + !boost::edge(parentVertex, *vit, graph).second) { //No edge going the other way, OK to add this edge. + + BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\"."; + + boost::add_edge(parentVertex, *vit, graph); + } + } + } + } + } + + void ClearEdges(PluginGraph& graph) { + + edge_it it, itend; + for (boost::tie(it, itend) = boost::edges(graph); it != itend; ++it) { + boost::remove_edge(*it, graph); + } + } } diff --git a/src/backend/graph.h b/src/backend/graph.h index cacc5ec8..4c7e97e7 100644 --- a/src/backend/graph.h +++ b/src/backend/graph.h @@ -39,6 +39,7 @@ namespace boss { typedef boost::graph_traits::vertex_descriptor vertex_t; typedef boost::graph_traits::vertex_iterator vertex_it; typedef boost::graph_traits::edge_descriptor edge_t; + typedef boost::graph_traits::edge_iterator edge_it; struct cycle_detector : public boost::dfs_visitor<> { inline cycle_detector() { } @@ -63,7 +64,13 @@ namespace boss { void Sort(const PluginGraph& graph, std::list& plugins); - void CheckForCycles(const PluginGraph& graph); + void CheckForCycles(const PluginGraph& graph); + + void AddNonOverlapEdges(PluginGraph& graph); + + void AddOverlapEdges(PluginGraph& graph, const boost::unordered_map< std::string, std::vector >& overlapMap); + + void ClearEdges(PluginGraph& graph); } #endif diff --git a/src/gui/main.cpp b/src/gui/main.cpp index abf7a114..c6825448 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -624,90 +624,10 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { boost::add_vertex(it, graph); } - //Vertices are numbered from 0 to (N - 1), where N is the number of vertices in the graph. A plugin's vertex number is therefore the same as its position in the list, and this can be used to create edges between plugins. + AddNonOverlapEdges(graph); + AddOverlapEdges(graph, overlapMap); - boss::vertex_it vitFirstNonMaster, vit, vitend; - for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) { - if (!graph[*vit]->IsMaster()) { - vitFirstNonMaster = vit; - break; - } - } - - for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) { - vertex_t parentVertex; - - BOOST_LOG_TRIVIAL(trace) << "Adding edges to vertex for \"" << graph[*vit]->Name() << "\"."; - - if (graph[*vit]->IsMaster()) { - BOOST_LOG_TRIVIAL(trace) << "Adding out-edges for non-master plugins."; - - for (boss::vertex_it vit2 = vitFirstNonMaster; vit2 != vitend; ++vit2) { - BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[*vit]->Name() << "\" to \"" << graph[*vit2]->Name() << "\"."; - - if (!boost::edge(*vit, *vit2, graph).second) //To avoid duplicates (helps visualisation). - boost::add_edge(*vit, *vit2, graph); - } - } - - BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for masters."; - vector strVec(graph[*vit]->Masters()); - for (vector::const_iterator it=strVec.begin(), itend=strVec.end(); it != itend; ++it) { - if (boss::GetVertexByName(graph, *it, parentVertex) && - !boost::edge(parentVertex, *vit, graph).second) { - - BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\"."; - - boost::add_edge(parentVertex, *vit, graph); - } - } - BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for requirements."; - set fileset(graph[*vit]->Reqs()); - for (set::const_iterator it=fileset.begin(), itend=fileset.end(); it != itend; ++it) { - if (boss::IsPlugin(it->Name()) && - boss::GetVertexByName(graph, it->Name(), parentVertex) && - !boost::edge(parentVertex, *vit, graph).second) { - - BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\"."; - - boost::add_edge(parentVertex, *vit, graph); - } - } - - BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for 'load after's."; - fileset = graph[*vit]->LoadAfter(); - for (set::const_iterator it=fileset.begin(), itend=fileset.end(); it != itend; ++it) { - if (boss::IsPlugin(it->Name()) && - boss::GetVertexByName(graph, it->Name(), parentVertex) && - !boost::edge(parentVertex, *vit, graph).second) { - - BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\"."; - - boost::add_edge(parentVertex, *vit, graph); - } - } - - - //Now add any overlaps, except where an edge already exists between the two plugins, going the other way, since overlap-based edges have the lowest priority and are not a candidate for causing cyclic loop errors. - BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for overlaps."; - boost::unordered_map< string, vector >::const_iterator overlapIt = overlapMap.find(graph[*vit]->Name()); - if (overlapIt != overlapMap.end()) { - for (vector::const_iterator it=overlapIt->second.begin(), itend=overlapIt->second.end(); it != itend; ++it) { - if (boss::GetVertexByName(graph, *it, parentVertex) && - !boost::edge(*vit, parentVertex, graph).second) { //No edge going the other way, OK to add this edge. - - BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\"."; - - boost::add_edge(parentVertex, *vit, graph); - } - } - } - - progDia->Pulse(); - - } - //Just for fun - output the graph as a ".dot" file for external rendering. If I can get this pretty, I might add it to a tab in the BOSS Report - here's a few Javascript libraries for displaying .dot files, but in my test case the graph is too complex and both libraries I found ran out of memory. //The .dot file can be converted to an SVG using Graphviz: the command is `dot -Tsvg output.dot -o output.svg`. if (fs::exists(g_path_graphvis)) {