Chris@16: // (C) Copyright Jeremy Siek 2004 Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_PROPERTY_HPP Chris@16: #define BOOST_PROPERTY_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: struct no_property {}; Chris@16: Chris@16: template Chris@16: struct property { Chris@16: typedef Base next_type; Chris@16: typedef Tag tag_type; Chris@16: typedef T value_type; Chris@16: property(const T& v = T()) : m_value(v) { } Chris@16: property(const T& v, const Base& b) : m_value(v), m_base(b) { } Chris@16: // copy constructor and assignment operator will be generated by compiler Chris@16: Chris@16: T m_value; Chris@16: Base m_base; Chris@16: }; Chris@16: Chris@16: // Kinds of properties Chris@16: namespace graph_introspect_detail { Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(kind) Chris@16: template struct get_kind {typedef void type;}; Chris@16: template struct get_kind {typedef typename T::kind type;}; Chris@16: } Chris@16: Chris@16: // Having a default is to make this trait work for any type, not just valid Chris@16: // properties, to work around VC++ <= 10 bugs related to SFINAE in Chris@16: // compressed_sparse_row_graph's get functions and similar Chris@16: template Chris@16: struct property_kind: Chris@16: graph_introspect_detail::get_kind::value> Chris@16: {}; Chris@16: Chris@16: // Some standard properties defined independently of Boost.Graph: Chris@16: enum vertex_all_t {vertex_all}; Chris@16: enum edge_all_t {edge_all}; Chris@16: enum graph_all_t {graph_all}; Chris@16: enum vertex_bundle_t {vertex_bundle}; Chris@16: enum edge_bundle_t {edge_bundle}; Chris@16: enum graph_bundle_t {graph_bundle}; Chris@16: Chris@16: // Code to look up one property in a property list: Chris@16: template Chris@16: struct lookup_one_property_internal {BOOST_STATIC_CONSTANT(bool, found = false); typedef void type;}; Chris@16: Chris@16: // Special-case properties (vertex_all, edge_all, graph_all) Chris@16: #define BGL_ALL_PROP(tag) \ Chris@16: template \ Chris@16: struct lookup_one_property_internal { \ Chris@16: BOOST_STATIC_CONSTANT(bool, found = true); \ Chris@16: typedef T type; \ Chris@16: static T& lookup(T& x, tag) {return x;} \ Chris@16: static const T& lookup(const T& x, tag) {return x;} \ Chris@16: }; \ Chris@16: template \ Chris@16: struct lookup_one_property_internal, tag> { /* Avoid ambiguity */ \ Chris@16: BOOST_STATIC_CONSTANT(bool, found = true); \ Chris@16: typedef property type; \ Chris@16: static type& lookup(type& x, tag) {return x;} \ Chris@16: static const type& lookup(const type& x, tag) {return x;} \ Chris@16: }; Chris@16: Chris@16: BGL_ALL_PROP(vertex_all_t) Chris@16: BGL_ALL_PROP(edge_all_t) Chris@16: BGL_ALL_PROP(graph_all_t) Chris@16: #undef BGL_ALL_PROP Chris@16: Chris@16: // *_bundled; these need to be macros rather than inheritance to resolve ambiguities Chris@16: #define BGL_DO_ONE_BUNDLE_TYPE(kind) \ Chris@16: template \ Chris@16: struct lookup_one_property_internal { \ Chris@16: BOOST_STATIC_CONSTANT(bool, found = true); \ Chris@16: typedef T type; \ Chris@16: static T& lookup(T& x, BOOST_JOIN(kind, _bundle_t)) {return x;} \ Chris@16: static const T& lookup(const T& x, BOOST_JOIN(kind, _bundle_t)) {return x;} \ Chris@16: }; \ Chris@16: \ Chris@16: template \ Chris@16: struct lookup_one_property_internal, BOOST_JOIN(kind, _bundle_t)>: lookup_one_property_internal { \ Chris@16: private: \ Chris@16: typedef lookup_one_property_internal base_type; \ Chris@16: public: \ Chris@16: template \ Chris@16: static typename lazy_enable_if_c<(base_type::found && (is_same::value)), \ Chris@16: add_reference >::type \ Chris@16: lookup(property& p, BundleTag) {return base_type::lookup(p.m_base, BOOST_JOIN(kind, _bundle_t)());} \ Chris@16: template \ Chris@16: static typename lazy_enable_if_c<(base_type::found && (is_same::value)), \ Chris@16: add_reference >::type \ Chris@16: lookup(const property& p, BundleTag) {return base_type::lookup(p.m_base, BOOST_JOIN(kind, _bundle_t)());} \ Chris@16: }; \ Chris@16: Chris@16: BGL_DO_ONE_BUNDLE_TYPE(vertex) Chris@16: BGL_DO_ONE_BUNDLE_TYPE(edge) Chris@16: BGL_DO_ONE_BUNDLE_TYPE(graph) Chris@16: #undef BGL_DO_ONE_BUNDLE_TYPE Chris@16: Chris@16: // Normal old-style properties; second case also handles chaining of bundled property accesses Chris@16: template Chris@16: struct lookup_one_property_internal, Tag> { Chris@16: BOOST_STATIC_CONSTANT(bool, found = true); Chris@16: typedef property prop; Chris@16: typedef T type; Chris@16: template Chris@16: static typename enable_if, T&>::type Chris@16: lookup(U& prop, const Tag&) {return prop.m_value;} Chris@16: template Chris@16: static typename enable_if, const T&>::type Chris@16: lookup(const U& prop, const Tag&) {return prop.m_value;} Chris@16: }; Chris@16: Chris@16: template Chris@16: struct lookup_one_property_internal, PropName>: lookup_one_property_internal { Chris@16: private: Chris@16: typedef lookup_one_property_internal base_type; Chris@16: public: Chris@16: template Chris@16: static typename lazy_enable_if >, Chris@16: add_reference >::type Chris@16: lookup(PL& prop, const PropName& tag) { Chris@16: return base_type::lookup(prop.m_base, tag); Chris@16: } Chris@16: template Chris@16: static typename lazy_enable_if >, Chris@16: add_reference >::type Chris@16: lookup(const PL& prop, const PropName& tag) { Chris@16: return base_type::lookup(prop.m_base, tag); Chris@16: } Chris@16: }; Chris@16: Chris@16: // Pointer-to-member access to bundled properties Chris@16: #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES Chris@16: template Chris@16: struct lookup_one_property_internal >::type> { Chris@16: BOOST_STATIC_CONSTANT(bool, found = true); Chris@16: typedef R type; Chris@16: static R& lookup(T& x, R TMaybeBase::*ptr) {return x.*ptr;} Chris@16: static const R& lookup(const T& x, R TMaybeBase::*ptr) {return x.*ptr;} Chris@16: }; Chris@16: #endif Chris@16: Chris@16: // Version of above handling const property lists properly Chris@16: template Chris@16: struct lookup_one_property: lookup_one_property_internal {}; Chris@16: Chris@16: template Chris@16: struct lookup_one_property { Chris@16: BOOST_STATIC_CONSTANT(bool, found = (lookup_one_property_internal::found)); Chris@16: typedef const typename lookup_one_property_internal::type type; Chris@16: template Chris@16: static typename lazy_enable_if, Chris@16: add_reference::type> >::type Chris@16: lookup(const U& p, Tag tag) { Chris@16: return lookup_one_property_internal::lookup(p, tag); Chris@16: } Chris@16: }; Chris@16: Chris@16: // The BGL properties specialize property_kind and Chris@16: // property_num, and use enum's for the Property type (see Chris@16: // graph/properties.hpp), but the user may want to use a class Chris@16: // instead with a nested kind type and num. Also, we may want to Chris@16: // switch BGL back to using class types for properties at some point. Chris@16: Chris@16: template Chris@16: struct has_property : boost::mpl::true_ {}; Chris@16: template <> Chris@16: struct has_property : boost::mpl::false_ {}; Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: template Chris@16: struct property_value: lookup_one_property {}; Chris@16: Chris@16: template Chris@16: inline typename lookup_one_property::type& Chris@16: get_property_value(PropertyList& p, Tag tag) { Chris@16: return lookup_one_property::lookup(p, tag); Chris@16: } Chris@16: Chris@16: template Chris@16: inline const typename lookup_one_property::type& Chris@16: get_property_value(const PropertyList& p, Tag tag) { Chris@16: return lookup_one_property::lookup(p, tag); Chris@16: } Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: /** This trait returns true if T is no_property. */ Chris@16: template Chris@16: struct is_no_property Chris@16: : mpl::bool_::value> Chris@16: { }; Chris@16: Chris@16: template Chris@16: class lookup_one_property_f; Chris@16: Chris@16: template struct lookup_one_property_f_result; Chris@16: Chris@16: template Chris@16: struct lookup_one_property_f_result(PList)> { Chris@16: typedef typename lookup_one_property::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct lookup_one_property_f_result(PList&)> { Chris@16: typedef typename lookup_one_property::type& type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct lookup_one_property_f_result(const PList&)> { Chris@16: typedef const typename lookup_one_property::type& type; Chris@16: }; Chris@16: Chris@16: template Chris@16: class lookup_one_property_f { Chris@16: Tag tag; Chris@16: public: Chris@16: lookup_one_property_f(Tag tag): tag(tag) {} Chris@16: template struct result: lookup_one_property_f_result {}; Chris@16: Chris@16: typename lookup_one_property_f_result::type Chris@16: operator()(PList& pl) const { Chris@16: return lookup_one_property::lookup(pl, tag); Chris@16: } Chris@16: }; Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: namespace detail { Chris@16: // Stuff for directed_graph and undirected_graph to skip over their first Chris@16: // vertex_index and edge_index properties when providing vertex_all and Chris@16: // edge_all; make sure you know the exact structure of your properties if you Chris@16: // use there. Chris@16: struct remove_first_property { Chris@16: template Chris@16: struct result { Chris@16: typedef typename boost::function_traits::arg1_type a1; Chris@16: typedef typename boost::remove_reference::type non_ref; Chris@16: typedef typename non_ref::next_type nx; Chris@16: typedef typename boost::mpl::if_, boost::add_const, nx>::type with_const; Chris@16: typedef typename boost::add_reference::type type; Chris@16: }; Chris@16: template Chris@16: typename Prop::next_type& operator()(Prop& p) const {return p.m_base;} Chris@16: template Chris@16: const typename Prop::next_type& operator()(const Prop& p) const {return p.m_base;} Chris@16: }; Chris@16: } Chris@16: Chris@16: } // namesapce boost Chris@16: Chris@16: #endif /* BOOST_PROPERTY_HPP */