register_binding.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Boost.TypeErasure library
  2. //
  3. // Copyright 2015 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_REGISTER_BINDING_HPP_INCLUDED
  11. #define BOOST_TYPE_ERASURE_REGISTER_BINDING_HPP_INCLUDED
  12. #include <boost/type_erasure/detail/check_map.hpp>
  13. #include <boost/type_erasure/detail/get_placeholders.hpp>
  14. #include <boost/type_erasure/detail/rebind_placeholders.hpp>
  15. #include <boost/type_erasure/detail/normalize.hpp>
  16. #include <boost/type_erasure/detail/adapt_to_vtable.hpp>
  17. #include <boost/type_erasure/detail/auto_link.hpp>
  18. #include <boost/type_erasure/static_binding.hpp>
  19. #include <boost/mpl/transform.hpp>
  20. #include <boost/mpl/remove_if.hpp>
  21. #include <boost/mpl/fold.hpp>
  22. #include <boost/mpl/at.hpp>
  23. #include <boost/mpl/has_key.hpp>
  24. #include <boost/mpl/insert.hpp>
  25. #include <boost/mpl/front.hpp>
  26. #include <boost/mpl/size.hpp>
  27. #include <boost/mpl/equal_to.hpp>
  28. #include <boost/mpl/or.hpp>
  29. #include <boost/mpl/set.hpp>
  30. #include <boost/mpl/map.hpp>
  31. #include <boost/mpl/vector.hpp>
  32. #include <boost/mpl/int.hpp>
  33. #include <boost/mpl/bool.hpp>
  34. #include <boost/mpl/pair.hpp>
  35. #include <boost/mpl/back_inserter.hpp>
  36. #include <boost/mpl/for_each.hpp>
  37. #include <vector>
  38. #include <typeinfo>
  39. namespace boost {
  40. namespace type_erasure {
  41. namespace detail {
  42. typedef std::vector<const std::type_info*> key_type;
  43. typedef void (*value_type)();
  44. BOOST_TYPE_ERASURE_DECL void register_function_impl(const key_type& key, value_type fn);
  45. BOOST_TYPE_ERASURE_DECL value_type lookup_function_impl(const key_type& key);
  46. template<class Map>
  47. struct append_to_key_static {
  48. append_to_key_static(key_type* k) : key(k) {}
  49. template<class P>
  50. void operator()(P) {
  51. #ifndef BOOST_TYPE_ERASURE_USE_MP11
  52. key->push_back(&typeid(typename ::boost::mpl::at<Map, P>::type));
  53. #else
  54. key->push_back(&typeid(::boost::mp11::mp_second< ::boost::mp11::mp_map_find<Map, P> >));
  55. #endif
  56. }
  57. key_type* key;
  58. };
  59. // This placeholder exists solely to create a normalized
  60. // representation of a primitive concept. For the moment
  61. // I'm going to be conservative and require a bijection
  62. // between the original placeholders and the normalized
  63. // placeholders. It should be safe to map everything
  64. // to a single placeholder, though, as long as the
  65. // key includes every instance of each placeholder
  66. // as a separate element. i.e. we should be able to
  67. // turn addable<_a, _b> into addable<_, _> and
  68. // addable<_a, _a> into addable<_, _> as well if we always
  69. // add typeids for both arguments to the search key.
  70. template<int N>
  71. struct _ : ::boost::type_erasure::placeholder {};
  72. struct counting_map_appender
  73. {
  74. template<class State, class Key>
  75. struct apply
  76. {
  77. typedef typename ::boost::mpl::insert<
  78. State,
  79. ::boost::mpl::pair<
  80. Key,
  81. ::boost::type_erasure::detail::_<
  82. ::boost::mpl::size<State>::value
  83. >
  84. >
  85. >::type type;
  86. };
  87. };
  88. template<class Map>
  89. struct register_function {
  90. template<class F>
  91. void operator()(F) {
  92. key_type key;
  93. #ifndef BOOST_TYPE_ERASURE_USE_MP11
  94. typedef typename ::boost::type_erasure::detail::get_placeholders<F, ::boost::mpl::set0<> >::type placeholders;
  95. #else
  96. typedef typename ::boost::type_erasure::detail::get_placeholders<F, ::boost::mp11::mp_list<> >::type placeholders;
  97. #endif
  98. typedef typename ::boost::mpl::fold<
  99. placeholders,
  100. ::boost::mpl::map0<>,
  101. ::boost::type_erasure::detail::counting_map_appender
  102. >::type placeholder_map;
  103. key.push_back(&typeid(typename ::boost::type_erasure::detail::rebind_placeholders<F, placeholder_map>::type));
  104. ::boost::mpl::for_each<placeholders>(append_to_key_static<Map>(&key));
  105. value_type fn = reinterpret_cast<value_type>(&::boost::type_erasure::detail::rebind_placeholders<F, Map>::type::value);
  106. ::boost::type_erasure::detail::register_function_impl(key, fn);
  107. }
  108. };
  109. }
  110. /**
  111. * Registers a model of a concept to allow downcasting @ref any
  112. * via \dynamic_any_cast.
  113. */
  114. template<class Concept, class Map>
  115. void register_binding(const static_binding<Map>&)
  116. {
  117. typedef typename ::boost::type_erasure::detail::normalize_concept<
  118. Concept
  119. >::type normalized;
  120. typedef typename ::boost::mpl::transform<normalized,
  121. ::boost::type_erasure::detail::maybe_adapt_to_vtable< ::boost::mpl::_1>
  122. >::type actual_concept;
  123. typedef typename ::boost::type_erasure::detail::get_placeholder_normalization_map<
  124. Concept
  125. >::type placeholder_subs;
  126. typedef typename ::boost::type_erasure::detail::add_deductions<Map, placeholder_subs>::type actual_map;
  127. ::boost::mpl::for_each<actual_concept>(::boost::type_erasure::detail::register_function<actual_map>());
  128. }
  129. /**
  130. * \overload
  131. */
  132. template<class Concept, class T>
  133. void register_binding()
  134. {
  135. // Find all placeholders
  136. typedef typename ::boost::type_erasure::detail::normalize_concept_impl<Concept>::type normalized;
  137. typedef typename normalized::first basic;
  138. typedef typename ::boost::mpl::fold<
  139. basic,
  140. #ifndef BOOST_TYPE_ERASURE_USE_MP11
  141. ::boost::mpl::set0<>,
  142. #else
  143. ::boost::mp11::mp_list<>,
  144. #endif
  145. ::boost::type_erasure::detail::get_placeholders< ::boost::mpl::_2, ::boost::mpl::_1>
  146. >::type all_placeholders;
  147. // remove deduced placeholders
  148. typedef typename ::boost::mpl::fold<
  149. typename normalized::second,
  150. ::boost::mpl::set0<>,
  151. ::boost::mpl::insert< ::boost::mpl::_1, ::boost::mpl::second< ::boost::mpl::_2> >
  152. >::type xtra_deduced;
  153. typedef typename ::boost::mpl::remove_if<
  154. all_placeholders,
  155. ::boost::mpl::or_<
  156. ::boost::type_erasure::detail::is_deduced< ::boost::mpl::_1>,
  157. ::boost::mpl::has_key<xtra_deduced, ::boost::mpl::_1>
  158. >,
  159. ::boost::mpl::back_inserter< ::boost::mpl::vector0<> >
  160. >::type unknown_placeholders;
  161. // Bind the single remaining placeholder to T
  162. BOOST_MPL_ASSERT((boost::mpl::equal_to<boost::mpl::size<unknown_placeholders>, boost::mpl::int_<1> >));
  163. register_binding<Concept>(::boost::type_erasure::make_binding<
  164. ::boost::mpl::map< ::boost::mpl::pair<typename ::boost::mpl::front<unknown_placeholders>::type, T> > >());
  165. }
  166. }
  167. }
  168. #endif