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