1 // Copyright 2015-2018 Klemens D. Morgenstern
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 #ifndef BOOST_DLL_DETAIL_IMPORT_MANGLED_HELPERS_HPP_
8 #define BOOST_DLL_DETAIL_IMPORT_MANGLED_HELPERS_HPP_
9 
10 
11 #include <boost/type_traits/conditional.hpp>
12 #include <boost/type_traits/is_same.hpp>
13 #include <boost/type_traits/is_class.hpp>
14 #include <boost/type_traits/is_function.hpp>
15 #include <boost/type_traits/remove_cv.hpp>
16 
17 
18 #ifdef BOOST_HAS_PRAGMA_ONCE
19 # pragma once
20 #endif
21 
22 namespace boost { namespace dll { namespace experimental { namespace detail {
23 
24 //the following could be done by fusion, though it's simple enough to just declare it here.
25 template<class ...Args>
26 struct sequence {};
27 
28 template<class Value, class Seq> struct push_front;
29 template<class Value, class ...Args>
30 struct push_front<Value, sequence<Args...>>
31 {
32     typedef sequence<Value, Args...> type;
33 };
34 
35 template<class Lhs, class Rhs>
36 struct unqalified_is_same :
37         boost::is_same<
38             typename boost::remove_cv<Lhs>::type,
39             typename boost::remove_cv<Rhs>::type
40         >
41 {
42 };
43 
44 /* ********************************** function sequence type traits ******************************/
45 
46 //determine if it's a sequence of functions.
47 template<class T> struct is_function_seq;
48 
49 //type-trait for function overloads
50 template<class Class, class...Args> struct is_function_seq<sequence<Class, Args...>>
51             : boost::conditional<
52                 boost::is_function<Class>::value,
53                 is_function_seq<sequence<Args...>>,
54                 boost::false_type>::type
55 {};
56 
57 template<class Class>
58 struct is_function_seq<sequence<Class>> : boost::is_function<Class>
59 {
60 };
61 
62 template<>
63 struct is_function_seq<sequence<>> : boost::false_type
64 {
65 };
66 
67 /* ********************************* Function Tuple ***************************  */
68 
69 //a tuple of plain functions.
70 template <class ...Ts>
71 struct function_tuple;
72 
73 template <class Return, class...Args, class T2, class ...Ts>
74 struct function_tuple<Return(Args...), T2, Ts...>
75     : function_tuple<T2, Ts...>
76 {
77     Return(*f_)(Args...);
78 
function_tupleboost::dll::experimental::detail::function_tuple79     constexpr function_tuple(Return(* t)(Args...), T2* t2, Ts* ... ts)
80         : function_tuple<T2, Ts...>(t2, ts...)
81         , f_(t)
82     {}
83 
operator ()boost::dll::experimental::detail::function_tuple84     Return operator()(Args...args) const {
85         return (*f_)(static_cast<Args>(args)...);
86     }
87     using function_tuple<T2, Ts...>::operator();
88 };
89 
90 template <class Return, class...Args>
91 struct function_tuple<Return(Args...)> {
92     Return(*f_)(Args...);
93 
function_tupleboost::dll::experimental::detail::function_tuple94     constexpr function_tuple(Return(* t)(Args...))
95         : f_(t)
96     {}
97 
operator ()boost::dll::experimental::detail::function_tuple98     Return operator()(Args...args) const {
99         return (*f_)(static_cast<Args>(args)...);
100     }
101 };
102 
103 
104 /* ********************************** MemFn sequence type traits ******************************/
105 
106 template<class Class, class Func>
107 struct mem_fn_def
108 {
109     typedef Class class_type;
110     typedef Func  func_type;
111     typedef typename boost::dll::detail::get_mem_fn_type<Class, Func>::mem_fn mem_fn;
112 };
113 
114 template<class ...Args>
115 struct make_mem_fn_seq;
116 
117 // B: is T1 another version of T0?
118 template<bool, class T0, class T1, class T2>
119 struct make_mem_fn_seq_getter;
120 
121 template<class T0, class T1, class T2>
122 struct make_mem_fn_seq_getter<true, T0, T1, T2>
123 {
124     typedef mem_fn_def<T1, T2> type;
125 };
126 
127 template<class T0, class T1, class T2>
128 struct make_mem_fn_seq_getter<false, T0, T1, T2>
129 {
130     typedef mem_fn_def<T0, T1> type;
131 };
132 
133 template<class Class, class Signature>
134 struct make_mem_fn_seq<Class, Signature>
135 {
136     typedef mem_fn_def<Class, Signature> mem_fn;
137     typedef sequence<mem_fn>   type;
138 };
139 
140 template<class Class>
141 struct make_mem_fn_seq<Class>
142 {
143     typedef sequence<>   type;
144 };
145 
146 template<class T0, class T1, class T2, class ... Args>
147 struct make_mem_fn_seq<T0, T1, T2, Args...>
148 {
149     /* Since we might have ovls, it might be :
150      * Class, void(int), void(int, int) //--> just us class for both
151      * Class, const Class, void(int)//--> ovl class.
152      *
153      */
154     static_assert(boost::is_object<T0>::value, "");
155     typedef typename make_mem_fn_seq_getter<
156            unqalified_is_same<T0, T1>::value, T0, T1, T2>::type mem_fn_type;
157 
158     typedef typename boost::conditional<
159         unqalified_is_same<T0, T1>::value,
160         make_mem_fn_seq<T1, Args...>,
161         make_mem_fn_seq<T0, T2, Args...>> ::type next;
162 
163     typedef typename push_front<mem_fn_type, typename next::type>::type type;
164 };
165 
166 
167 
168 
169 /* Ok, this needs to be documented, so here's some pseudo-code:
170  *
171  * @code
172  *
173  * bool unqalified_is_same(lhs, rhs)
174  * {
175  *    return remove_cv(lhs) == remove_cv(rhs);
176  * }
177  *
178  * mem_fn make_mem_fn_seq_getter(b, cl, T2, T3)
179  * {
180  *    if (b) //b means, that T2 is another version of cl, i.e. qualified
181  *       return get_mem_fn_type(T2, T3);
182  *    else //means that T2 is a function.
183  *       return get_mem_fn_type(cl, T2);
184  * }
185  *
186  * sequence make_mem_fn_seq(type cl, type T2, type T3, types...)
187  * {
188  *     mem_fn = make_mem_fn_seq_getter(
189  *               unqalified_is_same(cl, T2), cl, T2, T3);
190  *
191  *     next = unqalified_is_same(cl, T2) ?
192  *              make_mem_fn_seq(T2, types...) //because: T2 is another version of cl, hence i use this. T3 was already consumed.
193  *              :
194  *              make_mem_fn_seq(Class, T3, types...) //because: T2 was a function, hence it is consumed and class remains unchanged.
195  *              ;
196  *     return push_front(mem_fn, next) ;
197  * };
198  * @endcode
199  */
200 
201 
202 
203 template<class T, class U, class ...Args>
204 struct is_mem_fn_seq_impl
205 {
206     typedef typename boost::conditional<
207                  boost::is_function<U>::value || boost::dll::experimental::detail::unqalified_is_same<T, U>::value,
208                  typename is_mem_fn_seq_impl<T, Args...>::type,
209                  boost::false_type>::type type;
210 };
211 
212 template<class T, class U>
213 struct is_mem_fn_seq_impl<T, U>
214 {
215     typedef typename boost::conditional<
216                  boost::is_function<U>::value && boost::is_object<T>::value,
217                  boost::true_type, boost::false_type>::type type;
218 };
219 
220 template<class T, class U, class Last>
221 struct is_mem_fn_seq_impl<T, U, Last>
222 {
223     typedef typename boost::conditional<
224                  (boost::is_function<U>::value || boost::dll::experimental::detail::unqalified_is_same<T, U>::value)
225                  && boost::is_function<Last>::value,
226                  boost::true_type, boost::false_type>::type type;
227 };
228 
229 template<class T> struct is_mem_fn_seq : boost::false_type {};
230 
231 //If only two arguments are provided at all.
232 template<class T, class U>
233 struct is_mem_fn_seq<sequence<T, U>> : boost::conditional<
234                  boost::is_object<T>::value && boost::is_function<U>::value,
235                  boost::true_type, boost::false_type>::type
236 {
237 };
238 
239 
240 template<class T, class Func, class ...Args>
241 struct is_mem_fn_seq<sequence<T, Func, Args...>> :
242         boost::conditional<
243             boost::is_class<T>::value && boost::is_function<Func>::value,
244             typename is_mem_fn_seq_impl<T, Args...>::type,
245             boost::false_type>::type {};
246 
247 
248 /* ********************************** mem fn sequence tuple ******************************/
249 
250 /* A tuple of member functions
251  * Unlike for plain functions a sequence here might contain classes as well as functions.
252  */
253 template <class ...Ts>
254 struct mem_fn_tuple;
255 
256 template <class Class, class Return, class...Args, class T2, class ...Ts>
257 struct mem_fn_tuple<mem_fn_def<Class, Return(Args...)>, T2, Ts...>
258     : mem_fn_tuple<T2, Ts...>
259 {
260     typedef typename boost::dll::detail::get_mem_fn_type<Class, Return(Args...)>::mem_fn mem_fn;
261     mem_fn f_;
262 
mem_fn_tupleboost::dll::experimental::detail::mem_fn_tuple263     constexpr mem_fn_tuple(mem_fn f, typename T2::mem_fn t2, typename Ts::mem_fn ... ts)
264         : mem_fn_tuple<T2, Ts...>(t2, ts...)
265         , f_(f)
266     {}
267 
operator ()boost::dll::experimental::detail::mem_fn_tuple268     Return operator()(Class* const cl, Args...args) const {
269         return (cl->*f_)(static_cast<Args>(args)...);
270     }
271     using mem_fn_tuple<T2, Ts...>::operator();
272 
273 };
274 
275 template <class Class, class Return, class...Args>
276 struct mem_fn_tuple<mem_fn_def<Class, Return(Args...)>> {
277     typedef typename boost::dll::detail::get_mem_fn_type<Class, Return(Args...)>::mem_fn mem_fn;
278     mem_fn f_;
279 
mem_fn_tupleboost::dll::experimental::detail::mem_fn_tuple280     constexpr mem_fn_tuple(mem_fn f)
281         : f_(f)
282     {}
283 
operator ()boost::dll::experimental::detail::mem_fn_tuple284     Return operator()(Class * const cl, Args...args) const {
285         return (cl->*f_)(static_cast<Args>(args)...);
286     }
287 };
288 
289 }}}}
290 #endif /* BOOST_DLL_DETAIL_IMPORT_MANGLED_HELPERS_HPP_ */
291