blob: ff9c6ebfc41abae175a2f2652a5d29f669fadf60 [file] [log] [blame]
Wenzel Jakob38bd7112015-07-05 20:05:44 +02001/*
2 pybind/mpl.h: Simple library for type manipulation and template metaprogramming
3
4 Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
5
6 All rights reserved. Use of this source code is governed by a
7 BSD-style license that can be found in the LICENSE file.
8*/
9
10#if !defined(__PYBIND_MPL_H)
11#define __PYBIND_MPL_H
12
13#include "common.h"
14#include <tuple>
15
16NAMESPACE_BEGIN(pybind)
17NAMESPACE_BEGIN(mpl)
18
19/// Index sequence for convenient template metaprogramming involving tuples
20template<size_t ...> struct index_sequence { };
21template<size_t N, size_t ...S> struct make_index_sequence : make_index_sequence <N - 1, N - 1, S...> { };
22template<size_t ...S> struct make_index_sequence <0, S...> { typedef index_sequence<S...> type; };
23
24/// Helper template to strip away type modifiers
25template <typename T> struct normalize_type { typedef T type; };
26template <typename T> struct normalize_type<const T> { typedef typename normalize_type<T>::type type; };
27template <typename T> struct normalize_type<T*> { typedef typename normalize_type<T>::type type; };
28template <typename T> struct normalize_type<T&> { typedef typename normalize_type<T>::type type; };
29template <typename T> struct normalize_type<T&&> { typedef typename normalize_type<T>::type type; };
30template <typename T, size_t N> struct normalize_type<const T[N]> { typedef typename normalize_type<T>::type type; };
31template <typename T, size_t N> struct normalize_type<T[N]> { typedef typename normalize_type<T>::type type; };
32
33NAMESPACE_BEGIN(detail)
34
35/// Strip the class from a method type
36template <typename T> struct remove_class {};
37template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { typedef R type(A...); };
38template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { typedef R type(A...); };
39
40/**
41 * \brief Convert a lambda function to a std::function
42 * From http://stackoverflow.com/questions/11893141/inferring-the-call-signature-of-a-lambda-or-arbitrary-callable-for-make-functio
43 */
44template <typename T> struct lambda_signature_impl {
45 using type = typename remove_class<
46 decltype(&std::remove_reference<T>::type::operator())>::type;
47};
48template <typename R, typename... A> struct lambda_signature_impl<R (A...)> { typedef R type(A...); };
49template <typename R, typename... A> struct lambda_signature_impl<R (&)(A...)> { typedef R type(A...); };
50template <typename R, typename... A> struct lambda_signature_impl<R (*)(A...)> { typedef R type(A...); };
51template <typename T> using lambda_signature = typename lambda_signature_impl<T>::type;
52template <typename F> using make_function_type = std::function<lambda_signature<F>>;
53
54NAMESPACE_END(detail)
55
56template<typename F> detail::make_function_type<F> make_function(F &&f) {
57 return detail::make_function_type<F>(std::forward<F>(f)); }
58
59NAMESPACE_BEGIN(detail)
60
61struct void_type { };
62
63/// Helper functions for calling a function using a tuple argument while dealing with void/non-void return values
64template <typename RetType> struct tuple_dispatch {
65 typedef RetType return_type;
66 template<typename Func, typename Arg, size_t ... S> return_type operator()(const Func &f, Arg && args, index_sequence<S...>) {
67 return f(std::get<S>(std::forward<Arg>(args))...);
68 }
69};
70
71/// Helper functions for calling a function using a tuple argument (special case for void return values)
72template <> struct tuple_dispatch<void> {
73 typedef void_type return_type;
74 template<typename Func, typename Arg, size_t ... S> return_type operator()(const Func &f, Arg &&args, index_sequence<S...>) {
75 f(std::get<S>(std::forward<Arg>(args))...);
76 return return_type();
77 }
78};
79
80NAMESPACE_END(detail)
81
82/// For lambda functions delegate to their 'operator()'
83template <typename T> struct function_traits : public function_traits<typename detail::make_function_type<T>> { };
84
85/// Type traits for function pointers
86template <typename ReturnType, typename... Args>
87struct function_traits<ReturnType(*)(Args...)> {
88 enum {
89 nargs = sizeof...(Args),
90 is_method = 0,
91 is_const = 0
92 };
93 typedef std::function<ReturnType (Args...)> f_type;
94 typedef detail::tuple_dispatch<ReturnType> dispatch_type;
95 typedef typename dispatch_type::return_type return_type;
96 typedef std::tuple<Args...> args_type;
97
98 template <size_t i> struct arg {
99 typedef typename std::tuple_element<i, args_type>::type type;
100 };
101
102 static f_type cast(ReturnType (*func)(Args ...)) { return func; }
103
104 static return_type dispatch(const f_type &f, args_type &&args) {
105 return dispatch_type()(f, std::move(args),
106 typename make_index_sequence<nargs>::type());
107 }
108};
109
110/// Type traits for ordinary methods
111template <typename ClassType, typename ReturnType, typename... Args>
112struct function_traits<ReturnType(ClassType::*)(Args...)> {
113 enum {
114 nargs = sizeof...(Args),
115 is_method = 1,
116 is_const = 0
117 };
118 typedef std::function<ReturnType(ClassType &, Args...)> f_type;
119 typedef detail::tuple_dispatch<ReturnType> dispatch_type;
120 typedef typename dispatch_type::return_type return_type;
121 typedef std::tuple<ClassType&, Args...> args_type;
122
123 template <size_t i> struct arg {
124 typedef typename std::tuple_element<i, args_type>::type type;
125 };
126
127 static f_type cast(ReturnType (ClassType::*func)(Args ...)) { return std::mem_fn(func); }
128
129 static return_type dispatch(const f_type &f, args_type &&args) {
130 return dispatch_type()(f, std::move(args),
131 typename make_index_sequence<nargs+1>::type());
132 }
133};
134
135/// Type traits for const methods
136template <typename ClassType, typename ReturnType, typename... Args>
137struct function_traits<ReturnType(ClassType::*)(Args...) const> {
138 enum {
139 nargs = sizeof...(Args),
140 is_method = 1,
141 is_const = 1
142 };
143 typedef std::function<ReturnType (const ClassType &, Args...)> f_type;
144 typedef detail::tuple_dispatch<ReturnType> dispatch_type;
145 typedef typename dispatch_type::return_type return_type;
146 typedef std::tuple<const ClassType&, Args...> args_type;
147
148 template <size_t i> struct arg {
149 typedef typename std::tuple_element<i, args_type>::type type;
150 };
151
152 static f_type cast(ReturnType (ClassType::*func)(Args ...) const) {
153 return std::mem_fn(func);
154 }
155
156 static return_type dispatch(const f_type &f, args_type &&args) {
157 return dispatch_type()(f, std::move(args),
158 typename make_index_sequence<nargs+1>::type());
159 }
160};
161
162/// Type traits for std::functions
163template <typename ReturnType, typename... Args>
164struct function_traits<std::function<ReturnType(Args...)>> {
165 enum {
166 nargs = sizeof...(Args),
167 is_method = 0,
168 is_const = 0
169 };
170 typedef std::function<ReturnType (Args...)> f_type;
171 typedef detail::tuple_dispatch<ReturnType> dispatch_type;
172 typedef typename dispatch_type::return_type return_type;
173 typedef std::tuple<Args...> args_type;
174
175 template <size_t i> struct arg {
176 typedef typename std::tuple_element<i, args_type>::type type;
177 };
178
179 static f_type cast(const f_type &func) { return func; }
180
181 static return_type dispatch(const f_type &f, args_type &&args) {
182 return dispatch_type()(f, std::move(args),
183 typename make_index_sequence<nargs>::type());
184 }
185};
186
187NAMESPACE_END(mpl)
188NAMESPACE_END(pybind)
189
190#endif /* __PYBIND_MPL_H */