1 // Copyright (C) 2007 Douglas Gregor
3 // Use, modification and distribution is subject to the Boost Software
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 // Provides support for named vertices in graphs, allowing one to more
8 // easily associate unique external names (URLs, city names, employee
9 // ID numbers, etc.) with the vertices of a graph.
10 #ifndef BOOST_GRAPH_NAMED_GRAPH_HPP
11 #define BOOST_GRAPH_NAMED_GRAPH_HPP
13 #include <boost/config.hpp>
14 #include <boost/type_traits/remove_cv.hpp>
15 #include <boost/type_traits/remove_reference.hpp>
16 #include <boost/multi_index_container.hpp>
17 #include <boost/multi_index/hashed_index.hpp>
18 #include <boost/multi_index/member.hpp>
19 #include <boost/optional.hpp>
20 #include <boost/throw_exception.hpp>
21 #include <stdexcept> // for std::runtime_error
23 namespace boost { namespace graph {
25 /*******************************************************************
26 * User-customized traits *
27 *******************************************************************/
30 * @brief Trait used to extract the internal vertex name from a vertex
33 * To enable the use of internal vertex names in a graph type,
34 * specialize the @c internal_vertex_name trait for your graph
35 * property (e.g., @c a City class, which stores information about the
36 * vertices in a road map).
38 template<typename VertexProperty>
39 struct internal_vertex_name
42 * The @c type field provides a function object that extracts a key
43 * from the @c VertexProperty. The function object type must have a
44 * nested @c result_type that provides the type of the key. For
45 * more information, see the @c KeyExtractor concept in the
46 * Boost.MultiIndex documentation: @c type must either be @c void
47 * (if @c VertexProperty does not have an internal vertex name) or
48 * a model of @c KeyExtractor.
53 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
55 * Extract the internal vertex name from a @c property structure by
56 * looking at its base.
58 template<typename Tag, typename T, typename Base>
59 struct internal_vertex_name<property<Tag, T, Base> >
60 : internal_vertex_name<Base> { };
64 * Construct an instance of @c VertexProperty directly from its
65 * name. This function object should be used within the @c
66 * internal_vertex_constructor trait.
68 template<typename VertexProperty>
69 struct vertex_from_name
72 typedef typename internal_vertex_name<VertexProperty>::type extract_name_type;
74 typedef typename remove_cv<
75 typename remove_reference<
76 typename extract_name_type::result_type>::type>::type
80 typedef vertex_name_type argument_type;
81 typedef VertexProperty result_type;
83 VertexProperty operator()(const vertex_name_type& name)
85 return VertexProperty(name);
90 * Throw an exception whenever one tries to construct a @c
91 * VertexProperty instance from its name.
93 template<typename VertexProperty>
94 struct cannot_add_vertex
97 typedef typename internal_vertex_name<VertexProperty>::type extract_name_type;
99 typedef typename remove_cv<
100 typename remove_reference<
101 typename extract_name_type::result_type>::type>::type
105 typedef vertex_name_type argument_type;
106 typedef VertexProperty result_type;
108 VertexProperty operator()(const vertex_name_type& name)
110 boost::throw_exception(std::runtime_error("add_vertex: "
111 "unable to create a vertex from its name"));
116 * @brief Trait used to construct an instance of a @c VertexProperty,
117 * which is a class type that stores the properties associated with a
118 * vertex in a graph, from just the name of that vertex property. This
119 * operation is used when an operation is required to map from a
120 * vertex name to a vertex descriptor (e.g., to add an edge outgoing
121 * from that vertex), but no vertex by the name exists. The function
122 * object provided by this trait will be used to add new vertices
123 * based only on their names. Since this cannot be done for arbitrary
124 * types, the default behavior is to throw an exception when this
125 * routine is called, which requires that all named vertices be added
126 * before adding any edges by name.
128 template<typename VertexProperty>
129 struct internal_vertex_constructor
132 * The @c type field provides a function object that constructs a
133 * new instance of @c VertexProperty from the name of the vertex (as
134 * determined by @c internal_vertex_name). The function object shall
135 * accept a vertex name and return a @c VertexProperty. Predefined
138 * @c vertex_from_name<VertexProperty>: construct an instance of
139 * @c VertexProperty directly from the name.
141 * @c cannot_add_vertex<VertexProperty>: the default value, which
142 * throws an @c std::runtime_error if one attempts to add a vertex
143 * given just the name.
145 typedef cannot_add_vertex<VertexProperty> type;
148 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
150 * Extract the internal vertex constructor from a @c property structure by
151 * looking at its base.
153 template<typename Tag, typename T, typename Base>
154 struct internal_vertex_constructor<property<Tag, T, Base> >
155 : internal_vertex_constructor<Base> { };
158 /*******************************************************************
159 * Named graph-specific metafunctions *
160 *******************************************************************/
163 * Extracts the type of a bundled vertex property from a vertex
164 * property. The primary template matches when we have hit the end
165 * of the @c property<> list.
167 template<typename VertexProperty>
168 struct extract_bundled_vertex
170 typedef VertexProperty type;
174 * Recursively extract the bundled vertex property from a vertex
177 template<typename Tag, typename T, typename Base>
178 struct extract_bundled_vertex<property<Tag, T, Base> >
179 : extract_bundled_vertex<Base>
183 * We have found the bundled vertex property type, marked with
186 template<typename T, typename Base>
187 struct extract_bundled_vertex<property<vertex_bundle_t, T, Base> >
193 * Translate @c no_property into @c error_property_not_found when we
194 * have failed to extract a bundled vertex property type.
197 struct extract_bundled_vertex<no_property>
199 typedef boost::detail::error_property_not_found type;
203 /*******************************************************************
204 * Named graph mixin *
205 *******************************************************************/
208 * named_graph is a mixin that provides names for the vertices of a
209 * graph, including a mapping from names to vertices. Graph types that
210 * may or may not be have vertex names (depending on the properties
211 * supplied by the user) should use maybe_named_graph.
213 * Template parameters:
215 * Graph: the graph type that derives from named_graph
217 * Vertex: the type of a vertex descriptor in Graph. Note: we cannot
218 * use graph_traits here, because the Graph is not yet defined.
220 * VertexProperty: the type stored with each vertex in the Graph.
222 template<typename Graph, typename Vertex, typename VertexProperty>
226 /// The type of the function object that extracts names from vertex
228 typedef typename internal_vertex_name<VertexProperty>::type extract_name_type;
229 /// The type of the "bundled" property, from which the name can be
231 typedef typename detail::extract_bundled_vertex<VertexProperty>::type
232 bundled_vertex_property_type;
234 /// The type of the function object that generates vertex properties
235 /// from names, for the implicit addition of vertices.
236 typedef typename internal_vertex_constructor<VertexProperty>::type
237 vertex_constructor_type;
239 /// The type used to name vertices in the graph
240 typedef typename remove_cv<
241 typename remove_reference<
242 typename extract_name_type::result_type>::type>::type
245 /// The type of vertex descriptors in the graph
246 typedef Vertex vertex_descriptor;
249 /// Key extractor for use with the multi_index_container
250 struct extract_name_from_vertex
252 typedef vertex_name_type result_type;
254 extract_name_from_vertex(Graph& graph, const extract_name_type& extract)
255 : graph(graph), extract(extract) { }
257 const result_type& operator()(Vertex vertex) const
259 return extract(graph[vertex]);
263 extract_name_type extract;
267 /// The type that maps names to vertices
268 typedef multi_index::multi_index_container<
270 multi_index::indexed_by<
271 multi_index::hashed_unique<multi_index::tag<vertex_name_t>,
272 extract_name_from_vertex> >
273 > named_vertices_type;
275 /// The set of vertices, indexed by name
276 typedef typename named_vertices_type::template index<vertex_name_t>::type
277 vertices_by_name_type;
279 /// Construct an instance of the named graph mixin, using the given
280 /// function object to extract a name from the bundled property
281 /// associated with a vertex.
282 named_graph(const extract_name_type& extract = extract_name_type(),
283 const vertex_constructor_type& vertex_constructor
284 = vertex_constructor_type());
286 /// Notify the named_graph that we have added the given vertex. The
287 /// name of the vertex will be added to the mapping.
288 void added_vertex(Vertex vertex);
290 /// Notify the named_graph that we are removing the given
291 /// vertex. The name of the vertex will be removed from the mapping.
292 void removing_vertex(Vertex vertex);
294 /// Notify the named_graph that we are clearing the graph.
295 /// This will clear out all of the name->vertex mappings
296 void clearing_graph();
298 /// Retrieve the derived instance
299 Graph& derived() { return static_cast<Graph&>(*this); }
300 const Graph& derived() const { return static_cast<const Graph&>(*this); }
302 /// Extract the name from a vertex property instance
303 typename extract_name_type::result_type
304 extract_name(const bundled_vertex_property_type& property);
306 /// Search for a vertex that has the given property (based on its
308 optional<vertex_descriptor>
309 vertex_by_property(const bundled_vertex_property_type& property);
311 /// Mapping from names to vertices
312 named_vertices_type named_vertices;
314 /// Constructs a vertex from the name of that vertex
315 vertex_constructor_type vertex_constructor;
318 /// Helper macro containing the template parameters of named_graph
319 #define BGL_NAMED_GRAPH_PARAMS \
320 typename Graph, typename Vertex, typename VertexProperty
321 /// Helper macro containing the named_graph<...> instantiation
322 #define BGL_NAMED_GRAPH \
323 named_graph<Graph, Vertex, VertexProperty>
325 template<BGL_NAMED_GRAPH_PARAMS>
326 BGL_NAMED_GRAPH::named_graph(const extract_name_type& extract,
327 const vertex_constructor_type& vertex_constructor)
329 typename named_vertices_type::ctor_args_list(
332 0, // initial number of buckets
333 extract_name_from_vertex(derived(), extract),
334 boost::hash<vertex_name_type>(),
335 std::equal_to<vertex_name_type>())))),
336 vertex_constructor(vertex_constructor)
340 template<BGL_NAMED_GRAPH_PARAMS>
341 inline void BGL_NAMED_GRAPH::added_vertex(Vertex vertex)
343 named_vertices.insert(vertex);
346 template<BGL_NAMED_GRAPH_PARAMS>
347 inline void BGL_NAMED_GRAPH::removing_vertex(Vertex vertex)
349 typedef typename BGL_NAMED_GRAPH::vertex_name_type vertex_name_type;
350 const vertex_name_type& vertex_name = extract_name(derived()[vertex]);
351 named_vertices.erase(vertex_name);
354 template<BGL_NAMED_GRAPH_PARAMS>
355 inline void BGL_NAMED_GRAPH::clearing_graph()
357 named_vertices.clear();
360 template<BGL_NAMED_GRAPH_PARAMS>
361 typename BGL_NAMED_GRAPH::extract_name_type::result_type
362 BGL_NAMED_GRAPH::extract_name(const bundled_vertex_property_type& property)
364 return named_vertices.key_extractor().extract(property);
367 template<BGL_NAMED_GRAPH_PARAMS>
368 optional<typename BGL_NAMED_GRAPH::vertex_descriptor>
370 vertex_by_property(const bundled_vertex_property_type& property)
372 return find_vertex(extract_name(property), *this);
375 /// Retrieve the vertex associated with the given name
376 template<BGL_NAMED_GRAPH_PARAMS>
378 find_vertex(typename BGL_NAMED_GRAPH::vertex_name_type const& name,
379 const BGL_NAMED_GRAPH& g)
381 typedef typename BGL_NAMED_GRAPH::vertices_by_name_type
382 vertices_by_name_type;
384 // Retrieve the set of vertices indexed by name
385 vertices_by_name_type const& vertices_by_name
386 = g.named_vertices.template get<vertex_name_t>();
388 /// Look for a vertex with the given name
389 typename vertices_by_name_type::const_iterator iter
390 = vertices_by_name.find(name);
392 if (iter == vertices_by_name.end())
393 return optional<Vertex>(); // vertex not found
398 /// Retrieve the vertex associated with the given name, or add a new
399 /// vertex with that name if no such vertex is available.
400 template<BGL_NAMED_GRAPH_PARAMS>
402 add_vertex(typename BGL_NAMED_GRAPH::vertex_name_type const& name,
405 if (optional<Vertex> vertex = find_vertex(name, g))
406 /// We found the vertex, so return it
409 /// There is no vertex with the given name, so create one
410 return add_vertex(g.vertex_constructor(name), g.derived());
413 /// Add an edge using vertex names to refer to the vertices
414 template<BGL_NAMED_GRAPH_PARAMS>
415 std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
416 add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
417 typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
420 return add_edge(add_vertex(u_name, g.derived()),
421 add_vertex(v_name, g.derived()),
425 /// Add an edge using vertex descriptors or names to refer to the vertices
426 template<BGL_NAMED_GRAPH_PARAMS>
427 std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
428 add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u,
429 typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
433 add_vertex(v_name, g.derived()),
437 /// Add an edge using vertex descriptors or names to refer to the vertices
438 template<BGL_NAMED_GRAPH_PARAMS>
439 std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
440 add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
441 typename BGL_NAMED_GRAPH::vertex_descriptor const& v,
444 return add_edge(add_vertex(u_name, g.derived()),
449 #undef BGL_NAMED_GRAPH
450 #undef BGL_NAMED_GRAPH_PARAMS
452 /*******************************************************************
453 * Maybe named graph mixin *
454 *******************************************************************/
456 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
458 * A graph mixin that can provide a mapping from names to vertices,
459 * and use that mapping to simplify creation and manipulation of
462 template<typename Graph, typename Vertex, typename VertexProperty,
464 = typename internal_vertex_name<VertexProperty>::type>
465 struct maybe_named_graph : public named_graph<Graph, Vertex, VertexProperty>
470 * A graph mixin that can provide a mapping from names to vertices,
471 * and use that mapping to simplify creation and manipulation of
472 * graphs. This partial specialization turns off this functionality
473 * when the @c VertexProperty does not have an internal vertex name.
475 template<typename Graph, typename Vertex, typename VertexProperty>
476 struct maybe_named_graph<Graph, Vertex, VertexProperty, void>
478 /// The type of the "bundled" property, from which the name can be
480 typedef typename detail::extract_bundled_vertex<VertexProperty>::type
481 bundled_vertex_property_type;
483 /// Notify the named_graph that we have added the given vertex. This
485 void added_vertex(Vertex) { }
487 /// Notify the named_graph that we are removing the given
488 /// vertex. This is a no-op.
489 void removing_vertex(Vertex) { }
491 /// Notify the named_graph that we are clearing the graph. This is a
493 void clearing_graph() { }
495 /// Search for a vertex that has the given property (based on its
496 /// name). This always returns an empty optional<>
498 vertex_by_property(const bundled_vertex_property_type&)
500 return optional<Vertex>();
504 template<typename Graph, typename Vertex, typename VertexProperty,
506 = typename internal_vertex_name<VertexProperty>::type>
507 struct maybe_named_graph
509 /// The type of the "bundled" property, from which the name can be
511 typedef typename detail::extract_bundled_vertex<VertexProperty>::type
512 bundled_vertex_property_type;
514 /// Notify the named_graph that we have added the given vertex. This
516 void added_vertex(Vertex) { }
518 /// Notify the named_graph that we are removing the given
519 /// vertex. This is a no-op.
520 void removing_vertex(Vertex) { }
522 /// Notify the named_graph that we are clearing the graph. This is a
524 void clearing_graph() { }
526 /// Search for a vertex that has the given property (based on its
527 /// name). This always returns an empty optional<>
528 template<typename Property>
530 vertex_by_property(const bundled_vertex_property_type&)
532 return optional<Vertex>();
535 #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
537 } } // end namespace boost::graph
539 #endif // BOOST_GRAPH_NAMED_GRAPH_HPP