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"
33 template<typename Thunk_>
40 CallbackBase(void *environment, Thunk function) : m_environment(environment), m_thunk(function) {
43 void *getEnvironment() const {
47 Thunk getThunk() const {
52 template<typename Thunk>
53 inline bool operator==(const CallbackBase<Thunk> &self, const CallbackBase<Thunk> &other) {
54 return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk();
57 template<typename Thunk>
58 inline bool operator!=(const CallbackBase<Thunk> &self, const CallbackBase<Thunk> &other) {
59 return !(self == other);
62 template<typename Thunk>
63 inline bool operator<(const CallbackBase<Thunk> &self, const CallbackBase<Thunk> &other) {
64 return self.getEnvironment() < other.getEnvironment() ||
65 (!(other.getEnvironment() < self.getEnvironment()) && self.getThunk() < other.getThunk());
72 template<typename Type>
73 inline void *convertToOpaque(Type *t) {
77 template<typename Type>
78 inline void *convertToOpaque(const Type *t) {
79 return const_cast<Type *>( t );
82 template<typename Type>
83 inline void *convertToOpaque(Type &t) {
87 template<typename Type>
88 inline void *convertToOpaque(const Type &t) {
89 return const_cast<Type *>( &t );
93 template<typename Type>
94 class ConvertFromOpaque {
97 template<typename Type>
98 class ConvertFromOpaque<Type &> {
100 static Type &apply(void *p) {
101 return *static_cast<Type *>( p );
105 template<typename Type>
106 class ConvertFromOpaque<const Type &> {
108 static const Type &apply(void *p) {
109 return *static_cast<Type *>( p );
114 template<typename Type>
115 class ConvertFromOpaque<Type *> {
117 static Type *apply(void *p) {
119 return reinterpret_cast<Type *>( p );
123 template<typename Type>
124 class ConvertFromOpaque<const Type *> {
126 static const Type *apply(void *p) {
127 return static_cast<Type *>( p );
131 template<class Caller, class F>
132 class BindFirstOpaqueN;
134 template<class Caller, class R, class FirstBound, class... Ts>
135 class BindFirstOpaqueN<Caller, R(FirstBound, Ts...)> {
136 FirstBound firstBound;
138 explicit BindFirstOpaqueN(FirstBound firstBound) : firstBound(firstBound) {
141 R operator()(Ts... args) const {
142 return Caller::call(firstBound, args...);
145 FirstBound getBound() const {
149 static R thunk(void *environment, Ts... args) {
150 return Caller::call(detail::ConvertFromOpaque<FirstBound>::apply(environment), args...);
153 void *getEnvironment() const {
154 return detail::convertToOpaque(firstBound);
160 template<class Caller>
161 using BindFirstOpaque = detail::BindFirstOpaqueN<Caller, get_func<Caller>>;
163 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer.
165 /// Use with the callback constructors MemberCaller0, ConstMemberCaller0, ReferenceCaller0, ConstReferenceCaller0, PointerCaller0, ConstPointerCaller0 and FreeCaller0.
169 template<class R, class... Ts>
170 class Callback<R(Ts...)> : public detail::CallbackBase<R(*)(void *, Ts...)> {
171 using Base = detail::CallbackBase<R (*)(void *, Ts...)>;
173 static R nullThunk(void *, Ts...) {
177 using func = R(Ts...);
179 Callback() : Base(0, nullThunk) {
182 template<typename Caller>
183 Callback(const BindFirstOpaque<Caller> &caller) : Base(caller.getEnvironment(), BindFirstOpaque<Caller>::thunk) {
186 Callback(void *environment, typename Base::Thunk function) : Base(environment, function) {
189 R operator()(Ts... args) const {
190 return Base::getThunk()(Base::getEnvironment(), args...);
198 template<class R, class Head, class... Ts>
199 struct Arglist<R(Head, Ts...)> {
200 using type = R(Head, Ts...);
202 template <class Unshift>
203 using unshift = Arglist<R(Unshift, Head, Ts...)>;
205 using shift = Arglist<R(Ts...)>;
208 template<class R, class... Ts>
209 struct Arglist<R(Ts...)> {
210 using type = R(Ts...);
212 template <class Unshift>
213 using unshift = Arglist<R(Unshift, Ts...)>;
217 using ArgShift = typename detail::Arglist<F>::shift::type;
219 template<class F, class T>
220 using ArgUnshift = typename detail::Arglist<F>::template unshift<T>::type;
223 template<typename Caller>
224 inline Callback<detail::ArgShift<get_func<Caller>>> makeCallback(const Caller &caller, get_argument<Caller, 0> callee) {
225 return BindFirstOpaque<Caller>(callee);
228 template<class Caller, class F>
229 class CallerShiftFirst;
231 template<class Caller, class R, class FirstArgument, class... Ts>
232 class CallerShiftFirst<Caller, R(FirstArgument, Ts...)> {
234 using func = R(FirstArgument, Ts...);
236 static R call(FirstArgument, Ts... args) {
237 return Caller::call(args...);
241 template<typename Caller>
242 inline Callback<get_func<Caller>> makeStatelessCallback(const Caller &caller) {
243 return makeCallback(CallerShiftFirst<Caller, detail::ArgUnshift<get_func<Caller>, void *>>(), nullptr);
246 /// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function.
247 template<class Environment, class F, MemberFunction<Environment, F> member>
248 using MemberCaller = BindFirstOpaque<Member<Environment, F, member>>;
250 /// \brief Constructs a Callback1 from a non-const \p functor
252 /// \param Functor Must define \c first_argument_type and \c operator()(first_argument_type).
253 template<typename Functor>
254 inline Callback<get_func<Functor>> makeCallback(Functor &functor) {
255 return MemberCaller<Functor, get_func<Functor>, &Functor::operator()>(functor);
258 /// \brief Forms a Callback from a const Environment reference and a const Environment member-function.
259 template<class Environment, class F, ConstMemberFunction<Environment, F> member>
260 using ConstMemberCaller = BindFirstOpaque<ConstMember<Environment, F, member>>;
262 /// \brief Constructs a Callback1 from a const \p functor
264 /// \param Functor Must define \c first_argument_type and const \c operator()(first_argument_type).
265 template<typename Functor>
266 inline Callback<get_func<Functor>> makeCallback(const Functor &functor) {
267 return ConstMemberCaller<Functor, get_func<Functor>, &Functor::operator()>(functor);
270 /// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference.
271 template<class Environment, class F, detail::ArgUnshift<F, Environment &> *func>
272 using ReferenceCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, Environment &>, func>>;
274 /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference.
275 template<class Environment, class F, detail::ArgUnshift<F, const Environment &> *func>
276 using ConstReferenceCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, const Environment &>, func>>;
278 /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer.
279 template<class Environment, class F, detail::ArgUnshift<F, Environment *> *func>
280 using PointerCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, Environment *>, func>>;
282 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer.
283 template<class Environment, class F, detail::ArgUnshift<F, const Environment *> *func>
284 using ConstPointerCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, const Environment *>, func>>;
287 template<class Caller, class F>
288 class FreeCaller : public BindFirstOpaque<CallerShiftFirst<Caller, detail::ArgUnshift<F, void *>>> {
290 FreeCaller() : BindFirstOpaque<CallerShiftFirst<Caller, detail::ArgUnshift<F, void *>>>(nullptr) {
295 struct freecallwrapper;
297 template <class R, class... Ts>
298 struct freecallwrapper<R(Ts...)> {
299 using func = R(R(Ts...), Ts...);
300 static R call(R(*f)(Ts...), Ts... args) {
301 // ideally, we'd get the implementation of the function type directly. Instead, it's passed in
307 /// \brief Forms a Callback from a free function
308 template<class F, F *func>
309 using FreeCaller = detail::FreeCaller<Function<F, func>, F>;
312 inline Callback<F> makeCallbackF(F *func) {
314 return Callback<F>(reinterpret_cast<void *>(func), BindFirstOpaque<detail::freecallwrapper<F>>::thunk);
318 struct ImportExportCallback {
319 using Import_t = Callback<void(T)>;
321 using Export_t = Callback<void(const Callback<void(T)> &)>;