summaryrefslogtreecommitdiff
path: root/boost/graph/graph_traits.hpp
blob: fad82f9d2f913856e716f149ab9b0cf5d4dd94b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef BOOST_GRAPH_TRAITS_HPP
#define BOOST_GRAPH_TRAITS_HPP

#include <boost/config.hpp>
#include <iterator>
#include <utility> /* Primarily for std::pair */
#include <boost/tuple/tuple.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/not.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/pending/property.hpp>
#include <boost/detail/workaround.hpp>

namespace boost {

    template <typename G>
    struct graph_traits {
        typedef typename G::vertex_descriptor      vertex_descriptor;
        typedef typename G::edge_descriptor        edge_descriptor;
        typedef typename G::adjacency_iterator     adjacency_iterator;
        typedef typename G::out_edge_iterator      out_edge_iterator;
        typedef typename G::in_edge_iterator       in_edge_iterator;
        typedef typename G::vertex_iterator        vertex_iterator;
        typedef typename G::edge_iterator          edge_iterator;

        typedef typename G::directed_category      directed_category;
        typedef typename G::edge_parallel_category edge_parallel_category;
        typedef typename G::traversal_category     traversal_category;

        typedef typename G::vertices_size_type     vertices_size_type;
        typedef typename G::edges_size_type        edges_size_type;
        typedef typename G::degree_size_type       degree_size_type;

        static inline vertex_descriptor null_vertex();
    };

    template <typename G>
    inline typename graph_traits<G>::vertex_descriptor
    graph_traits<G>::null_vertex()
    { return G::null_vertex(); }

    // directed_category tags
    struct directed_tag { };
    struct undirected_tag { };
    struct bidirectional_tag : public directed_tag { };

    namespace detail {
        inline bool is_directed(directed_tag) { return true; }
        inline bool is_directed(undirected_tag) { return false; }
    }

    /** Return true if the given graph is directed. */
    template <typename Graph>
    bool is_directed(const Graph&) {
        typedef typename graph_traits<Graph>::directed_category Cat;
        return detail::is_directed(Cat());
    }

    /** Return true if the given graph is undirected. */
    template <typename Graph>
    bool is_undirected(const Graph& g) {
        return !is_directed(g);
    }

    /** @name Directed/Undirected Graph Traits */
    //@{
    namespace graph_detail {
        template <typename Tag>
        struct is_directed_tag
            : mpl::bool_<is_convertible<Tag, directed_tag>::value>
        { };
    } // namespace graph_detail

    template <typename Graph>
    struct is_directed_graph
        : graph_detail::is_directed_tag<
            typename graph_traits<Graph>::directed_category
        >
    { };

    template <typename Graph>
    struct is_undirected_graph
        : mpl::not_< is_directed_graph<Graph> >
    { };
    //@}

    // edge_parallel_category tags
    struct allow_parallel_edge_tag { };
    struct disallow_parallel_edge_tag { };

    namespace detail {
        inline bool allows_parallel(allow_parallel_edge_tag) { return true; }
        inline bool allows_parallel(disallow_parallel_edge_tag) { return false; }
    }

    template <typename Graph>
    bool allows_parallel_edges(const Graph&) {
        typedef typename graph_traits<Graph>::edge_parallel_category Cat;
        return detail::allows_parallel(Cat());
    }

    /** @name Parallel Edges Traits */
    //@{
    /**
     * The is_multigraph metafunction returns true if the graph allows
     * parallel edges. Technically, a multigraph is a simple graph that
     * allows parallel edges, but since there are no traits for the allowance
     * or disallowance of loops, this is a moot point.
     */
    template <typename Graph>
    struct is_multigraph
        : mpl::bool_<
            is_same<
                typename graph_traits<Graph>::edge_parallel_category,
                allow_parallel_edge_tag
            >::value
        >
    { };
    //@}

    // traversal_category tags
    struct incidence_graph_tag { };
    struct adjacency_graph_tag { };
    struct bidirectional_graph_tag : virtual incidence_graph_tag { };
    struct vertex_list_graph_tag { };
    struct edge_list_graph_tag { };
    struct adjacency_matrix_tag { };

    /** @name Taversal Category Traits
     * These traits classify graph types by their supported methods of
     * vertex and edge traversal.
     */
    //@{
    template <typename Graph>
    struct is_incidence_graph
        : mpl::bool_<
            is_convertible<
                typename graph_traits<Graph>::traversal_category,
                incidence_graph_tag
            >::value
        >
    { };

    template <typename Graph>
    struct is_bidirectional_graph
        : mpl::bool_<
            is_convertible<
                typename graph_traits<Graph>::traversal_category,
                bidirectional_graph_tag
            >::value
        >
    { };

    template <typename Graph>
    struct is_vertex_list_graph
        : mpl::bool_<
            is_convertible<
                typename graph_traits<Graph>::traversal_category,
                vertex_list_graph_tag
            >::value
        >
    { };

    template <typename Graph>
    struct is_edge_list_graph
        : mpl::bool_<
            is_convertible<
                typename graph_traits<Graph>::traversal_category,
                edge_list_graph_tag
            >::value
        >
    { };

    template <typename Graph>
    struct is_adjacency_matrix
        : mpl::bool_<
            is_convertible<
                typename graph_traits<Graph>::traversal_category,
                adjacency_matrix_tag
            >::value
        >
    { };
    //@}

    /** @name Directed Graph Traits
     * These metafunctions are used to fully classify directed vs. undirected
     * graphs. Recall that an undirected graph is also bidirectional, but it
     * cannot be both undirected and directed at the same time.
     */
    //@{
    template <typename Graph>
    struct is_directed_unidirectional_graph
        : mpl::and_<
            is_directed_graph<Graph>, mpl::not_< is_bidirectional_graph<Graph> >
        >
    { };

    template <typename Graph>
    struct is_directed_bidirectional_graph
        : mpl::and_<
            is_directed_graph<Graph>, is_bidirectional_graph<Graph>
        >
    { };
    //@}

    //?? not the right place ?? Lee
    typedef boost::forward_traversal_tag multi_pass_input_iterator_tag;

    // Forward declare graph_bundle_t property name (from
    // boost/graph/properties.hpp, which includes this file) for
    // bundled_result.
    enum graph_bundle_t {graph_bundle};

    template <typename G>
    struct graph_property_type {
      typedef typename G::graph_property_type type;
    };
    template <typename G>
    struct edge_property_type {
      typedef typename G::edge_property_type type;
    };
    template <typename G>
    struct vertex_property_type {
      typedef typename G::vertex_property_type type;
    };

    struct no_bundle { };
    struct no_graph_bundle : no_bundle { };
    struct no_vertex_bundle : no_bundle { };
    struct no_edge_bundle : no_bundle { };

    template<typename G>
    struct graph_bundle_type {
      typedef typename G::graph_bundled type;
    };

    template<typename G>
    struct vertex_bundle_type {
      typedef typename G::vertex_bundled type;
    };

    template<typename G>
    struct edge_bundle_type {
      typedef typename G::edge_bundled type;
    };

    namespace graph { namespace detail {
        template<typename Graph, typename Descriptor>
        class bundled_result {
            typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
            typedef typename mpl::if_c<(is_same<Descriptor, Vertex>::value),
                                        vertex_bundle_type<Graph>,
                                        edge_bundle_type<Graph> >::type bundler;
        public:
            typedef typename bundler::type type;
        };

        template<typename Graph>
        class bundled_result<Graph, graph_bundle_t> {
            typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
            typedef graph_bundle_type<Graph> bundler;
        public:
            typedef typename bundler::type type;
        };

    } } // namespace graph::detail

    namespace graph_detail {
      // A helper metafunction for determining whether or not a type is
      // bundled.
      template <typename T>
      struct is_no_bundle : mpl::bool_<is_convertible<T, no_bundle>::value>
      { };
    } // namespace graph_detail

    /** @name Graph Property Traits
     * These metafunctions (along with those above), can be used to access the
     * vertex and edge properties (bundled or otherwise) of vertices and
     * edges.
     */
    //@{
    template<typename Graph>
    struct has_graph_property
      : mpl::not_<
        typename detail::is_no_property<
          typename graph_property_type<Graph>::type
        >::type
      >::type
    { };

    template<typename Graph>
    struct has_bundled_graph_property
      : mpl::not_<
        graph_detail::is_no_bundle<typename graph_bundle_type<Graph>::type>
      >
    { };

    template <typename Graph>
    struct has_vertex_property
        : mpl::not_<
            typename detail::is_no_property<typename vertex_property_type<Graph>::type>
        >::type
    { };

    template <typename Graph>
    struct has_bundled_vertex_property
        : mpl::not_<
            graph_detail::is_no_bundle<typename vertex_bundle_type<Graph>::type>
        >
    { };

    template <typename Graph>
    struct has_edge_property
        : mpl::not_<
            typename detail::is_no_property<typename edge_property_type<Graph>::type>
        >::type
    { };

    template <typename Graph>
    struct has_bundled_edge_property
        : mpl::not_<
            graph_detail::is_no_bundle<typename edge_bundle_type<Graph>::type>
        >
    { };
    //@}

} // namespace boost

// Since pair is in namespace std, Koenig lookup will find source and
// target if they are also defined in namespace std.  This is illegal,
// but the alternative is to put source and target in the global
// namespace which causes name conflicts with other libraries (like
// SUIF).
namespace std {

  /* Some helper functions for dealing with pairs as edges */
  template <class T, class G>
  T source(pair<T,T> p, const G&) { return p.first; }

  template <class T, class G>
  T target(pair<T,T> p, const G&) { return p.second; }

}

#if defined(__GNUC__) && defined(__SGI_STL_PORT)
// For some reason g++ with STLport does not see the above definition
// of source() and target() unless we bring them into the boost
// namespace.
namespace boost {
  using std::source;
  using std::target;
}
#endif

#endif // BOOST_GRAPH_TRAITS_HPP