williamr@2: //======================================================================= williamr@2: // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. williamr@2: // Copyright 2003 Bruce Barr williamr@2: // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. 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: williamr@2: // Nonrecursive implementation of depth_first_visit_impl submitted by williamr@2: // Bruce Barr, schmoost yahoo.com, May/June 2003. williamr@2: #ifndef BOOST_GRAPH_RECURSIVE_DFS_HPP williamr@2: #define BOOST_GRAPH_RECURSIVE_DFS_HPP williamr@2: williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: #include williamr@2: #include williamr@2: williamr@2: #include williamr@2: #include williamr@2: williamr@2: namespace boost { williamr@2: williamr@2: template williamr@2: class DFSVisitorConcept { williamr@2: public: williamr@2: void constraints() { williamr@2: function_requires< CopyConstructibleConcept >(); williamr@2: vis.initialize_vertex(u, g); williamr@2: vis.start_vertex(u, g); williamr@2: vis.discover_vertex(u, g); williamr@2: vis.examine_edge(e, g); williamr@2: vis.tree_edge(e, g); williamr@2: vis.back_edge(e, g); williamr@2: vis.forward_or_cross_edge(e, g); williamr@2: vis.finish_vertex(u, g); williamr@2: } williamr@2: private: williamr@2: Visitor vis; williamr@2: Graph g; williamr@2: typename graph_traits::vertex_descriptor u; williamr@2: typename graph_traits::edge_descriptor e; williamr@2: }; williamr@2: williamr@2: namespace detail { williamr@2: williamr@2: struct nontruth2 { williamr@2: template williamr@2: bool operator()(const T&, const T2&) const { return false; } williamr@2: }; williamr@2: williamr@2: williamr@2: // Define BOOST_RECURSIVE_DFS to use older, recursive version. williamr@2: // It is retained for a while in order to perform performance williamr@2: // comparison. williamr@2: #ifndef BOOST_RECURSIVE_DFS williamr@2: williamr@2: // If the vertex u and the iterators ei and ei_end are thought of as the williamr@2: // context of the algorithm, each push and pop from the stack could williamr@2: // be thought of as a context shift. williamr@2: // Each pass through "while (ei != ei_end)" may refer to the out-edges of williamr@2: // an entirely different vertex, because the context of the algorithm williamr@2: // shifts every time a white adjacent vertex is discovered. williamr@2: // The corresponding context shift back from the adjacent vertex occurs williamr@2: // after all of its out-edges have been examined. williamr@2: // williamr@2: // See http://lists.boost.org/MailArchives/boost/msg48752.php for FAQ. williamr@2: williamr@2: template williamr@2: void depth_first_visit_impl williamr@2: (const IncidenceGraph& g, williamr@2: typename graph_traits::vertex_descriptor u, williamr@2: DFSVisitor& vis, williamr@2: ColorMap color, TerminatorFunc func = TerminatorFunc()) williamr@2: { williamr@2: function_requires >(); williamr@2: function_requires >(); williamr@2: typedef typename graph_traits::vertex_descriptor Vertex; williamr@2: function_requires< ReadWritePropertyMapConcept >(); williamr@2: typedef typename property_traits::value_type ColorValue; williamr@2: function_requires< ColorValueConcept >(); williamr@2: typedef color_traits Color; williamr@2: typedef typename graph_traits::out_edge_iterator Iter; williamr@2: typedef std::pair > VertexInfo; williamr@2: williamr@2: Iter ei, ei_end; williamr@2: std::vector stack; williamr@2: williamr@2: // Possible optimization for vector williamr@2: //stack.reserve(num_vertices(g)); williamr@2: williamr@2: typedef typename unwrap_reference::type TF; williamr@2: williamr@2: put(color, u, Color::gray()); williamr@2: vis.discover_vertex(u, g); williamr@2: tie(ei, ei_end) = out_edges(u, g); williamr@2: // Variable is needed to workaround a borland bug. williamr@2: TF& fn = static_cast(func); williamr@2: if (fn(u, g)) { williamr@2: // If this vertex terminates the search, we push empty range williamr@2: stack.push_back(std::make_pair(u, std::make_pair(ei_end, ei_end))); williamr@2: } else { williamr@2: stack.push_back(std::make_pair(u, std::make_pair(ei, ei_end))); williamr@2: } williamr@2: while (!stack.empty()) { williamr@2: VertexInfo& back = stack.back(); williamr@2: u = back.first; williamr@2: tie(ei, ei_end) = back.second; williamr@2: stack.pop_back(); williamr@2: while (ei != ei_end) { williamr@2: Vertex v = target(*ei, g); williamr@2: vis.examine_edge(*ei, g); williamr@2: ColorValue v_color = get(color, v); williamr@2: if (v_color == Color::white()) { williamr@2: vis.tree_edge(*ei, g); williamr@2: stack.push_back(std::make_pair(u, std::make_pair(++ei, ei_end))); williamr@2: u = v; williamr@2: put(color, u, Color::gray()); williamr@2: vis.discover_vertex(u, g); williamr@2: tie(ei, ei_end) = out_edges(u, g); williamr@2: if (fn(u, g)) { williamr@2: ei = ei_end; williamr@2: } williamr@2: } else if (v_color == Color::gray()) { williamr@2: vis.back_edge(*ei, g); williamr@2: ++ei; williamr@2: } else { williamr@2: vis.forward_or_cross_edge(*ei, g); williamr@2: ++ei; williamr@2: } williamr@2: } williamr@2: put(color, u, Color::black()); williamr@2: vis.finish_vertex(u, g); williamr@2: } williamr@2: } williamr@2: williamr@2: #else // BOOST_RECURSIVE_DFS is defined williamr@2: williamr@2: template williamr@2: void depth_first_visit_impl williamr@2: (const IncidenceGraph& g, williamr@2: typename graph_traits::vertex_descriptor u, williamr@2: DFSVisitor& vis, // pass-by-reference here, important! williamr@2: ColorMap color, TerminatorFunc func) williamr@2: { williamr@2: function_requires >(); williamr@2: function_requires >(); williamr@2: typedef typename graph_traits::vertex_descriptor Vertex; williamr@2: function_requires< ReadWritePropertyMapConcept >(); williamr@2: typedef typename property_traits::value_type ColorValue; williamr@2: function_requires< ColorValueConcept >(); williamr@2: typedef color_traits Color; williamr@2: typename graph_traits::out_edge_iterator ei, ei_end; williamr@2: williamr@2: put(color, u, Color::gray()); vis.discover_vertex(u, g); williamr@2: williamr@2: typedef typename unwrap_reference::type TF; williamr@2: // Variable is needed to workaround a borland bug. williamr@2: TF& fn = static_cast(func); williamr@2: if (!fn(u, g)) williamr@2: for (tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) { williamr@2: Vertex v = target(*ei, g); vis.examine_edge(*ei, g); williamr@2: ColorValue v_color = get(color, v); williamr@2: if (v_color == Color::white()) { vis.tree_edge(*ei, g); williamr@2: depth_first_visit_impl(g, v, vis, color, func); williamr@2: } else if (v_color == Color::gray()) vis.back_edge(*ei, g); williamr@2: else vis.forward_or_cross_edge(*ei, g); williamr@2: } williamr@2: put(color, u, Color::black()); vis.finish_vertex(u, g); williamr@2: } williamr@2: williamr@2: #endif williamr@2: williamr@2: } // namespace detail williamr@2: williamr@2: template williamr@2: void williamr@2: depth_first_search(const VertexListGraph& g, DFSVisitor vis, ColorMap color, williamr@2: typename graph_traits::vertex_descriptor start_vertex) williamr@2: { williamr@2: typedef typename graph_traits::vertex_descriptor Vertex; williamr@2: function_requires >(); williamr@2: typedef typename property_traits::value_type ColorValue; williamr@2: typedef color_traits Color; williamr@2: williamr@2: typename graph_traits::vertex_iterator ui, ui_end; williamr@2: for (tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { williamr@2: put(color, *ui, Color::white()); vis.initialize_vertex(*ui, g); williamr@2: } williamr@2: williamr@2: if (start_vertex != implicit_cast(*vertices(g).first)){ vis.start_vertex(start_vertex, g); williamr@2: detail::depth_first_visit_impl(g, start_vertex, vis, color, williamr@2: detail::nontruth2()); williamr@2: } williamr@2: williamr@2: for (tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { williamr@2: ColorValue u_color = get(color, *ui); williamr@2: if (u_color == Color::white()) { vis.start_vertex(*ui, g); williamr@2: detail::depth_first_visit_impl(g, *ui, vis, color, detail::nontruth2()); williamr@2: } williamr@2: } williamr@2: } williamr@2: williamr@2: template williamr@2: void williamr@2: depth_first_search(const VertexListGraph& g, DFSVisitor vis, ColorMap color) williamr@2: { williamr@2: if (vertices(g).first == vertices(g).second) williamr@2: return; williamr@2: williamr@2: depth_first_search(g, vis, color, *vertices(g).first); williamr@2: } williamr@2: williamr@2: namespace detail { williamr@2: template williamr@2: struct dfs_dispatch { williamr@2: williamr@2: template williamr@2: static void williamr@2: apply(const VertexListGraph& g, DFSVisitor vis, Vertex start_vertex, williamr@2: const bgl_named_params&, williamr@2: ColorMap color) williamr@2: { williamr@2: depth_first_search(g, vis, color, start_vertex); williamr@2: } williamr@2: }; williamr@2: williamr@2: template <> williamr@2: struct dfs_dispatch { williamr@2: template williamr@2: static void williamr@2: apply(const VertexListGraph& g, DFSVisitor vis, Vertex start_vertex, williamr@2: const bgl_named_params& params, williamr@2: detail::error_property_not_found) williamr@2: { williamr@2: std::vector color_vec(num_vertices(g)); williamr@2: default_color_type c = white_color; // avoid warning about un-init williamr@2: depth_first_search williamr@2: (g, vis, make_iterator_property_map williamr@2: (color_vec.begin(), williamr@2: choose_const_pmap(get_param(params, vertex_index), williamr@2: g, vertex_index), c), williamr@2: start_vertex); williamr@2: } williamr@2: }; williamr@2: } // namespace detail williamr@2: williamr@2: williamr@2: template williamr@2: class dfs_visitor { williamr@2: public: williamr@2: dfs_visitor() { } williamr@2: dfs_visitor(Visitors vis) : m_vis(vis) { } williamr@2: williamr@2: template williamr@2: void initialize_vertex(Vertex u, const Graph& g) { williamr@2: invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex()); williamr@2: } williamr@2: template williamr@2: void start_vertex(Vertex u, const Graph& g) { williamr@2: invoke_visitors(m_vis, u, g, ::boost::on_start_vertex()); williamr@2: } williamr@2: template williamr@2: void discover_vertex(Vertex u, const Graph& g) { williamr@2: invoke_visitors(m_vis, u, g, ::boost::on_discover_vertex()); williamr@2: } williamr@2: template williamr@2: void examine_edge(Edge u, const Graph& g) { williamr@2: invoke_visitors(m_vis, u, g, ::boost::on_examine_edge()); williamr@2: } williamr@2: template williamr@2: void tree_edge(Edge u, const Graph& g) { williamr@2: invoke_visitors(m_vis, u, g, ::boost::on_tree_edge()); williamr@2: } williamr@2: template williamr@2: void back_edge(Edge u, const Graph& g) { williamr@2: invoke_visitors(m_vis, u, g, ::boost::on_back_edge()); williamr@2: } williamr@2: template williamr@2: void forward_or_cross_edge(Edge u, const Graph& g) { williamr@2: invoke_visitors(m_vis, u, g, ::boost::on_forward_or_cross_edge()); williamr@2: } williamr@2: template williamr@2: void finish_vertex(Vertex u, const Graph& g) { williamr@2: invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex()); williamr@2: } williamr@2: williamr@2: BOOST_GRAPH_EVENT_STUB(on_initialize_vertex,dfs) williamr@2: BOOST_GRAPH_EVENT_STUB(on_start_vertex,dfs) williamr@2: BOOST_GRAPH_EVENT_STUB(on_discover_vertex,dfs) williamr@2: BOOST_GRAPH_EVENT_STUB(on_examine_edge,dfs) williamr@2: BOOST_GRAPH_EVENT_STUB(on_tree_edge,dfs) williamr@2: BOOST_GRAPH_EVENT_STUB(on_back_edge,dfs) williamr@2: BOOST_GRAPH_EVENT_STUB(on_forward_or_cross_edge,dfs) williamr@2: BOOST_GRAPH_EVENT_STUB(on_finish_vertex,dfs) williamr@2: williamr@2: protected: williamr@2: Visitors m_vis; williamr@2: }; williamr@2: template williamr@2: dfs_visitor williamr@2: make_dfs_visitor(Visitors vis) { williamr@2: return dfs_visitor(vis); williamr@2: } williamr@2: typedef dfs_visitor<> default_dfs_visitor; williamr@2: williamr@2: williamr@2: // Named Parameter Variant williamr@2: template williamr@2: void williamr@2: depth_first_search(const VertexListGraph& g, williamr@2: const bgl_named_params& params) williamr@2: { williamr@2: typedef typename property_value< bgl_named_params, williamr@2: vertex_color_t>::type C; williamr@2: if (vertices(g).first == vertices(g).second) williamr@2: return; williamr@2: detail::dfs_dispatch::apply williamr@2: (g, williamr@2: choose_param(get_param(params, graph_visitor), williamr@2: make_dfs_visitor(null_visitor())), williamr@2: choose_param(get_param(params, root_vertex_t()), williamr@2: *vertices(g).first), williamr@2: params, williamr@2: get_param(params, vertex_color) williamr@2: ); williamr@2: } williamr@2: williamr@2: template williamr@2: void depth_first_visit williamr@2: (const IncidenceGraph& g, williamr@2: typename graph_traits::vertex_descriptor u, williamr@2: DFSVisitor vis, ColorMap color) williamr@2: { williamr@2: vis.start_vertex(u, g); williamr@2: detail::depth_first_visit_impl(g, u, vis, color, detail::nontruth2()); williamr@2: } williamr@2: williamr@2: template williamr@2: void depth_first_visit williamr@2: (const IncidenceGraph& g, williamr@2: typename graph_traits::vertex_descriptor u, williamr@2: DFSVisitor vis, ColorMap color, TerminatorFunc func = TerminatorFunc()) williamr@2: { williamr@2: vis.start_vertex(u, g); williamr@2: detail::depth_first_visit_impl(g, u, vis, color, func); williamr@2: } williamr@2: williamr@2: williamr@2: } // namespace boost williamr@2: williamr@2: williamr@2: #endif