Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / pending / property.hpp
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 */