2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
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.
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.
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
22 #if !defined( INCLUDED_GENERIC_CLOSURE_H )
23 #define INCLUDED_GENERIC_CLOSURE_H
26 /// \brief Type-safe techniques for binding the first argument of an opaque callback.
29 #include "functional.h"
31 template<typename Type>
32 inline void* convertToOpaque( Type* t ){
35 template<typename Type>
36 inline void* convertToOpaque( const Type* t ){
37 return const_cast<Type*>( t );
39 template<typename Type>
40 inline void* convertToOpaque( Type& t ){
43 template<typename Type>
44 inline void* convertToOpaque( const Type& t ){
45 return const_cast<Type*>( &t );
49 template<typename Type>
50 class ConvertFromOpaque
54 template<typename Type>
55 class ConvertFromOpaque<Type&>
58 static Type& apply( void* p ){
59 return *static_cast<Type*>( p );
63 template<typename Type>
64 class ConvertFromOpaque<const Type&>
67 static const Type& apply( void* p ){
68 return *static_cast<Type*>( p );
73 template<typename Type>
74 class ConvertFromOpaque<Type*>
77 static Type* apply( void* p ){
78 return static_cast<Type*>( p );
82 template<typename Type>
83 class ConvertFromOpaque<const Type*>
86 static const Type* apply( void* p ){
87 return static_cast<Type*>( p );
91 template<typename Thunk_>
98 CallbackBase( void* environment, Thunk function ) : m_environment( environment ), m_thunk( function ){
100 void* getEnvironment() const {
101 return m_environment;
103 Thunk getThunk() const {
108 template<typename Thunk>
109 inline bool operator==( const CallbackBase<Thunk>& self, const CallbackBase<Thunk>& other ){
110 return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk();
112 template<typename Thunk>
113 inline bool operator!=( const CallbackBase<Thunk>& self, const CallbackBase<Thunk>& other ){
114 return !( self == other );
116 template<typename Thunk>
117 inline bool operator<( const CallbackBase<Thunk>& self, const CallbackBase<Thunk>& other ){
118 return self.getEnvironment() < other.getEnvironment() ||
119 ( !( other.getEnvironment() < self.getEnvironment() ) && self.getThunk() < other.getThunk() );
122 template<class Caller, class F>
123 class BindFirstOpaqueN;
125 template<class Caller, class R, class FirstBound, class... Ts>
126 class BindFirstOpaqueN<Caller, R(FirstBound, Ts...)> {
127 FirstBound firstBound;
129 explicit BindFirstOpaqueN(FirstBound firstBound) : firstBound(firstBound) {
132 R operator()(Ts... args) const {
133 return Caller::call(firstBound, args...);
136 FirstBound getBound() const {
140 static R thunk(void *environment, Ts... args) {
141 return Caller::call(ConvertFromOpaque<FirstBound>::apply(environment), args...);
144 void *getEnvironment() const {
145 return convertToOpaque(firstBound);
149 template<class Caller>
150 using BindFirstOpaque = BindFirstOpaqueN<Caller, get_func<Caller>>;
152 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer.
154 /// Use with the callback constructors MemberCaller, ConstMemberCaller, ReferenceCaller, ConstReferenceCaller, PointerCaller, ConstPointerCaller and FreeCaller.
158 template<class R, class... Ts>
159 class CallbackN<R(Ts...)> : public CallbackBase<R(*)(void *, Ts...)> {
160 using Base = CallbackBase<R (*)(void *, Ts...)>;
162 static R nullThunk(void *, Ts...) {
166 using func = R(Ts...);
168 CallbackN() : Base(0, nullThunk) {
171 template<typename Caller>
172 CallbackN(const BindFirstOpaque<Caller> &caller) : Base(caller.getEnvironment(), BindFirstOpaque<Caller>::thunk) {
175 CallbackN(void *environment, typename Base::Thunk function) : Base(environment, function) {
178 R operator()(Ts... args) const {
179 return Base::getThunk()(Base::getEnvironment(), args...);
187 template<class R, class Head, class... Ts>
188 struct Arglist<R(Head, Ts...)> {
189 using type = R(Head, Ts...);
191 template <class Unshift>
192 using unshift = Arglist<R(Unshift, Head, Ts...)>;
194 using shift = Arglist<R(Ts...)>;
197 template<class R, class... Ts>
198 struct Arglist<R(Ts...)> {
199 using type = R(Ts...);
201 template <class Unshift>
202 using unshift = Arglist<R(Unshift, Ts...)>;
206 template<typename Caller>
207 inline CallbackN<typename detail::Arglist<get_func<Caller>>::shift::type> makeCallbackN(const Caller &caller, get_argument<Caller, 0> callee) {
208 return CallbackN<typename detail::Arglist<get_func<Caller>>::shift::type>(BindFirstOpaque<Caller>(callee));
211 template<typename Caller>
212 inline CallbackN<get_func<Caller>> makeStatelessCallbackN(const Caller &caller) {
213 return makeCallbackN(CallerShiftFirst<Caller, typename detail::Arglist<get_func<Caller>>::template unshift<void *>::type>(), nullptr);
217 template<class Object, class F>
218 struct MemberFunction;
220 template<class Object, class R, class... Ts>
221 struct MemberFunction<Object, R(Ts...)> {
222 using type = R(Object::*)(Ts...);
223 using type_const = R(Object::*)(Ts...) const;
227 template<class Object, class F>
228 using MemberFunction = typename detail::MemberFunction<Object, F>::type;
230 template<class Object, class F>
231 using ConstMemberFunction = typename detail::MemberFunction<Object, F>::type_const;
233 /// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function.
235 /// \dontinclude generic/callback.cpp
236 /// \skipline MemberCaller example
237 /// \until end example
239 template<class Environment, class F, MemberFunction<Environment, F> member>
240 using MemberCallerN = BindFirstOpaque<typename MemberN<Environment, F>::template instance<member>>;
242 /// \brief Forms a Callback from a const Environment reference and a const Environment member-function.
244 /// \dontinclude generic/callback.cpp
245 /// \skipline MemberCaller example
246 /// \until end example
247 template<class Environment, class F, ConstMemberFunction<Environment, F> member>
248 using ConstMemberCallerN = BindFirstOpaque<typename ConstMemberN<Environment, F>::template instance<member>>;
250 /// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference.
252 /// \dontinclude generic/callback.cpp
253 /// \skipline ReferenceCaller example
254 /// \until end example
255 template<class Environment, class F, typename detail::Arglist<F>::template unshift<Environment &>::type *func>
256 using ReferenceCallerN = BindFirstOpaque<typename FunctionN<typename detail::Arglist<F>::template unshift<Environment &>::type>::template instance<func>>;
258 /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference.
260 /// \dontinclude generic/callback.cpp
261 /// \skipline ReferenceCaller example
262 /// \until end example
263 template<class Environment, class F, typename detail::Arglist<F>::template unshift<const Environment &>::type *func>
264 using ConstReferenceCallerN = BindFirstOpaque<typename FunctionN<typename detail::Arglist<F>::template unshift<const Environment &>::type>::template instance<func>>;
266 /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer.
267 template<class Environment, class F, typename detail::Arglist<F>::template unshift<Environment *>::type *func>
268 using PointerCallerN = BindFirstOpaque<typename FunctionN<typename detail::Arglist<F>::template unshift<Environment *>::type>::template instance<func>>;
270 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer.
271 template<class Environment, class F, typename detail::Arglist<F>::template unshift<const Environment *>::type *func>
272 using ConstPointerCallerN = BindFirstOpaque<typename FunctionN<typename detail::Arglist<F>::template unshift<const Environment *>::type>::template instance<func>>;
274 /// \brief Forms a Callback from a free function
275 template<class F, F *func>
276 class FreeCallerN : public BindFirstOpaque<CallerShiftFirst<
277 typename FunctionN<F>::template instance<func>,
278 typename detail::Arglist<F>::template unshift<void *>::type
282 : BindFirstOpaque<CallerShiftFirst<
283 typename FunctionN<F>::template instance<func>,
284 typename detail::Arglist<F>::template unshift<void *>::type
289 /// \brief Constructs a Callback1 from a non-const \p functor
291 /// \param Functor Must define \c first_argument_type and \c operator()(first_argument_type).
292 template<typename Functor>
293 inline CallbackN<get_func<Functor>> makeCallbackN(Functor &functor) {
294 return CallbackN<get_func<Functor>>(MemberCallerN<Functor, get_func<Functor>, &Functor::operator()>(functor));
297 /// \brief Constructs a Callback1 from a const \p functor
299 /// \param Functor Must define \c first_argument_type and const \c operator()(first_argument_type).
300 template<typename Functor>
301 inline CallbackN<get_func<Functor>> makeCallbackN(const Functor &functor) {
302 return CallbackN<get_func<Functor>>(ConstMemberCallerN<Functor, get_func<Functor>, &Functor::operator()>(functor));
307 #define makeCallback makeCallbackN
309 using Callback = CallbackN<void()>;
311 template<class Result>
312 using Callback0 = CallbackN<Result()>;
314 template<class FirstArgument, class Result = void>
315 using Callback1 = CallbackN<Result(FirstArgument)>;
317 template<typename FirstArgument, typename SecondArgument, typename Result = void>
318 using Callback2 = CallbackN<Result(FirstArgument, SecondArgument)>;
320 template<typename FirstArgument, typename SecondArgument, typename ThirdArgument, typename Result = void>
321 using Callback3 = CallbackN<Result(FirstArgument, SecondArgument, ThirdArgument)>;
323 #define makeCallback0 makeCallbackN
324 #define makeStatelessCallback0 makeStatelessCallbackN
326 #define makeCallback1 makeCallbackN
327 #define makeStatelessCallback1 makeStatelessCallbackN
329 #define makeCallback2 makeCallbackN
330 #define makeStatelessCallback2 makeStatelessCallbackN
332 #define makeCallback3 makeCallbackN
333 #define makeStatelessCallback3 makeStatelessCallbackN
335 template<class Environment, void(Environment::*member)()>
336 using MemberCaller = MemberCallerN<Environment, void(), member>;
338 template<class Environment, void(Environment::*member)() const>
339 using ConstMemberCaller = ConstMemberCallerN<Environment, void(), member>;
341 template<class Environment, class FirstArgument, void(Environment::*member)(FirstArgument)>
342 using MemberCaller1 = MemberCallerN<Environment, void(FirstArgument), member>;
344 template<class Environment, class FirstArgument, void(Environment::*member)(FirstArgument) const>
345 using ConstMemberCaller1 = ConstMemberCallerN<Environment, void(FirstArgument), member>;
347 template<class Environment, void(*func)(Environment &)>
348 using ReferenceCaller = ReferenceCallerN<Environment, void(), func>;
350 template<class Environment, void(*func)(const Environment &)>
351 using ConstReferenceCaller = ConstReferenceCallerN<Environment, void(), func>;
353 /// \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.
354 template<class Environment, class FirstArgument, void(*func)(Environment &, FirstArgument)>
355 using ReferenceCaller1 = ReferenceCallerN<Environment, void(FirstArgument), func>;
357 /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference and one other argument.
358 template<class Environment, class FirstArgument, void(*func)(const Environment &, FirstArgument)>
359 using ConstReferenceCaller1 = ConstReferenceCallerN<Environment, void(FirstArgument), func>;
361 /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer.
362 template<class Environment, void(*func)(Environment *)>
363 using PointerCaller = PointerCallerN<Environment, void(), func>;
365 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer.
366 template<class Environment, void(*func)(const Environment *)>
367 using ConstPointerCaller = ConstPointerCallerN<Environment, void(), func>;
369 /// \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.
370 template<class Environment, class FirstArgument, void(*func)(Environment *, FirstArgument)>
371 using PointerCaller1 = PointerCallerN<Environment, void(FirstArgument), func>;
373 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer and one other argument.
374 template<class Environment, class FirstArgument, void(*func)(const Environment *, FirstArgument)>
375 using ConstPointerCaller1 = ConstPointerCallerN<Environment, void(FirstArgument), func>;
377 template<void(*func)()>
378 using FreeCaller = FreeCallerN<void(), func>;
380 template<class FirstArgument, void(*func)(FirstArgument)>
381 using FreeCaller1 = FreeCallerN<void(FirstArgument), func>;
383 typedef Callback1<bool> BoolImportCallback;
384 typedef Callback1<const BoolImportCallback&> BoolExportCallback;
386 typedef Callback1<int> IntImportCallback;
387 typedef Callback1<const IntImportCallback&> IntExportCallback;
389 typedef Callback1<float> FloatImportCallback;
390 typedef Callback1<const FloatImportCallback&> FloatExportCallback;
392 typedef Callback1<const char*> StringImportCallback;
393 typedef Callback1<const StringImportCallback&> StringExportCallback;
395 typedef Callback1<std::size_t> SizeImportCallback;
396 typedef Callback1<const SizeImportCallback&> SizeExportCallback;