]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/generic/functional.h
Callback: remove fixed-arity wrappers
[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 namespace detail {
76     template<class Object, class F>
77     struct MemberFunction;
78
79     template<class Object, class R, class... Ts>
80     struct MemberFunction<Object, R(Ts...)> {
81         using type = R(Object::*)(Ts...);
82         using type_const = R(Object::*)(Ts...) const;
83     };
84 }
85
86 template<class Object, class F>
87 using MemberFunction = typename detail::MemberFunction<Object, F>::type;
88
89 template<class Object, class F>
90 using ConstMemberFunction = typename detail::MemberFunction<Object, F>::type_const;
91
92 template<class Object, class F>
93 class MemberN;
94
95 template<class Object, class R, class... Ts>
96 class MemberN<Object, R(Ts...)> {
97 public:
98     template<R(Object::*f)(Ts...)>
99     class instance {
100     public:
101         using func = R(Object &, Ts...);
102
103         static R call(Object &object, Ts... args) {
104             return (object.*f)(args...);
105         }
106     };
107 };
108
109 template<class Object, class F, MemberFunction<Object, F> func>
110 using Member = typename MemberN<Object, F>::template instance<func>;
111
112 template<class Object, class F>
113 class ConstMemberN;
114
115 template<class Object, class R, class... Ts>
116 class ConstMemberN<Object, R(Ts...)> {
117 public:
118     template<R(Object::*f)(Ts...) const>
119     class instance {
120     public:
121         using func = R(const Object &, Ts...);
122
123         static R call(const Object &object, Ts... args) {
124             return (object.*f)(args...);
125         }
126     };
127 };
128
129 template<class Object, class F, ConstMemberFunction<Object, F> func>
130 using ConstMember = typename ConstMemberN<Object, F>::template instance<func>;
131
132 template<class F>
133 class FunctionN;
134
135 template<class R, class... Ts>
136 class FunctionN<R(Ts...)> {
137 public:
138     template<R(*f)(Ts...)>
139     class instance {
140     public:
141         using func = R(Ts...);
142
143         static R call(Ts... args) {
144             return (f)(args...);
145         }
146     };
147 };
148
149 template<class F, F *func>
150 using Function = typename FunctionN<F>::template instance<func>;
151
152 template<class Caller, class F>
153 class CallerShiftFirst;
154
155 template<class Caller, class R, class FirstArgument, class... Ts>
156 class CallerShiftFirst<Caller, R(FirstArgument, Ts...)> {
157 public:
158     using func = R(FirstArgument, Ts...);
159
160     static R call(FirstArgument, Ts... args) {
161         return Caller::call(args...);
162     }
163 };
164
165 template<class Functor, class F>
166 class FunctorNInvoke;
167
168 namespace detail {
169     template<int ...>
170     struct seq {
171     };
172
173     template<int N, int... S>
174     struct gens : gens<N - 1, N - 1, S...> {
175     };
176
177     template<int... S>
178     struct gens<0, S...> {
179         using type = seq<S...>;
180     };
181
182     template<int N>
183     using seq_new = typename gens<N>::type;
184 }
185
186 template<class Functor, class R, class... Ts>
187 class FunctorNInvoke<Functor, R(Ts...)> {
188     std::tuple<Ts...> args;
189
190     template<class T>
191     struct caller;
192
193     template<int ...I>
194     struct caller<detail::seq<I...>> {
195         static inline R call(FunctorNInvoke<Functor, R(Ts...)> *self, Functor functor) {
196             (void) self;
197             return functor(std::get<I>(self->args)...);
198         }
199     };
200
201 public:
202     FunctorNInvoke(Ts... args) : args(args...) {
203     }
204
205     inline R operator()(Functor functor) {
206         return caller<detail::seq_new<sizeof...(Ts)>>::call(this, functor);
207     }
208 };
209
210 template<class Functor>
211 using FunctorInvoke = FunctorNInvoke<Functor, get_func<Functor>>;
212
213 #endif