// Copyright David Abrahams 2002. Permission to copy, use, // modify, sell and distribute this software is granted provided this // copyright notice appears in all copies. This software is provided // "as is" without express or implied warranty, and with no claim as // to its suitability for any purpose. //#include #include #include #include #include #include #include namespace boost { namespace { // // Here we put together the low-level data structures of the // inheritance graph representation. // //typedef python::converter::undecorated_type_id_t class_id; //llee boost/mpl/select_type.hpp is not in the cvs yet :-( typedef int class_id; struct vertex; enum direction_t { up, down }; struct edge { edge(direction_t direction, vertex const* target, void*(*cast)(void*)) : direction(direction) , target(target) , cast(cast) {} direction_t direction; vertex const* target; void* (*cast)(void*); }; typedef std::vector edge_list_t; struct vertex : std::vector { vertex(class_id source) : source(source) {} bool operator<(vertex const& rhs) const { return this->source < rhs.source; } class_id source; edge_list_t edges; int color; }; //llee: struct my_color_map { typedef vertex const* key_type; typedef int value_type; typedef int& reference; typedef read_write_property_map_tag category; }; //llee int get(my_color_map, const vertex const* v) { return v->color; } //llee void put(my_color_map, vertex const* vv, int i) { vertex * v = const_cast(vv); v->color = i; } typedef std::set vertex_set; vertex_set& vertices() { static vertex_set v; return v; } // // Now we build two different BGL graphs on top of the vertex_set: // full_graph is a BGL representation of the entire graph, and // up_graph is a filtered view of just the up-edges. // // Why do we have to do this at all? It should be trivial to // redefine adjacency_list so that it can use a set<> as its // backbone, if it already works with list<>. // This is the base for both views of the graph struct graph_base { graph_base() : m_vertices(vertices()) {} typedef graph_base self; // // Graph requirements // typedef vertex const* vertex_descriptor; typedef std::pair edge_descriptor; typedef directed_tag directed_category; typedef disallow_parallel_edge_tag edge_parallel_category; struct traversal_category : public virtual vertex_list_graph_tag, public virtual incidence_graph_tag, public virtual adjacency_graph_tag { }; // // IncidenceGraph requirements // // A function object which builds an edge_descriptor from a // vertex_descriptor and an edge. // // We have to do this because the graph library requires that // every IncidenceGraph support source(e), returning the source // vertex of an arbitrary edge. Our graph doesn't store the // source vertex in the edge structure, so we need to cobble // together a pair which can supply the needed information. // // I think this is much less-efficient than it has to be for // most graph algorithms. Probably a new concept is needed to // distinguish a graph that doesn't support source(e). struct build_edge_descriptor { typedef edge_descriptor result_type; build_edge_descriptor() {} //llee: required by transform_iterator_policies build_edge_descriptor(vertex_descriptor source) : source(source) {} result_type operator()(edge const& e) const //llee: add const { return result_type(source, &e); } vertex_descriptor source; }; typedef edge_list_t::size_type degree_size_type; friend vertex_descriptor source(edge_descriptor const& e, self const&) { return e.first; } friend vertex_descriptor target(edge_descriptor const& e, self const&) { return e.second->target; } friend degree_size_type inline out_degree(vertex_descriptor v, self const&) { return v->edges.size(); } // // VertexListGraph requirements // typedef vertex_set::const_iterator vertex_iterator; typedef vertex_set::size_type vertices_size_type; friend std::pair vertices(self const& g) { return std::make_pair(g.m_vertices.begin(), g.m_vertices.end()); } friend vertices_size_type num_vertices(self const& g) { return g.m_vertices.size(); } // Garbage for graph_traits<>: what causes the library to require these? typedef void in_edge_iterator; typedef void edge_iterator; typedef void edges_size_type; protected: vertex_set const& m_vertices; }; // This intermediate class is used to generate the information // specific to the view. The EdgeIterator type determines whether // we're looking at all edges or just the up-edges. template struct inheritance_graph : graph_base { typedef Graph self; // // IncidenceGraph requirements // // Construct the outgoing edge iterator type. See the // description of build_edge_descriptor from graph_base, above, // for an explanation. typedef boost::transform_iterator_generator< build_edge_descriptor,EdgeIterator >::type out_edge_iterator; friend std::pair out_edges(vertex_descriptor v, self const&) { return std::pair( out_edge_iterator( EdgeIterator(v->edges.begin()) , out_edge_iterator::policies_type(v)) , out_edge_iterator( EdgeIterator(v->edges.end()) , out_edge_iterator::policies_type(v)) ); } // // AdjacencyGraph requirements // // This is just boilerplate that makes an IncidenceGraph into an // AdjacencyGraph. Probably the BGL ought to have a graph // adaptor for this purpose. typedef boost::adjacency_iterator_generator< self, vertex_descriptor, out_edge_iterator >::type adjacency_iterator; friend std::pair adjacent_vertices(vertex_descriptor v, self const& g) { return out_edges(v, g); } }; // The unfiltered graph type struct full_graph : inheritance_graph { }; // // Define the filtered graph type // // First build the filtered edge iterator struct is_up { bool operator()(edge const& e) { return e.direction == up; } }; typedef boost::filter_iterator_generator< is_up , edge_list_t::const_iterator , edge , edge const& , edge const >::type up_edge_iterator; // Then use it to define the up_graph struct up_graph : inheritance_graph { }; // A utility function for graph building void add_cast(class_id source, class_id target, void*(*cast)(void*), direction_t direction) { vertex_set& g = vertices(); std::pair s = g.insert(source); std::pair t = g.insert(target); const_cast(*s.first).push_back( edge(direction, &*t.first, cast)); } } namespace python { namespace object { BOOST_DECL void add_upcast(class_id source, class_id target, void*(*cast)(void*)) { add_cast(source, target, cast, up); // Just test the graph to see if we've met requirements. up_graph g; boost::my_color_map color; //llee breadth_first_visit( #if 0 //llee g, &*vertices().find(source), visitor(bfs_visitor()) #else //llee //g, &*vertices().find(source), q, default_bfs_visitor(), color //or g, &*vertices().find(source), color_map(color).visitor(default_bfs_visitor()) #endif ); } BOOST_DECL void add_downcast(class_id source, class_id target, void*(*cast)(void*)) { add_cast(source, target, cast, down); } }}} // namespace boost::python::object