]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/generic/functional.h
8843e363b8325fd4c870249941bc5049573e6db9
[xonotic/netradiant.git] / libs / generic / functional.h
1 #if !defined( INCLUDED_FUNCTIONAL_H )
2 #define INCLUDED_FUNCTIONAL_H
3
4 #include <functional>
5 #include <tuple>
6
7 namespace detail {
8
9     template<int N>
10     struct rank : rank<N - 1> {
11     };
12
13     template<>
14     struct rank<0> {
15     };
16
17     struct get_func {
18
19         template<class T>
20         struct wrapper {
21             using type = T;
22         };
23
24         template<class F>
25         using func_member = wrapper<typename F::func>;
26
27         template<class F>
28         static wrapper<func_member<F>> test(rank<2>) { return {}; }
29
30         template<class F>
31         struct func_lambda {
32             using type = typename func_lambda<decltype(&F::operator())>::type;
33         };
34
35         template<class R, class... Ts>
36         struct func_lambda<R(*)(Ts...)> {
37             using type = R(Ts...);
38         };
39
40         template<class Object, class R, class... Ts>
41         struct func_lambda<R(Object::*)(Ts...) const> {
42             using type = R(Ts...);
43         };
44
45         template<class Object, class R, class... Ts>
46         struct func_lambda<R(Object::*)(Ts...)> {
47             using type = R(Ts...);
48         };
49
50         template<class F, class = func_lambda<F>>
51         static wrapper<func_lambda<F>> test(rank<1>) { return {}; }
52     };
53
54     template<class F>
55     struct Fn;
56
57     template<class R, class... Ts>
58     struct Fn<R(Ts...)> {
59         using result_type = R;
60
61         template<int N>
62         using get = typename std::tuple_element<N, std::tuple<Ts...>>::type;
63     };
64 }
65
66 template<class Caller>
67 using get_func = typename decltype(detail::get_func::test<Caller>(detail::rank<2>{}))::type::type;
68
69 template<class Caller>
70 using get_result_type = typename detail::Fn<get_func<Caller>>::result_type;
71
72 template<class Caller, int N>
73 using get_argument = typename detail::Fn<get_func<Caller>>::template get<N>;
74
75 template<class Object, class F>
76 class MemberN;
77
78 template<class Object, class R, class... Ts>
79 class MemberN<Object, R(Ts...)> {
80 public:
81     template<R(Object::*f)(Ts...)>
82     class instance {
83     public:
84         using func = R(Object &, Ts...);
85
86         static R call(Object &object, Ts... args) {
87             return (object.*f)(args...);
88         }
89     };
90 };
91
92 template<class Object, class F>
93 class ConstMemberN;
94
95 template<class Object, class R, class... Ts>
96 class ConstMemberN<Object, R(Ts...)> {
97 public:
98     template<R(Object::*f)(Ts...) const>
99     class instance {
100     public:
101         using func = R(const Object &, Ts...);
102
103         static R call(const Object &object, Ts... args) {
104             return (object.*f)(args...);
105         }
106     };
107 };
108
109 template<class F>
110 class FunctionN;
111
112 template<class R, class... Ts>
113 class FunctionN<R(Ts...)> {
114 public:
115     template<R(*f)(Ts...)>
116     class instance {
117     public:
118         using func = R(Ts...);
119
120         static R call(Ts... args) {
121             return (f)(args...);
122         }
123     };
124 };
125
126 template<class Caller, class F>
127 class CallerShiftFirst;
128
129 template<class Caller, class R, class FirstArgument, class... Ts>
130 class CallerShiftFirst<Caller, R(FirstArgument, Ts...)> {
131 public:
132     using func = R(FirstArgument, Ts...);
133
134     static R call(FirstArgument, Ts... args) {
135         return Caller::call(args...);
136     }
137 };
138
139 template<class Functor, class F>
140 class FunctorNInvoke;
141
142 namespace detail {
143     template<int ...>
144     struct seq {
145     };
146
147     template<int N, int... S>
148     struct gens : gens<N - 1, N - 1, S...> {
149     };
150
151     template<int... S>
152     struct gens<0, S...> {
153         using type = seq<S...>;
154     };
155
156     template<int N>
157     using seq_new = typename gens<N>::type;
158 }
159
160 template<class Functor, class R, class... Ts>
161 class FunctorNInvoke<Functor, R(Ts...)> {
162     std::tuple<Ts...> args;
163
164     template<class T>
165     struct caller;
166
167     template<int ...I>
168     struct caller<detail::seq<I...>> {
169         static inline R call(FunctorNInvoke<Functor, R(Ts...)> *self, Functor functor) {
170             (void) self;
171             return functor(std::get<I>(self->args)...);
172         }
173     };
174
175 public:
176     FunctorNInvoke(Ts... args) : args(args...) {
177     }
178
179     inline R operator()(Functor functor) {
180         return caller<detail::seq_new<sizeof...(Ts)>>::call(this, functor);
181     }
182 };
183
184 template<class Functor>
185 using FunctorInvoke = FunctorNInvoke<Functor, get_func<Functor>>;
186
187 template<class Object, class R, R(Object::*member)()>
188 using Member = typename MemberN<Object, R()>::template instance<member>;
189
190 template<class Object, class R, R(Object::*member)() const>
191 using ConstMember = typename ConstMemberN<Object, R()>::template instance<member>;
192
193 template<class Object, class A1, class R, R(Object::*member)(A1)>
194 using Member1 = typename MemberN<Object, R(A1)>::template instance<member>;
195
196 template<class Object, class A1, class R, R(Object::*member)(A1) const>
197 using ConstMember1 = typename ConstMemberN<Object, R(A1)>::template instance<member>;
198
199 template<class Object, class A1, class A2, class R, R(Object::*member)(A1, A2)>
200 using Member2 = typename MemberN<Object, R(A1, A2)>::template instance<member>;
201
202 template<class Object, class A1, class A2, class R, R(Object::*member)(A1, A2) const>
203 using ConstMember2 = typename ConstMemberN<Object, R(A1, A2)>::template instance<member>;
204
205 template<class Object, class A1, class A2, class A3, class R, R(Object::*member)(A1, A2, A3)>
206 using Member3 = typename MemberN<Object, R(A1, A2, A3)>::template instance<member>;
207
208 template<class Object, class A1, class A2, class A3, class R, R(Object::*member)(A1, A2, A3) const>
209 using ConstMember3 = typename ConstMemberN<Object, R(A1, A2, A3)>::template instance<member>;
210
211 template<class R, R(*func)()>
212 using Function0 = typename FunctionN<R()>::template instance<func>;
213
214 template<class A1, class R, R(*func)(A1)>
215 using Function1 = typename FunctionN<R(A1)>::template instance<func>;
216
217 template<class A1, class A2, class R, R(*func)(A1, A2)>
218 using Function2 = typename FunctionN<R(A1, A2)>::template instance<func>;
219
220 template<class A1, class A2, class A3, class R, R(*func)(A1, A2, A3)>
221 using Function3 = typename FunctionN<R(A1, A2, A3)>::template instance<func>;
222
223 template<class A1, class A2, class A3, class A4, class R, R(*func)(A1, A2, A3, A4)>
224 using Function4 = typename FunctionN<R(A1, A2, A3, A4)>::template instance<func>;
225
226 template<class Caller, class FirstArgument = void *>
227 using Caller0To1 = CallerShiftFirst<Caller, get_result_type<Caller>(
228         FirstArgument
229 )>;
230
231 template<class Caller, class FirstArgument = void *>
232 using Caller1To2 = CallerShiftFirst<Caller, get_result_type<Caller>(
233         FirstArgument,
234         get_argument<Caller, 0>
235 )>;
236
237 template<class Caller, class FirstArgument = void *>
238 using Caller2To3 = CallerShiftFirst<Caller, get_result_type<Caller>(
239         FirstArgument,
240         get_argument<Caller, 0>,
241         get_argument<Caller, 1>
242 )>;
243
244 template<class Caller, class FirstArgument = void *>
245 using Caller3To4 = CallerShiftFirst<Caller, get_result_type<Caller>(
246         FirstArgument,
247         get_argument<Caller, 0>,
248         get_argument<Caller, 1>,
249         get_argument<Caller, 2>
250 )>;
251
252 #endif