/* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined(INCLUDED_GENERIC_CLOSURE_H) #define INCLUDED_GENERIC_CLOSURE_H /// \file /// \brief Type-safe techniques for binding the first argument of an anonymous callback. #include /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer. /// /// Use with the callback constructors MemberCaller, ConstMemberCaller, ReferenceCaller, ConstReferenceCaller, PointerCaller, ConstPointerCaller and FreeCaller. class Callback { typedef void (*Thunk)(void*); void* m_environment; Thunk m_thunk; static void nullThunk(void*) { } public: Callback() : m_environment(0), m_thunk(nullThunk) { } Callback(void* environment, Thunk function) : m_environment(environment), m_thunk(function) { } void* getEnvironment() const { return m_environment; } Thunk getThunk() const { return m_thunk; } void operator()() const { m_thunk(m_environment); } }; inline bool operator==(const Callback& self, const Callback& other) { return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk(); } inline bool operator<(const Callback& self, const Callback& other) { return self.getEnvironment() < other.getEnvironment() || (!(other.getEnvironment() < self.getEnvironment()) && self.getThunk() < other.getThunk()); } /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and one other argument. /// /// Use with the callback constructors MemberCaller1, ConstMemberCaller1, ReferenceCaller1, ConstReferenceCaller1, PointerCaller1, ConstPointerCaller1 and FreeCaller1. template class Callback1 { typedef void (*Thunk)(void*, FirstArgument); void* m_environment; Thunk m_thunk; static void nullThunk(void*, FirstArgument) { } public: typedef FirstArgument first_argument_type; Callback1() : m_environment(0), m_thunk(nullThunk) { } Callback1(void* environment, Thunk function) : m_environment(environment), m_thunk(function) { } void* getEnvironment() const { return m_environment; } Thunk getThunk() const { return m_thunk; } void operator()(FirstArgument firstArgument) const { m_thunk(m_environment, firstArgument); } }; template inline bool operator==(const Callback1& self, const Callback1& other) { return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk(); } template inline bool operator<(const Callback1& self, const Callback1& other) { return self.getEnvironment() < other.getEnvironment() || (!(other.getEnvironment() < self.getEnvironment()) && self.getThunk() < other.getThunk()); } template class FunctorInvoke { public: inline void operator()(Functor functor) { functor(); } }; typedef FunctorInvoke CallbackInvoke; template class Functor1Invoke { FirstArgument m_firstArgument; public: Functor1Invoke(FirstArgument firstArgument) : m_firstArgument(firstArgument) { } inline void operator()(Functor functor) { functor(m_firstArgument); } }; typedef Callback1 BoolImportCallback; typedef Callback1 BoolExportCallback; typedef Callback1 IntImportCallback; typedef Callback1 IntExportCallback; typedef Callback1 FloatImportCallback; typedef Callback1 FloatExportCallback; typedef Callback1 StringImportCallback; typedef Callback1 StringExportCallback; typedef Callback1 SizeImportCallback; typedef Callback1 SizeExportCallback; /// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function. /// /// \dontinclude generic/callback.cpp /// \skipline MemberCaller example /// \until end example template class MemberCaller { Environment& m_environment; public: MemberCaller(Environment& environment) : m_environment(environment) { } void* getEnvironment() const { return &m_environment; } static void thunk(void* environment) { ((*reinterpret_cast(environment)).*member)(); } operator Callback() const { return Callback(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a const Environment reference and a const Environment member-function. /// /// \dontinclude generic/callback.cpp /// \skipline MemberCaller example /// \until end example template class ConstMemberCaller { const Environment& m_environment; public: ConstMemberCaller(const Environment& environment) : m_environment(environment) { } void* getEnvironment() const { return const_cast(&m_environment); } static void thunk(void* environment) { ((*reinterpret_cast(environment)).*member)(); } operator Callback() const { return Callback(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a non-const Environment reference and a const Environment member-function which takes one argument. template class MemberCaller1 { Environment& m_environment; public: MemberCaller1(Environment& environment) : m_environment(environment) { } void* getEnvironment() const { return &m_environment; } static void thunk(void* environment, FirstArgument firstArgument) { ((*reinterpret_cast(environment)).*member)(firstArgument); } operator Callback1() const { return Callback1(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a const Environment reference and a const Environment member-function which takes one argument. template class ConstMemberCaller1 { const Environment& m_environment; public: ConstMemberCaller1(const Environment& environment) : m_environment(environment) { } void* getEnvironment() const { return const_cast(&m_environment); } static void thunk(void* environment, FirstArgument firstArgument) { ((*reinterpret_cast(environment)).*member)(firstArgument); } operator Callback1() const { return Callback1(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference. /// /// \dontinclude generic/callback.cpp /// \skipline ReferenceCaller example /// \until end example template class ReferenceCaller { Environment& m_environment; public: ReferenceCaller(Environment& environment) : m_environment(environment) { } void* getEnvironment() const { return &m_environment; } static void thunk(void* environment) { (func)(*reinterpret_cast(environment)); } operator Callback() const { return Callback(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference. /// /// \dontinclude generic/callback.cpp /// \skipline ReferenceCaller example /// \until end example template class ConstReferenceCaller { const Environment& m_environment; public: ConstReferenceCaller(const Environment& environment) : m_environment(environment) { } void* getEnvironment() const { return const_cast(&m_environment); } static void thunk(void* environment) { (func)(*reinterpret_cast(environment)); } operator Callback() const { return Callback(getEnvironment(), thunk); } }; /// \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. template class ReferenceCaller1 { Environment& m_environment; public: ReferenceCaller1(Environment& environment) : m_environment(environment) { } void* getEnvironment() const { return &m_environment; } static void thunk(void* environment, FirstArgument firstArgument) { (func)(*reinterpret_cast(environment), firstArgument); } operator Callback1() const { return Callback1(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference and one other argument. template class ConstReferenceCaller1 { const Environment& m_environment; public: ConstReferenceCaller1(const Environment& environment) : m_environment(environment) { } void* getEnvironment() const { return const_cast(&m_environment); } static void thunk(void* environment, FirstArgument firstArgument) { (func)(*reinterpret_cast(environment), firstArgument); } operator Callback1() const { return Callback1(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer. template class PointerCaller { Environment* m_environment; public: PointerCaller(Environment* environment) : m_environment(environment) { } void* getEnvironment() const { return m_environment; } static void thunk(void* environment) { (func)(reinterpret_cast(environment)); } operator Callback() const { return Callback(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer. template class ConstPointerCaller { const Environment* m_environment; public: ConstPointerCaller(const Environment* environment) : m_environment(environment) { } void* getEnvironment() const { return const_cast(m_environment); } static void thunk(void* environment) { (func)(reinterpret_cast(environment)); } operator Callback() const { return Callback(getEnvironment(), thunk); } }; /// \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. template class PointerCaller1 { Environment* m_environment; public: PointerCaller1(Environment* environment) : m_environment(environment) { } void* getEnvironment() const { return m_environment; } static void thunk(void* environment, FirstArgument firstArgument) { (func)(reinterpret_cast(environment), firstArgument); } operator Callback1() const { return Callback1(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer and one other argument. template class ConstPointerCaller1 { const Environment* m_environment; public: ConstPointerCaller1(const Environment* environment) : m_environment(environment) { } void* getEnvironment() const { return const_cast(m_environment); } static void thunk(void* environment, FirstArgument firstArgument) { (func)(reinterpret_cast(environment), firstArgument); } operator Callback1() const { return Callback1(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a free function which takes no arguments. template class FreeCaller { public: void* getEnvironment() const { return 0; } static void thunk(void*) { (func)(); } operator Callback() const { return Callback(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a free function which takes a single argument. template class FreeCaller1 { public: void* getEnvironment() const { return 0; } static void thunk(void*, FirstArgument firstArgument) { (func)(firstArgument); } operator Callback1() const { return Callback1(getEnvironment(), thunk); } }; /// \brief Constructs a Callback from a non-const \p functor with zero arguments. /// /// \param Functor Must define \c operator()(). template inline Callback makeCallback(Functor& functor) { return Callback(MemberCaller(functor)); } /// \brief Constructs a Callback from a const \p functor with zero arguments. /// /// \param Functor Must define const \c operator()(). template inline Callback makeCallback(const Functor& functor) { return Callback(ConstMemberCaller(functor)); } /// \brief Constructs a Callback1 from a non-const \p functor with one argument. /// /// \param Functor Must define \c first_argument_type and \c operator()(first_argument_type). template inline Callback1 makeCallback1(Functor& functor) { typedef typename Functor::first_argument_type FirstArgument; return Callback1(MemberCaller1(functor)); } /// \brief Constructs a Callback1 from a const \p functor with one argument. /// /// \param Functor Must define \c first_argument_type and const \c operator()(first_argument_type). template inline Callback1 makeCallback1(const Functor& functor) { typedef typename Functor::first_argument_type FirstArgument; return Callback1(ConstMemberCaller1(functor)); } #endif