Line data Source code
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 : struct no_property {};
19 :
20 : template <class Tag, class T, class Base = no_property>
21 : struct property {
22 : typedef Base next_type;
23 : typedef Tag tag_type;
24 : typedef T value_type;
25 0 : property(const T& v = T()) : m_value(v) { }
26 : property(const T& v, const Base& b) : m_value(v), m_base(b) { }
27 : // copy constructor and assignment operator will be generated by compiler
28 :
29 : T m_value;
30 : Base m_base;
31 : };
32 :
33 : // Kinds of properties
34 : namespace graph_introspect_detail {
35 : BOOST_MPL_HAS_XXX_TRAIT_DEF(kind)
36 : template <typename T, bool Cond> struct get_kind {typedef void type;};
37 : template <typename T> struct get_kind<T, true> {typedef typename T::kind type;};
38 : }
39 :
40 : // Having a default is to make this trait work for any type, not just valid
41 : // properties, to work around VC++ <= 10 bugs related to SFINAE in
42 : // compressed_sparse_row_graph's get functions and similar
43 : template <class PropertyTag>
44 : struct property_kind:
45 : graph_introspect_detail::get_kind<PropertyTag, graph_introspect_detail::has_kind<PropertyTag>::value>
46 : {};
47 :
48 : // Some standard properties defined independently of Boost.Graph:
49 : enum vertex_all_t {vertex_all};
50 : enum edge_all_t {edge_all};
51 : enum graph_all_t {graph_all};
52 : enum vertex_bundle_t {vertex_bundle};
53 : enum edge_bundle_t {edge_bundle};
54 : enum graph_bundle_t {graph_bundle};
55 :
56 : // Code to look up one property in a property list:
57 : template <typename PList, typename PropName, typename Enable = void>
58 : struct lookup_one_property_internal {BOOST_STATIC_CONSTANT(bool, found = false); typedef void type;};
59 :
60 : // Special-case properties (vertex_all, edge_all, graph_all)
61 : #define BGL_ALL_PROP(tag) \
62 : template <typename T> \
63 : struct lookup_one_property_internal<T, tag> { \
64 : BOOST_STATIC_CONSTANT(bool, found = true); \
65 : typedef T type; \
66 : static T& lookup(T& x, tag) {return x;} \
67 : static const T& lookup(const T& x, tag) {return x;} \
68 : }; \
69 : template <typename Tag, typename T, typename Base> \
70 : struct lookup_one_property_internal<property<Tag, T, Base>, tag> { /* Avoid ambiguity */ \
71 : BOOST_STATIC_CONSTANT(bool, found = true); \
72 : typedef property<Tag, T, Base> type; \
73 : static type& lookup(type& x, tag) {return x;} \
74 : static const type& lookup(const type& x, tag) {return x;} \
75 : };
76 :
77 : BGL_ALL_PROP(vertex_all_t)
78 : BGL_ALL_PROP(edge_all_t)
79 : BGL_ALL_PROP(graph_all_t)
80 : #undef BGL_ALL_PROP
81 :
82 : // *_bundled; these need to be macros rather than inheritance to resolve ambiguities
83 : #define BGL_DO_ONE_BUNDLE_TYPE(kind) \
84 : template <typename T> \
85 : struct lookup_one_property_internal<T, BOOST_JOIN(kind, _bundle_t)> { \
86 : BOOST_STATIC_CONSTANT(bool, found = true); \
87 : typedef T type; \
88 : static T& lookup(T& x, BOOST_JOIN(kind, _bundle_t)) {return x;} \
89 : static const T& lookup(const T& x, BOOST_JOIN(kind, _bundle_t)) {return x;} \
90 : }; \
91 : \
92 : template <typename Tag, typename T, typename Base> \
93 : struct lookup_one_property_internal<property<Tag, T, Base>, BOOST_JOIN(kind, _bundle_t)>: lookup_one_property_internal<Base, BOOST_JOIN(kind, _bundle_t)> { \
94 : private: \
95 : typedef lookup_one_property_internal<Base, BOOST_JOIN(kind, _bundle_t)> base_type; \
96 : public: \
97 : template <typename BundleTag> \
98 : static typename lazy_enable_if_c<(base_type::found && (is_same<BundleTag, BOOST_JOIN(kind, _bundle_t)>::value)), \
99 : add_reference<typename base_type::type> >::type \
100 : lookup(property<Tag, T, Base>& p, BundleTag) {return base_type::lookup(p.m_base, BOOST_JOIN(kind, _bundle_t)());} \
101 : template <typename BundleTag> \
102 : static typename lazy_enable_if_c<(base_type::found && (is_same<BundleTag, BOOST_JOIN(kind, _bundle_t)>::value)), \
103 : add_reference<const typename base_type::type> >::type \
104 : lookup(const property<Tag, T, Base>& p, BundleTag) {return base_type::lookup(p.m_base, BOOST_JOIN(kind, _bundle_t)());} \
105 : }; \
106 :
107 0 : BGL_DO_ONE_BUNDLE_TYPE(vertex)
108 0 : BGL_DO_ONE_BUNDLE_TYPE(edge)
109 : BGL_DO_ONE_BUNDLE_TYPE(graph)
110 : #undef BGL_DO_ONE_BUNDLE_TYPE
111 :
112 : // Normal old-style properties; second case also handles chaining of bundled property accesses
113 : template <typename Tag, typename T, typename Base>
114 : struct lookup_one_property_internal<boost::property<Tag, T, Base>, Tag> {
115 : BOOST_STATIC_CONSTANT(bool, found = true);
116 : typedef property<Tag, T, Base> prop;
117 : typedef T type;
118 : template <typename U>
119 : static typename enable_if<is_same<prop, U>, T&>::type
120 : lookup(U& prop, const Tag&) {return prop.m_value;}
121 : template <typename U>
122 : static typename enable_if<is_same<prop, U>, const T&>::type
123 0 : lookup(const U& prop, const Tag&) {return prop.m_value;}
124 : };
125 :
126 : template <typename Tag, typename T, typename Base, typename PropName>
127 : struct lookup_one_property_internal<boost::property<Tag, T, Base>, PropName>: lookup_one_property_internal<Base, PropName> {
128 : private:
129 : typedef lookup_one_property_internal<Base, PropName> base_type;
130 : public:
131 : template <typename PL>
132 : static typename lazy_enable_if<is_same<PL, boost::property<Tag, T, Base> >,
133 : add_reference<typename base_type::type> >::type
134 : lookup(PL& prop, const PropName& tag) {
135 : return base_type::lookup(prop.m_base, tag);
136 : }
137 : template <typename PL>
138 : static typename lazy_enable_if<is_same<PL, boost::property<Tag, T, Base> >,
139 : add_reference<const typename base_type::type> >::type
140 : lookup(const PL& prop, const PropName& tag) {
141 : return base_type::lookup(prop.m_base, tag);
142 : }
143 : };
144 :
145 : // Pointer-to-member access to bundled properties
146 : #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
147 : template <typename T, typename TMaybeBase, typename R>
148 : struct lookup_one_property_internal<T, R TMaybeBase::*, typename enable_if<is_base_of<TMaybeBase, T> >::type> {
149 : BOOST_STATIC_CONSTANT(bool, found = true);
150 : typedef R type;
151 : static R& lookup(T& x, R TMaybeBase::*ptr) {return x.*ptr;}
152 : static const R& lookup(const T& x, R TMaybeBase::*ptr) {return x.*ptr;}
153 : };
154 : #endif
155 :
156 : // Version of above handling const property lists properly
157 : template <typename T, typename Tag>
158 : struct lookup_one_property: lookup_one_property_internal<T, Tag> {};
159 :
160 : template <typename T, typename Tag>
161 : struct lookup_one_property<const T, Tag> {
162 : BOOST_STATIC_CONSTANT(bool, found = (lookup_one_property_internal<T, Tag>::found));
163 : typedef const typename lookup_one_property_internal<T, Tag>::type type;
164 : template <typename U>
165 : static typename lazy_enable_if<is_same<T, U>,
166 : add_reference<const typename lookup_one_property_internal<T, Tag>::type> >::type
167 : lookup(const U& p, Tag tag) {
168 : return lookup_one_property_internal<T, Tag>::lookup(p, tag);
169 : }
170 : };
171 :
172 : // The BGL properties specialize property_kind and
173 : // property_num, and use enum's for the Property type (see
174 : // graph/properties.hpp), but the user may want to use a class
175 : // instead with a nested kind type and num. Also, we may want to
176 : // switch BGL back to using class types for properties at some point.
177 :
178 : template <class P>
179 : struct has_property : boost::mpl::true_ {};
180 : template <>
181 : struct has_property<no_property> : boost::mpl::false_ {};
182 :
183 : } // namespace boost
184 :
185 : #include <boost/pending/detail/property.hpp>
186 :
187 : namespace boost {
188 :
189 : template <class PropertyList, class Tag>
190 : struct property_value: lookup_one_property<PropertyList, Tag> {};
191 :
192 : template <class PropertyList, class Tag>
193 : inline typename lookup_one_property<PropertyList, Tag>::type&
194 0 : get_property_value(PropertyList& p, Tag tag) {
195 0 : return lookup_one_property<PropertyList, Tag>::lookup(p, tag);
196 : }
197 :
198 : template <class PropertyList, class Tag>
199 : inline const typename lookup_one_property<PropertyList, Tag>::type&
200 0 : get_property_value(const PropertyList& p, Tag tag) {
201 0 : return lookup_one_property<PropertyList, Tag>::lookup(p, tag);
202 : }
203 :
204 : namespace detail {
205 :
206 : /** This trait returns true if T is no_property. */
207 : template <typename T>
208 : struct is_no_property
209 : : mpl::bool_<is_same<T, no_property>::value>
210 : { };
211 :
212 : template <typename PList, typename Tag>
213 : class lookup_one_property_f;
214 :
215 : template <typename PList, typename Tag, typename F> struct lookup_one_property_f_result;
216 :
217 : template <typename PList, typename Tag>
218 : struct lookup_one_property_f_result<PList, Tag, const lookup_one_property_f<PList, Tag>(PList)> {
219 : typedef typename lookup_one_property<PList, Tag>::type type;
220 : };
221 :
222 : template <typename PList, typename Tag>
223 : struct lookup_one_property_f_result<PList, Tag, const lookup_one_property_f<PList, Tag>(PList&)> {
224 : typedef typename lookup_one_property<PList, Tag>::type& type;
225 : };
226 :
227 : template <typename PList, typename Tag>
228 : struct lookup_one_property_f_result<PList, Tag, const lookup_one_property_f<PList, Tag>(const PList&)> {
229 : typedef const typename lookup_one_property<PList, Tag>::type& type;
230 : };
231 :
232 : template <typename PList, typename Tag>
233 : class lookup_one_property_f {
234 : Tag tag;
235 : public:
236 : lookup_one_property_f(Tag tag): tag(tag) {}
237 : template <typename F> struct result: lookup_one_property_f_result<PList, Tag, F> {};
238 :
239 : typename lookup_one_property_f_result<PList, Tag, const lookup_one_property_f(PList&)>::type
240 : operator()(PList& pl) const {
241 : return lookup_one_property<PList, Tag>::lookup(pl, tag);
242 : }
243 : };
244 :
245 : } // namespace detail
246 :
247 : namespace detail {
248 : // Stuff for directed_graph and undirected_graph to skip over their first
249 : // vertex_index and edge_index properties when providing vertex_all and
250 : // edge_all; make sure you know the exact structure of your properties if you
251 : // use there.
252 : struct remove_first_property {
253 : template <typename F>
254 : struct result {
255 : typedef typename boost::function_traits<F>::arg1_type a1;
256 : typedef typename boost::remove_reference<a1>::type non_ref;
257 : typedef typename non_ref::next_type nx;
258 : typedef typename boost::mpl::if_<boost::is_const<non_ref>, boost::add_const<nx>, nx>::type with_const;
259 : typedef typename boost::add_reference<with_const>::type type;
260 : };
261 : template <typename Prop>
262 : typename Prop::next_type& operator()(Prop& p) const {return p.m_base;}
263 : template <typename Prop>
264 : const typename Prop::next_type& operator()(const Prop& p) const {return p.m_base;}
265 : };
266 : }
267 :
268 : } // namesapce boost
269 :
270 : #endif /* BOOST_PROPERTY_HPP */
|