summaryrefslogtreecommitdiff
path: root/boost/pending/property.hpp
blob: e63a2d203f4641957910ed7d2b686b8e2933b886 (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
//  (C) Copyright Jeremy Siek 2004
//  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_PROPERTY_HPP
#define BOOST_PROPERTY_HPP

#include <boost/mpl/bool.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/has_xxx.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>

namespace boost {

  struct no_property {};

  template <class Tag, class T, class Base = no_property>
  struct property {
    typedef Base next_type;
    typedef Tag tag_type;
    typedef T value_type;
    property(const T& v = T()) : m_value(v) { }
    property(const T& v, const Base& b) : m_value(v), m_base(b) { }
    // copy constructor and assignment operator will be generated by compiler

    T m_value;
    Base m_base;
  };

  // Kinds of properties
  namespace graph_introspect_detail {
    BOOST_MPL_HAS_XXX_TRAIT_DEF(kind)
    template <typename T, bool Cond> struct get_kind {typedef void type;};
    template <typename T> struct get_kind<T, true> {typedef typename T::kind type;};
  }

  // Having a default is to make this trait work for any type, not just valid
  // properties, to work around VC++ <= 10 bugs related to SFINAE in
  // compressed_sparse_row_graph's get functions and similar
  template <class PropertyTag>
  struct property_kind:
    graph_introspect_detail::get_kind<PropertyTag, graph_introspect_detail::has_kind<PropertyTag>::value>
  {};

  // Some standard properties defined independently of Boost.Graph:
  enum vertex_all_t {vertex_all};
  enum edge_all_t {edge_all};
  enum graph_all_t {graph_all};
  enum vertex_bundle_t {vertex_bundle};
  enum edge_bundle_t {edge_bundle};
  enum graph_bundle_t {graph_bundle};

  // Code to look up one property in a property list:
  template <typename PList, typename PropName, typename Enable = void>
  struct lookup_one_property_internal {BOOST_STATIC_CONSTANT(bool, found = false); typedef void type;};

  // Special-case properties (vertex_all, edge_all, graph_all)
#define BGL_ALL_PROP(tag) \
  template <typename T> \
  struct lookup_one_property_internal<T, tag> { \
    BOOST_STATIC_CONSTANT(bool, found = true); \
    typedef T type; \
    static T& lookup(T& x, tag) {return x;} \
    static const T& lookup(const T& x, tag) {return x;} \
  }; \
  template <typename Tag, typename T, typename Base> \
  struct lookup_one_property_internal<property<Tag, T, Base>, tag> { /* Avoid ambiguity */ \
    BOOST_STATIC_CONSTANT(bool, found = true); \
    typedef property<Tag, T, Base> type; \
    static type& lookup(type& x, tag) {return x;} \
    static const type& lookup(const type& x, tag) {return x;} \
  };

  BGL_ALL_PROP(vertex_all_t)
  BGL_ALL_PROP(edge_all_t)
  BGL_ALL_PROP(graph_all_t)
#undef BGL_ALL_PROP

  // *_bundled; these need to be macros rather than inheritance to resolve ambiguities
  #define BGL_DO_ONE_BUNDLE_TYPE(kind) \
  template <typename T> \
  struct lookup_one_property_internal<T, BOOST_JOIN(kind, _bundle_t)> { \
    BOOST_STATIC_CONSTANT(bool, found = true); \
    typedef T type; \
    static T& lookup(T& x, BOOST_JOIN(kind, _bundle_t)) {return x;} \
    static const T& lookup(const T& x, BOOST_JOIN(kind, _bundle_t)) {return x;} \
  }; \
 \
  template <typename Tag, typename T, typename Base> \
  struct lookup_one_property_internal<property<Tag, T, Base>, BOOST_JOIN(kind, _bundle_t)>: lookup_one_property_internal<Base, BOOST_JOIN(kind, _bundle_t)> { \
    private: \
    typedef lookup_one_property_internal<Base, BOOST_JOIN(kind, _bundle_t)> base_type; \
    public: \
    template <typename BundleTag> \
    static typename lazy_enable_if_c<(base_type::found && (is_same<BundleTag, BOOST_JOIN(kind, _bundle_t)>::value)), \
                                     add_reference<typename base_type::type> >::type \
    lookup(property<Tag, T, Base>& p, BundleTag) {return base_type::lookup(p.m_base, BOOST_JOIN(kind, _bundle_t)());} \
    template <typename BundleTag> \
    static typename lazy_enable_if_c<(base_type::found && (is_same<BundleTag, BOOST_JOIN(kind, _bundle_t)>::value)), \
                                     add_reference<const typename base_type::type> >::type \
    lookup(const property<Tag, T, Base>& p, BundleTag) {return base_type::lookup(p.m_base, BOOST_JOIN(kind, _bundle_t)());} \
  }; \

  BGL_DO_ONE_BUNDLE_TYPE(vertex)
  BGL_DO_ONE_BUNDLE_TYPE(edge)
  BGL_DO_ONE_BUNDLE_TYPE(graph)
#undef BGL_DO_ONE_BUNDLE_TYPE

  // Normal old-style properties; second case also handles chaining of bundled property accesses
  template <typename Tag, typename T, typename Base>
  struct lookup_one_property_internal<boost::property<Tag, T, Base>, Tag> {
    BOOST_STATIC_CONSTANT(bool, found = true);
    typedef property<Tag, T, Base> prop;
    typedef T type;
    template <typename U>
    static typename enable_if<is_same<prop, U>, T&>::type
    lookup(U& prop, const Tag&) {return prop.m_value;}
    template <typename U>
    static typename enable_if<is_same<prop, U>, const T&>::type
    lookup(const U& prop, const Tag&) {return prop.m_value;}
  };

  template <typename Tag, typename T, typename Base, typename PropName>
  struct lookup_one_property_internal<boost::property<Tag, T, Base>, PropName>: lookup_one_property_internal<Base, PropName> {
    private:
    typedef lookup_one_property_internal<Base, PropName> base_type;
    public:
    template <typename PL>
    static typename lazy_enable_if<is_same<PL, boost::property<Tag, T, Base> >,
                                   add_reference<typename base_type::type> >::type
    lookup(PL& prop, const PropName& tag) {
      return base_type::lookup(prop.m_base, tag);
    }
    template <typename PL>
    static typename lazy_enable_if<is_same<PL, boost::property<Tag, T, Base> >,
                                   add_reference<const typename base_type::type> >::type
    lookup(const PL& prop, const PropName& tag) {
      return base_type::lookup(prop.m_base, tag);
    }
  };

  // Pointer-to-member access to bundled properties
#ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
  template <typename T, typename TMaybeBase, typename R>
  struct lookup_one_property_internal<T, R TMaybeBase::*, typename enable_if<is_base_of<TMaybeBase, T> >::type> {
    BOOST_STATIC_CONSTANT(bool, found = true);
    typedef R type;
    static R& lookup(T& x, R TMaybeBase::*ptr) {return x.*ptr;}
    static const R& lookup(const T& x, R TMaybeBase::*ptr) {return x.*ptr;}
  };
#endif

  // Version of above handling const property lists properly
  template <typename T, typename Tag>
  struct lookup_one_property: lookup_one_property_internal<T, Tag> {};

  template <typename T, typename Tag>
  struct lookup_one_property<const T, Tag> {
    BOOST_STATIC_CONSTANT(bool, found = (lookup_one_property_internal<T, Tag>::found));
    typedef const typename lookup_one_property_internal<T, Tag>::type type;
    template <typename U>
    static typename lazy_enable_if<is_same<T, U>,
                                   add_reference<const typename lookup_one_property_internal<T, Tag>::type> >::type
    lookup(const U& p, Tag tag) {
      return lookup_one_property_internal<T, Tag>::lookup(p, tag);
    }
  };

  // The BGL properties specialize property_kind and
  // property_num, and use enum's for the Property type (see
  // graph/properties.hpp), but the user may want to use a class
  // instead with a nested kind type and num.  Also, we may want to
  // switch BGL back to using class types for properties at some point.

  template <class P>
  struct has_property : boost::mpl::true_ {};
  template <>
  struct has_property<no_property> : boost::mpl::false_ {};

} // namespace boost

#include <boost/pending/detail/property.hpp>

namespace boost {

  template <class PropertyList, class Tag>
  struct property_value: lookup_one_property<PropertyList, Tag> {};

  template <class PropertyList, class Tag>
  inline typename lookup_one_property<PropertyList, Tag>::type&
  get_property_value(PropertyList& p, Tag tag) {
    return lookup_one_property<PropertyList, Tag>::lookup(p, tag);
  }

  template <class PropertyList, class Tag>
  inline const typename lookup_one_property<PropertyList, Tag>::type&
  get_property_value(const PropertyList& p, Tag tag) {
    return lookup_one_property<PropertyList, Tag>::lookup(p, tag);
  }

 namespace detail {

     /** This trait returns true if T is no_property. */
    template <typename T>
    struct is_no_property
        : mpl::bool_<is_same<T, no_property>::value>
    { };

    template <typename PList, typename Tag>
    class lookup_one_property_f;

    template <typename PList, typename Tag, typename F> struct lookup_one_property_f_result;

    template <typename PList, typename Tag>
    struct lookup_one_property_f_result<PList, Tag, const lookup_one_property_f<PList, Tag>(PList)> {
      typedef typename lookup_one_property<PList, Tag>::type type;
    };

    template <typename PList, typename Tag>
    struct lookup_one_property_f_result<PList, Tag, const lookup_one_property_f<PList, Tag>(PList&)> {
      typedef typename lookup_one_property<PList, Tag>::type& type;
    };

    template <typename PList, typename Tag>
    struct lookup_one_property_f_result<PList, Tag, const lookup_one_property_f<PList, Tag>(const PList&)> {
      typedef const typename lookup_one_property<PList, Tag>::type& type;
    };

    template <typename PList, typename Tag>
    class lookup_one_property_f {
      Tag tag;
      public:
      lookup_one_property_f(Tag tag): tag(tag) {}
      template <typename F> struct result: lookup_one_property_f_result<PList, Tag, F> {};

      typename lookup_one_property_f_result<PList, Tag, const lookup_one_property_f(PList&)>::type
      operator()(PList& pl) const {
        return lookup_one_property<PList, Tag>::lookup(pl, tag);
      }
    };

} // namespace detail

namespace detail {
  // Stuff for directed_graph and undirected_graph to skip over their first
  // vertex_index and edge_index properties when providing vertex_all and
  // edge_all; make sure you know the exact structure of your properties if you
  // use there.
  struct remove_first_property {
    template <typename F>
    struct result {
      typedef typename boost::function_traits<F>::arg1_type a1;
      typedef typename boost::remove_reference<a1>::type non_ref;
      typedef typename non_ref::next_type nx;
      typedef typename boost::mpl::if_<boost::is_const<non_ref>, boost::add_const<nx>, nx>::type with_const;
      typedef typename boost::add_reference<with_const>::type type;
    };
    template <typename Prop>
    typename Prop::next_type& operator()(Prop& p) const {return p.m_base;}
    template <typename Prop>
    const typename Prop::next_type& operator()(const Prop& p) const {return p.m_base;}
  };
}

} // namesapce boost

#endif /* BOOST_PROPERTY_HPP */