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