161 lines
5.6 KiB
C++
161 lines
5.6 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_DETAIL_PROPERTY_HPP
|
|
#define BOOST_DETAIL_PROPERTY_HPP
|
|
|
|
#include <utility> // for std::pair
|
|
#include <boost/type_traits/same_traits.hpp> // for is_same
|
|
|
|
namespace boost {
|
|
|
|
namespace detail {
|
|
|
|
template <class PropertyTag1, class PropertyTag2>
|
|
struct same_property {
|
|
enum { value = is_same<PropertyTag1,PropertyTag2>::value };
|
|
};
|
|
|
|
struct error_property_not_found { };
|
|
|
|
template <int TagMatched>
|
|
struct property_value_dispatch {
|
|
template <class PropertyTag, class T, class Tag>
|
|
inline static T& get_value(PropertyTag& p, T*, Tag) {
|
|
return p.m_value;
|
|
}
|
|
template <class PropertyTag, class T, class Tag>
|
|
inline static const T& const_get_value(const PropertyTag& p, T*, Tag) {
|
|
return p.m_value;
|
|
}
|
|
};
|
|
|
|
template <class PropertyList>
|
|
struct property_value_end {
|
|
template <class T> struct result { typedef T type; };
|
|
|
|
template <class T, class Tag>
|
|
inline static T& get_value(PropertyList& p, T* t, Tag tag) {
|
|
typedef typename PropertyList::next_type Next;
|
|
typedef typename Next::tag_type Next_tag;
|
|
enum { match = same_property<Next_tag,Tag>::value };
|
|
return property_value_dispatch<match>
|
|
::get_value(static_cast<Next&>(p), t, tag);
|
|
}
|
|
template <class T, class Tag>
|
|
inline static const T& const_get_value(const PropertyList& p, T* t, Tag tag) {
|
|
typedef typename PropertyList::next_type Next;
|
|
typedef typename Next::tag_type Next_tag;
|
|
enum { match = same_property<Next_tag,Tag>::value };
|
|
return property_value_dispatch<match>
|
|
::const_get_value(static_cast<const Next&>(p), t, tag);
|
|
}
|
|
};
|
|
template <>
|
|
struct property_value_end<no_property> {
|
|
template <class T> struct result {
|
|
typedef detail::error_property_not_found type;
|
|
};
|
|
|
|
// Stop the recursion and return error
|
|
template <class T, class Tag>
|
|
inline static detail::error_property_not_found&
|
|
get_value(no_property&, T*, Tag) {
|
|
static error_property_not_found s_prop_not_found;
|
|
return s_prop_not_found;
|
|
}
|
|
template <class T, class Tag>
|
|
inline static const detail::error_property_not_found&
|
|
const_get_value(const no_property&, T*, Tag) {
|
|
static error_property_not_found s_prop_not_found;
|
|
return s_prop_not_found;
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct property_value_dispatch<0> {
|
|
template <class PropertyList, class T, class Tag>
|
|
inline static typename property_value_end<PropertyList>::template result<T>::type&
|
|
get_value(PropertyList& p, T* t, Tag tag) {
|
|
return property_value_end<PropertyList>::get_value(p, t, tag);
|
|
}
|
|
template <class PropertyList, class T, class Tag>
|
|
inline static const typename property_value_end<PropertyList>::template result<T>::type&
|
|
const_get_value(const PropertyList& p, T* t, Tag tag) {
|
|
return property_value_end<PropertyList>::const_get_value(p, t, tag);
|
|
}
|
|
};
|
|
|
|
template <class PropertyList>
|
|
struct build_property_tag_value_alist
|
|
{
|
|
typedef typename PropertyList::next_type NextProperty;
|
|
typedef typename PropertyList::value_type Value;
|
|
typedef typename PropertyList::tag_type Tag;
|
|
typedef typename build_property_tag_value_alist<NextProperty>::type Next;
|
|
typedef std::pair< std::pair<Tag,Value>, Next> type;
|
|
};
|
|
template <>
|
|
struct build_property_tag_value_alist<no_property>
|
|
{
|
|
typedef no_property type;
|
|
};
|
|
|
|
#if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
|
template <class TagValueAList, class Tag>
|
|
struct extract_value {
|
|
typedef error_property_not_found type;
|
|
};
|
|
template <class Value, class Tag1, class Tag2, class Rest>
|
|
struct extract_value< std::pair<std::pair<Tag1,Value>,Rest>, Tag2> {
|
|
typedef typename extract_value<Rest,Tag2>::type type;
|
|
};
|
|
template <class Value, class Tag, class Rest>
|
|
struct extract_value< std::pair<std::pair<Tag,Value>,Rest>, Tag> {
|
|
typedef Value type;
|
|
};
|
|
#else
|
|
// VC++ workaround:
|
|
// The main idea here is to replace partial specialization with
|
|
// nested template member classes. Of course there is the
|
|
// further complication that the outer class of the nested
|
|
// template class cannot itself be a template class.
|
|
// Hence the need for the ev_selector. -JGS
|
|
|
|
struct recursive_extract;
|
|
struct end_extract;
|
|
|
|
template <class TagValueAList>
|
|
struct ev_selector { typedef recursive_extract type; };
|
|
template <>
|
|
struct ev_selector<no_property> { typedef end_extract type; };
|
|
|
|
struct recursive_extract {
|
|
template <class TagValueAList, class Tag1>
|
|
struct bind_ {
|
|
typedef typename TagValueAList::first_type AListFirst;
|
|
typedef typename AListFirst::first_type Tag2;
|
|
typedef typename AListFirst::second_type Value;
|
|
enum { match = same_property<Tag1,Tag2>::value };
|
|
typedef typename TagValueAList::second_type Next;
|
|
typedef typename ev_selector<Next>::type Extractor;
|
|
typedef typename boost::ct_if< match, Value,
|
|
typename Extractor::template bind_<Next,Tag1>::type
|
|
>::type type;
|
|
};
|
|
};
|
|
struct end_extract {
|
|
template <class AList, class Tag1>
|
|
struct bind_ {
|
|
typedef error_property_not_found type;
|
|
};
|
|
};
|
|
#endif //!defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
|
|
|
} // namespace detail
|
|
} // namespace boost
|
|
|
|
#endif // BOOST_DETAIL_PROPERTY_HPP
|