// (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 */