]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/generic/callback.h
Merge remote-tracking branch 'ttimo/master'
[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 Caller>
93 class BindFirstOpaque
94 {
95 typedef typename Caller::first_argument_type FirstBound;
96 FirstBound firstBound;
97 public:
98 typedef typename Caller::result_type result_type;
99 explicit BindFirstOpaque( FirstBound firstBound ) : firstBound( firstBound ){
100 }
101 result_type operator()() const {
102         return Caller::call( firstBound );
103 }
104 FirstBound getBound() const {
105         return firstBound;
106 }
107 static result_type thunk( void* environment ){
108         return Caller::call( ConvertFromOpaque<FirstBound>::apply( environment ) );
109 }
110 void* getEnvironment() const {
111         return convertToOpaque( firstBound );
112 }
113 };
114
115 template<typename Caller>
116 class BindFirstOpaque1
117 {
118 typedef typename Caller::first_argument_type FirstBound;
119 FirstBound firstBound;
120 public:
121 typedef typename Caller::second_argument_type first_argument_type;
122 typedef typename Caller::result_type result_type;
123 explicit BindFirstOpaque1( FirstBound firstBound ) : firstBound( firstBound ){
124 }
125 result_type operator()( first_argument_type a1 ) const {
126         return Caller::call( firstBound, a1 );
127 }
128 FirstBound getBound() const {
129         return firstBound;
130 }
131 static result_type thunk( void* environment, first_argument_type a1 ){
132         return Caller::call( ConvertFromOpaque<FirstBound>::apply( environment ), a1 );
133 }
134 void* getEnvironment() const {
135         return convertToOpaque( firstBound );
136 }
137 };
138
139 template<typename Caller>
140 class BindFirstOpaque2
141 {
142 typedef typename Caller::first_argument_type FirstBound;
143 FirstBound firstBound;
144 public:
145 typedef typename Caller::second_argument_type first_argument_type;
146 typedef typename Caller::third_argument_type second_argument_type;
147 typedef typename Caller::result_type result_type;
148 explicit BindFirstOpaque2( FirstBound firstBound ) : firstBound( firstBound ){
149 }
150 result_type operator()( first_argument_type a1, second_argument_type a2 ) const {
151         return Caller::call( firstBound, a1, a2 );
152 }
153 FirstBound getBound() const {
154         return firstBound;
155 }
156 static result_type thunk( void* environment, first_argument_type a1, second_argument_type a2 ){
157         return Caller::call( ConvertFromOpaque<FirstBound>::apply( environment ), a1, a2 );
158 }
159 void* getEnvironment() const {
160         return convertToOpaque( firstBound );
161 }
162 };
163
164 template<typename Caller>
165 class BindFirstOpaque3
166 {
167 typedef typename Caller::first_argument_type FirstBound;
168 FirstBound firstBound;
169 public:
170 typedef typename Caller::second_argument_type first_argument_type;
171 typedef typename Caller::third_argument_type second_argument_type;
172 typedef typename Caller::fourth_argument_type third_argument_type;
173 typedef typename Caller::result_type result_type;
174 explicit BindFirstOpaque3( FirstBound firstBound ) : firstBound( firstBound ){
175 }
176 result_type operator()( first_argument_type a1, second_argument_type a2, third_argument_type a3 ) const {
177         return Caller::call( firstBound, a1, a2, a3 );
178 }
179 FirstBound getBound() const {
180         return firstBound;
181 }
182 static result_type thunk( void* environment, first_argument_type a1, second_argument_type a2, third_argument_type a3 ){
183         return Caller::call( ConvertFromOpaque<FirstBound>::apply( environment ), a1, a2, a3 );
184 }
185 void* getEnvironment() const {
186         return convertToOpaque( firstBound );
187 }
188 };
189
190 template<typename Thunk_>
191 class CallbackBase
192 {
193 void* m_environment;
194 Thunk_ m_thunk;
195 public:
196 typedef Thunk_ Thunk;
197 CallbackBase( void* environment, Thunk function ) : m_environment( environment ), m_thunk( function ){
198 }
199 void* getEnvironment() const {
200         return m_environment;
201 }
202 Thunk getThunk() const {
203         return m_thunk;
204 }
205 };
206
207 template<typename Thunk>
208 inline bool operator==( const CallbackBase<Thunk>& self, const CallbackBase<Thunk>& other ){
209         return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk();
210 }
211 template<typename Thunk>
212 inline bool operator!=( const CallbackBase<Thunk>& self, const CallbackBase<Thunk>& other ){
213         return !( self == other );
214 }
215 template<typename Thunk>
216 inline bool operator<( const CallbackBase<Thunk>& self, const CallbackBase<Thunk>& other ){
217         return self.getEnvironment() < other.getEnvironment() ||
218                    ( !( other.getEnvironment() < self.getEnvironment() ) && self.getThunk() < other.getThunk() );
219 }
220
221
222 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer.
223 ///
224 /// Use with the callback constructors MemberCaller, ConstMemberCaller, ReferenceCaller, ConstReferenceCaller, PointerCaller, ConstPointerCaller and FreeCaller.
225 template<typename Result>
226 class Callback0 : public CallbackBase<Result ( * )( void* )>
227 {
228 typedef CallbackBase<Result ( * )( void* )> Base;
229 static Result nullThunk( void* ){
230 }
231
232 public:
233 typedef Result result_type;
234
235 Callback0() : Base( 0, nullThunk ){
236 }
237 template<typename Caller>
238 Callback0( const BindFirstOpaque<Caller>& caller ) : Base( caller.getEnvironment(), BindFirstOpaque<Caller>::thunk ){
239 }
240 Callback0( void* environment, typename Base::Thunk function ) : Base( environment, function ){
241 }
242 result_type operator()() const {
243         return Base::getThunk() ( Base::getEnvironment() );
244 }
245 };
246
247 template<typename Caller>
248 inline Callback0<typename Caller::result_type> makeCallback0( const Caller& caller, typename Caller::first_argument_type callee ){
249         return Callback0<typename Caller::result_type>( BindFirstOpaque<Caller>( callee ) );
250 }
251 template<typename Caller>
252 inline Callback0<typename Caller::result_type> makeStatelessCallback0( const Caller& caller ){
253         return makeCallback0( Caller0To1<Caller>(), 0 );
254 }
255
256 typedef Callback0<void> Callback;
257
258
259
260 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and one other argument.
261 ///
262 /// Use with the callback constructors MemberCaller1, ConstMemberCaller1, ReferenceCaller1, ConstReferenceCaller1, PointerCaller1, ConstPointerCaller1 and FreeCaller1.
263 template<typename FirstArgument, typename Result>
264 class Callback1 : public CallbackBase<Result ( * )( void*, FirstArgument )>
265 {
266 typedef CallbackBase<Result ( * )( void*, FirstArgument )> Base;
267 static Result nullThunk( void*, FirstArgument ){
268 }
269
270 public:
271 typedef FirstArgument first_argument_type;
272 typedef Result result_type;
273
274 Callback1() : Base( 0, nullThunk ){
275 }
276 template<typename Caller>
277 Callback1( const BindFirstOpaque1<Caller>& caller ) : Base( caller.getEnvironment(), BindFirstOpaque1<Caller>::thunk ){
278 }
279 Callback1( void* environment, typename Base::Thunk function ) : Base( environment, function ){
280 }
281 result_type operator()( FirstArgument firstArgument ) const {
282         return Base::getThunk() ( Base::getEnvironment(), firstArgument );
283 }
284 };
285
286 template<typename Caller>
287 inline Callback1<typename Caller::second_argument_type, typename Caller::result_type> makeCallback1( const Caller& caller, typename Caller::first_argument_type callee ){
288         return Callback1<typename Caller::second_argument_type, typename Caller::result_type>( BindFirstOpaque1<Caller>( callee ) );
289 }
290 template<typename Caller>
291 inline Callback1<typename Caller::second_argument_type, typename Caller::result_type> makeStatelessCallback1( const Caller& caller ){
292         return makeCallback1( Caller1To2<Caller>(), 0 );
293 }
294
295
296 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and two other arguments.
297 ///
298 template<typename FirstArgument, typename SecondArgument, typename Result>
299 class Callback2 : public CallbackBase<Result ( * )( void*, FirstArgument, SecondArgument )>
300 {
301 typedef CallbackBase<Result ( * )( void*, FirstArgument, SecondArgument )> Base;
302 static Result nullThunk( void*, FirstArgument, SecondArgument ){
303 }
304
305 public:
306 typedef FirstArgument first_argument_type;
307 typedef SecondArgument second_argument_type;
308 typedef Result result_type;
309
310 Callback2() : Base( 0, nullThunk ){
311 }
312 template<typename Caller>
313 Callback2( const BindFirstOpaque2<Caller>& caller ) : Base( caller.getEnvironment(), BindFirstOpaque2<Caller>::thunk ){
314 }
315 Callback2( void* environment, typename Base::Thunk function ) : Base( environment, function ){
316 }
317 result_type operator()( FirstArgument firstArgument, SecondArgument secondArgument ) const {
318         return Base::getThunk() ( Base::getEnvironment(), firstArgument, secondArgument );
319 }
320 };
321
322 template<typename Caller>
323 inline Callback2<
324         typename Caller::second_argument_type,
325         typename Caller::third_argument_type,
326         typename Caller::result_type
327         > makeCallback2( const Caller& caller, typename Caller::first_argument_type callee ){
328         return Callback2<
329                            typename Caller::second_argument_type,
330                            typename Caller::third_argument_type,
331                            typename Caller::result_type
332                            >( BindFirstOpaque2<Caller>( callee ) );
333 }
334 template<typename Caller>
335 inline Callback2<
336         typename Caller::first_argument_type,
337         typename Caller::second_argument_type,
338         typename Caller::result_type
339         > makeStatelessCallback2( const Caller& caller ){
340         return makeCallback2( Caller2To3<Caller>(), 0 );
341 }
342
343
344 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and three other arguments.
345 ///
346 template<typename FirstArgument, typename SecondArgument, typename ThirdArgument, typename Result>
347 class Callback3 : public CallbackBase<Result ( * )( void*, FirstArgument, SecondArgument, ThirdArgument )>
348 {
349 typedef CallbackBase<Result ( * )( void*, FirstArgument, SecondArgument, ThirdArgument )> Base;
350 static Result nullThunk( void*, FirstArgument, SecondArgument, ThirdArgument ){
351 }
352
353 public:
354 typedef FirstArgument first_argument_type;
355 typedef SecondArgument second_argument_type;
356 typedef ThirdArgument third_argument_type;
357 typedef Result result_type;
358
359 Callback3() : Base( 0, nullThunk ){
360 }
361 template<typename Caller>
362 Callback3( const BindFirstOpaque3<Caller>& caller ) : Base( caller.getEnvironment(), BindFirstOpaque3<Caller>::thunk ){
363 }
364 Callback3( void* environment, typename Base::Thunk function ) : Base( environment, function ){
365 }
366 result_type operator()( FirstArgument firstArgument, SecondArgument secondArgument, ThirdArgument thirdArgument ) const {
367         return Base::getThunk() ( Base::getEnvironment(), firstArgument, secondArgument, thirdArgument );
368 }
369 };
370
371 template<typename Caller>
372 inline Callback3<
373         typename Caller::second_argument_type,
374         typename Caller::third_argument_type,
375         typename Caller::fourth_argument_type,
376         typename Caller::result_type
377         > makeCallback3( const Caller& caller, typename Caller::first_argument_type callee ){
378         return Callback3<
379                            typename Caller::second_argument_type,
380                            typename Caller::third_argument_type,
381                            typename Caller::fourth_argument_type,
382                            typename Caller::result_type
383                            >( BindFirstOpaque3<Caller>( callee ) );
384 }
385 template<typename Caller>
386 inline Callback3<
387         typename Caller::first_argument_type,
388         typename Caller::second_argument_type,
389         typename Caller::third_argument_type,
390         typename Caller::result_type
391         > makeStatelessCallback3( const Caller& caller ){
392         return makeCallback3( Caller3To4<Caller>(), 0 );
393 }
394
395
396 /// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function.
397 ///
398 /// \dontinclude generic/callback.cpp
399 /// \skipline MemberCaller example
400 /// \until end example
401 template<typename Environment, void( Environment::*member ) ( )>
402 class MemberCaller : public BindFirstOpaque< Member<Environment, void, member> >
403 {
404 public:
405 MemberCaller( Environment& environment ) : BindFirstOpaque< Member<Environment, void, member> >( environment ){
406 }
407 };
408
409 /// \brief Forms a Callback from a const Environment reference and a const Environment member-function.
410 ///
411 /// \dontinclude generic/callback.cpp
412 /// \skipline MemberCaller example
413 /// \until end example
414 template<typename Environment, void( Environment::*member ) ( ) const>
415 class ConstMemberCaller : public BindFirstOpaque< ConstMember<Environment, void, member> >
416 {
417 public:
418 ConstMemberCaller( const Environment& environment ) : BindFirstOpaque< ConstMember<Environment, void, member> >( environment ){
419 }
420 };
421
422 /// \brief Forms a Callback from a non-const Environment reference and a const Environment member-function which takes one argument.
423 template<typename Environment, typename FirstArgument, void( Environment::*member ) (FirstArgument)>
424 class MemberCaller1 : public BindFirstOpaque1< Member1<Environment, FirstArgument, void, member> >
425 {
426 public:
427 MemberCaller1( Environment& environment ) : BindFirstOpaque1< Member1<Environment, FirstArgument, void, member> >( environment ){
428 }
429 };
430
431 /// \brief Forms a Callback from a const Environment reference and a const Environment member-function which takes one argument.
432 template<typename Environment, typename FirstArgument, void( Environment::*member ) (FirstArgument) const>
433 class ConstMemberCaller1 : public BindFirstOpaque1< ConstMember1<Environment, FirstArgument, void, member> >
434 {
435 public:
436 ConstMemberCaller1( const Environment& environment ) : BindFirstOpaque1< ConstMember1<Environment, FirstArgument, void, member> >( environment ){
437 }
438 };
439
440 /// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference.
441 ///
442 /// \dontinclude generic/callback.cpp
443 /// \skipline ReferenceCaller example
444 /// \until end example
445 template<typename Environment, void( *func ) (Environment&)>
446 class ReferenceCaller : public BindFirstOpaque< Function1<Environment&, void, func> >
447 {
448 public:
449 ReferenceCaller( Environment& environment ) : BindFirstOpaque< Function1<Environment&, void, func> >( environment ){
450 }
451 };
452
453 /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference.
454 ///
455 /// \dontinclude generic/callback.cpp
456 /// \skipline ReferenceCaller example
457 /// \until end example
458 template<typename Environment, void( *func ) (const Environment&)>
459 class ConstReferenceCaller : public BindFirstOpaque< Function1<const Environment&, void, func> >
460 {
461 public:
462 ConstReferenceCaller( const Environment& environment ) : BindFirstOpaque< Function1<const Environment&, void, func> >( environment ){
463 }
464 };
465
466 /// \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.
467 template<typename Environment, typename FirstArgument, void( *func ) ( Environment&, FirstArgument )>
468 class ReferenceCaller1 : public BindFirstOpaque1< Function2<Environment&, FirstArgument, void, func> >
469 {
470 public:
471 ReferenceCaller1( Environment& environment ) : BindFirstOpaque1< Function2<Environment&, FirstArgument, void, func> >( environment ){
472 }
473 };
474
475 /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference and one other argument.
476 template<typename Environment, typename FirstArgument, void( *func ) ( const Environment&, FirstArgument )>
477 class ConstReferenceCaller1 : public BindFirstOpaque1< Function2<const Environment&, FirstArgument, void, func> >
478 {
479 public:
480 ConstReferenceCaller1( const Environment& environment ) : BindFirstOpaque1< Function2<const Environment&, FirstArgument, void, func> >( environment ){
481 }
482 };
483
484 /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer.
485 template<typename Environment, void( *func ) (Environment*)>
486 class PointerCaller : public BindFirstOpaque< Function1<Environment*, void, func> >
487 {
488 public:
489 PointerCaller( Environment* environment ) : BindFirstOpaque< Function1<Environment*, void, func> >( environment ){
490 }
491 };
492
493 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer.
494 template<typename Environment, void( *func ) (const Environment*)>
495 class ConstPointerCaller : public BindFirstOpaque< Function1<const Environment*, void, func> >
496 {
497 public:
498 ConstPointerCaller( const Environment* environment ) : BindFirstOpaque< Function1<const Environment*, void, func> >( environment ){
499 }
500 };
501
502 /// \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.
503 template<typename Environment, typename FirstArgument, void( *func ) ( Environment*, FirstArgument )>
504 class PointerCaller1 : public BindFirstOpaque1< Function2<Environment*, FirstArgument, void, func> >
505 {
506 public:
507 PointerCaller1( Environment* environment ) : BindFirstOpaque1< Function2<Environment*, FirstArgument, void, func> >( environment ){
508 }
509 };
510
511 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer and one other argument.
512 template<typename Environment, typename FirstArgument, void( *func ) ( const Environment*, FirstArgument )>
513 class ConstPointerCaller1 : public BindFirstOpaque1< Function2<const Environment*, FirstArgument, void, func> >
514 {
515 public:
516 ConstPointerCaller1( const Environment* environment ) : BindFirstOpaque1< Function2<const Environment*, FirstArgument, void, func> >( environment ){
517 }
518 };
519
520 /// \brief Forms a Callback from a free function which takes no arguments.
521 template<void( *func ) ( )>
522 class FreeCaller : public BindFirstOpaque< Caller0To1< Function0<void, func> > >
523 {
524 public:
525 FreeCaller() : BindFirstOpaque< Caller0To1< Function0<void, func> > >( 0 ){
526 }
527 };
528
529 /// \brief Forms a Callback from a free function which takes a single argument.
530 template<typename FirstArgument, void( *func ) (FirstArgument)>
531 class FreeCaller1 : public BindFirstOpaque1< Caller1To2< Function1<FirstArgument, void, func> > >
532 {
533 public:
534 FreeCaller1() : BindFirstOpaque1< Caller1To2< Function1<FirstArgument, void, func> > >( 0 ){
535 }
536 };
537
538
539 /// \brief Constructs a Callback from a non-const \p functor with zero arguments.
540 ///
541 /// \param Functor Must define \c operator()().
542 template<typename Functor>
543 inline Callback makeCallback( Functor& functor ){
544         return Callback( MemberCaller<Functor, &Functor::operator()>( functor ) );
545 }
546
547 /// \brief  Constructs a Callback from a const \p functor with zero arguments.
548 ///
549 /// \param Functor Must define const \c operator()().
550 template<typename Functor>
551 inline Callback makeCallback( const Functor& functor ){
552         return Callback( ConstMemberCaller<Functor, &Functor::operator()>( functor ) );
553 }
554
555 /// \brief  Constructs a Callback1 from a non-const \p functor with one argument.
556 ///
557 /// \param Functor Must define \c first_argument_type and \c operator()(first_argument_type).
558 template<typename Functor>
559 inline Callback1<typename Functor::first_argument_type> makeCallback1( Functor& functor ){
560         typedef typename Functor::first_argument_type FirstArgument;
561         return Callback1<FirstArgument>( MemberCaller1<Functor, FirstArgument, &Functor::operator()>( functor ) );
562 }
563
564 /// \brief  Constructs a Callback1 from a const \p functor with one argument.
565 ///
566 /// \param Functor Must define \c first_argument_type and const \c operator()(first_argument_type).
567 template<typename Functor>
568 inline Callback1<typename Functor::first_argument_type> makeCallback1( const Functor& functor ){
569         typedef typename Functor::first_argument_type FirstArgument;
570         return Callback1<FirstArgument>( ConstMemberCaller1<Functor, FirstArgument, &Functor::operator()>( functor ) );
571 }
572
573
574 typedef Callback1<bool> BoolImportCallback;
575 typedef Callback1<const BoolImportCallback&> BoolExportCallback;
576
577 typedef Callback1<int> IntImportCallback;
578 typedef Callback1<const IntImportCallback&> IntExportCallback;
579
580 typedef Callback1<float> FloatImportCallback;
581 typedef Callback1<const FloatImportCallback&> FloatExportCallback;
582
583 typedef Callback1<const char*> StringImportCallback;
584 typedef Callback1<const StringImportCallback&> StringExportCallback;
585
586 typedef Callback1<std::size_t> SizeImportCallback;
587 typedef Callback1<const SizeImportCallback&> SizeExportCallback;
588
589
590 #endif