blob: 8ee02b7115efae83f5dd7e4fea9d0ae9abb2de91 [file] [log] [blame]
// (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>
namespace boost {
struct no_property {
typedef no_property tag_type;
typedef no_property next_type;
typedef no_property value_type;
enum { num = 0 };
typedef void kind;
};
template <class Tag, class T, class Base = no_property>
struct property : public Base {
typedef Base next_type;
typedef Tag tag_type;
typedef T value_type;
#if BOOST_WORKAROUND (__GNUC__, < 3)
property() { }
#else
property() : m_value() { }
#endif
property(const T& v) : m_value(v) { }
property(const T& v, const Base& b) : Base(b), m_value(v) { }
// copy constructor and assignment operator will be generated by compiler
T m_value;
};
// 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 PropertyTag>
struct property_kind {
typedef typename PropertyTag::kind type;
};
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 {
#if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
typedef typename detail::build_property_tag_value_alist<PropertyList>::type AList;
typedef typename detail::extract_value<AList,Tag>::type type;
#else
typedef typename detail::build_property_tag_value_alist<PropertyList>::type AList;
typedef typename detail::ev_selector<AList>::type Extractor;
typedef typename Extractor::template bind_<AList,Tag>::type type;
#endif
};
template <class Tag2>
inline detail::error_property_not_found
get_property_value(const no_property& p, Tag2) {
return detail::error_property_not_found();
}
template <class Tag1, class Tag2, class T1, class Base>
inline typename property_value<property<Tag1,T1,Base>, Tag2>::type&
get_property_value(property<Tag1,T1,Base>& p, Tag2 tag2) {
BOOST_STATIC_CONSTANT(bool,
match = (detail::same_property<Tag1,Tag2>::value));
typedef property<Tag1,T1,Base> Prop;
typedef typename property_value<Prop, Tag2>::type T2;
T2* t2 = 0;
typedef detail::property_value_dispatch<match> Dispatcher;
return Dispatcher::get_value(p, t2, tag2);
}
template <class Tag1, class Tag2, class T1, class Base>
inline
const typename property_value<property<Tag1,T1,Base>, Tag2>::type&
get_property_value(const property<Tag1,T1,Base>& p, Tag2 tag2) {
BOOST_STATIC_CONSTANT(bool,
match = (detail::same_property<Tag1,Tag2>::value));
typedef property<Tag1,T1,Base> Prop;
typedef typename property_value<Prop, Tag2>::type T2;
T2* t2 = 0;
typedef detail::property_value_dispatch<match> Dispatcher;
return Dispatcher::const_get_value(p, t2, tag2);
}
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>
{ };
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
/** @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<typename FinalTag, typename FinalType>
struct retag_property_list
{
typedef property<FinalTag, FinalType> type;
typedef FinalType retagged;
};
// Recursively retag the nested property list.
template<typename FinalTag, typename Tag, typename T, typename Base>
struct retag_property_list<FinalTag, property<Tag, T, Base> >
{
private:
typedef retag_property_list<FinalTag, Base> next;
public:
typedef property<Tag, T, typename next::type> 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<typename FinalTag, typename FinalType>
struct retag_property_list<FinalTag, property<FinalTag, FinalType> >
{
public:
typedef property<FinalTag, FinalType> type;
typedef FinalType retagged;
};
// A final base case of the retag_property_list, this will terminate a
// properly structured list.
template<typename FinalTag>
struct retag_property_list<FinalTag, no_property>
{
typedef no_property type;
typedef no_property retagged;
};
//@}
#endif
} // namespace detail
} // namesapce boost
#endif /* BOOST_PROPERTY_HPP */