comparison DEPENDENCIES/generic/include/boost/graph/named_graph.hpp @ 16:2665513ce2d3

Add boost headers
author Chris Cannam
date Tue, 05 Aug 2014 11:11:38 +0100
parents
children c530137014c0
comparison
equal deleted inserted replaced
15:663ca0da4350 16:2665513ce2d3
1 // Copyright (C) 2007 Douglas Gregor
2
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)
6
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
12
13 #include <boost/config.hpp>
14 #include <boost/static_assert.hpp>
15 #include <boost/functional/hash.hpp>
16 #include <boost/graph/graph_traits.hpp>
17 #include <boost/graph/properties.hpp>
18 #include <boost/multi_index/hashed_index.hpp>
19 #include <boost/multi_index/member.hpp>
20 #include <boost/multi_index_container.hpp>
21 #include <boost/optional.hpp>
22 #include <boost/pending/property.hpp> // for boost::lookup_one_property
23 #include <boost/pending/container_traits.hpp>
24 #include <boost/throw_exception.hpp>
25 #include <boost/tuple/tuple.hpp> // for boost::make_tuple
26 #include <boost/type_traits/is_same.hpp>
27 #include <boost/type_traits/is_base_of.hpp>
28 #include <boost/type_traits/remove_cv.hpp>
29 #include <boost/type_traits/remove_reference.hpp>
30 #include <boost/utility/enable_if.hpp>
31 #include <functional> // for std::equal_to
32 #include <stdexcept> // for std::runtime_error
33 #include <utility> // for std::pair
34
35 namespace boost { namespace graph {
36
37 /*******************************************************************
38 * User-customized traits *
39 *******************************************************************/
40
41 /**
42 * @brief Trait used to extract the internal vertex name from a vertex
43 * property.
44 *
45 * To enable the use of internal vertex names in a graph type,
46 * specialize the @c internal_vertex_name trait for your graph
47 * property (e.g., @c a City class, which stores information about the
48 * vertices in a road map).
49 */
50 template<typename VertexProperty>
51 struct internal_vertex_name
52 {
53 /**
54 * The @c type field provides a function object that extracts a key
55 * from the @c VertexProperty. The function object type must have a
56 * nested @c result_type that provides the type of the key. For
57 * more information, see the @c KeyExtractor concept in the
58 * Boost.MultiIndex documentation: @c type must either be @c void
59 * (if @c VertexProperty does not have an internal vertex name) or
60 * a model of @c KeyExtractor.
61 */
62 typedef void type;
63 };
64
65 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
66 /**
67 * Extract the internal vertex name from a @c property structure by
68 * looking at its base.
69 */
70 template<typename Tag, typename T, typename Base>
71 struct internal_vertex_name<property<Tag, T, Base> >
72 : internal_vertex_name<Base> { };
73 #endif
74
75 /**
76 * Construct an instance of @c VertexProperty directly from its
77 * name. This function object should be used within the @c
78 * internal_vertex_constructor trait.
79 */
80 template<typename VertexProperty>
81 struct vertex_from_name
82 {
83 private:
84 typedef typename internal_vertex_name<VertexProperty>::type extract_name_type;
85
86 typedef typename remove_cv<
87 typename remove_reference<
88 typename extract_name_type::result_type>::type>::type
89 vertex_name_type;
90
91 public:
92 typedef vertex_name_type argument_type;
93 typedef VertexProperty result_type;
94
95 VertexProperty operator()(const vertex_name_type& name)
96 {
97 return VertexProperty(name);
98 }
99 };
100
101 /**
102 * Throw an exception whenever one tries to construct a @c
103 * VertexProperty instance from its name.
104 */
105 template<typename VertexProperty>
106 struct cannot_add_vertex
107 {
108 private:
109 typedef typename internal_vertex_name<VertexProperty>::type extract_name_type;
110
111 typedef typename remove_cv<
112 typename remove_reference<
113 typename extract_name_type::result_type>::type>::type
114 vertex_name_type;
115
116 public:
117 typedef vertex_name_type argument_type;
118 typedef VertexProperty result_type;
119
120 VertexProperty operator()(const vertex_name_type&)
121 {
122 boost::throw_exception(std::runtime_error("add_vertex: "
123 "unable to create a vertex from its name"));
124 }
125 };
126
127 /**
128 * @brief Trait used to construct an instance of a @c VertexProperty,
129 * which is a class type that stores the properties associated with a
130 * vertex in a graph, from just the name of that vertex property. This
131 * operation is used when an operation is required to map from a
132 * vertex name to a vertex descriptor (e.g., to add an edge outgoing
133 * from that vertex), but no vertex by the name exists. The function
134 * object provided by this trait will be used to add new vertices
135 * based only on their names. Since this cannot be done for arbitrary
136 * types, the default behavior is to throw an exception when this
137 * routine is called, which requires that all named vertices be added
138 * before adding any edges by name.
139 */
140 template<typename VertexProperty>
141 struct internal_vertex_constructor
142 {
143 /**
144 * The @c type field provides a function object that constructs a
145 * new instance of @c VertexProperty from the name of the vertex (as
146 * determined by @c internal_vertex_name). The function object shall
147 * accept a vertex name and return a @c VertexProperty. Predefined
148 * options include:
149 *
150 * @c vertex_from_name<VertexProperty>: construct an instance of
151 * @c VertexProperty directly from the name.
152 *
153 * @c cannot_add_vertex<VertexProperty>: the default value, which
154 * throws an @c std::runtime_error if one attempts to add a vertex
155 * given just the name.
156 */
157 typedef cannot_add_vertex<VertexProperty> type;
158 };
159
160 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
161 /**
162 * Extract the internal vertex constructor from a @c property structure by
163 * looking at its base.
164 */
165 template<typename Tag, typename T, typename Base>
166 struct internal_vertex_constructor<property<Tag, T, Base> >
167 : internal_vertex_constructor<Base> { };
168 #endif
169
170 /*******************************************************************
171 * Named graph mixin *
172 *******************************************************************/
173
174 /**
175 * named_graph is a mixin that provides names for the vertices of a
176 * graph, including a mapping from names to vertices. Graph types that
177 * may or may not be have vertex names (depending on the properties
178 * supplied by the user) should use maybe_named_graph.
179 *
180 * Template parameters:
181 *
182 * Graph: the graph type that derives from named_graph
183 *
184 * Vertex: the type of a vertex descriptor in Graph. Note: we cannot
185 * use graph_traits here, because the Graph is not yet defined.
186 *
187 * VertexProperty: the type stored with each vertex in the Graph.
188 */
189 template<typename Graph, typename Vertex, typename VertexProperty>
190 class named_graph
191 {
192 public:
193 /// The type of the function object that extracts names from vertex
194 /// properties.
195 typedef typename internal_vertex_name<VertexProperty>::type extract_name_type;
196 /// The type of the "bundled" property, from which the name can be
197 /// extracted.
198 typedef typename lookup_one_property<VertexProperty, vertex_bundle_t>::type
199 bundled_vertex_property_type;
200
201 /// The type of the function object that generates vertex properties
202 /// from names, for the implicit addition of vertices.
203 typedef typename internal_vertex_constructor<VertexProperty>::type
204 vertex_constructor_type;
205
206 /// The type used to name vertices in the graph
207 typedef typename remove_cv<
208 typename remove_reference<
209 typename extract_name_type::result_type>::type>::type
210 vertex_name_type;
211
212 /// The type of vertex descriptors in the graph
213 typedef Vertex vertex_descriptor;
214
215 private:
216 /// Key extractor for use with the multi_index_container
217 struct extract_name_from_vertex
218 {
219 typedef vertex_name_type result_type;
220
221 extract_name_from_vertex(Graph& graph, const extract_name_type& extract)
222 : graph(graph), extract(extract) { }
223
224 const result_type& operator()(Vertex vertex) const
225 {
226 return extract(graph[vertex]);
227 }
228
229 Graph& graph;
230 extract_name_type extract;
231 };
232
233 public:
234 /// The type that maps names to vertices
235 typedef multi_index::multi_index_container<
236 Vertex,
237 multi_index::indexed_by<
238 multi_index::hashed_unique<multi_index::tag<vertex_name_t>,
239 extract_name_from_vertex> >
240 > named_vertices_type;
241
242 /// The set of vertices, indexed by name
243 typedef typename named_vertices_type::template index<vertex_name_t>::type
244 vertices_by_name_type;
245
246 /// Construct an instance of the named graph mixin, using the given
247 /// function object to extract a name from the bundled property
248 /// associated with a vertex.
249 named_graph(const extract_name_type& extract = extract_name_type(),
250 const vertex_constructor_type& vertex_constructor
251 = vertex_constructor_type());
252
253 /// Notify the named_graph that we have added the given vertex. The
254 /// name of the vertex will be added to the mapping.
255 void added_vertex(Vertex vertex);
256
257 /// Notify the named_graph that we are removing the given
258 /// vertex. The name of the vertex will be removed from the mapping.
259 template <typename VertexIterStability>
260 void removing_vertex(Vertex vertex, VertexIterStability);
261
262 /// Notify the named_graph that we are clearing the graph.
263 /// This will clear out all of the name->vertex mappings
264 void clearing_graph();
265
266 /// Retrieve the derived instance
267 Graph& derived() { return static_cast<Graph&>(*this); }
268 const Graph& derived() const { return static_cast<const Graph&>(*this); }
269
270 /// Extract the name from a vertex property instance
271 typename extract_name_type::result_type
272 extract_name(const bundled_vertex_property_type& property);
273
274 /// Search for a vertex that has the given property (based on its
275 /// name)
276 optional<vertex_descriptor>
277 vertex_by_property(const bundled_vertex_property_type& property);
278
279 /// Mapping from names to vertices
280 named_vertices_type named_vertices;
281
282 /// Constructs a vertex from the name of that vertex
283 vertex_constructor_type vertex_constructor;
284 };
285
286 /// Helper macro containing the template parameters of named_graph
287 #define BGL_NAMED_GRAPH_PARAMS \
288 typename Graph, typename Vertex, typename VertexProperty
289 /// Helper macro containing the named_graph<...> instantiation
290 #define BGL_NAMED_GRAPH \
291 named_graph<Graph, Vertex, VertexProperty>
292
293 template<BGL_NAMED_GRAPH_PARAMS>
294 BGL_NAMED_GRAPH::named_graph(const extract_name_type& extract,
295 const vertex_constructor_type& vertex_constructor)
296 : named_vertices(
297 typename named_vertices_type::ctor_args_list(
298 boost::make_tuple(
299 boost::make_tuple(
300 0, // initial number of buckets
301 extract_name_from_vertex(derived(), extract),
302 boost::hash<vertex_name_type>(),
303 std::equal_to<vertex_name_type>())))),
304 vertex_constructor(vertex_constructor)
305 {
306 }
307
308 template<BGL_NAMED_GRAPH_PARAMS>
309 inline void BGL_NAMED_GRAPH::added_vertex(Vertex vertex)
310 {
311 named_vertices.insert(vertex);
312 }
313
314 template<BGL_NAMED_GRAPH_PARAMS>
315 template<typename VertexIterStability>
316 inline void BGL_NAMED_GRAPH::removing_vertex(Vertex vertex, VertexIterStability)
317 {
318 BOOST_STATIC_ASSERT_MSG ((boost::is_base_of<boost::graph_detail::stable_tag, VertexIterStability>::value), "Named graphs cannot use vecS as vertex container and remove vertices; the lack of vertex descriptor stability (which iterator stability is a proxy for) means that the name -> vertex mapping would need to be completely rebuilt after each deletion. See https://svn.boost.org/trac/boost/ticket/7863 for more information and a test case.");
319 typedef typename BGL_NAMED_GRAPH::vertex_name_type vertex_name_type;
320 const vertex_name_type& vertex_name = extract_name(derived()[vertex]);
321 named_vertices.erase(vertex_name);
322 }
323
324 template<BGL_NAMED_GRAPH_PARAMS>
325 inline void BGL_NAMED_GRAPH::clearing_graph()
326 {
327 named_vertices.clear();
328 }
329
330 template<BGL_NAMED_GRAPH_PARAMS>
331 typename BGL_NAMED_GRAPH::extract_name_type::result_type
332 BGL_NAMED_GRAPH::extract_name(const bundled_vertex_property_type& property)
333 {
334 return named_vertices.key_extractor().extract(property);
335 }
336
337 template<BGL_NAMED_GRAPH_PARAMS>
338 optional<typename BGL_NAMED_GRAPH::vertex_descriptor>
339 BGL_NAMED_GRAPH::
340 vertex_by_property(const bundled_vertex_property_type& property)
341 {
342 return find_vertex(extract_name(property), *this);
343 }
344
345 /// Retrieve the vertex associated with the given name
346 template<BGL_NAMED_GRAPH_PARAMS>
347 optional<Vertex>
348 find_vertex(typename BGL_NAMED_GRAPH::vertex_name_type const& name,
349 const BGL_NAMED_GRAPH& g)
350 {
351 typedef typename BGL_NAMED_GRAPH::vertices_by_name_type
352 vertices_by_name_type;
353
354 // Retrieve the set of vertices indexed by name
355 vertices_by_name_type const& vertices_by_name
356 = g.named_vertices.template get<vertex_name_t>();
357
358 /// Look for a vertex with the given name
359 typename vertices_by_name_type::const_iterator iter
360 = vertices_by_name.find(name);
361
362 if (iter == vertices_by_name.end())
363 return optional<Vertex>(); // vertex not found
364 else
365 return *iter;
366 }
367
368 /// Retrieve the vertex associated with the given name, or add a new
369 /// vertex with that name if no such vertex is available.
370 /// Note: This is enabled only when the vertex property type is different
371 /// from the vertex name to avoid ambiguous overload problems with
372 /// the add_vertex() function that takes a vertex property.
373 template<BGL_NAMED_GRAPH_PARAMS>
374 typename disable_if<is_same<
375 typename BGL_NAMED_GRAPH::vertex_name_type,
376 VertexProperty
377 >,
378 Vertex>::type
379 add_vertex(typename BGL_NAMED_GRAPH::vertex_name_type const& name,
380 BGL_NAMED_GRAPH& g)
381 {
382 if (optional<Vertex> vertex = find_vertex(name, g))
383 /// We found the vertex, so return it
384 return *vertex;
385 else
386 /// There is no vertex with the given name, so create one
387 return add_vertex(g.vertex_constructor(name), g.derived());
388 }
389
390 /// Add an edge using vertex names to refer to the vertices
391 template<BGL_NAMED_GRAPH_PARAMS>
392 std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
393 add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
394 typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
395 BGL_NAMED_GRAPH& g)
396 {
397 return add_edge(add_vertex(u_name, g.derived()),
398 add_vertex(v_name, g.derived()),
399 g.derived());
400 }
401
402 /// Add an edge using vertex descriptors or names to refer to the vertices
403 template<BGL_NAMED_GRAPH_PARAMS>
404 std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
405 add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u,
406 typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
407 BGL_NAMED_GRAPH& g)
408 {
409 return add_edge(u,
410 add_vertex(v_name, g.derived()),
411 g.derived());
412 }
413
414 /// Add an edge using vertex descriptors or names to refer to the vertices
415 template<BGL_NAMED_GRAPH_PARAMS>
416 std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
417 add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
418 typename BGL_NAMED_GRAPH::vertex_descriptor const& v,
419 BGL_NAMED_GRAPH& g)
420 {
421 return add_edge(add_vertex(u_name, g.derived()),
422 v,
423 g.derived());
424 }
425
426 // Overloads to support EdgeMutablePropertyGraph graphs
427 template <BGL_NAMED_GRAPH_PARAMS>
428 std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
429 add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u,
430 typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
431 typename edge_property_type<Graph>::type const& p,
432 BGL_NAMED_GRAPH& g) {
433 return add_edge(u, add_vertex(v_name, g.derived()), p, g.derived());
434 }
435
436 template <BGL_NAMED_GRAPH_PARAMS>
437 std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
438 add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
439 typename BGL_NAMED_GRAPH::vertex_descriptor const& v,
440 typename edge_property_type<Graph>::type const& p,
441 BGL_NAMED_GRAPH& g) {
442 return add_edge(add_vertex(u_name, g.derived()), v, p, g.derived());
443 }
444
445 template <BGL_NAMED_GRAPH_PARAMS>
446 std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
447 add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
448 typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
449 typename edge_property_type<Graph>::type const& p,
450 BGL_NAMED_GRAPH& g) {
451 return add_edge(add_vertex(u_name, g.derived()),
452 add_vertex(v_name, g.derived()), p, g.derived());
453 }
454
455 #undef BGL_NAMED_GRAPH
456 #undef BGL_NAMED_GRAPH_PARAMS
457
458 /*******************************************************************
459 * Maybe named graph mixin *
460 *******************************************************************/
461
462 #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
463 /**
464 * A graph mixin that can provide a mapping from names to vertices,
465 * and use that mapping to simplify creation and manipulation of
466 * graphs.
467 */
468 template<typename Graph, typename Vertex, typename VertexProperty,
469 typename ExtractName
470 = typename internal_vertex_name<VertexProperty>::type>
471 struct maybe_named_graph : public named_graph<Graph, Vertex, VertexProperty>
472 {
473 };
474
475 /**
476 * A graph mixin that can provide a mapping from names to vertices,
477 * and use that mapping to simplify creation and manipulation of
478 * graphs. This partial specialization turns off this functionality
479 * when the @c VertexProperty does not have an internal vertex name.
480 */
481 template<typename Graph, typename Vertex, typename VertexProperty>
482 struct maybe_named_graph<Graph, Vertex, VertexProperty, void>
483 {
484 /// The type of the "bundled" property, from which the name can be
485 /// extracted.
486 typedef typename lookup_one_property<VertexProperty, vertex_bundle_t>::type
487 bundled_vertex_property_type;
488
489 /// Notify the named_graph that we have added the given vertex. This
490 /// is a no-op.
491 void added_vertex(Vertex) { }
492
493 /// Notify the named_graph that we are removing the given
494 /// vertex. This is a no-op.
495 template <typename VertexIterStability>
496 void removing_vertex(Vertex, VertexIterStability) { }
497
498 /// Notify the named_graph that we are clearing the graph. This is a
499 /// no-op.
500 void clearing_graph() { }
501
502 /// Search for a vertex that has the given property (based on its
503 /// name). This always returns an empty optional<>
504 optional<Vertex>
505 vertex_by_property(const bundled_vertex_property_type&)
506 {
507 return optional<Vertex>();
508 }
509 };
510 #else
511 template<typename Graph, typename Vertex, typename VertexProperty,
512 typename ExtractName
513 = typename internal_vertex_name<VertexProperty>::type>
514 struct maybe_named_graph
515 {
516 /// The type of the "bundled" property, from which the name can be
517 /// extracted.
518 typedef typename detail::extract_bundled_vertex<VertexProperty>::type
519 bundled_vertex_property_type;
520
521 /// Notify the named_graph that we have added the given vertex. This
522 /// is a no-op.
523 void added_vertex(Vertex) { }
524
525 /// Notify the named_graph that we are removing the given
526 /// vertex. This is a no-op.
527 template <typename VertexIterStability>
528 void removing_vertex(Vertex, VertexIterStability) { }
529
530 /// Notify the named_graph that we are clearing the graph. This is a
531 /// no-op.
532 void clearing_graph() { }
533
534 /// Search for a vertex that has the given property (based on its
535 /// name). This always returns an empty optional<>
536 template<typename Property>
537 optional<Vertex>
538 vertex_by_property(const bundled_vertex_property_type&)
539 {
540 return optional<Vertex>();
541 }
542 };
543 #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
544
545 } } // end namespace boost::graph
546
547 #endif // BOOST_GRAPH_NAMED_GRAPH_HPP