]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/generic/callback.h
Support lambda callbacks
[xonotic/netradiant.git] / libs / generic / callback.h
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #if !defined( INCLUDED_GENERIC_CLOSURE_H )
23 #define INCLUDED_GENERIC_CLOSURE_H
24
25 /// \file
26 /// \brief Type-safe techniques for binding the first argument of an opaque callback.
27
28 #include <cstddef>
29 #include "functional.h"
30 #include "callbackfwd.h"
31
32 template<typename Type>
33 inline void* convertToOpaque( Type* t ){
34         return t;
35 }
36 template<typename Type>
37 inline void* convertToOpaque( const Type* t ){
38         return const_cast<Type*>( t );
39 }
40 template<typename Type>
41 inline void* convertToOpaque( Type& t ){
42         return &t;
43 }
44 template<typename Type>
45 inline void* convertToOpaque( const Type& t ){
46         return const_cast<Type*>( &t );
47 }
48
49
50 template<typename Type>
51 class ConvertFromOpaque
52 {
53 };
54
55 template<typename Type>
56 class ConvertFromOpaque<Type&>
57 {
58 public:
59 static Type& apply( void* p ){
60         return *static_cast<Type*>( p );
61 }
62 };
63
64 template<typename Type>
65 class ConvertFromOpaque<const Type&>
66 {
67 public:
68 static const Type& apply( void* p ){
69         return *static_cast<Type*>( p );
70 }
71 };
72
73
74 template<typename Type>
75 class ConvertFromOpaque<Type*>
76 {
77 public:
78 static Type* apply( void* p ){
79         return static_cast<Type*>( p );
80 }
81 };
82
83 template<typename Type>
84 class ConvertFromOpaque<const Type*>
85 {
86 public:
87 static const Type* apply( void* p ){
88         return static_cast<Type*>( p );
89 }
90 };
91
92 template<typename Thunk_>
93 class CallbackBase
94 {
95 void* m_environment;
96 Thunk_ m_thunk;
97 public:
98 typedef Thunk_ Thunk;
99 CallbackBase( void* environment, Thunk function ) : m_environment( environment ), m_thunk( function ){
100 }
101 void* getEnvironment() const {
102         return m_environment;
103 }
104 Thunk getThunk() const {
105         return m_thunk;
106 }
107 };
108
109 template<typename Thunk>
110 inline bool operator==( const CallbackBase<Thunk>& self, const CallbackBase<Thunk>& other ){
111         return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk();
112 }
113 template<typename Thunk>
114 inline bool operator!=( const CallbackBase<Thunk>& self, const CallbackBase<Thunk>& other ){
115         return !( self == other );
116 }
117 template<typename Thunk>
118 inline bool operator<( const CallbackBase<Thunk>& self, const CallbackBase<Thunk>& other ){
119         return self.getEnvironment() < other.getEnvironment() ||
120                    ( !( other.getEnvironment() < self.getEnvironment() ) && self.getThunk() < other.getThunk() );
121 }
122
123 template<class Caller, class F>
124 class BindFirstOpaqueN;
125
126 template<class Caller, class R, class FirstBound, class... Ts>
127 class BindFirstOpaqueN<Caller, R(FirstBound, Ts...)> {
128         FirstBound firstBound;
129 public:
130         explicit BindFirstOpaqueN(FirstBound firstBound) : firstBound(firstBound) {
131         }
132
133         R operator()(Ts... args) const {
134                 return Caller::call(firstBound, args...);
135         }
136
137         FirstBound getBound() const {
138                 return firstBound;
139         }
140
141         static R thunk(void *environment, Ts... args) {
142                 return Caller::call(ConvertFromOpaque<FirstBound>::apply(environment), args...);
143         }
144
145         void *getEnvironment() const {
146                 return convertToOpaque(firstBound);
147         }
148 };
149
150 template<class Caller>
151 using BindFirstOpaque = BindFirstOpaqueN<Caller, get_func<Caller>>;
152
153 template<class F>
154 class CallbackN;
155
156 template<class R, class... Ts>
157 class CallbackN<R(Ts...)> : public CallbackBase<R(*)(void *, Ts...)> {
158         using Base = CallbackBase<R (*)(void *, Ts...)>;
159
160         static R nullThunk(void *, Ts...) {
161         }
162
163 public:
164         using func = R(Ts...);
165
166         CallbackN() : Base(0, nullThunk) {
167         }
168
169         template<typename Caller>
170         CallbackN(const BindFirstOpaque<Caller> &caller) : Base(caller.getEnvironment(), BindFirstOpaque<Caller>::thunk) {
171         }
172
173         CallbackN(void *environment, typename Base::Thunk function) : Base(environment, function) {
174         }
175
176         R operator()(Ts... args) const {
177                 return Base::getThunk()(Base::getEnvironment(), args...);
178         }
179 };
180
181 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer.
182 ///
183 /// Use with the callback constructors MemberCaller, ConstMemberCaller, ReferenceCaller, ConstReferenceCaller, PointerCaller, ConstPointerCaller and FreeCaller.
184 template<class Result>
185 class Callback0 : public CallbackN<Result()> {
186 public:
187         using CallbackN<Result()>::CallbackN;
188 };
189
190 template<typename Caller>
191 inline Callback0<get_result_type<Caller>> makeCallback0(const Caller &caller, get_argument<Caller, 0> callee) {
192         return Callback0<get_result_type<Caller>>(BindFirstOpaque<Caller>(callee));
193 }
194 template<typename Caller>
195 inline Callback0<get_result_type<Caller>> makeStatelessCallback0(const Caller &caller) {
196         return makeCallback0( Caller0To1<Caller>(), 0 );
197 }
198
199 typedef Callback0<void> Callback;
200
201
202
203 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and one other argument.
204 ///
205 /// Use with the callback constructors MemberCaller1, ConstMemberCaller1, ReferenceCaller1, ConstReferenceCaller1, PointerCaller1, ConstPointerCaller1 and FreeCaller1.
206 template<class FirstArgument, class Result>
207 class Callback1 : public CallbackN<Result(FirstArgument)> {
208 public:
209         using CallbackN<Result(FirstArgument)>::CallbackN;
210 };
211
212 template<typename Caller>
213 inline Callback1<get_argument<Caller, 1>, get_result_type<Caller>>
214 makeCallback1(const Caller &caller, get_argument<Caller, 0> callee) {
215         return Callback1<get_argument<Caller, 1>, get_result_type<Caller>>(BindFirstOpaque<Caller>(callee));
216 }
217 template<typename Caller>
218 inline Callback1<get_argument<Caller, 1>, get_result_type<Caller>> makeStatelessCallback1(const Caller &caller) {
219         return makeCallback1( Caller1To2<Caller>(), 0 );
220 }
221
222
223 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and two other arguments.
224 ///
225 template<typename FirstArgument, typename SecondArgument, typename Result>
226 class Callback2 : public CallbackN<Result(FirstArgument, SecondArgument)> {
227 public:
228         using CallbackN<Result(FirstArgument, SecondArgument)>::CallbackN;
229 };
230
231 template<typename Caller>
232 inline Callback2<
233                 get_argument<Caller, 1>,
234                 get_argument<Caller, 2>,
235                 get_result_type<Caller>
236 > makeCallback2(const Caller &caller, get_argument<Caller, 0> callee) {
237         return Callback2<
238                         get_argument<Caller, 1>,
239                         get_argument<Caller, 2>,
240                         get_result_type<Caller>
241         >(BindFirstOpaque<Caller>(callee));
242 }
243 template<typename Caller>
244 inline Callback2<
245                 get_argument<Caller, 0>,
246                 get_argument<Caller, 1>,
247                 get_result_type<Caller>
248 > makeStatelessCallback2(const Caller &caller) {
249         return makeCallback2( Caller2To3<Caller>(), 0 );
250 }
251
252
253 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and three other arguments.
254 ///
255 template<typename FirstArgument, typename SecondArgument, typename ThirdArgument, typename Result>
256 class Callback3 : public CallbackN<Result(FirstArgument, SecondArgument, ThirdArgument)> {
257 public:
258         using CallbackN<Result(FirstArgument, SecondArgument, ThirdArgument)>::CallbackN;
259 };
260
261 template<typename Caller>
262 inline Callback3<
263                 get_argument<Caller, 1>,
264                 get_argument<Caller, 2>,
265                 get_argument<Caller, 3>,
266                 get_result_type<Caller>
267 > makeCallback3(const Caller &caller, get_argument<Caller, 0> callee) {
268         return Callback3<
269                         get_argument<Caller, 1>,
270                         get_argument<Caller, 2>,
271                         get_argument<Caller, 3>,
272                         get_result_type<Caller>
273         >(BindFirstOpaque<Caller>(callee));
274 }
275 template<typename Caller>
276 inline Callback3<
277                 get_argument<Caller, 0>,
278                 get_argument<Caller, 1>,
279                 get_argument<Caller, 2>,
280                 get_result_type<Caller>
281 > makeStatelessCallback3(const Caller &caller) {
282         return makeCallback3( Caller3To4<Caller>(), 0 );
283 }
284
285
286 /// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function.
287 ///
288 /// \dontinclude generic/callback.cpp
289 /// \skipline MemberCaller example
290 /// \until end example
291 template<class Environment, void(Environment::*member)()>
292 using MemberCaller = BindFirstOpaque<Member<Environment, void, member>>;
293
294 /// \brief Forms a Callback from a const Environment reference and a const Environment member-function.
295 ///
296 /// \dontinclude generic/callback.cpp
297 /// \skipline MemberCaller example
298 /// \until end example
299 template<class Environment, void(Environment::*member)() const>
300 using ConstMemberCaller = BindFirstOpaque<ConstMember<Environment, void, member>>;
301
302 /// \brief Forms a Callback from a non-const Environment reference and a const Environment member-function which takes one argument.
303 template<class Environment, class FirstArgument, void(Environment::*member)(FirstArgument)>
304 using MemberCaller1 = BindFirstOpaque<Member1<Environment, FirstArgument, void, member>>;
305
306 /// \brief Forms a Callback from a const Environment reference and a const Environment member-function which takes one argument.
307 template<class Environment, class FirstArgument, void(Environment::*member)(FirstArgument) const>
308 using ConstMemberCaller1 = BindFirstOpaque<ConstMember1<Environment, FirstArgument, void, member>>;
309
310 /// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference.
311 ///
312 /// \dontinclude generic/callback.cpp
313 /// \skipline ReferenceCaller example
314 /// \until end example
315 template<class Environment, void(*func)(Environment &)>
316 using ReferenceCaller = BindFirstOpaque<Function1<Environment &, void, func>>;
317
318 /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference.
319 ///
320 /// \dontinclude generic/callback.cpp
321 /// \skipline ReferenceCaller example
322 /// \until end example
323 template<class Environment, void(*func)(const Environment &)>
324 using ConstReferenceCaller = BindFirstOpaque<Function1<const Environment &, void, func>>;
325
326 /// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference and one other argument.
327 template<class Environment, class FirstArgument, void(*func)(Environment &, FirstArgument)>
328 using ReferenceCaller1 = BindFirstOpaque<Function2<Environment &, FirstArgument, void, func>>;
329
330 /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference and one other argument.
331 template<class Environment, class FirstArgument, void(*func)(const Environment &, FirstArgument)>
332 using ConstReferenceCaller1 = BindFirstOpaque<Function2<const Environment &, FirstArgument, void, func>>;
333
334 /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer.
335 template<class Environment, void(*func)(Environment *)>
336 using PointerCaller = BindFirstOpaque<Function1<Environment *, void, func>>;
337
338 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer.
339 template<class Environment, void(*func)(const Environment *)>
340 using ConstPointerCaller = BindFirstOpaque<Function1<const Environment *, void, func>>;
341
342 /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer and one other argument.
343 template<class Environment, class FirstArgument, void(*func)(Environment *, FirstArgument)>
344 using PointerCaller1 = BindFirstOpaque<Function2<Environment *, FirstArgument, void, func>>;
345
346 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer and one other argument.
347 template<class Environment, class FirstArgument, void(*func)(const Environment *, FirstArgument)>
348 using ConstPointerCaller1 = BindFirstOpaque<Function2<const Environment *, FirstArgument, void, func>>;
349
350 /// \brief Forms a Callback from a free function which takes no arguments.
351 template<void(*func)()>
352 class FreeCaller : public BindFirstOpaque<Caller0To1<Function0<void, func>>> {
353 public:
354         FreeCaller() : BindFirstOpaque<Caller0To1<Function0<void, func>>>(0) {
355         }
356 };
357
358 /// \brief Forms a Callback from a free function which takes a single argument.
359 template<class FirstArgument, void(*func)(FirstArgument)>
360 class FreeCaller1 : public BindFirstOpaque<Caller1To2<Function1<FirstArgument, void, func>>> {
361 public:
362         FreeCaller1() : BindFirstOpaque<Caller1To2<Function1<FirstArgument, void, func>>>(0) {
363         }
364 };
365
366
367 /// \brief Constructs a Callback from a non-const \p functor with zero arguments.
368 ///
369 /// \param Functor Must define \c operator()().
370 template<typename Functor>
371 inline Callback makeCallback( Functor& functor ){
372         return Callback( MemberCaller<Functor, &Functor::operator()>( functor ) );
373 }
374
375 /// \brief  Constructs a Callback from a const \p functor with zero arguments.
376 ///
377 /// \param Functor Must define const \c operator()().
378 template<typename Functor>
379 inline Callback makeCallback( const Functor& functor ){
380         return Callback( ConstMemberCaller<Functor, &Functor::operator()>( functor ) );
381 }
382
383 /// \brief  Constructs a Callback1 from a non-const \p functor with one argument.
384 ///
385 /// \param Functor Must define \c first_argument_type and \c operator()(first_argument_type).
386 template<typename Functor>
387 inline Callback1<get_argument<Functor, 0>> makeCallback1(Functor &functor) {
388         typedef get_argument<Functor, 0> FirstArgument;
389         return Callback1<FirstArgument>( MemberCaller1<Functor, FirstArgument, &Functor::operator()>( functor ) );
390 }
391
392 /// \brief  Constructs a Callback1 from a const \p functor with one argument.
393 ///
394 /// \param Functor Must define \c first_argument_type and const \c operator()(first_argument_type).
395 template<typename Functor>
396 inline Callback1<get_argument<Functor, 0>> makeCallback1(const Functor &functor) {
397         typedef get_argument<Functor, 0> FirstArgument;
398         return Callback1<FirstArgument>( ConstMemberCaller1<Functor, FirstArgument, &Functor::operator()>( functor ) );
399 }
400
401
402 typedef Callback1<bool> BoolImportCallback;
403 typedef Callback1<const BoolImportCallback&> BoolExportCallback;
404
405 typedef Callback1<int> IntImportCallback;
406 typedef Callback1<const IntImportCallback&> IntExportCallback;
407
408 typedef Callback1<float> FloatImportCallback;
409 typedef Callback1<const FloatImportCallback&> FloatExportCallback;
410
411 typedef Callback1<const char*> StringImportCallback;
412 typedef Callback1<const StringImportCallback&> StringExportCallback;
413
414 typedef Callback1<std::size_t> SizeImportCallback;
415 typedef Callback1<const SizeImportCallback&> SizeExportCallback;
416
417
418 #endif