// (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 #include #include #include #include namespace boost { struct no_property {}; template 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 struct get_kind {typedef void type;}; template struct get_kind {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 struct property_kind: graph_introspect_detail::get_kind::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 struct lookup_one_property_internal {BOOST_STATIC_CONSTANT(bool, found = false);}; // Special-case properties (vertex_all, edge_all, graph_all) #define BGL_ALL_PROP(tag) \ template \ struct lookup_one_property_internal { \ 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 \ struct lookup_one_property_internal, tag> { /* Avoid ambiguity */ \ BOOST_STATIC_CONSTANT(bool, found = true); \ typedef property 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 \ struct lookup_one_property_internal { \ 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 \ struct lookup_one_property_internal, BOOST_JOIN(kind, _bundle_t)>: lookup_one_property_internal { \ private: \ typedef lookup_one_property_internal base_type; \ public: \ static typename base_type::type& lookup(property& p, BOOST_JOIN(kind, _bundle_t)) {return base_type::lookup(p.m_base, BOOST_JOIN(kind, _bundle_t)());} \ static const typename base_type::type& lookup(const property& p, BOOST_JOIN(kind, _bundle_t)) {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 struct lookup_one_property_internal, Tag> { BOOST_STATIC_CONSTANT(bool, found = true); typedef property prop; typedef T type; template static typename enable_if, T&>::type lookup(U& prop, const Tag&) {return prop.m_value;} template static typename enable_if, const T&>::type lookup(const U& prop, const Tag&) {return prop.m_value;} }; template struct lookup_one_property_internal, PropName>: lookup_one_property_internal { private: typedef lookup_one_property_internal base_type; public: template static typename enable_if >, typename base_type::type&>::type lookup(PL& prop, const PropName& tag) { return base_type::lookup(prop.m_base, tag); } template static typename enable_if >, 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 struct lookup_one_property_internal { BOOST_STATIC_CONSTANT(bool, found = true); typedef R type; static R& lookup(T& x, R T::*ptr) {return x.*ptr;} static const R& lookup(const T& x, R T::*ptr) {return x.*ptr;} }; #endif // Version of above handling const property lists properly template struct lookup_one_property: lookup_one_property_internal {}; template struct lookup_one_property { BOOST_STATIC_CONSTANT(bool, found = (lookup_one_property_internal::found)); typedef const typename lookup_one_property_internal::type type; template static typename enable_if, const typename lookup_one_property_internal::type&>::type lookup(const U& p, Tag tag) { return lookup_one_property_internal::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 struct has_property : boost::mpl::true_ {}; template <> struct has_property : boost::mpl::false_ {}; } // namespace boost #include namespace boost { template struct property_value: lookup_one_property {}; template inline typename lookup_one_property::type& get_property_value(PropertyList& p, Tag tag) { return lookup_one_property::lookup(p, tag); } template inline const typename lookup_one_property::type& get_property_value(const PropertyList& p, Tag tag) { return lookup_one_property::lookup(p, tag); } namespace detail { /** This trait returns true if T is no_property. */ template struct is_no_property : mpl::bool_::value> { }; /** @internal @name Retag Property List * This metafunction is used internally to normalize a property if it is * actually modeling a property. Specifically this is used in Boost.Graph * to map user-provided classes into bundled properties. */ //@{ // One base case of the recursive form (see below). This matches any // retag request that does not include a property<...> or no_property as // the FinalType. This is used for generating bundles in Boost.Graph. template struct retag_property_list { typedef property type; typedef FinalType retagged; }; // Recursively retag the nested property list. template struct retag_property_list > { private: typedef retag_property_list next; public: typedef property type; typedef typename next::retagged retagged; }; // This base case will correctly deduce the final property type if the // retagged property is given in property form. This should not hide // the base case below. // NOTE: This addresses a problem of layering bundled properties in the BGL // where multiple retaggings will fail to deduce the correct retagged // type. template struct retag_property_list > { public: typedef property type; typedef FinalType retagged; }; // A final base case of the retag_property_list, this will terminate a // properly structured list. template struct retag_property_list { typedef no_property type; typedef no_property retagged; }; //@} template class lookup_one_property_f; template struct lookup_one_property_f_result; template struct lookup_one_property_f_result(PList)> { typedef typename lookup_one_property::type type; }; template struct lookup_one_property_f_result(PList&)> { typedef typename lookup_one_property::type& type; }; template struct lookup_one_property_f_result(const PList&)> { typedef const typename lookup_one_property::type& type; }; template class lookup_one_property_f { Tag tag; public: lookup_one_property_f(Tag tag): tag(tag) {} template struct result: lookup_one_property_f_result {}; typename lookup_one_property_f_result::type operator()(PList& pl) const { return lookup_one_property::lookup(pl, tag); } }; } // namespace detail } // namesapce boost #endif /* BOOST_PROPERTY_HPP */