/* 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" 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 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() ); } template class BindFirstOpaqueN; template class BindFirstOpaqueN { FirstBound firstBound; public: explicit BindFirstOpaqueN(FirstBound firstBound) : firstBound(firstBound) { } R operator()(Ts... args) const { return Caller::call(firstBound, args...); } FirstBound getBound() const { return firstBound; } static R thunk(void *environment, Ts... args) { return Caller::call(ConvertFromOpaque::apply(environment), args...); } void *getEnvironment() const { return convertToOpaque(firstBound); } }; template using BindFirstOpaque = BindFirstOpaqueN>; /// \brief Combines a void pointer with a pointer to a function which operates on a void pointer. /// /// Use with the callback constructors MemberCaller0, ConstMemberCaller0, ReferenceCaller0, ConstReferenceCaller0, PointerCaller0, ConstPointerCaller0 and FreeCaller0. template class Callback; template class Callback : public CallbackBase { using Base = CallbackBase; static R nullThunk(void *, Ts...) { } public: using func = R(Ts...); Callback() : Base(0, nullThunk) { } template Callback(const BindFirstOpaque &caller) : Base(caller.getEnvironment(), BindFirstOpaque::thunk) { } Callback(void *environment, typename Base::Thunk function) : Base(environment, function) { } R operator()(Ts... args) const { return Base::getThunk()(Base::getEnvironment(), args...); } }; namespace detail { template struct Arglist; template struct Arglist { using type = R(Head, Ts...); template using unshift = Arglist; using shift = Arglist; }; template struct Arglist { using type = R(Ts...); template using unshift = Arglist; }; } template inline Callback>::shift::type> makeCallback(const Caller &caller, get_argument callee) { return Callback>::shift::type>(BindFirstOpaque(callee)); } template inline Callback> makeStatelessCallback(const Caller &caller) { return makeCallback(CallerShiftFirst>::template unshift::type>(), nullptr); } /// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function. /// /// \dontinclude generic/callback.cpp /// \skipline MemberCaller0 example /// \until end example template member> using MemberCaller = BindFirstOpaque::template instance>; /// \brief Forms a Callback from a const Environment reference and a const Environment member-function. /// /// \dontinclude generic/callback.cpp /// \skipline MemberCaller0 example /// \until end example template member> using ConstMemberCaller = BindFirstOpaque::template instance>; /// \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 ReferenceCaller0 example /// \until end example template::template unshift::type *func> using ReferenceCaller = BindFirstOpaque::template unshift::type>::template instance>; /// \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 ReferenceCaller0 example /// \until end example template::template unshift::type *func> using ConstReferenceCaller = BindFirstOpaque::template unshift::type>::template instance>; /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer. template::template unshift::type *func> using PointerCaller = BindFirstOpaque::template unshift::type>::template instance>; /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer. template::template unshift::type *func> using ConstPointerCaller = BindFirstOpaque::template unshift::type>::template instance>; /// \brief Forms a Callback from a free function template class FreeCaller : public BindFirstOpaque::template instance, typename detail::Arglist::template unshift::type >> { public: FreeCaller() : BindFirstOpaque::template instance, typename detail::Arglist::template unshift::type >>(nullptr) { } }; /// \brief Constructs a Callback1 from a non-const \p functor /// /// \param Functor Must define \c first_argument_type and \c operator()(first_argument_type). template inline Callback> makeCallback(Functor &functor) { return Callback>(MemberCaller, &Functor::operator()>(functor)); } /// \brief Constructs a Callback1 from a const \p functor /// /// \param Functor Must define \c first_argument_type and const \c operator()(first_argument_type). template inline Callback> makeCallback(const Functor &functor) { return Callback>(ConstMemberCaller, &Functor::operator()>(functor)); } using BoolImportCallback = Callback; using BoolExportCallback = Callback; using IntImportCallback = Callback; using IntExportCallback = Callback; using FloatImportCallback = Callback; using FloatExportCallback = Callback; using StringImportCallback = Callback; using StringExportCallback = Callback; using SizeImportCallback = Callback; using SizeExportCallback = Callback; #endif