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 MemberCaller0, ConstMemberCaller0, ReferenceCaller0, ConstReferenceCaller0, PointerCaller0, ConstPointerCaller0 and FreeCaller0.
158 template<class R, class... Ts>
159 class Callback<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 Callback() : Base(0, nullThunk) {
171 template<typename Caller>
172 Callback(const BindFirstOpaque<Caller> &caller) : Base(caller.getEnvironment(), BindFirstOpaque<Caller>::thunk) {
175 Callback(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 Callback<typename detail::Arglist<get_func<Caller>>::shift::type> makeCallback(const Caller &caller, get_argument<Caller, 0> callee) {
208 return Callback<typename detail::Arglist<get_func<Caller>>::shift::type>(BindFirstOpaque<Caller>(callee));
211 template<typename Caller>
212 inline Callback<get_func<Caller>> makeStatelessCallback(const Caller &caller) {
213 return makeCallback(CallerShiftFirst<Caller, typename detail::Arglist<get_func<Caller>>::template unshift<void *>::type>(), nullptr);
216 /// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function.
218 /// \dontinclude generic/callback.cpp
219 /// \skipline MemberCaller0 example
220 /// \until end example
222 template<class Environment, class F, MemberFunction<Environment, F> member>
223 using MemberCaller = BindFirstOpaque<typename MemberN<Environment, F>::template instance<member>>;
225 /// \brief Forms a Callback from a const Environment reference and a const Environment member-function.
227 /// \dontinclude generic/callback.cpp
228 /// \skipline MemberCaller0 example
229 /// \until end example
230 template<class Environment, class F, ConstMemberFunction<Environment, F> member>
231 using ConstMemberCaller = BindFirstOpaque<typename ConstMemberN<Environment, F>::template instance<member>>;
233 /// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference.
235 /// \dontinclude generic/callback.cpp
236 /// \skipline ReferenceCaller0 example
237 /// \until end example
238 template<class Environment, class F, typename detail::Arglist<F>::template unshift<Environment &>::type *func>
239 using ReferenceCaller = BindFirstOpaque<typename FunctionN<typename detail::Arglist<F>::template unshift<Environment &>::type>::template instance<func>>;
241 /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference.
243 /// \dontinclude generic/callback.cpp
244 /// \skipline ReferenceCaller0 example
245 /// \until end example
246 template<class Environment, class F, typename detail::Arglist<F>::template unshift<const Environment &>::type *func>
247 using ConstReferenceCaller = BindFirstOpaque<typename FunctionN<typename detail::Arglist<F>::template unshift<const Environment &>::type>::template instance<func>>;
249 /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer.
250 template<class Environment, class F, typename detail::Arglist<F>::template unshift<Environment *>::type *func>
251 using PointerCaller = BindFirstOpaque<typename FunctionN<typename detail::Arglist<F>::template unshift<Environment *>::type>::template instance<func>>;
253 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer.
254 template<class Environment, class F, typename detail::Arglist<F>::template unshift<const Environment *>::type *func>
255 using ConstPointerCaller = BindFirstOpaque<typename FunctionN<typename detail::Arglist<F>::template unshift<const Environment *>::type>::template instance<func>>;
257 /// \brief Forms a Callback from a free function
258 template<class F, F *func>
259 class FreeCaller : public BindFirstOpaque<CallerShiftFirst<
260 typename FunctionN<F>::template instance<func>,
261 typename detail::Arglist<F>::template unshift<void *>::type
265 : BindFirstOpaque<CallerShiftFirst<
266 typename FunctionN<F>::template instance<func>,
267 typename detail::Arglist<F>::template unshift<void *>::type
272 /// \brief Constructs a Callback1 from a non-const \p functor
274 /// \param Functor Must define \c first_argument_type and \c operator()(first_argument_type).
275 template<typename Functor>
276 inline Callback<get_func<Functor>> makeCallback(Functor &functor) {
277 return Callback<get_func<Functor>>(MemberCaller<Functor, get_func<Functor>, &Functor::operator()>(functor));
280 /// \brief Constructs a Callback1 from a const \p functor
282 /// \param Functor Must define \c first_argument_type and const \c operator()(first_argument_type).
283 template<typename Functor>
284 inline Callback<get_func<Functor>> makeCallback(const Functor &functor) {
285 return Callback<get_func<Functor>>(ConstMemberCaller<Functor, get_func<Functor>, &Functor::operator()>(functor));
288 using BoolImportCallback = Callback<void(bool)>;
289 using BoolExportCallback = Callback<void(const BoolImportCallback&)>;
291 using IntImportCallback = Callback<void(int)>;
292 using IntExportCallback = Callback<void(const IntImportCallback&)>;
294 using FloatImportCallback = Callback<void(float)>;
295 using FloatExportCallback = Callback<void(const FloatImportCallback&)>;
297 using StringImportCallback = Callback<void(const char*)>;
298 using StringExportCallback = Callback<void(const StringImportCallback&)>;
300 using SizeImportCallback = Callback<void(std::size_t)>;
301 using SizeExportCallback = Callback<void(const SizeImportCallback&)>;