]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | 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 | BGL_DO_ONE_BUNDLE_TYPE(vertex) | |
108 | 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 | 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 | get_property_value(PropertyList& p, Tag tag) { | |
195 | 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 | get_property_value(const PropertyList& p, Tag tag) { | |
201 | 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 */ |