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