1 // (C) Copyright Jeremy Siek 2004
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
6 #ifndef BOOST_DETAIL_PROPERTY_HPP
7 #define BOOST_DETAIL_PROPERTY_HPP
9 #include <utility> // for std::pair
10 #include <boost/type_traits/same_traits.hpp> // for is_same
16 template <class PropertyTag1, class PropertyTag2>
17 struct same_property {
18 enum { value = is_same<PropertyTag1,PropertyTag2>::value };
21 struct error_property_not_found { };
23 template <int TagMatched>
24 struct property_value_dispatch {
25 template <class PropertyTag, class T, class Tag>
26 inline static T& get_value(PropertyTag& p, T*, Tag) {
29 template <class PropertyTag, class T, class Tag>
30 inline static const T& const_get_value(const PropertyTag& p, T*, Tag) {
35 template <class PropertyList>
36 struct property_value_end {
37 template <class T> struct result { typedef T type; };
39 template <class T, class Tag>
40 inline static T& get_value(PropertyList& p, T* t, Tag tag) {
41 typedef typename PropertyList::next_type Next;
42 typedef typename Next::tag_type Next_tag;
43 enum { match = same_property<Next_tag,Tag>::value };
44 return property_value_dispatch<match>
45 ::get_value(static_cast<Next&>(p), t, tag);
47 template <class T, class Tag>
48 inline static const T& const_get_value(const PropertyList& p, T* t, Tag tag) {
49 typedef typename PropertyList::next_type Next;
50 typedef typename Next::tag_type Next_tag;
51 enum { match = same_property<Next_tag,Tag>::value };
52 return property_value_dispatch<match>
53 ::const_get_value(static_cast<const Next&>(p), t, tag);
57 struct property_value_end<no_property> {
58 template <class T> struct result {
59 typedef detail::error_property_not_found type;
62 // Stop the recursion and return error
63 template <class T, class Tag>
64 inline static detail::error_property_not_found&
65 get_value(no_property&, T*, Tag) {
66 static error_property_not_found s_prop_not_found;
67 return s_prop_not_found;
69 template <class T, class Tag>
70 inline static const detail::error_property_not_found&
71 const_get_value(const no_property&, T*, Tag) {
72 static error_property_not_found s_prop_not_found;
73 return s_prop_not_found;
78 struct property_value_dispatch<0> {
79 template <class PropertyList, class T, class Tag>
80 inline static typename property_value_end<PropertyList>::template result<T>::type&
81 get_value(PropertyList& p, T* t, Tag tag) {
82 return property_value_end<PropertyList>::get_value(p, t, tag);
84 template <class PropertyList, class T, class Tag>
85 inline static const typename property_value_end<PropertyList>::template result<T>::type&
86 const_get_value(const PropertyList& p, T* t, Tag tag) {
87 return property_value_end<PropertyList>::const_get_value(p, t, tag);
91 template <class PropertyList>
92 struct build_property_tag_value_alist
94 typedef typename PropertyList::next_type NextProperty;
95 typedef typename PropertyList::value_type Value;
96 typedef typename PropertyList::tag_type Tag;
97 typedef typename build_property_tag_value_alist<NextProperty>::type Next;
98 typedef std::pair< std::pair<Tag,Value>, Next> type;
101 struct build_property_tag_value_alist<no_property>
103 typedef no_property type;
106 #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
107 template <class TagValueAList, class Tag>
108 struct extract_value {
109 typedef error_property_not_found type;
111 template <class Value, class Tag1, class Tag2, class Rest>
112 struct extract_value< std::pair<std::pair<Tag1,Value>,Rest>, Tag2> {
113 typedef typename extract_value<Rest,Tag2>::type type;
115 template <class Value, class Tag, class Rest>
116 struct extract_value< std::pair<std::pair<Tag,Value>,Rest>, Tag> {
121 // The main idea here is to replace partial specialization with
122 // nested template member classes. Of course there is the
123 // further complication that the outer class of the nested
124 // template class cannot itself be a template class.
125 // Hence the need for the ev_selector. -JGS
127 struct recursive_extract;
130 template <class TagValueAList>
131 struct ev_selector { typedef recursive_extract type; };
133 struct ev_selector<no_property> { typedef end_extract type; };
135 struct recursive_extract {
136 template <class TagValueAList, class Tag1>
138 typedef typename TagValueAList::first_type AListFirst;
139 typedef typename AListFirst::first_type Tag2;
140 typedef typename AListFirst::second_type Value;
141 enum { match = same_property<Tag1,Tag2>::value };
142 typedef typename TagValueAList::second_type Next;
143 typedef typename ev_selector<Next>::type Extractor;
144 typedef typename boost::ct_if< match, Value,
145 typename Extractor::template bind_<Next,Tag1>::type
150 template <class AList, class Tag1>
152 typedef error_property_not_found type;
155 #endif //!defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
157 } // namespace detail
160 #endif // BOOST_DETAIL_PROPERTY_HPP