williamr@2: //======================================================================= williamr@2: // Copyright 2001 University of Notre Dame. williamr@2: // Copyright 2003 Jeremy Siek williamr@2: // Authors: Lie-Quan Lee and Jeremy Siek williamr@2: // williamr@2: // Distributed under the Boost Software License, Version 1.0. (See williamr@2: // accompanying file LICENSE_1_0.txt or copy at williamr@2: // http://www.boost.org/LICENSE_1_0.txt) williamr@2: //======================================================================= williamr@2: #ifndef BOOST_GRAPHVIZ_HPP williamr@2: #define BOOST_GRAPHVIZ_HPP williamr@2: williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include // for FILE williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: #ifdef BOOST_HAS_DECLSPEC williamr@2: # if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_GRAPH_DYN_LINK) williamr@2: # ifdef BOOST_GRAPH_SOURCE williamr@2: # define BOOST_GRAPH_DECL __declspec(dllexport) williamr@2: # else williamr@2: # define BOOST_GRAPH_DECL __declspec(dllimport) williamr@2: # endif // BOOST_GRAPH_SOURCE williamr@2: # endif // DYN_LINK williamr@2: #endif // BOOST_HAS_DECLSPEC williamr@2: williamr@2: #ifndef BOOST_GRAPH_DECL williamr@2: # define BOOST_GRAPH_DECL williamr@2: #endif williamr@2: williamr@2: namespace boost { williamr@2: williamr@2: template williamr@2: struct graphviz_io_traits { williamr@2: static std::string name() { williamr@2: return "digraph"; williamr@2: } williamr@2: static std::string delimiter() { williamr@2: return "->"; williamr@2: } }; williamr@2: williamr@2: template <> williamr@2: struct graphviz_io_traits { williamr@2: static std::string name() { williamr@2: return "graph"; williamr@2: } williamr@2: static std::string delimiter() { williamr@2: return "--"; williamr@2: } williamr@2: }; williamr@2: williamr@2: struct default_writer { williamr@2: void operator()(std::ostream&) const { williamr@2: } williamr@2: template williamr@2: void operator()(std::ostream&, const VorE&) const { williamr@2: } williamr@2: }; williamr@2: williamr@2: template williamr@2: class label_writer { williamr@2: public: williamr@2: label_writer(Name _name) : name(_name) {} williamr@2: template williamr@2: void operator()(std::ostream& out, const VertexOrEdge& v) const { williamr@2: out << "[label=\"" << get(name, v) << "\"]"; williamr@2: } williamr@2: private: williamr@2: Name name; williamr@2: }; williamr@2: template williamr@2: inline label_writer williamr@2: make_label_writer(Name n) { williamr@2: return label_writer(n); williamr@2: } williamr@2: williamr@2: enum edge_attribute_t { edge_attribute = 1111 }; williamr@2: enum vertex_attribute_t { vertex_attribute = 2222 }; williamr@2: enum graph_graph_attribute_t { graph_graph_attribute = 3333 }; williamr@2: enum graph_vertex_attribute_t { graph_vertex_attribute = 4444 }; williamr@2: enum graph_edge_attribute_t { graph_edge_attribute = 5555 }; williamr@2: williamr@2: BOOST_INSTALL_PROPERTY(edge, attribute); williamr@2: BOOST_INSTALL_PROPERTY(vertex, attribute); williamr@2: BOOST_INSTALL_PROPERTY(graph, graph_attribute); williamr@2: BOOST_INSTALL_PROPERTY(graph, vertex_attribute); williamr@2: BOOST_INSTALL_PROPERTY(graph, edge_attribute); williamr@2: williamr@2: williamr@2: template williamr@2: inline void write_attributes(const Attribute& attr, std::ostream& out) { williamr@2: typename Attribute::const_iterator i, iend; williamr@2: i = attr.begin(); williamr@2: iend = attr.end(); williamr@2: williamr@2: while ( i != iend ) { williamr@2: out << i->first << "=\"" << i->second << "\""; williamr@2: ++i; williamr@2: if ( i != iend ) williamr@2: out << ", "; williamr@2: } williamr@2: } williamr@2: williamr@2: template williamr@2: inline void write_all_attributes(Attributes attributes, williamr@2: const std::string& name, williamr@2: std::ostream& out) williamr@2: { williamr@2: typename Attributes::const_iterator i = attributes.begin(), williamr@2: end = attributes.end(); williamr@2: if (i != end) { williamr@2: out << name << " [\n"; williamr@2: write_attributes(attributes, out); williamr@2: out << "];\n"; williamr@2: } williamr@2: } williamr@2: williamr@2: inline void write_all_attributes(detail::error_property_not_found, williamr@2: const std::string&, williamr@2: std::ostream&) williamr@2: { williamr@2: // Do nothing - no attributes exist williamr@2: } williamr@2: williamr@2: williamr@2: williamr@2: williamr@2: template williamr@2: struct graph_attributes_writer williamr@2: { williamr@2: graph_attributes_writer(GraphGraphAttributes gg, williamr@2: GraphNodeAttributes gn, williamr@2: GraphEdgeAttributes ge) williamr@2: : g_attributes(gg), n_attributes(gn), e_attributes(ge) { } williamr@2: williamr@2: void operator()(std::ostream& out) const { williamr@2: write_all_attributes(g_attributes, "graph", out); williamr@2: write_all_attributes(n_attributes, "node", out); williamr@2: write_all_attributes(e_attributes, "edge", out); williamr@2: } williamr@2: GraphGraphAttributes g_attributes; williamr@2: GraphNodeAttributes n_attributes; williamr@2: GraphEdgeAttributes e_attributes; williamr@2: }; williamr@2: williamr@2: template williamr@2: graph_attributes_writer williamr@2: make_graph_attributes_writer(const GAttrMap& g_attr, const NAttrMap& n_attr, williamr@2: const EAttrMap& e_attr) { williamr@2: return graph_attributes_writer williamr@2: (g_attr, n_attr, e_attr); williamr@2: } williamr@2: williamr@2: williamr@2: template williamr@2: graph_attributes_writer williamr@2: ::type, williamr@2: typename graph_property::type, williamr@2: typename graph_property::type> williamr@2: make_graph_attributes_writer(const Graph& g) williamr@2: { williamr@2: typedef typename graph_property::type williamr@2: GAttrMap; williamr@2: typedef typename graph_property::type williamr@2: NAttrMap; williamr@2: typedef typename graph_property::type williamr@2: EAttrMap; williamr@2: GAttrMap gam = get_property(g, graph_graph_attribute); williamr@2: NAttrMap nam = get_property(g, graph_vertex_attribute); williamr@2: EAttrMap eam = get_property(g, graph_edge_attribute); williamr@2: graph_attributes_writer writer(gam, nam, eam); williamr@2: return writer; williamr@2: } williamr@2: williamr@2: template williamr@2: struct attributes_writer { williamr@2: attributes_writer(AttributeMap attr) williamr@2: : attributes(attr) { } williamr@2: williamr@2: template williamr@2: void operator()(std::ostream& out, const VorE& e) const { williamr@2: this->write_attribute(out, attributes[e]); williamr@2: } williamr@2: williamr@2: private: williamr@2: template williamr@2: void write_attribute(std::ostream& out, williamr@2: const AttributeSequence& seq) const williamr@2: { williamr@2: if (!seq.empty()) { williamr@2: out << "["; williamr@2: write_attributes(seq, out); williamr@2: out << "]"; williamr@2: } williamr@2: } williamr@2: williamr@2: void write_attribute(std::ostream&, williamr@2: detail::error_property_not_found) const williamr@2: { williamr@2: } williamr@2: AttributeMap attributes; williamr@2: }; williamr@2: williamr@2: template williamr@2: attributes_writer williamr@2: ::const_type> williamr@2: make_edge_attributes_writer(const Graph& g) williamr@2: { williamr@2: typedef typename property_map::const_type williamr@2: EdgeAttributeMap; williamr@2: return attributes_writer(get(edge_attribute, g)); williamr@2: } williamr@2: williamr@2: template williamr@2: attributes_writer williamr@2: ::const_type> williamr@2: make_vertex_attributes_writer(const Graph& g) williamr@2: { williamr@2: typedef typename property_map::const_type williamr@2: VertexAttributeMap; williamr@2: return attributes_writer(get(vertex_attribute, g)); williamr@2: } williamr@2: williamr@2: template williamr@2: inline void write_graphviz(std::ostream& out, const Graph& g, williamr@2: VertexPropertiesWriter vpw, williamr@2: EdgePropertiesWriter epw, williamr@2: GraphPropertiesWriter gpw, williamr@2: VertexID vertex_id) williamr@2: { williamr@2: typedef typename graph_traits::directed_category cat_type; williamr@2: typedef graphviz_io_traits Traits; williamr@2: std::string name = "G"; williamr@2: out << Traits::name() << " " << name << " {" << std::endl; williamr@2: williamr@2: gpw(out); //print graph properties williamr@2: williamr@2: typename graph_traits::vertex_iterator i, end; williamr@2: williamr@2: for(tie(i,end) = vertices(g); i != end; ++i) { williamr@2: out << get(vertex_id, *i); williamr@2: vpw(out, *i); //print vertex attributes williamr@2: out << ";" << std::endl; williamr@2: } williamr@2: typename graph_traits::edge_iterator ei, edge_end; williamr@2: for(tie(ei, edge_end) = edges(g); ei != edge_end; ++ei) { williamr@2: out << get(vertex_id, source(*ei, g)) << Traits::delimiter() << get(vertex_id, target(*ei, g)) << " "; williamr@2: epw(out, *ei); //print edge attributes williamr@2: out << ";" << std::endl; williamr@2: } williamr@2: out << "}" << std::endl; williamr@2: } williamr@2: williamr@2: template williamr@2: inline void write_graphviz(std::ostream& out, const Graph& g, williamr@2: VertexPropertiesWriter vpw, williamr@2: EdgePropertiesWriter epw, williamr@2: GraphPropertiesWriter gpw) williamr@2: { write_graphviz(out, g, vpw, epw, gpw, get(vertex_index, g)); } williamr@2: williamr@2: #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 williamr@2: // ambiguous overload problem with VC++ williamr@2: template williamr@2: inline void williamr@2: write_graphviz(std::ostream& out, const Graph& g) { williamr@2: default_writer dw; williamr@2: default_writer gw; williamr@2: write_graphviz(out, g, dw, dw, gw); williamr@2: } williamr@2: #endif williamr@2: williamr@2: template williamr@2: inline void williamr@2: write_graphviz(std::ostream& out, const Graph& g, VertexWriter vw) { williamr@2: default_writer dw; williamr@2: default_writer gw; williamr@2: write_graphviz(out, g, vw, dw, gw); williamr@2: } williamr@2: williamr@2: template williamr@2: inline void williamr@2: write_graphviz(std::ostream& out, const Graph& g, williamr@2: VertexWriter vw, EdgeWriter ew) { williamr@2: default_writer gw; williamr@2: write_graphviz(out, g, vw, ew, gw); williamr@2: } williamr@2: williamr@2: namespace detail { williamr@2: williamr@2: template williamr@2: void write_graphviz_subgraph (std::ostream& out, williamr@2: const subgraph& g, williamr@2: RandomAccessIterator vertex_marker, williamr@2: RandomAccessIterator edge_marker, williamr@2: VertexID vertex_id) williamr@2: { williamr@2: typedef subgraph Graph; williamr@2: typedef typename graph_traits::vertex_descriptor Vertex; williamr@2: typedef typename graph_traits::directed_category cat_type; williamr@2: typedef graphviz_io_traits Traits; williamr@2: williamr@2: typedef typename graph_property::type NameType; williamr@2: const NameType& g_name = get_property(g, graph_name); williamr@2: williamr@2: if ( g.is_root() ) williamr@2: out << Traits::name() ; williamr@2: else williamr@2: out << "subgraph"; williamr@2: williamr@2: out << " " << g_name << " {" << std::endl; williamr@2: williamr@2: typename Graph::const_children_iterator i_child, j_child; williamr@2: williamr@2: //print graph/node/edge attributes williamr@2: #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 williamr@2: typedef typename graph_property::type williamr@2: GAttrMap; williamr@2: typedef typename graph_property::type williamr@2: NAttrMap; williamr@2: typedef typename graph_property::type williamr@2: EAttrMap; williamr@2: GAttrMap gam = get_property(g, graph_graph_attribute); williamr@2: NAttrMap nam = get_property(g, graph_vertex_attribute); williamr@2: EAttrMap eam = get_property(g, graph_edge_attribute); williamr@2: graph_attributes_writer writer(gam, nam, eam); williamr@2: writer(out); williamr@2: #else williamr@2: make_graph_attributes_writer(g)(out); williamr@2: #endif williamr@2: williamr@2: //print subgraph williamr@2: for ( tie(i_child,j_child) = g.children(); williamr@2: i_child != j_child; ++i_child ) williamr@2: write_graphviz_subgraph(out, *i_child, vertex_marker, edge_marker, williamr@2: vertex_id); williamr@2: williamr@2: // Print out vertices and edges not in the subgraphs. williamr@2: williamr@2: typename graph_traits::vertex_iterator i, end; williamr@2: typename graph_traits::edge_iterator ei, edge_end; williamr@2: williamr@2: for(tie(i,end) = vertices(g); i != end; ++i) { williamr@2: Vertex v = g.local_to_global(*i); williamr@2: int pos = get(vertex_id, v); williamr@2: if ( vertex_marker[pos] ) { williamr@2: vertex_marker[pos] = false; williamr@2: out << pos; williamr@2: #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 williamr@2: typedef typename property_map::const_type williamr@2: VertexAttributeMap; williamr@2: attributes_writer vawriter(get(vertex_attribute, williamr@2: g.root())); williamr@2: vawriter(out, v); williamr@2: #else williamr@2: make_vertex_attributes_writer(g.root())(out, v); williamr@2: #endif williamr@2: out << ";" << std::endl; williamr@2: } williamr@2: } williamr@2: williamr@2: for (tie(ei, edge_end) = edges(g); ei != edge_end; ++ei) { williamr@2: Vertex u = g.local_to_global(source(*ei,g)), williamr@2: v = g.local_to_global(target(*ei, g)); williamr@2: int pos = get(get(edge_index, g.root()), g.local_to_global(*ei)); williamr@2: if ( edge_marker[pos] ) { williamr@2: edge_marker[pos] = false; williamr@2: out << get(vertex_id, u) << " " << Traits::delimiter() williamr@2: << " " << get(vertex_id, v); williamr@2: #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 williamr@2: typedef typename property_map::const_type williamr@2: EdgeAttributeMap; williamr@2: attributes_writer eawriter(get(edge_attribute, g)); williamr@2: eawriter(out, *ei); williamr@2: #else williamr@2: make_edge_attributes_writer(g)(out, *ei); //print edge properties williamr@2: #endif williamr@2: out << ";" << std::endl; williamr@2: } williamr@2: } williamr@2: out << "}" << std::endl; williamr@2: } williamr@2: } // namespace detail williamr@2: williamr@2: // requires graph_name graph property williamr@2: template williamr@2: void write_graphviz(std::ostream& out, const subgraph& g) { williamr@2: std::vector edge_marker(num_edges(g), true); williamr@2: std::vector vertex_marker(num_vertices(g), true); williamr@2: williamr@2: detail::write_graphviz_subgraph(out, g, williamr@2: vertex_marker.begin(), williamr@2: edge_marker.begin(), williamr@2: get(vertex_index, g)); williamr@2: } williamr@2: williamr@2: template williamr@2: void write_graphviz(const std::string& filename, const subgraph& g) { williamr@2: std::ofstream out(filename.c_str()); williamr@2: std::vector edge_marker(num_edges(g), true); williamr@2: std::vector vertex_marker(num_vertices(g), true); williamr@2: williamr@2: detail::write_graphviz_subgraph(out, g, williamr@2: vertex_marker.begin(), williamr@2: edge_marker.begin(), williamr@2: get(vertex_index, g)); williamr@2: } williamr@2: williamr@2: template williamr@2: void write_graphviz(std::ostream& out, const subgraph& g, williamr@2: VertexID vertex_id) williamr@2: { williamr@2: std::vector edge_marker(num_edges(g), true); williamr@2: std::vector vertex_marker(num_vertices(g), true); williamr@2: williamr@2: detail::write_graphviz_subgraph(out, g, williamr@2: vertex_marker.begin(), williamr@2: edge_marker.begin(), williamr@2: vertex_id); williamr@2: } williamr@2: williamr@2: template williamr@2: void write_graphviz(const std::string& filename, const subgraph& g, williamr@2: VertexID vertex_id) williamr@2: { williamr@2: std::ofstream out(filename.c_str()); williamr@2: std::vector edge_marker(num_edges(g), true); williamr@2: std::vector vertex_marker(num_vertices(g), true); williamr@2: williamr@2: detail::write_graphviz_subgraph(out, g, williamr@2: vertex_marker.begin(), williamr@2: edge_marker.begin(), williamr@2: vertex_id); williamr@2: } williamr@2: williamr@2: typedef std::map GraphvizAttrList; williamr@2: williamr@2: typedef property williamr@2: GraphvizVertexProperty; williamr@2: williamr@2: typedef property > williamr@2: GraphvizEdgeProperty; williamr@2: williamr@2: typedef property > > > williamr@2: GraphvizGraphProperty; williamr@2: williamr@2: typedef subgraph > williamr@2: GraphvizDigraph; williamr@2: williamr@2: typedef subgraph > williamr@2: GraphvizGraph; williamr@2: williamr@2: williamr@2: // These four require linking the BGL-Graphviz library: libbgl-viz.a williamr@2: // from the /src directory. williamr@2: extern void read_graphviz(const std::string& file, GraphvizDigraph& g); williamr@2: extern void read_graphviz(FILE* file, GraphvizDigraph& g); williamr@2: williamr@2: extern void read_graphviz(const std::string& file, GraphvizGraph& g); williamr@2: extern void read_graphviz(FILE* file, GraphvizGraph& g); williamr@2: williamr@2: class dynamic_properties_writer williamr@2: { williamr@2: public: williamr@2: dynamic_properties_writer(const dynamic_properties& dp) : dp(&dp) { } williamr@2: williamr@2: template williamr@2: void operator()(std::ostream& out, Descriptor key) const williamr@2: { williamr@2: bool first = true; williamr@2: for (dynamic_properties::const_iterator i = dp->begin(); williamr@2: i != dp->end(); ++i) { williamr@2: if (typeid(key) == i->second->key()) { williamr@2: if (first) out << " ["; williamr@2: else out << ", "; williamr@2: first = false; williamr@2: williamr@2: out << i->first << "=\"" << i->second->get_string(key) << "\""; williamr@2: } williamr@2: } williamr@2: williamr@2: if (!first) out << "]"; williamr@2: } williamr@2: williamr@2: private: williamr@2: const dynamic_properties* dp; williamr@2: }; williamr@2: williamr@2: class dynamic_vertex_properties_writer williamr@2: { williamr@2: public: williamr@2: dynamic_vertex_properties_writer(const dynamic_properties& dp, williamr@2: const std::string& node_id) williamr@2: : dp(&dp), node_id(&node_id) { } williamr@2: williamr@2: template williamr@2: void operator()(std::ostream& out, Descriptor key) const williamr@2: { williamr@2: bool first = true; williamr@2: for (dynamic_properties::const_iterator i = dp->begin(); williamr@2: i != dp->end(); ++i) { williamr@2: if (typeid(key) == i->second->key() williamr@2: && i->first != *node_id) { williamr@2: if (first) out << " ["; williamr@2: else out << ", "; williamr@2: first = false; williamr@2: williamr@2: out << i->first << "=\"" << i->second->get_string(key) << "\""; williamr@2: } williamr@2: } williamr@2: williamr@2: if (!first) out << "]"; williamr@2: } williamr@2: williamr@2: private: williamr@2: const dynamic_properties* dp; williamr@2: const std::string* node_id; williamr@2: }; williamr@2: williamr@2: namespace graph { namespace detail { williamr@2: williamr@2: template williamr@2: struct node_id_property_map williamr@2: { williamr@2: typedef std::string value_type; williamr@2: typedef value_type reference; williamr@2: typedef Vertex key_type; williamr@2: typedef readable_property_map_tag category; williamr@2: williamr@2: node_id_property_map() {} williamr@2: williamr@2: node_id_property_map(const dynamic_properties& dp, williamr@2: const std::string& node_id) williamr@2: : dp(&dp), node_id(&node_id) { } williamr@2: williamr@2: const dynamic_properties* dp; williamr@2: const std::string* node_id; williamr@2: }; williamr@2: williamr@2: template williamr@2: inline std::string williamr@2: get(node_id_property_map pm, williamr@2: typename node_id_property_map::key_type v) williamr@2: { return get(*pm.node_id, *pm.dp, v); } williamr@2: williamr@2: } } // end namespace graph::detail williamr@2: williamr@2: template williamr@2: inline void williamr@2: write_graphviz(std::ostream& out, const Graph& g, williamr@2: const dynamic_properties& dp, williamr@2: const std::string& node_id = "node_id") williamr@2: { williamr@2: typedef typename graph_traits::vertex_descriptor Vertex; williamr@2: write_graphviz(out, g, dp, node_id, williamr@2: graph::detail::node_id_property_map(dp, node_id)); williamr@2: } williamr@2: williamr@2: template williamr@2: void williamr@2: write_graphviz(std::ostream& out, const Graph& g, williamr@2: const dynamic_properties& dp, const std::string& node_id, williamr@2: VertexID id) williamr@2: { williamr@2: write_graphviz williamr@2: (out, g, williamr@2: /*vertex_writer=*/dynamic_vertex_properties_writer(dp, node_id), williamr@2: /*edge_writer=*/dynamic_properties_writer(dp), williamr@2: /*graph_writer=*/default_writer(), williamr@2: id); williamr@2: } williamr@2: williamr@2: ///////////////////////////////////////////////////////////////////////////// williamr@2: // Graph reader exceptions williamr@2: ///////////////////////////////////////////////////////////////////////////// williamr@2: struct graph_exception : public std::exception { williamr@2: virtual ~graph_exception() throw() {} williamr@2: virtual const char* what() const throw() = 0; williamr@2: }; williamr@2: williamr@2: struct bad_parallel_edge : public graph_exception { williamr@2: std::string from; williamr@2: std::string to; williamr@2: mutable std::string statement; williamr@2: bad_parallel_edge(const std::string& i, const std::string& j) : williamr@2: from(i), to(j) {} williamr@2: williamr@2: virtual ~bad_parallel_edge() throw() {} williamr@2: const char* what() const throw() { williamr@2: if(statement.empty()) williamr@2: statement = williamr@2: std::string("Failed to add parallel edge: (") williamr@2: + from + "," + to + ")\n"; williamr@2: williamr@2: return statement.c_str(); williamr@2: } williamr@2: }; williamr@2: williamr@2: struct directed_graph_error : public graph_exception { williamr@2: virtual ~directed_graph_error() throw() {} williamr@2: virtual const char* what() const throw() { williamr@2: return williamr@2: "read_graphviz: " williamr@2: "Tried to read a directed graph into an undirected graph."; williamr@2: } williamr@2: }; williamr@2: williamr@2: struct undirected_graph_error : public graph_exception { williamr@2: virtual ~undirected_graph_error() throw() {} williamr@2: virtual const char* what() const throw() { williamr@2: return williamr@2: "read_graphviz: " williamr@2: "Tried to read an undirected graph into a directed graph."; williamr@2: } williamr@2: }; williamr@2: williamr@2: namespace detail { namespace graph { williamr@2: williamr@2: typedef std::string id_t; williamr@2: typedef id_t node_t; williamr@2: williamr@2: // edges are not uniquely determined by adjacent nodes williamr@2: class edge_t { williamr@2: int idx_; williamr@2: explicit edge_t(int i) : idx_(i) {} williamr@2: public: williamr@2: static edge_t new_edge() { williamr@2: static int idx = 0; williamr@2: return edge_t(idx++); williamr@2: }; williamr@2: williamr@2: bool operator==(const edge_t& rhs) const { williamr@2: return idx_ == rhs.idx_; williamr@2: } williamr@2: bool operator<(const edge_t& rhs) const { williamr@2: return idx_ < rhs.idx_; williamr@2: } williamr@2: }; williamr@2: williamr@2: class mutate_graph williamr@2: { williamr@2: public: williamr@2: virtual ~mutate_graph() {} williamr@2: virtual bool is_directed() const = 0; williamr@2: virtual void do_add_vertex(const node_t& node) = 0; williamr@2: williamr@2: virtual void williamr@2: do_add_edge(const edge_t& edge, const node_t& source, const node_t& target) williamr@2: = 0; williamr@2: williamr@2: virtual void williamr@2: set_node_property(const id_t& key, const node_t& node, const id_t& value) = 0; williamr@2: williamr@2: virtual void williamr@2: set_edge_property(const id_t& key, const edge_t& edge, const id_t& value) = 0; williamr@2: }; williamr@2: williamr@2: template williamr@2: class mutate_graph_impl : public mutate_graph williamr@2: { williamr@2: typedef typename graph_traits::vertex_descriptor bgl_vertex_t; williamr@2: typedef typename graph_traits::edge_descriptor bgl_edge_t; williamr@2: williamr@2: public: williamr@2: mutate_graph_impl(MutableGraph& graph, dynamic_properties& dp, williamr@2: std::string node_id_prop) williamr@2: : graph_(graph), dp_(dp), node_id_prop_(node_id_prop) { } williamr@2: williamr@2: ~mutate_graph_impl() {} williamr@2: williamr@2: bool is_directed() const williamr@2: { williamr@2: return williamr@2: boost::is_convertible< williamr@2: typename boost::graph_traits::directed_category, williamr@2: boost::directed_tag>::value; williamr@2: } williamr@2: williamr@2: virtual void do_add_vertex(const node_t& node) williamr@2: { williamr@2: // Add the node to the graph. williamr@2: bgl_vertex_t v = add_vertex(graph_); williamr@2: williamr@2: // Set up a mapping from name to BGL vertex. williamr@2: bgl_nodes.insert(std::make_pair(node, v)); williamr@2: williamr@2: // node_id_prop_ allows the caller to see the real id names for nodes. williamr@2: put(node_id_prop_, dp_, v, node); williamr@2: } williamr@2: williamr@2: void williamr@2: do_add_edge(const edge_t& edge, const node_t& source, const node_t& target) williamr@2: { williamr@2: std::pair result = williamr@2: add_edge(bgl_nodes[source], bgl_nodes[target], graph_); williamr@2: williamr@2: if(!result.second) { williamr@2: // In the case of no parallel edges allowed williamr@2: throw bad_parallel_edge(source, target); williamr@2: } else { williamr@2: bgl_edges.insert(std::make_pair(edge, result.first)); williamr@2: } williamr@2: } williamr@2: williamr@2: void williamr@2: set_node_property(const id_t& key, const node_t& node, const id_t& value) williamr@2: { williamr@2: put(key, dp_, bgl_nodes[node], value); williamr@2: } williamr@2: williamr@2: void williamr@2: set_edge_property(const id_t& key, const edge_t& edge, const id_t& value) williamr@2: { williamr@2: put(key, dp_, bgl_edges[edge], value); williamr@2: } williamr@2: williamr@2: protected: williamr@2: MutableGraph& graph_; williamr@2: dynamic_properties& dp_; williamr@2: std::string node_id_prop_; williamr@2: std::map bgl_nodes; williamr@2: std::map bgl_edges; williamr@2: }; williamr@2: williamr@2: BOOST_GRAPH_DECL williamr@2: bool read_graphviz(std::istream& in, mutate_graph& graph); williamr@2: williamr@2: } } // end namespace detail::graph williamr@2: williamr@2: // Parse the passed stream as a GraphViz dot file. williamr@2: template williamr@2: bool read_graphviz(std::istream& in, MutableGraph& graph, williamr@2: dynamic_properties& dp, williamr@2: std::string const& node_id = "node_id") williamr@2: { williamr@2: detail::graph::mutate_graph_impl m_graph(graph, dp, node_id); williamr@2: return detail::graph::read_graphviz(in, m_graph); williamr@2: } williamr@2: williamr@2: } // namespace boost williamr@2: williamr@2: #ifdef BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS williamr@2: # include williamr@2: #endif // BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS williamr@2: williamr@2: #endif // BOOST_GRAPHVIZ_HPP