ok
[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 anonymous callback. 
27
28 #include <cstddef>
29
30 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer.
31 ///
32 /// Use with the callback constructors MemberCaller, ConstMemberCaller, ReferenceCaller, ConstReferenceCaller, PointerCaller, ConstPointerCaller and FreeCaller.
33 class Callback
34 {
35   typedef void (*Thunk)(void*);
36   void* m_environment;
37   Thunk m_thunk;
38
39   static void nullThunk(void*)
40   {
41   }
42
43 public:
44   Callback() : m_environment(0), m_thunk(nullThunk)
45   {
46   }
47   Callback(void* environment, Thunk function) : m_environment(environment), m_thunk(function)
48   {
49   }
50   void* getEnvironment() const
51   {
52     return m_environment;
53   }
54   Thunk getThunk() const
55   {
56     return m_thunk;
57   }
58   void operator()() const
59   {
60     m_thunk(m_environment);
61   }
62 };
63
64 inline bool operator==(const Callback& self, const Callback& other)
65 {
66   return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk();
67 }
68 inline bool operator<(const Callback& self, const Callback& other)
69 {
70   return self.getEnvironment() < other.getEnvironment() || 
71         (!(other.getEnvironment() < self.getEnvironment()) && self.getThunk() < other.getThunk()); 
72 }
73
74 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and one other argument. 
75 ///
76 /// Use with the callback constructors MemberCaller1, ConstMemberCaller1, ReferenceCaller1, ConstReferenceCaller1, PointerCaller1, ConstPointerCaller1 and FreeCaller1.
77 template<typename FirstArgument>
78 class Callback1
79 {
80   typedef void (*Thunk)(void*, FirstArgument);
81   void* m_environment;
82   Thunk m_thunk;
83
84   static void nullThunk(void*, FirstArgument)
85   {
86   }
87
88 public:
89   typedef FirstArgument first_argument_type;
90
91   Callback1() : m_environment(0), m_thunk(nullThunk)
92   {
93   }
94   Callback1(void* environment, Thunk function) : m_environment(environment), m_thunk(function)
95   {
96   }
97   void* getEnvironment() const
98   {
99     return m_environment;
100   }
101   Thunk getThunk() const
102   {
103     return m_thunk;
104   }
105   void operator()(FirstArgument firstArgument) const
106   {
107     m_thunk(m_environment, firstArgument);
108   }
109 };
110
111 template<typename FirstArgument>
112 inline bool operator==(const Callback1<FirstArgument>& self, const Callback1<FirstArgument>& other)
113 {
114   return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk();
115 }
116 template<typename FirstArgument>
117 inline bool operator<(const Callback1<FirstArgument>& self, const Callback1<FirstArgument>& other)
118 {
119   return self.getEnvironment() < other.getEnvironment() || 
120         (!(other.getEnvironment() < self.getEnvironment()) && self.getThunk() < other.getThunk()); 
121 }
122
123 template<typename Functor>
124 class FunctorInvoke
125 {
126 public:
127   inline void operator()(Functor functor)
128   {
129     functor();
130   }
131 };
132
133 typedef FunctorInvoke<Callback> CallbackInvoke;
134
135
136 template<typename Functor, typename FirstArgument>
137 class Functor1Invoke
138 {
139   FirstArgument m_firstArgument;
140 public:
141   Functor1Invoke(FirstArgument firstArgument) : m_firstArgument(firstArgument)
142   {
143   }
144   inline void operator()(Functor functor)
145   {
146     functor(m_firstArgument);
147   }
148 };
149
150
151 typedef Callback1<bool> BoolImportCallback;
152 typedef Callback1<const BoolImportCallback&> BoolExportCallback;
153
154 typedef Callback1<int> IntImportCallback;
155 typedef Callback1<const IntImportCallback&> IntExportCallback;
156
157 typedef Callback1<float> FloatImportCallback;
158 typedef Callback1<const FloatImportCallback&> FloatExportCallback;
159
160 typedef Callback1<const char*> StringImportCallback;
161 typedef Callback1<const StringImportCallback&> StringExportCallback;
162
163 typedef Callback1<std::size_t> SizeImportCallback;
164 typedef Callback1<const SizeImportCallback&> SizeExportCallback;
165
166
167 /// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function.
168 ///
169 /// \dontinclude generic/callback.cpp
170 /// \skipline MemberCaller example
171 /// \until end example
172 template<typename Environment, void (Environment::*member)()>
173 class MemberCaller
174 {
175   Environment& m_environment;
176 public:
177   MemberCaller(Environment& environment) : m_environment(environment)
178   {
179   }
180   void* getEnvironment() const
181   {
182     return &m_environment;
183   }
184   static void thunk(void* environment)
185   {
186     ((*reinterpret_cast<Environment*>(environment)).*member)();
187   }
188   operator Callback() const
189   {
190     return Callback(getEnvironment(), thunk);
191   }
192 };
193
194 /// \brief Forms a Callback from a const Environment reference and a const Environment member-function.
195 ///
196 /// \dontinclude generic/callback.cpp
197 /// \skipline MemberCaller example
198 /// \until end example
199 template<typename Environment, void (Environment::*member)() const>
200 class ConstMemberCaller
201 {
202   const Environment& m_environment;
203 public:
204   ConstMemberCaller(const Environment& environment) : m_environment(environment)
205   {
206   }
207   void* getEnvironment() const
208   {
209     return const_cast<Environment*>(&m_environment);
210   }
211   static void thunk(void* environment)
212   {
213     ((*reinterpret_cast<const Environment*>(environment)).*member)();
214   }
215   operator Callback() const
216   {
217     return Callback(getEnvironment(), thunk);
218   }
219 };
220
221 /// \brief Forms a Callback from a non-const Environment reference and a const Environment member-function which takes one argument.
222 template<typename Environment, typename FirstArgument, void (Environment::*member)(FirstArgument)>
223 class MemberCaller1
224 {
225   Environment& m_environment;
226 public:
227   MemberCaller1(Environment& environment) : m_environment(environment)
228   {
229   }
230   void* getEnvironment() const
231   {
232     return &m_environment;
233   }
234   static void thunk(void* environment, FirstArgument firstArgument)
235   {
236     ((*reinterpret_cast<Environment*>(environment)).*member)(firstArgument);
237   }
238   operator Callback1<FirstArgument>() const
239   {
240     return Callback1<FirstArgument>(getEnvironment(), thunk);
241   }
242 };
243
244 /// \brief Forms a Callback from a const Environment reference and a const Environment member-function which takes one argument.
245 template<typename Environment, typename FirstArgument, void (Environment::*member)(FirstArgument) const>
246 class ConstMemberCaller1
247 {
248   const Environment& m_environment;
249 public:
250   ConstMemberCaller1(const Environment& environment) : m_environment(environment)
251   {
252   }
253   void* getEnvironment() const
254   {
255     return const_cast<Environment*>(&m_environment);
256   }
257   static void thunk(void* environment, FirstArgument firstArgument)
258   {
259     ((*reinterpret_cast<Environment*>(environment)).*member)(firstArgument);
260   }
261   operator Callback1<FirstArgument>() const
262   {
263     return Callback1<FirstArgument>(getEnvironment(), thunk);
264   }
265 };
266
267 /// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference.
268 ///
269 /// \dontinclude generic/callback.cpp
270 /// \skipline ReferenceCaller example
271 /// \until end example
272 template<typename Environment, void (*func)(Environment&)> 
273 class ReferenceCaller
274 {
275   Environment& m_environment;
276 public:
277   ReferenceCaller(Environment& environment) : m_environment(environment)
278   {
279   }
280   void* getEnvironment() const
281   {
282     return &m_environment;
283   }
284   static void thunk(void* environment)
285   {
286     (func)(*reinterpret_cast<Environment*>(environment));
287   }
288   operator Callback() const
289   {
290     return Callback(getEnvironment(), thunk);
291   }
292 };
293
294 /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference.
295 ///
296 /// \dontinclude generic/callback.cpp
297 /// \skipline ReferenceCaller example
298 /// \until end example
299 template<typename Environment, void (*func)(const Environment&)> 
300 class ConstReferenceCaller
301 {
302   const Environment& m_environment;
303 public:
304   ConstReferenceCaller(const Environment& environment) : m_environment(environment)
305   {
306   }
307   void* getEnvironment() const
308   {
309     return const_cast<Environment*>(&m_environment);
310   }
311   static void thunk(void* environment)
312   {
313     (func)(*reinterpret_cast<const Environment*>(environment));
314   }
315   operator Callback() const
316   {
317     return Callback(getEnvironment(), thunk);
318   }
319 };
320
321 /// \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.
322 template<typename Environment, typename FirstArgument, void (*func)(Environment&, FirstArgument)> 
323 class ReferenceCaller1
324 {
325   Environment& m_environment;
326 public:
327   ReferenceCaller1(Environment& environment) : m_environment(environment)
328   {
329   }
330   void* getEnvironment() const
331   {
332     return &m_environment;
333   }
334   static void thunk(void* environment, FirstArgument firstArgument)
335   {
336     (func)(*reinterpret_cast<Environment*>(environment), firstArgument);
337   }
338   operator Callback1<FirstArgument>() const
339   {
340     return Callback1<FirstArgument>(getEnvironment(), thunk);
341   }
342 };
343
344 /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference and one other argument.
345 template<typename Environment, typename FirstArgument, void (*func)(const Environment&, FirstArgument)> 
346 class ConstReferenceCaller1
347 {
348   const Environment& m_environment;
349 public:
350   ConstReferenceCaller1(const Environment& environment) : m_environment(environment)
351   {
352   }
353   void* getEnvironment() const
354   {
355     return const_cast<Environment*>(&m_environment);
356   }
357   static void thunk(void* environment, FirstArgument firstArgument)
358   {
359     (func)(*reinterpret_cast<const Environment*>(environment), firstArgument);
360   }
361   operator Callback1<FirstArgument>() const
362   {
363     return Callback1<FirstArgument>(getEnvironment(), thunk);
364   }
365 };
366
367 /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer.
368 template<typename Environment, void (*func)(Environment*)> 
369 class PointerCaller
370 {
371   Environment* m_environment;
372 public:
373   PointerCaller(Environment* environment) : m_environment(environment)
374   {
375   }
376   void* getEnvironment() const
377   {
378     return m_environment;
379   }
380   static void thunk(void* environment)
381   {
382     (func)(reinterpret_cast<Environment*>(environment));
383   }
384   operator Callback() const
385   {
386     return Callback(getEnvironment(), thunk);
387   }
388 };
389
390 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer.
391 template<typename Environment, void (*func)(const Environment*)> 
392 class ConstPointerCaller
393 {
394   const Environment* m_environment;
395 public:
396   ConstPointerCaller(const Environment* environment) : m_environment(environment)
397   {
398   }
399   void* getEnvironment() const
400   {
401     return const_cast<Environment*>(m_environment);
402   }
403   static void thunk(void* environment)
404   {
405     (func)(reinterpret_cast<const Environment*>(environment));
406   }
407   operator Callback() const
408   {
409     return Callback(getEnvironment(), thunk);
410   }
411 };
412
413 /// \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.
414 template<typename Environment, typename FirstArgument, void (*func)(Environment*, FirstArgument)> 
415 class PointerCaller1
416 {
417   Environment* m_environment;
418 public:
419   PointerCaller1(Environment* environment) : m_environment(environment)
420   {
421   }
422   void* getEnvironment() const
423   {
424     return m_environment;
425   }
426   static void thunk(void* environment, FirstArgument firstArgument)
427   {
428     (func)(reinterpret_cast<Environment*>(environment), firstArgument);
429   }
430   operator Callback1<FirstArgument>() const
431   {
432     return Callback1<FirstArgument>(getEnvironment(), thunk);
433   }
434 };
435
436 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer and one other argument.
437 template<typename Environment, typename FirstArgument, void (*func)(const Environment*, FirstArgument)> 
438 class ConstPointerCaller1
439 {
440   const Environment* m_environment;
441 public:
442   ConstPointerCaller1(const Environment* environment) : m_environment(environment)
443   {
444   }
445   void* getEnvironment() const
446   {
447     return const_cast<Environment*>(m_environment);
448   }
449   static void thunk(void* environment, FirstArgument firstArgument)
450   {
451     (func)(reinterpret_cast<const Environment*>(environment), firstArgument);
452   }
453   operator Callback1<FirstArgument>() const
454   {
455     return Callback1<FirstArgument>(getEnvironment(), thunk);
456   }
457 };
458
459
460 /// \brief Forms a Callback from a free function which takes no arguments.
461 template<void (*func)()> 
462 class FreeCaller
463 {
464 public:
465   void* getEnvironment() const
466   {
467     return 0;
468   }
469   static void thunk(void*)
470   {
471     (func)();
472   }
473   operator Callback() const
474   {
475     return Callback(getEnvironment(), thunk);
476   }
477 };
478
479 /// \brief Forms a Callback from a free function which takes a single argument.
480 template<typename FirstArgument, void (*func)(FirstArgument)> 
481 class FreeCaller1
482 {
483 public:
484   void* getEnvironment() const
485   {
486     return 0;
487   }
488   static void thunk(void*, FirstArgument firstArgument)
489   {
490     (func)(firstArgument);
491   }
492   operator Callback1<FirstArgument>() const
493   {
494     return Callback1<FirstArgument>(getEnvironment(), thunk);
495   }
496 };
497
498
499 /// \brief Constructs a Callback from a non-const \p functor with zero arguments.
500 /// 
501 /// \param Functor Must define \c operator()().
502 template<typename Functor>
503 inline Callback makeCallback(Functor& functor)
504 {
505   return Callback(MemberCaller<Functor, &Functor::operator()>(functor));
506 }
507
508 /// \brief  Constructs a Callback from a const \p functor with zero arguments.
509 /// 
510 /// \param Functor Must define const \c operator()().
511 template<typename Functor>
512 inline Callback makeCallback(const Functor& functor)
513 {
514   return Callback(ConstMemberCaller<Functor, &Functor::operator()>(functor));
515 }
516
517 /// \brief  Constructs a Callback1 from a non-const \p functor with one argument.
518 /// 
519 /// \param Functor Must define \c first_argument_type and \c operator()(first_argument_type).
520 template<typename Functor>
521 inline Callback1<typename Functor::first_argument_type> makeCallback1(Functor& functor)
522 {
523   typedef typename Functor::first_argument_type FirstArgument;
524   return Callback1<FirstArgument>(MemberCaller1<Functor, FirstArgument, &Functor::operator()>(functor));
525 }
526
527 /// \brief  Constructs a Callback1 from a const \p functor with one argument.
528 /// 
529 /// \param Functor Must define \c first_argument_type and const \c operator()(first_argument_type).
530 template<typename Functor>
531 inline Callback1<typename Functor::first_argument_type> makeCallback1(const Functor& functor)
532 {
533   typedef typename Functor::first_argument_type FirstArgument;
534   return Callback1<FirstArgument>(ConstMemberCaller1<Functor, FirstArgument, &Functor::operator()>(functor));
535 }
536
537 #endif