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