1 // Boost.TypeErasure library
3 // Copyright 2011 Steven Watanabe
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)
11 #ifndef BOOST_TYPE_ERASURE_BINDING_HPP_INCLUDED
12 #define BOOST_TYPE_ERASURE_BINDING_HPP_INCLUDED
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>
37 namespace type_erasure {
40 class dynamic_binding;
44 template<class Source, class Dest, class Map>
45 struct can_optimize_conversion : ::boost::mpl::and_<
46 ::boost::is_same<Source, Dest>,
48 typename ::boost::mpl::find_if<
52 ::boost::mpl::first< ::boost::mpl::_1>,
53 ::boost::mpl::second< ::boost::mpl::_1>
57 typename ::boost::mpl::end<Map>::type
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.
68 template<class Concept>
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<
80 >::type placeholder_subs;
84 * \pre @ref relaxed must be in @c Concept.
88 binding() { BOOST_MPL_ASSERT((::boost::type_erasure::is_relaxed<Concept>)); }
91 * \pre @c Map must be an MPL map with an entry for each placeholder
92 * referred to by @c Concept.
97 explicit binding(const Map&)
99 BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map),
100 static_binding<Map>()
105 * \pre @c Map must be an MPL map with an entry for each placeholder
106 * referred to by @c Concept.
111 binding(const static_binding<Map>&)
113 BOOST_TYPE_ERASURE_INSTANTIATE(Concept, Map),
114 static_binding<Map>()
119 * Converts from another set of bindings.
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.
125 * \throws std::bad_alloc
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<
132 ::boost::type_erasure::detail::check_map<Concept, Map>,
133 ::boost::type_erasure::is_subconcept<Concept, Concept2, Map>
140 static_binding<Map>(),
141 ::boost::type_erasure::detail::can_optimize_conversion<Concept2, Concept, Map>()
146 * Converts from another set of bindings.
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.
152 * \throws std::bad_alloc
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<
159 ::boost::type_erasure::detail::check_map<Concept, Map>,
160 ::boost::type_erasure::is_subconcept<Concept, Concept2, Map>
167 static_binding<Map>(),
168 ::boost::type_erasure::detail::can_optimize_conversion<Concept2, Concept, Map>()
173 * Converts from another set of bindings.
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.
179 * \throws std::bad_alloc
180 * \throws std::bad_any_cast
182 template<class Placeholders, class Map>
183 binding(const dynamic_binding<Placeholders>& other, const static_binding<Map>&)
186 static_binding<Map>()
191 * \return true iff the sets of types that the placeholders
192 * bind to are the same for both arguments.
196 friend bool operator==(const binding& lhs, const binding& rhs)
197 { return *lhs.impl.table == *rhs.impl.table; }
200 * \return true iff the arguments do not map to identical
205 friend bool operator!=(const binding& lhs, const binding& rhs)
206 { return !(lhs == rhs); }
210 typename T::type find() const { return impl.table->lookup((T*)0); }
213 friend class binding;
215 friend class dynamic_binding;
220 table = &::boost::type_erasure::detail::make_vtable_init<
221 typename ::boost::mpl::transform<
223 ::boost::type_erasure::detail::get_null_vtable_entry<
231 impl_type(const static_binding<Map>&)
233 table = &::boost::type_erasure::detail::make_vtable_init<
234 typename ::boost::mpl::transform<
236 ::boost::type_erasure::detail::rebind_placeholders<
238 typename ::boost::type_erasure::detail::add_deductions<
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)
251 manager->template convert_from<
252 typename ::boost::type_erasure::detail::convert_deductions<
255 typename binding<Concept2>::placeholder_subs
257 >(*other.impl.table);
258 table = manager.get();
260 template<class PlaceholderList, class Map>
261 impl_type(const dynamic_binding<PlaceholderList>& other, const static_binding<Map>&)
262 : manager(new table_type)
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<
271 table = manager.get();
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)
278 const table_type* table;
279 ::boost::shared_ptr<table_type> manager;