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());
73 struct ConvertFromOpaque {
79 inline const void *convertToOpaque(const T &t) {
84 struct ConvertFromOpaque<const T &> {
85 static T const &apply(void *p) {
86 return *static_cast<const T *>(p);
91 inline void *convertToOpaque(T &t) {
96 struct ConvertFromOpaque<T &> {
97 static T &apply(void *p) {
98 return *static_cast<T *>( p );
105 inline const void *convertToOpaque(const T *t) {
110 struct ConvertFromOpaque<const T *> {
111 static const T *apply(void *p) {
112 return static_cast<const T *>(p);
117 inline void *convertToOpaque(T *t) {
122 struct ConvertFromOpaque<T *> {
123 static T *apply(void *p) {
124 return static_cast<T *>(p);
130 template<class R, class... Ts>
131 inline const void *convertToOpaque(R(*const &t)(Ts...)) {
135 template<class R, class... Ts>
136 struct ConvertFromOpaque<R(*const &)(Ts...)> {
137 using Type = R(*)(Ts...);
139 static Type const &apply(void *p) {
140 return *static_cast<Type *>(p);
144 template<class R, class... Ts>
145 inline void *convertToOpaque(R(*&t)(Ts...)) {
149 template<class R, class... Ts>
150 struct ConvertFromOpaque<R(*&)(Ts...)> {
151 using Type = R(*)(Ts...);
153 static Type &apply(void *p) {
154 return *static_cast<Type *>(p);
158 template<class Caller, class F>
159 class BindFirstOpaqueN;
161 template<class Caller, class R, class FirstBound, class... Ts>
162 class BindFirstOpaqueN<Caller, R(FirstBound, Ts...)> {
163 FirstBound firstBound;
165 explicit BindFirstOpaqueN(FirstBound firstBound) : firstBound(firstBound) {
168 R operator()(Ts... args) const {
169 return Caller::call(firstBound, args...);
172 FirstBound getBound() const {
176 static R thunk(void *environment, Ts... args) {
177 return thunk_(detail::ConvertFromOpaque<FirstBound>::apply(environment), args...);
180 static R thunk_(FirstBound environment, Ts... args) {
181 return Caller::call(environment, args...);
184 void *getEnvironment() const {
185 return const_cast<void *>(detail::convertToOpaque(firstBound));
191 template<class Caller>
192 using BindFirstOpaque = detail::BindFirstOpaqueN<Caller, get_func<Caller>>;
194 /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer.
196 /// Use with the callback constructors MemberCaller0, ConstMemberCaller0, ReferenceCaller0, ConstReferenceCaller0, PointerCaller0, ConstPointerCaller0 and FreeCaller0.
200 template<class R, class... Ts>
201 class Callback<R(Ts...)> : public detail::CallbackBase<R(*)(void *, Ts...)> {
202 using Base = detail::CallbackBase<R (*)(void *, Ts...)>;
204 static R nullThunk(void *, Ts...) {
208 using func = R(Ts...);
210 Callback() : Base(0, nullThunk) {
213 template<typename Caller>
214 Callback(const BindFirstOpaque<Caller> &caller) : Base(caller.getEnvironment(), BindFirstOpaque<Caller>::thunk) {
217 Callback(void *environment, typename Base::Thunk function) : Base(environment, function) {
220 R operator()(Ts... args) const {
221 return Base::getThunk()(Base::getEnvironment(), args...);
229 template<class R, class Head, class... Ts>
230 struct Arglist<R(Head, Ts...)> {
231 using type = R(Head, Ts...);
233 template <class Unshift>
234 using unshift = Arglist<R(Unshift, Head, Ts...)>;
236 using shift = Arglist<R(Ts...)>;
239 template<class R, class... Ts>
240 struct Arglist<R(Ts...)> {
241 using type = R(Ts...);
243 template <class Unshift>
244 using unshift = Arglist<R(Unshift, Ts...)>;
248 using ArgShift = typename detail::Arglist<F>::shift::type;
250 template<class F, class T>
251 using ArgUnshift = typename detail::Arglist<F>::template unshift<T>::type;
254 template<typename Caller>
255 inline Callback<detail::ArgShift<get_func<Caller>>> makeCallback(const Caller &caller, get_argument<Caller, 0> callee) {
256 return BindFirstOpaque<Caller>(callee);
259 template<class Caller, class F>
260 class CallerShiftFirst;
262 template<class Caller, class R, class FirstArgument, class... Ts>
263 class CallerShiftFirst<Caller, R(FirstArgument, Ts...)> {
265 using func = R(FirstArgument, Ts...);
267 static R call(FirstArgument, Ts... args) {
268 return Caller::call(args...);
272 template<typename Caller>
273 inline Callback<get_func<Caller>> makeStatelessCallback(const Caller &caller) {
274 return makeCallback(CallerShiftFirst<Caller, detail::ArgUnshift<get_func<Caller>, void *>>(), nullptr);
277 /// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function.
278 template<class Environment, class F, MemberFunction<Environment, F> member>
279 using MemberCaller = BindFirstOpaque<Member<Environment, F, member>>;
281 /// \brief Constructs a Callback1 from a non-const \p functor
283 /// \param Functor Must define \c first_argument_type and \c operator()(first_argument_type).
284 template<typename Functor>
285 inline Callback<get_func<Functor>> makeCallback(Functor &functor) {
286 return MemberCaller<Functor, get_func<Functor>, &Functor::operator()>(functor);
289 /// \brief Forms a Callback from a const Environment reference and a const Environment member-function.
290 template<class Environment, class F, ConstMemberFunction<Environment, F> member>
291 using ConstMemberCaller = BindFirstOpaque<ConstMember<Environment, F, member>>;
293 /// \brief Constructs a Callback1 from a const \p functor
295 /// \param Functor Must define \c first_argument_type and const \c operator()(first_argument_type).
296 template<typename Functor>
297 inline Callback<get_func<Functor>> makeCallback(const Functor &functor) {
298 return ConstMemberCaller<Functor, get_func<Functor>, &Functor::operator()>(functor);
301 /// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference.
302 template<class Environment, class F, detail::ArgUnshift<F, Environment &> *func>
303 using ReferenceCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, Environment &>, func>>;
305 /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference.
306 template<class Environment, class F, detail::ArgUnshift<F, const Environment &> *func>
307 using ConstReferenceCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, const Environment &>, func>>;
309 /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer.
310 template<class Environment, class F, detail::ArgUnshift<F, Environment *> *func>
311 using PointerCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, Environment *>, func>>;
313 /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer.
314 template<class Environment, class F, detail::ArgUnshift<F, const Environment *> *func>
315 using ConstPointerCaller = BindFirstOpaque<Function<detail::ArgUnshift<F, const Environment *>, func>>;
318 template<class Caller, class F>
319 class FreeCaller : public BindFirstOpaque<CallerShiftFirst<Caller, detail::ArgUnshift<F, void *>>> {
321 FreeCaller() : BindFirstOpaque<CallerShiftFirst<Caller, detail::ArgUnshift<F, void *>>>(nullptr) {
326 struct FreeCallerWrapper;
328 template<class R, class... Ts>
329 struct FreeCallerWrapper<R(Ts...)> {
330 using func = R(void *, Ts...);
332 static R call(void *f, Ts... args) {
333 // ideally, we'd get the implementation of the function type directly. Instead, it's passed in
334 return reinterpret_cast<R(*)(Ts...)>(f)(args...);
339 /// \brief Forms a Callback from a free function
340 template<class F, F *func>
341 using FreeCaller = detail::FreeCaller<Function<F, func>, F>;
343 template<class R, class... Ts>
344 inline Callback<R(Ts...)> makeCallbackF(R(*func)(Ts...)) {
345 void *pVoid = reinterpret_cast<void *>(func);
346 return BindFirstOpaque<detail::FreeCallerWrapper<R(Ts...)>>(pVoid);