• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
binding()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>
binding(const 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>
binding(const static_binding<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>
binding(const binding<Concept2> & other,const Map &,typename::boost::enable_if<::boost::mpl::and_<::boost::type_erasure::detail::check_map<Concept,Map>,::boost::type_erasure::is_subconcept<Concept,Concept2,Map>>>::type * =0)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>
binding(const binding<Concept2> & other,const static_binding<Map> &,typename::boost::enable_if<::boost::mpl::and_<::boost::type_erasure::detail::check_map<Concept,Map>,::boost::type_erasure::is_subconcept<Concept,Concept2,Map>>>::type * =0)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>
binding(const dynamic_binding<Placeholders> & other,const static_binding<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      */
operator ==(const binding & lhs,const binding & rhs)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      */
operator !=(const binding & lhs,const binding & rhs)205     friend bool operator!=(const binding& lhs, const binding& rhs)
206     { return !(lhs == rhs); }
207 
208     /** INTERNAL ONLY */
209     template<class T>
find() const210     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     {
impl_typeboost::type_erasure::binding::impl_type219         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>
impl_typeboost::type_erasure::binding::impl_type231         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>
impl_typeboost::type_erasure::binding::impl_type248         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>
impl_typeboost::type_erasure::binding::impl_type261         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>
impl_typeboost::type_erasure::binding::impl_type274         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
287