]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.TypeErasure library |
2 | // | |
3 | // Copyright 2011 Steven Watanabe | |
4 | // | |
5 | // Distributed under the Boost Software License Version 1.0. (See | |
6 | // accompanying file LICENSE_1_0.txt or copy at | |
7 | // http://www.boost.org/LICENSE_1_0.txt) | |
8 | // | |
9 | // $Id$ | |
10 | ||
11 | #ifndef BOOST_TYPE_ERASURE_BINDING_HPP_INCLUDED | |
12 | #define BOOST_TYPE_ERASURE_BINDING_HPP_INCLUDED | |
13 | ||
14 | #include <boost/config.hpp> | |
15 | #include <boost/shared_ptr.hpp> | |
16 | #include <boost/make_shared.hpp> | |
17 | #include <boost/utility/enable_if.hpp> | |
18 | #include <boost/mpl/transform.hpp> | |
19 | #include <boost/mpl/find_if.hpp> | |
20 | #include <boost/mpl/and.hpp> | |
21 | #include <boost/mpl/not.hpp> | |
22 | #include <boost/mpl/end.hpp> | |
23 | #include <boost/mpl/bool.hpp> | |
24 | #include <boost/mpl/pair.hpp> | |
25 | #include <boost/type_traits/is_same.hpp> | |
26 | #include <boost/type_erasure/static_binding.hpp> | |
27 | #include <boost/type_erasure/is_subconcept.hpp> | |
28 | #include <boost/type_erasure/detail/adapt_to_vtable.hpp> | |
29 | #include <boost/type_erasure/detail/null.hpp> | |
30 | #include <boost/type_erasure/detail/rebind_placeholders.hpp> | |
31 | #include <boost/type_erasure/detail/vtable.hpp> | |
32 | #include <boost/type_erasure/detail/normalize.hpp> | |
33 | #include <boost/type_erasure/detail/instantiate.hpp> | |
34 | #include <boost/type_erasure/detail/check_map.hpp> | |
35 | ||
36 | namespace boost { | |
37 | namespace type_erasure { | |
38 | ||
39 | template<class P> | |
40 | class dynamic_binding; | |
41 | ||
42 | namespace detail { | |
43 | ||
44 | template<class Source, class Dest, class Map> | |
45 | struct can_optimize_conversion : ::boost::mpl::and_< | |
46 | ::boost::is_same<Source, Dest>, | |
47 | ::boost::is_same< | |
48 | typename ::boost::mpl::find_if< | |
49 | Map, | |
50 | ::boost::mpl::not_< | |
51 | ::boost::is_same< | |
52 | ::boost::mpl::first< ::boost::mpl::_1>, | |
53 | ::boost::mpl::second< ::boost::mpl::_1> | |
54 | > | |
55 | > | |
56 | >::type, | |
57 | typename ::boost::mpl::end<Map>::type | |
58 | > | |
59 | >::type | |
60 | {}; | |
61 | ||
62 | } | |
63 | ||
64 | /** | |
65 | * Stores the binding of a @c Concept to a set of actual types. | |
66 | * @c Concept is interpreted in the same way as with @ref any. | |
67 | */ | |
68 | template<class Concept> | |
69 | class binding | |
70 | { | |
71 | typedef typename ::boost::type_erasure::detail::normalize_concept< | |
72 | Concept>::type normalized; | |
73 | typedef typename ::boost::mpl::transform<normalized, | |
74 | ::boost::type_erasure::detail::maybe_adapt_to_vtable< ::boost::mpl::_1> | |
75 | >::type actual_concept; | |
76 | typedef typename ::boost::type_erasure::detail::make_vtable< | |
77 | actual_concept>::type table_type; | |
78 | typedef typename ::boost::type_erasure::detail::get_placeholder_normalization_map< | |
79 | Concept | |
80 | >::type placeholder_subs; | |
81 | public: | |
82 | ||
83 | /** | |
84 | * \pre @ref relaxed must be in @c Concept. | |
85 | * | |
86 | * \throws Nothing. | |
87 | */ | |
88 | binding() { BOOST_MPL_ASSERT((::boost::type_erasure::is_relaxed<Concept>)); } | |
89 | ||
90 | /** | |
91 | * \pre @c Map must be an MPL map with an entry for each placeholder | |
92 | * referred to by @c Concept. | |
93 | * | |
94 | * \throws Nothing. | |
95 | */ | |
96 | template<class Map> | |
97 | explicit binding(const Map&) | |
98 | : impl(( | |
99 | BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map), | |
100 | static_binding<Map>() | |
101 | )) | |
102 | {} | |
103 | ||
104 | /** | |
105 | * \pre @c Map must be an MPL map with an entry for each placeholder | |
106 | * referred to by @c Concept. | |
107 | * | |
108 | * \throws Nothing. | |
109 | */ | |
110 | template<class Map> | |
111 | binding(const static_binding<Map>&) | |
112 | : impl(( | |
113 | BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map), | |
114 | static_binding<Map>() | |
115 | )) | |
116 | {} | |
117 | ||
118 | /** | |
119 | * Converts from another set of bindings. | |
120 | * | |
121 | * \pre Map must be an MPL map with an entry for each placeholder | |
122 | * referred to by @c Concept. The mapped type should be the | |
123 | * corresponding placeholder in Concept2. | |
124 | * | |
125 | * \throws std::bad_alloc | |
126 | */ | |
127 | template<class Concept2, class Map> | |
128 | binding(const binding<Concept2>& other, const Map& | |
129 | #ifndef BOOST_TYPE_ERASURE_DOXYGEN | |
130 | , typename ::boost::enable_if< | |
131 | ::boost::mpl::and_< | |
132 | ::boost::type_erasure::detail::check_map<Concept, Map>, | |
133 | ::boost::type_erasure::is_subconcept<Concept, Concept2, Map> | |
134 | > | |
135 | >::type* = 0 | |
136 | #endif | |
137 | ) | |
138 | : impl( | |
139 | other, | |
140 | static_binding<Map>(), | |
141 | ::boost::type_erasure::detail::can_optimize_conversion<Concept2, Concept, Map>() | |
142 | ) | |
143 | {} | |
144 | ||
145 | /** | |
146 | * Converts from another set of bindings. | |
147 | * | |
148 | * \pre Map must be an MPL map with an entry for each placeholder | |
149 | * referred to by @c Concept. The mapped type should be the | |
150 | * corresponding placeholder in Concept2. | |
151 | * | |
152 | * \throws std::bad_alloc | |
153 | */ | |
154 | template<class Concept2, class Map> | |
155 | binding(const binding<Concept2>& other, const static_binding<Map>& | |
156 | #ifndef BOOST_TYPE_ERASURE_DOXYGEN | |
157 | , typename ::boost::enable_if< | |
158 | ::boost::mpl::and_< | |
159 | ::boost::type_erasure::detail::check_map<Concept, Map>, | |
160 | ::boost::type_erasure::is_subconcept<Concept, Concept2, Map> | |
161 | > | |
162 | >::type* = 0 | |
163 | #endif | |
164 | ) | |
165 | : impl( | |
166 | other, | |
167 | static_binding<Map>(), | |
168 | ::boost::type_erasure::detail::can_optimize_conversion<Concept2, Concept, Map>() | |
169 | ) | |
170 | {} | |
171 | ||
172 | /** | |
173 | * Converts from another set of bindings. | |
174 | * | |
175 | * \pre Map must be an MPL map with an entry for each placeholder | |
176 | * referred to by @c Concept. The mapped type should be the | |
177 | * corresponding placeholder in Concept2. | |
178 | * | |
179 | * \throws std::bad_alloc | |
180 | * \throws std::bad_any_cast | |
181 | */ | |
182 | template<class Placeholders, class Map> | |
183 | binding(const dynamic_binding<Placeholders>& other, const static_binding<Map>&) | |
184 | : impl( | |
185 | other, | |
186 | static_binding<Map>() | |
187 | ) | |
188 | {} | |
189 | ||
190 | /** | |
191 | * \return true iff the sets of types that the placeholders | |
192 | * bind to are the same for both arguments. | |
193 | * | |
194 | * \throws Nothing. | |
195 | */ | |
196 | friend bool operator==(const binding& lhs, const binding& rhs) | |
197 | { return *lhs.impl.table == *rhs.impl.table; } | |
198 | ||
199 | /** | |
200 | * \return true iff the arguments do not map to identical | |
201 | * sets of types. | |
202 | * | |
203 | * \throws Nothing. | |
204 | */ | |
205 | friend bool operator!=(const binding& lhs, const binding& rhs) | |
206 | { return !(lhs == rhs); } | |
207 | ||
208 | /** INTERNAL ONLY */ | |
209 | template<class T> | |
210 | typename T::type find() const { return impl.table->lookup((T*)0); } | |
211 | private: | |
212 | template<class C2> | |
213 | friend class binding; | |
214 | template<class P> | |
215 | friend class dynamic_binding; | |
216 | /** INTERNAL ONLY */ | |
217 | struct impl_type | |
218 | { | |
219 | impl_type() { | |
220 | table = &::boost::type_erasure::detail::make_vtable_init< | |
221 | typename ::boost::mpl::transform< | |
222 | actual_concept, | |
223 | ::boost::type_erasure::detail::get_null_vtable_entry< | |
224 | ::boost::mpl::_1 | |
225 | > | |
226 | >::type, | |
227 | table_type | |
228 | >::type::value; | |
229 | } | |
230 | template<class Map> | |
231 | impl_type(const static_binding<Map>&) | |
232 | { | |
233 | table = &::boost::type_erasure::detail::make_vtable_init< | |
234 | typename ::boost::mpl::transform< | |
235 | actual_concept, | |
236 | ::boost::type_erasure::detail::rebind_placeholders< | |
237 | ::boost::mpl::_1, | |
238 | typename ::boost::type_erasure::detail::add_deductions< | |
239 | Map, | |
240 | placeholder_subs | |
241 | >::type | |
242 | > | |
243 | >::type, | |
244 | table_type | |
245 | >::type::value; | |
246 | } | |
247 | template<class Concept2, class Map> | |
248 | impl_type(const binding<Concept2>& other, const static_binding<Map>&, boost::mpl::false_) | |
249 | : manager(new table_type) | |
250 | { | |
251 | manager->template convert_from< | |
252 | typename ::boost::type_erasure::detail::convert_deductions< | |
253 | Map, | |
254 | placeholder_subs, | |
255 | typename binding<Concept2>::placeholder_subs | |
256 | >::type | |
257 | >(*other.impl.table); | |
258 | table = manager.get(); | |
259 | } | |
260 | template<class PlaceholderList, class Map> | |
261 | impl_type(const dynamic_binding<PlaceholderList>& other, const static_binding<Map>&) | |
262 | : manager(new table_type) | |
263 | { | |
264 | manager->template convert_from< | |
265 | // FIXME: What do we need to do with deduced placeholder in other | |
266 | typename ::boost::type_erasure::detail::add_deductions< | |
267 | Map, | |
268 | placeholder_subs | |
269 | >::type | |
270 | >(other.impl); | |
271 | table = manager.get(); | |
272 | } | |
273 | template<class Concept2, class Map> | |
274 | impl_type(const binding<Concept2>& other, const static_binding<Map>&, boost::mpl::true_) | |
275 | : table(other.impl.table), | |
276 | manager(other.impl.manager) | |
277 | {} | |
278 | const table_type* table; | |
279 | ::boost::shared_ptr<table_type> manager; | |
280 | } impl; | |
281 | }; | |
282 | ||
283 | } | |
284 | } | |
285 | ||
286 | #endif |