380 lines
14 KiB
C++
380 lines
14 KiB
C++
|
// (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 */
|