1 // Boost.TypeErasure library
2 //
3 // Copyright 2012 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_FREE_HPP_INCLUDED
12 #define BOOST_TYPE_ERASURE_FREE_HPP_INCLUDED
13 
14 #include <boost/detail/workaround.hpp>
15 #include <boost/preprocessor/repetition/enum.hpp>
16 #include <boost/preprocessor/repetition/enum_trailing.hpp>
17 #include <boost/preprocessor/repetition/enum_params.hpp>
18 #include <boost/preprocessor/repetition/enum_shifted_params.hpp>
19 #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
20 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
21 #include <boost/preprocessor/cat.hpp>
22 #include <boost/type_traits/remove_reference.hpp>
23 #include <boost/type_traits/remove_cv.hpp>
24 #include <boost/mpl/eval_if.hpp>
25 #include <boost/mpl/identity.hpp>
26 #include <boost/mpl/int.hpp>
27 #include <boost/mpl/next.hpp>
28 #include <boost/type_erasure/detail/macro.hpp>
29 #include <boost/type_erasure/detail/const.hpp>
30 #include <boost/type_erasure/config.hpp>
31 #include <boost/type_erasure/derived.hpp>
32 #include <boost/type_erasure/rebind_any.hpp>
33 #include <boost/type_erasure/param.hpp>
34 #include <boost/type_erasure/is_placeholder.hpp>
35 #include <boost/type_erasure/call.hpp>
36 #include <boost/type_erasure/concept_interface.hpp>
37 
38 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \
39     defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \
40     defined(BOOST_TYPE_ERASURE_DOXYGEN) || \
41     BOOST_WORKAROUND(BOOST_MSVC, == 1800)
42 
43 namespace boost {
44 namespace type_erasure {
45 namespace detail {
46 
47 template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_TYPE_ERASURE_MAX_ARITY, class T, void)>
48 struct first_placeholder {
49     typedef typename ::boost::mpl::eval_if<is_placeholder<T0>,
50         ::boost::mpl::identity<T0>,
51         first_placeholder<BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_TYPE_ERASURE_MAX_ARITY, T)>
52     >::type type;
53 };
54 
55 template<>
56 struct first_placeholder<> {};
57 
58 template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_TYPE_ERASURE_MAX_ARITY, class T, void)>
59 struct first_placeholder_index :
60     ::boost::mpl::eval_if<is_placeholder<T0>,
61         ::boost::mpl::int_<0>,
62         ::boost::mpl::next<first_placeholder_index<BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_TYPE_ERASURE_MAX_ARITY, T)> >
63     >::type
64 {};
65 
66 }
67 }
68 }
69 
70 /** INTERNAL ONLY */
71 #define BOOST_TYPE_ERASURE_FREE_QUALIFIED_ID(seq, N) \
72     BOOST_TYPE_ERASURE_QUALIFIED_NAME(seq)<R(BOOST_PP_ENUM_PARAMS(N, T))>
73 
74 /** INTERNAL ONLY */
75 #define BOOST_TYPE_ERASURE_FREE_UNQUALIFIED_PARAM_TYPE(z, n, data) \
76     typename ::boost::remove_cv<typename ::boost::remove_reference<BOOST_PP_CAT(T, n)>::type>::type
77 
78 /** INTERNAL ONLY */
79 #define BOOST_TYPE_ERASURE_FREE_PARAM_TYPE(z, n, data)                      \
80     typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == n), \
81         ::boost::type_erasure::detail::maybe_const_this_param<BOOST_PP_CAT(T, n), Base>,    \
82         ::boost::type_erasure::as_param<Base, BOOST_PP_CAT(T, n)>           \
83     >::type BOOST_PP_CAT(t, n)
84 
85 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
86 
87 /** INTERNAL ONLY */
88 #define BOOST_TYPE_ERASURE_FREE_FORWARD_I(z, n, data) ::std::forward<BOOST_PP_CAT(T, n)>(BOOST_PP_CAT(t, n))
89 /** INTERNAL ONLY */
90 #define BOOST_TYPE_ERASURE_FREE_FORWARD(n) BOOST_PP_ENUM(n, BOOST_TYPE_ERASURE_FREE_FORWARD_I, ~)
91 /** INTERNAL ONLY */
92 #define BOOST_TYPE_ERASURE_FREE_FORWARD_PARAM_I(z, n, data) \
93     ::std::forward<typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == n), \
94         ::boost::type_erasure::detail::maybe_const_this_param<BOOST_PP_CAT(T, n), Base>,    \
95         ::boost::type_erasure::as_param<Base, BOOST_PP_CAT(T, n)>           \
96     >::type>(BOOST_PP_CAT(t, n))
97 
98 #else
99 
100 #define BOOST_TYPE_ERASURE_FREE_FORWARD(n) BOOST_PP_ENUM_PARAMS(n, t)
101 #define BOOST_TYPE_ERASURE_FREE_FORWARD_PARAM_I(z, n, data) BOOST_PP_CAT(t, n)
102 
103 #endif
104 
105 /** INTERNAL ONLY */
106 #define BOOST_TYPE_ERASURE_FREE_II(qual_name, concept_name, function_name, N)  \
107     BOOST_TYPE_ERASURE_OPEN_NAMESPACE(qual_name)                        \
108                                                                         \
109     template<class Sig>                                                 \
110     struct concept_name;                                                \
111                                                                         \
112     template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T)>         \
113     struct concept_name<R(BOOST_PP_ENUM_PARAMS(N, T))> {                \
114         static R apply(BOOST_PP_ENUM_BINARY_PARAMS(N, T, t))            \
115         { return function_name(BOOST_TYPE_ERASURE_FREE_FORWARD(N)); }   \
116     };                                                                  \
117                                                                         \
118     template<BOOST_PP_ENUM_PARAMS(N, class T)>                          \
119     struct concept_name<void(BOOST_PP_ENUM_PARAMS(N, T))> {             \
120         static void apply(BOOST_PP_ENUM_BINARY_PARAMS(N, T, t))         \
121         { function_name(BOOST_TYPE_ERASURE_FREE_FORWARD(N)); }          \
122     };                                                                  \
123                                                                         \
124     BOOST_TYPE_ERASURE_CLOSE_NAMESPACE(qual_name)                       \
125                                                                         \
126     namespace boost {                                                   \
127     namespace type_erasure {                                            \
128                                                                         \
129     template<class R BOOST_PP_ENUM_TRAILING_PARAMS(N, class T), class Base> \
130     struct concept_interface<                                           \
131         BOOST_TYPE_ERASURE_FREE_QUALIFIED_ID(qual_name, N),             \
132         Base,                                                           \
133         typename ::boost::type_erasure::detail::first_placeholder<      \
134             BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FREE_UNQUALIFIED_PARAM_TYPE, ~)>::type  \
135     > : Base {                                                          \
136         typedef typename ::boost::type_erasure::detail::first_placeholder_index<    \
137             BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FREE_UNQUALIFIED_PARAM_TYPE, ~)>::type  \
138             _boost_type_erasure_free_p_idx;                             \
139         friend typename ::boost::type_erasure::rebind_any<Base, R>::type function_name(  \
140             BOOST_PP_ENUM(N, BOOST_TYPE_ERASURE_FREE_PARAM_TYPE, ~))    \
141         {                                                               \
142             return ::boost::type_erasure::call(                         \
143                 BOOST_TYPE_ERASURE_FREE_QUALIFIED_ID(qual_name, N)()    \
144                 BOOST_PP_ENUM_TRAILING(N, BOOST_TYPE_ERASURE_FREE_FORWARD_PARAM_I, ~)); \
145         }                                                               \
146     };                                                                  \
147                                                                         \
148     }                                                                   \
149     }
150 
151 #else
152 
153 namespace boost {
154 namespace type_erasure {
155 
156 template<int... N>
157 struct index_list {};
158 
159 namespace detail {
160 
161 template<class... T>
162 struct first_placeholder;
163 
164 template<class T0, class... T>
165 struct first_placeholder<T0, T...> {
166     typedef typename ::boost::mpl::eval_if<is_placeholder<T0>,
167         ::boost::mpl::identity<T0>,
168         first_placeholder<T...>
169     >::type type;
170 };
171 
172 template<>
173 struct first_placeholder<> {};
174 
175 template<class... T>
176 struct first_placeholder_index;
177 
178 template<class T0, class... T>
179 struct first_placeholder_index<T0, T...> :
180     ::boost::mpl::eval_if<is_placeholder<T0>,
181         ::boost::mpl::int_<0>,
182         ::boost::mpl::next<first_placeholder_index<T...> >
183     >::type
184 {};
185 
186 template<class Sig>
187 struct transform_free_signature;
188 
189 template<class T, int N>
190 struct push_back_index;
191 
192 template<int... N, int X>
193 struct push_back_index<index_list<N...>, X>
194 {
195     typedef index_list<N..., X> type;
196 };
197 
198 template<int N>
199 struct make_index_list {
200     typedef typename push_back_index<
201         typename make_index_list<N-1>::type,
202         N-1
203     >::type type;
204 };
205 
206 template<>
207 struct make_index_list<0> {
208     typedef index_list<> type;
209 };
210 
211 }
212 }
213 }
214 
215 /** INTERNAL ONLY */
216 #define BOOST_TYPE_ERASURE_FREE_II(qual_name, concept_name, function_name, N)  \
217     BOOST_TYPE_ERASURE_OPEN_NAMESPACE(qual_name)                        \
218                                                                         \
219     template<class Sig>                                                 \
220     struct concept_name;                                                \
221                                                                         \
222     template<class R, class... T>                                       \
223     struct concept_name<R(T...)> {                                      \
224         static R apply(T... t)                                          \
225         { return function_name(std::forward<T>(t)...); }                \
226     };                                                                  \
227                                                                         \
228     template<class... T>                                                \
229     struct concept_name<void(T...)> {                                   \
230         static void apply(T... t)                                       \
231         { function_name(std::forward<T>(t)...); }                       \
232     };                                                                  \
233                                                                         \
234     BOOST_TYPE_ERASURE_CLOSE_NAMESPACE(qual_name)                       \
235                                                                         \
236     namespace boost {                                                   \
237     namespace type_erasure {                                            \
238                                                                         \
239     template<class Sig, class Base, class Idx>                          \
240     struct inject ## concept_name;                                      \
241     template<class R, class... T, class Base, int... I>                 \
242     struct inject ## concept_name<R(T...), Base, index_list<I...> > : Base {\
243         typedef typename ::boost::type_erasure::detail::first_placeholder_index<    \
244             typename ::boost::remove_cv<                                \
245                 typename ::boost::remove_reference<T>::type             \
246             >::type...                                                  \
247         >::type _boost_type_erasure_free_p_idx;                         \
248         friend typename ::boost::type_erasure::rebind_any<Base, R>::type\
249         function_name(                                                  \
250             typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == I), \
251                 ::boost::type_erasure::detail::maybe_const_this_param<T, Base>, \
252                 ::boost::type_erasure::as_param<Base, T>                \
253             >::type... t)                                               \
254        {                                                                \
255             return ::boost::type_erasure::call(                         \
256                 BOOST_TYPE_ERASURE_QUALIFIED_NAME(qual_name)<R(T...)>(),\
257                 std::forward<typename ::boost::mpl::eval_if_c<(_boost_type_erasure_free_p_idx::value == I), \
258                     ::boost::type_erasure::detail::maybe_const_this_param<T, Base>, \
259                     ::boost::type_erasure::as_param<Base, T>            \
260                 >::type>(t)...);                                        \
261         }                                                               \
262     };                                                                  \
263                                                                         \
264     template<class R, class... T, class Base>                           \
265     struct concept_interface<                                           \
266         BOOST_TYPE_ERASURE_QUALIFIED_NAME(qual_name)<R(T...)>,          \
267         Base,                                                           \
268         typename ::boost::type_erasure::detail::first_placeholder<      \
269             typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type...>::type  \
270     > :  inject ## concept_name<R(T...), Base, typename ::boost::type_erasure::detail::make_index_list<sizeof...(T)>::type>\
271     {};                                                                 \
272                                                                         \
273     }                                                                   \
274     }
275 
276 #endif
277 
278 /** INTERNAL ONLY */
279 #define BOOST_TYPE_ERASURE_FREE_I(namespace_name, concept_name, function_name, N)\
280     BOOST_TYPE_ERASURE_FREE_II(namespace_name, concept_name, function_name, N)
281 
282 /**
283  * \brief Defines a primitive concept for a free function.
284  *
285  * \param qualified_name should be a preprocessor sequence
286  * of the form (namespace1)(namespace2)...(concept_name).
287  * \param function_name is the name of the function.
288  * \param N is the number of arguments of the function.
289  *
290  * The declaration of the concept is
291  * \code
292  * template<class Sig>
293  * struct ::namespace1::namespace2::...::concept_name;
294  * \endcode
295  * where Sig is a function type giving the
296  * signature of the function.
297  *
298  * This macro can only be used in the global namespace.
299  *
300  * Example:
301  *
302  * \code
303  * BOOST_TYPE_ERASURE_FREE((boost)(has_to_string), to_string, 1)
304  * \endcode
305  */
306 #define BOOST_TYPE_ERASURE_FREE(qualified_name, function_name, N)                           \
307     BOOST_TYPE_ERASURE_FREE_I(                                                              \
308         qualified_name,                                                                     \
309         BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(qualified_name)), qualified_name), \
310         function_name,                                                                             \
311         N)
312 
313 #endif
314