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