binding.hpp 8.8 KB

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