• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  (C) Copyright Jeremy Siek 2004
2 //  Distributed under the Boost Software License, Version 1.0. (See
3 //  accompanying file LICENSE_1_0.txt or copy at
4 //  http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef BOOST_PROPERTY_HPP
7 #define BOOST_PROPERTY_HPP
8 
9 #include <boost/mpl/bool.hpp>
10 #include <boost/mpl/if.hpp>
11 #include <boost/mpl/has_xxx.hpp>
12 #include <boost/utility/enable_if.hpp>
13 #include <boost/type_traits.hpp>
14 #include <boost/static_assert.hpp>
15 
16 namespace boost
17 {
18 
19 struct no_property
20 {
21 };
22 
23 template < class Tag, class T, class Base = no_property > struct property
24 {
25     typedef Base next_type;
26     typedef Tag tag_type;
27     typedef T value_type;
propertyboost::property28     property(const T& v = T()) : m_value(v) {}
propertyboost::property29     property(const T& v, const Base& b) : m_value(v), m_base(b) {}
30     // copy constructor and assignment operator will be generated by compiler
31 
32     T m_value;
33     Base m_base;
34 };
35 
36 // Kinds of properties
37 namespace graph_introspect_detail
38 {
39     BOOST_MPL_HAS_XXX_TRAIT_DEF(kind)
40     template < typename T, bool Cond > struct get_kind
41     {
42         typedef void type;
43     };
44     template < typename T > struct get_kind< T, true >
45     {
46         typedef typename T::kind type;
47     };
48 }
49 
50 // Having a default is to make this trait work for any type, not just valid
51 // properties, to work around VC++ <= 10 bugs related to SFINAE in
52 // compressed_sparse_row_graph's get functions and similar
53 template < class PropertyTag >
54 struct property_kind
55 : graph_introspect_detail::get_kind< PropertyTag,
56       graph_introspect_detail::has_kind< PropertyTag >::value >
57 {
58 };
59 
60 // Some standard properties defined independently of Boost.Graph:
61 enum vertex_all_t
62 {
63     vertex_all
64 };
65 enum edge_all_t
66 {
67     edge_all
68 };
69 enum graph_all_t
70 {
71     graph_all
72 };
73 enum vertex_bundle_t
74 {
75     vertex_bundle
76 };
77 enum edge_bundle_t
78 {
79     edge_bundle
80 };
81 enum graph_bundle_t
82 {
83     graph_bundle
84 };
85 
86 // Code to look up one property in a property list:
87 template < typename PList, typename PropName, typename Enable = void >
88 struct lookup_one_property_internal
89 {
90     BOOST_STATIC_CONSTANT(bool, found = false);
91     typedef void type;
92 };
93 
94 // Special-case properties (vertex_all, edge_all, graph_all)
95 #define BGL_ALL_PROP(tag)                                                 \
96     template < typename T > struct lookup_one_property_internal< T, tag > \
97     {                                                                     \
98         BOOST_STATIC_CONSTANT(bool, found = true);                        \
99         typedef T type;                                                   \
100         static T& lookup(T& x, tag) { return x; }                         \
101         static const T& lookup(const T& x, tag) { return x; }             \
102     };                                                                    \
103     template < typename Tag, typename T, typename Base >                  \
104     struct lookup_one_property_internal< property< Tag, T, Base >, tag >  \
105     { /* Avoid ambiguity */                                               \
106         BOOST_STATIC_CONSTANT(bool, found = true);                        \
107         typedef property< Tag, T, Base > type;                            \
108         static type& lookup(type& x, tag) { return x; }                   \
109         static const type& lookup(const type& x, tag) { return x; }       \
110     };
111 
112 BGL_ALL_PROP(vertex_all_t)
113 BGL_ALL_PROP(edge_all_t)
114 BGL_ALL_PROP(graph_all_t)
115 #undef BGL_ALL_PROP
116 
117 // *_bundled; these need to be macros rather than inheritance to resolve
118 // ambiguities
119 #define BGL_DO_ONE_BUNDLE_TYPE(kind)                                           \
120     template < typename T >                                                    \
121     struct lookup_one_property_internal< T, BOOST_JOIN(kind, _bundle_t) >      \
122     {                                                                          \
123         BOOST_STATIC_CONSTANT(bool, found = true);                             \
124         typedef T type;                                                        \
125         static T& lookup(T& x, BOOST_JOIN(kind, _bundle_t)) { return x; }      \
126         static const T& lookup(const T& x, BOOST_JOIN(kind, _bundle_t))        \
127         {                                                                      \
128             return x;                                                          \
129         }                                                                      \
130     };                                                                         \
131                                                                                \
132     template < typename Tag, typename T, typename Base >                       \
133     struct lookup_one_property_internal< property< Tag, T, Base >,             \
134         BOOST_JOIN(kind, _bundle_t) >                                          \
135     : lookup_one_property_internal< Base, BOOST_JOIN(kind, _bundle_t) >        \
136     {                                                                          \
137     private:                                                                   \
138         typedef lookup_one_property_internal< Base,                            \
139             BOOST_JOIN(kind, _bundle_t) >                                      \
140             base_type;                                                         \
141                                                                                \
142     public:                                                                    \
143         template < typename BundleTag >                                        \
144         static typename lazy_enable_if_c<                                      \
145             (base_type::found                                                  \
146                 && (is_same< BundleTag,                                        \
147                     BOOST_JOIN(kind, _bundle_t) >::value)),                    \
148             add_reference< typename base_type::type > >::type                  \
149         lookup(property< Tag, T, Base >& p, BundleTag)                         \
150         {                                                                      \
151             return base_type::lookup(p.m_base, BOOST_JOIN(kind, _bundle_t)()); \
152         }                                                                      \
153         template < typename BundleTag >                                        \
154         static typename lazy_enable_if_c<                                      \
155             (base_type::found                                                  \
156                 && (is_same< BundleTag,                                        \
157                     BOOST_JOIN(kind, _bundle_t) >::value)),                    \
158             add_reference< const typename base_type::type > >::type            \
159         lookup(const property< Tag, T, Base >& p, BundleTag)                   \
160         {                                                                      \
161             return base_type::lookup(p.m_base, BOOST_JOIN(kind, _bundle_t)()); \
162         }                                                                      \
163     };
164 
165 BGL_DO_ONE_BUNDLE_TYPE(vertex)
166 BGL_DO_ONE_BUNDLE_TYPE(edge)
167 BGL_DO_ONE_BUNDLE_TYPE(graph)
168 #undef BGL_DO_ONE_BUNDLE_TYPE
169 
170 // Normal old-style properties; second case also handles chaining of bundled
171 // property accesses
172 template < typename Tag, typename T, typename Base >
173 struct lookup_one_property_internal< boost::property< Tag, T, Base >, Tag >
174 {
175     BOOST_STATIC_CONSTANT(bool, found = true);
176     typedef property< Tag, T, Base > prop;
177     typedef T type;
178     template < typename U >
lookupboost::lookup_one_property_internal179     static typename enable_if< is_same< prop, U >, T& >::type lookup(
180         U& prop, const Tag&)
181     {
182         return prop.m_value;
183     }
184     template < typename U >
lookupboost::lookup_one_property_internal185     static typename enable_if< is_same< prop, U >, const T& >::type lookup(
186         const U& prop, const Tag&)
187     {
188         return prop.m_value;
189     }
190 };
191 
192 template < typename Tag, typename T, typename Base, typename PropName >
193 struct lookup_one_property_internal< boost::property< Tag, T, Base >, PropName >
194 : lookup_one_property_internal< Base, PropName >
195 {
196 private:
197     typedef lookup_one_property_internal< Base, PropName > base_type;
198 
199 public:
200     template < typename PL >
201     static
202         typename lazy_enable_if< is_same< PL, boost::property< Tag, T, Base > >,
203             add_reference< typename base_type::type > >::type
lookupboost::lookup_one_property_internal204         lookup(PL& prop, const PropName& tag)
205     {
206         return base_type::lookup(prop.m_base, tag);
207     }
208     template < typename PL >
209     static
210         typename lazy_enable_if< is_same< PL, boost::property< Tag, T, Base > >,
211             add_reference< const typename base_type::type > >::type
lookupboost::lookup_one_property_internal212         lookup(const PL& prop, const PropName& tag)
213     {
214         return base_type::lookup(prop.m_base, tag);
215     }
216 };
217 
218 // Pointer-to-member access to bundled properties
219 #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
220 template < typename T, typename TMaybeBase, typename R >
221 struct lookup_one_property_internal< T, R TMaybeBase::*,
222     typename enable_if< is_base_of< TMaybeBase, T > >::type >
223 {
224     BOOST_STATIC_CONSTANT(bool, found = true);
225     typedef R type;
lookupboost::lookup_one_property_internal226     static R& lookup(T& x, R TMaybeBase::*ptr) { return x.*ptr; }
lookupboost::lookup_one_property_internal227     static const R& lookup(const T& x, R TMaybeBase::*ptr) { return x.*ptr; }
228 };
229 #endif
230 
231 // Version of above handling const property lists properly
232 template < typename T, typename Tag >
233 struct lookup_one_property : lookup_one_property_internal< T, Tag >
234 {
235 };
236 
237 template < typename T, typename Tag > struct lookup_one_property< const T, Tag >
238 {
239     BOOST_STATIC_CONSTANT(
240         bool, found = (lookup_one_property_internal< T, Tag >::found));
241     typedef const typename lookup_one_property_internal< T, Tag >::type type;
242     template < typename U >
243     static typename lazy_enable_if< is_same< T, U >,
244         add_reference< const typename lookup_one_property_internal< T,
245             Tag >::type > >::type
lookupboost::lookup_one_property246     lookup(const U& p, Tag tag)
247     {
248         return lookup_one_property_internal< T, Tag >::lookup(p, tag);
249     }
250 };
251 
252 // The BGL properties specialize property_kind and
253 // property_num, and use enum's for the Property type (see
254 // graph/properties.hpp), but the user may want to use a class
255 // instead with a nested kind type and num.  Also, we may want to
256 // switch BGL back to using class types for properties at some point.
257 
258 template < class P > struct has_property : boost::mpl::true_
259 {
260 };
261 template <> struct has_property< no_property > : boost::mpl::false_
262 {
263 };
264 
265 } // namespace boost
266 
267 #include <boost/pending/detail/property.hpp>
268 
269 namespace boost
270 {
271 
272 template < class PropertyList, class Tag >
273 struct property_value : lookup_one_property< PropertyList, Tag >
274 {
275 };
276 
277 template < class PropertyList, class Tag >
278 inline typename lookup_one_property< PropertyList, Tag >::type&
get_property_value(PropertyList & p,Tag tag)279 get_property_value(PropertyList& p, Tag tag)
280 {
281     return lookup_one_property< PropertyList, Tag >::lookup(p, tag);
282 }
283 
284 template < class PropertyList, class Tag >
285 inline const typename lookup_one_property< PropertyList, Tag >::type&
get_property_value(const PropertyList & p,Tag tag)286 get_property_value(const PropertyList& p, Tag tag)
287 {
288     return lookup_one_property< PropertyList, Tag >::lookup(p, tag);
289 }
290 
291 namespace detail
292 {
293 
294     /** This trait returns true if T is no_property. */
295     template < typename T >
296     struct is_no_property : mpl::bool_< is_same< T, no_property >::value >
297     {
298     };
299 
300     template < typename PList, typename Tag > class lookup_one_property_f;
301 
302     template < typename PList, typename Tag, typename F >
303     struct lookup_one_property_f_result;
304 
305     template < typename PList, typename Tag >
306     struct lookup_one_property_f_result< PList, Tag,
307         const lookup_one_property_f< PList, Tag >(PList) >
308     {
309         typedef typename lookup_one_property< PList, Tag >::type type;
310     };
311 
312     template < typename PList, typename Tag >
313     struct lookup_one_property_f_result< PList, Tag,
314         const lookup_one_property_f< PList, Tag >(PList&) >
315     {
316         typedef typename lookup_one_property< PList, Tag >::type& type;
317     };
318 
319     template < typename PList, typename Tag >
320     struct lookup_one_property_f_result< PList, Tag,
321         const lookup_one_property_f< PList, Tag >(const PList&) >
322     {
323         typedef const typename lookup_one_property< PList, Tag >::type& type;
324     };
325 
326     template < typename PList, typename Tag > class lookup_one_property_f
327     {
328         Tag tag;
329 
330     public:
lookup_one_property_f(Tag tag)331         lookup_one_property_f(Tag tag) : tag(tag) {}
332         template < typename F >
333         struct result : lookup_one_property_f_result< PList, Tag, F >
334         {
335         };
336 
337         typename lookup_one_property_f_result< PList, Tag,
338             const lookup_one_property_f(PList&) >::type
operator ()(PList & pl) const339         operator()(PList& pl) const
340         {
341             return lookup_one_property< PList, Tag >::lookup(pl, tag);
342         }
343     };
344 
345 } // namespace detail
346 
347 namespace detail
348 {
349     // Stuff for directed_graph and undirected_graph to skip over their first
350     // vertex_index and edge_index properties when providing vertex_all and
351     // edge_all; make sure you know the exact structure of your properties if
352     // you use there.
353     struct remove_first_property
354     {
355         template < typename F > struct result
356         {
357             typedef typename boost::function_traits< F >::arg1_type a1;
358             typedef typename boost::remove_reference< a1 >::type non_ref;
359             typedef typename non_ref::next_type nx;
360             typedef typename boost::mpl::if_< boost::is_const< non_ref >,
361                 boost::add_const< nx >, nx >::type with_const;
362             typedef typename boost::add_reference< with_const >::type type;
363         };
364         template < typename Prop >
operator ()boost::detail::remove_first_property365         typename Prop::next_type& operator()(Prop& p) const
366         {
367             return p.m_base;
368         }
369         template < typename Prop >
operator ()boost::detail::remove_first_property370         const typename Prop::next_type& operator()(const Prop& p) const
371         {
372             return p.m_base;
373         }
374     };
375 }
376 
377 } // namesapce boost
378 
379 #endif /* BOOST_PROPERTY_HPP */
380