/* 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 opaque callback. #include #include "functional.h" #include "callbackfwd.h" template inline void* convertToOpaque( Type* t ){ return t; } template inline void* convertToOpaque( const Type* t ){ return const_cast( t ); } template inline void* convertToOpaque( Type& t ){ return &t; } template inline void* convertToOpaque( const Type& t ){ return const_cast( &t ); } template class ConvertFromOpaque { }; template class ConvertFromOpaque { public: static Type& apply( void* p ){ return *static_cast( p ); } }; template class ConvertFromOpaque { public: static const Type& apply( void* p ){ return *static_cast( p ); } }; template class ConvertFromOpaque { public: static Type* apply( void* p ){ return static_cast( p ); } }; template class ConvertFromOpaque { public: static const Type* apply( void* p ){ return static_cast( p ); } }; template class BindFirstOpaque { typedef typename Caller::first_argument_type FirstBound; FirstBound firstBound; public: typedef typename Caller::result_type result_type; explicit BindFirstOpaque( FirstBound firstBound ) : firstBound( firstBound ){ } result_type operator()() const { return Caller::call( firstBound ); } FirstBound getBound() const { return firstBound; } static result_type thunk( void* environment ){ return Caller::call( ConvertFromOpaque::apply( environment ) ); } void* getEnvironment() const { return convertToOpaque( firstBound ); } }; template class BindFirstOpaque1 { typedef typename Caller::first_argument_type FirstBound; FirstBound firstBound; public: typedef typename Caller::second_argument_type first_argument_type; typedef typename Caller::result_type result_type; explicit BindFirstOpaque1( FirstBound firstBound ) : firstBound( firstBound ){ } result_type operator()( first_argument_type a1 ) const { return Caller::call( firstBound, a1 ); } FirstBound getBound() const { return firstBound; } static result_type thunk( void* environment, first_argument_type a1 ){ return Caller::call( ConvertFromOpaque::apply( environment ), a1 ); } void* getEnvironment() const { return convertToOpaque( firstBound ); } }; template class BindFirstOpaque2 { typedef typename Caller::first_argument_type FirstBound; FirstBound firstBound; public: typedef typename Caller::second_argument_type first_argument_type; typedef typename Caller::third_argument_type second_argument_type; typedef typename Caller::result_type result_type; explicit BindFirstOpaque2( FirstBound firstBound ) : firstBound( firstBound ){ } result_type operator()( first_argument_type a1, second_argument_type a2 ) const { return Caller::call( firstBound, a1, a2 ); } FirstBound getBound() const { return firstBound; } static result_type thunk( void* environment, first_argument_type a1, second_argument_type a2 ){ return Caller::call( ConvertFromOpaque::apply( environment ), a1, a2 ); } void* getEnvironment() const { return convertToOpaque( firstBound ); } }; template class BindFirstOpaque3 { typedef typename Caller::first_argument_type FirstBound; FirstBound firstBound; public: typedef typename Caller::second_argument_type first_argument_type; typedef typename Caller::third_argument_type second_argument_type; typedef typename Caller::fourth_argument_type third_argument_type; typedef typename Caller::result_type result_type; explicit BindFirstOpaque3( FirstBound firstBound ) : firstBound( firstBound ){ } result_type operator()( first_argument_type a1, second_argument_type a2, third_argument_type a3 ) const { return Caller::call( firstBound, a1, a2, a3 ); } FirstBound getBound() const { return firstBound; } static result_type thunk( void* environment, first_argument_type a1, second_argument_type a2, third_argument_type a3 ){ return Caller::call( ConvertFromOpaque::apply( environment ), a1, a2, a3 ); } void* getEnvironment() const { return convertToOpaque( firstBound ); } }; template class CallbackBase { void* m_environment; Thunk_ m_thunk; public: typedef Thunk_ Thunk; CallbackBase( void* environment, Thunk function ) : m_environment( environment ), m_thunk( function ){ } void* getEnvironment() const { return m_environment; } Thunk getThunk() const { return m_thunk; } }; template inline bool operator==( const CallbackBase& self, const CallbackBase& other ){ return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk(); } template inline bool operator!=( const CallbackBase& self, const CallbackBase& other ){ return !( self == other ); } template inline bool operator<( const CallbackBase& self, const CallbackBase& 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. /// /// Use with the callback constructors MemberCaller, ConstMemberCaller, ReferenceCaller, ConstReferenceCaller, PointerCaller, ConstPointerCaller and FreeCaller. template class Callback0 : public CallbackBase { typedef CallbackBase Base; static Result nullThunk( void* ){ } public: typedef Result result_type; Callback0() : Base( 0, nullThunk ){ } template Callback0( const BindFirstOpaque& caller ) : Base( caller.getEnvironment(), BindFirstOpaque::thunk ){ } Callback0( void* environment, typename Base::Thunk function ) : Base( environment, function ){ } result_type operator()() const { return Base::getThunk() ( Base::getEnvironment() ); } }; template inline Callback0 makeCallback0( const Caller& caller, typename Caller::first_argument_type callee ){ return Callback0( BindFirstOpaque( callee ) ); } template inline Callback0 makeStatelessCallback0( const Caller& caller ){ return makeCallback0( Caller0To1(), 0 ); } typedef Callback0 Callback; /// \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 : public CallbackBase { typedef CallbackBase Base; static Result nullThunk( void*, FirstArgument ){ } public: typedef FirstArgument first_argument_type; typedef Result result_type; Callback1() : Base( 0, nullThunk ){ } template Callback1( const BindFirstOpaque1& caller ) : Base( caller.getEnvironment(), BindFirstOpaque1::thunk ){ } Callback1( void* environment, typename Base::Thunk function ) : Base( environment, function ){ } result_type operator()( FirstArgument firstArgument ) const { return Base::getThunk() ( Base::getEnvironment(), firstArgument ); } }; template inline Callback1 makeCallback1( const Caller& caller, typename Caller::first_argument_type callee ){ return Callback1( BindFirstOpaque1( callee ) ); } template inline Callback1 makeStatelessCallback1( const Caller& caller ){ return makeCallback1( Caller1To2(), 0 ); } /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and two other arguments. /// template class Callback2 : public CallbackBase { typedef CallbackBase Base; static Result nullThunk( void*, FirstArgument, SecondArgument ){ } public: typedef FirstArgument first_argument_type; typedef SecondArgument second_argument_type; typedef Result result_type; Callback2() : Base( 0, nullThunk ){ } template Callback2( const BindFirstOpaque2& caller ) : Base( caller.getEnvironment(), BindFirstOpaque2::thunk ){ } Callback2( void* environment, typename Base::Thunk function ) : Base( environment, function ){ } result_type operator()( FirstArgument firstArgument, SecondArgument secondArgument ) const { return Base::getThunk() ( Base::getEnvironment(), firstArgument, secondArgument ); } }; template inline Callback2< typename Caller::second_argument_type, typename Caller::third_argument_type, typename Caller::result_type > makeCallback2( const Caller& caller, typename Caller::first_argument_type callee ){ return Callback2< typename Caller::second_argument_type, typename Caller::third_argument_type, typename Caller::result_type >( BindFirstOpaque2( callee ) ); } template inline Callback2< typename Caller::first_argument_type, typename Caller::second_argument_type, typename Caller::result_type > makeStatelessCallback2( const Caller& caller ){ return makeCallback2( Caller2To3(), 0 ); } /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and three other arguments. /// template class Callback3 : public CallbackBase { typedef CallbackBase Base; static Result nullThunk( void*, FirstArgument, SecondArgument, ThirdArgument ){ } public: typedef FirstArgument first_argument_type; typedef SecondArgument second_argument_type; typedef ThirdArgument third_argument_type; typedef Result result_type; Callback3() : Base( 0, nullThunk ){ } template Callback3( const BindFirstOpaque3& caller ) : Base( caller.getEnvironment(), BindFirstOpaque3::thunk ){ } Callback3( void* environment, typename Base::Thunk function ) : Base( environment, function ){ } result_type operator()( FirstArgument firstArgument, SecondArgument secondArgument, ThirdArgument thirdArgument ) const { return Base::getThunk() ( Base::getEnvironment(), firstArgument, secondArgument, thirdArgument ); } }; template inline Callback3< typename Caller::second_argument_type, typename Caller::third_argument_type, typename Caller::fourth_argument_type, typename Caller::result_type > makeCallback3( const Caller& caller, typename Caller::first_argument_type callee ){ return Callback3< typename Caller::second_argument_type, typename Caller::third_argument_type, typename Caller::fourth_argument_type, typename Caller::result_type >( BindFirstOpaque3( callee ) ); } template inline Callback3< typename Caller::first_argument_type, typename Caller::second_argument_type, typename Caller::third_argument_type, typename Caller::result_type > makeStatelessCallback3( const Caller& caller ){ return makeCallback3( Caller3To4(), 0 ); } /// \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 : public BindFirstOpaque< Member > { public: MemberCaller( Environment& environment ) : BindFirstOpaque< Member >( environment ){ } }; /// \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 : public BindFirstOpaque< ConstMember > { public: ConstMemberCaller( const Environment& environment ) : BindFirstOpaque< ConstMember >( environment ){ } }; /// \brief Forms a Callback from a non-const Environment reference and a const Environment member-function which takes one argument. template class MemberCaller1 : public BindFirstOpaque1< Member1 > { public: MemberCaller1( Environment& environment ) : BindFirstOpaque1< Member1 >( environment ){ } }; /// \brief Forms a Callback from a const Environment reference and a const Environment member-function which takes one argument. template class ConstMemberCaller1 : public BindFirstOpaque1< ConstMember1 > { public: ConstMemberCaller1( const Environment& environment ) : BindFirstOpaque1< ConstMember1 >( environment ){ } }; /// \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 : public BindFirstOpaque< Function1 > { public: ReferenceCaller( Environment& environment ) : BindFirstOpaque< Function1 >( environment ){ } }; /// \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 : public BindFirstOpaque< Function1 > { public: ConstReferenceCaller( const Environment& environment ) : BindFirstOpaque< Function1 >( environment ){ } }; /// \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 : public BindFirstOpaque1< Function2 > { public: ReferenceCaller1( Environment& environment ) : BindFirstOpaque1< Function2 >( environment ){ } }; /// \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 : public BindFirstOpaque1< Function2 > { public: ConstReferenceCaller1( const Environment& environment ) : BindFirstOpaque1< Function2 >( environment ){ } }; /// \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 : public BindFirstOpaque< Function1 > { public: PointerCaller( Environment* environment ) : BindFirstOpaque< Function1 >( environment ){ } }; /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer. template class ConstPointerCaller : public BindFirstOpaque< Function1 > { public: ConstPointerCaller( const Environment* environment ) : BindFirstOpaque< Function1 >( environment ){ } }; /// \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 : public BindFirstOpaque1< Function2 > { public: PointerCaller1( Environment* environment ) : BindFirstOpaque1< Function2 >( environment ){ } }; /// \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 : public BindFirstOpaque1< Function2 > { public: ConstPointerCaller1( const Environment* environment ) : BindFirstOpaque1< Function2 >( environment ){ } }; /// \brief Forms a Callback from a free function which takes no arguments. template class FreeCaller : public BindFirstOpaque< Caller0To1< Function0 > > { public: FreeCaller() : BindFirstOpaque< Caller0To1< Function0 > >( 0 ){ } }; /// \brief Forms a Callback from a free function which takes a single argument. template class FreeCaller1 : public BindFirstOpaque1< Caller1To2< Function1 > > { public: FreeCaller1() : BindFirstOpaque1< Caller1To2< Function1 > >( 0 ){ } }; /// \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 ) ); } 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; #endif