1 // (C) Copyright Jeremy Siek 2004 |
1 // (C) Copyright Jeremy Siek 2004 |
2 // Distributed under the Boost Software License, Version 1.0. (See |
2 // Distributed under the Boost Software License, Version 1.0. (See |
3 // accompanying file LICENSE_1_0.txt or copy at |
3 // accompanying file LICENSE_1_0.txt or copy at |
4 // http://www.boost.org/LICENSE_1_0.txt) |
4 // http://www.boost.org/LICENSE_1_0.txt) |
5 |
5 |
6 #ifndef BOOST_PROPERTY_HPP |
6 #ifndef BOOST_DETAIL_PROPERTY_HPP |
7 #define BOOST_PROPERTY_HPP |
7 #define BOOST_DETAIL_PROPERTY_HPP |
8 |
8 |
9 #include <boost/pending/ct_if.hpp> |
9 #include <utility> // for std::pair |
|
10 #include <boost/type_traits/same_traits.hpp> // for is_same |
10 |
11 |
11 namespace boost { |
12 namespace boost { |
12 |
13 |
13 struct no_property { |
14 namespace detail { |
14 typedef no_property tag_type; |
|
15 typedef no_property next_type; |
|
16 typedef no_property value_type; |
|
17 enum { num = 0 }; |
|
18 typedef void kind; |
|
19 }; |
|
20 |
15 |
21 template <class Tag, class T, class Base = no_property> |
16 template <class PropertyTag1, class PropertyTag2> |
22 struct property : public Base { |
17 struct same_property { |
23 typedef Base next_type; |
18 enum { value = is_same<PropertyTag1,PropertyTag2>::value }; |
24 typedef Tag tag_type; |
19 }; |
25 typedef T value_type; |
20 |
26 #if BOOST_WORKAROUND (__GNUC__, < 3) |
21 struct error_property_not_found { }; |
27 property() { } |
22 |
|
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) { |
|
27 return p.m_value; |
|
28 } |
|
29 template <class PropertyTag, class T, class Tag> |
|
30 inline static const T& const_get_value(const PropertyTag& p, T*, Tag) { |
|
31 return p.m_value; |
|
32 } |
|
33 }; |
|
34 |
|
35 template <class PropertyList> |
|
36 struct property_value_end { |
|
37 template <class T> struct result { typedef T type; }; |
|
38 |
|
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); |
|
46 } |
|
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); |
|
54 } |
|
55 }; |
|
56 template <> |
|
57 struct property_value_end<no_property> { |
|
58 template <class T> struct result { |
|
59 typedef detail::error_property_not_found type; |
|
60 }; |
|
61 |
|
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; |
|
68 } |
|
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; |
|
74 } |
|
75 }; |
|
76 |
|
77 template <> |
|
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); |
|
83 } |
|
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); |
|
88 } |
|
89 }; |
|
90 |
|
91 template <class PropertyList> |
|
92 struct build_property_tag_value_alist |
|
93 { |
|
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; |
|
99 }; |
|
100 template <> |
|
101 struct build_property_tag_value_alist<no_property> |
|
102 { |
|
103 typedef no_property type; |
|
104 }; |
|
105 |
|
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; |
|
110 }; |
|
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; |
|
114 }; |
|
115 template <class Value, class Tag, class Rest> |
|
116 struct extract_value< std::pair<std::pair<Tag,Value>,Rest>, Tag> { |
|
117 typedef Value type; |
|
118 }; |
28 #else |
119 #else |
29 property() : m_value() { } |
120 // VC++ workaround: |
30 #endif |
121 // The main idea here is to replace partial specialization with |
31 property(const T& v) : m_value(v) { } |
122 // nested template member classes. Of course there is the |
32 property(const T& v, const Base& b) : Base(b), m_value(v) { } |
123 // further complication that the outer class of the nested |
33 // copy constructor and assignment operator will be generated by compiler |
124 // template class cannot itself be a template class. |
|
125 // Hence the need for the ev_selector. -JGS |
34 |
126 |
35 T m_value; |
127 struct recursive_extract; |
36 }; |
128 struct end_extract; |
37 |
129 |
38 // The BGL properties specialize property_kind and |
130 template <class TagValueAList> |
39 // property_num, and use enum's for the Property type (see |
131 struct ev_selector { typedef recursive_extract type; }; |
40 // graph/properties.hpp), but the user may want to use a class |
132 template <> |
41 // instead with a nested kind type and num. Also, we may want to |
133 struct ev_selector<no_property> { typedef end_extract type; }; |
42 // switch BGL back to using class types for properties at some point. |
|
43 |
134 |
44 template <class PropertyTag> |
135 struct recursive_extract { |
45 struct property_kind { |
136 template <class TagValueAList, class Tag1> |
46 typedef typename PropertyTag::kind type; |
137 struct bind_ { |
47 }; |
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 |
|
146 >::type type; |
|
147 }; |
|
148 }; |
|
149 struct end_extract { |
|
150 template <class AList, class Tag1> |
|
151 struct bind_ { |
|
152 typedef error_property_not_found type; |
|
153 }; |
|
154 }; |
|
155 #endif //!defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION |
48 |
156 |
49 template <class P> |
157 } // namespace detail |
50 struct has_property { |
|
51 BOOST_STATIC_CONSTANT(bool, value = true); |
|
52 typedef true_type type; |
|
53 }; |
|
54 template <> |
|
55 struct has_property<no_property> { |
|
56 BOOST_STATIC_CONSTANT(bool, value = false); |
|
57 typedef false_type type; |
|
58 }; |
|
59 |
|
60 } // namespace boost |
158 } // namespace boost |
61 |
159 |
62 #include <boost/pending/detail/property.hpp> |
160 #endif // BOOST_DETAIL_PROPERTY_HPP |
63 |
|
64 namespace boost { |
|
65 |
|
66 template <class PropertyList, class Tag> |
|
67 struct property_value { |
|
68 #if !defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION |
|
69 typedef typename detail::build_property_tag_value_alist<PropertyList>::type AList; |
|
70 typedef typename detail::extract_value<AList,Tag>::type type; |
|
71 #else |
|
72 typedef typename detail::build_property_tag_value_alist<PropertyList>::type AList; |
|
73 typedef typename detail::ev_selector<AList>::type Extractor; |
|
74 typedef typename Extractor::template bind_<AList,Tag>::type type; |
|
75 #endif |
|
76 }; |
|
77 |
|
78 template <class Tag1, class Tag2, class T1, class Base> |
|
79 inline typename property_value<property<Tag1,T1,Base>, Tag2>::type& |
|
80 get_property_value(property<Tag1,T1,Base>& p, Tag2 tag2) { |
|
81 BOOST_STATIC_CONSTANT(bool, |
|
82 match = (detail::same_property<Tag1,Tag2>::value)); |
|
83 typedef property<Tag1,T1,Base> Prop; |
|
84 typedef typename property_value<Prop, Tag2>::type T2; |
|
85 T2* t2 = 0; |
|
86 typedef detail::property_value_dispatch<match> Dispatcher; |
|
87 return Dispatcher::get_value(p, t2, tag2); |
|
88 } |
|
89 template <class Tag1, class Tag2, class T1, class Base> |
|
90 inline |
|
91 const typename property_value<property<Tag1,T1,Base>, Tag2>::type& |
|
92 get_property_value(const property<Tag1,T1,Base>& p, Tag2 tag2) { |
|
93 BOOST_STATIC_CONSTANT(bool, |
|
94 match = (detail::same_property<Tag1,Tag2>::value)); |
|
95 typedef property<Tag1,T1,Base> Prop; |
|
96 typedef typename property_value<Prop, Tag2>::type T2; |
|
97 T2* t2 = 0; |
|
98 typedef detail::property_value_dispatch<match> Dispatcher; |
|
99 return Dispatcher::const_get_value(p, t2, tag2); |
|
100 } |
|
101 |
|
102 namespace detail { |
|
103 #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) |
|
104 template<typename FinalTag, typename FinalType> |
|
105 struct retag_property_list |
|
106 { |
|
107 typedef property<FinalTag, FinalType> type; |
|
108 typedef FinalType retagged; |
|
109 }; |
|
110 |
|
111 template<typename FinalTag, typename Tag, typename T, typename Base> |
|
112 struct retag_property_list<FinalTag, property<Tag, T, Base> > |
|
113 { |
|
114 private: |
|
115 typedef retag_property_list<FinalTag, Base> next; |
|
116 |
|
117 public: |
|
118 typedef property<Tag, T, typename next::type> type; |
|
119 typedef typename next::retagged retagged; |
|
120 }; |
|
121 |
|
122 template<typename FinalTag> |
|
123 struct retag_property_list<FinalTag, no_property> |
|
124 { |
|
125 typedef no_property type; |
|
126 typedef no_property retagged; |
|
127 }; |
|
128 #endif |
|
129 } |
|
130 } // namesapce boost |
|
131 |
|
132 #endif /* BOOST_PROPERTY_HPP */ |
|