gtkradiant/tools/urt/libs/generic/callback.h

455 lines
14 KiB
C
Raw Normal View History

#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 <cstddef>
/// \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<typename FirstArgument>
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<typename FirstArgument>
inline bool operator==( const Callback1<FirstArgument>& self, const Callback1<FirstArgument>& other ){
return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk();
}
template<typename FirstArgument>
inline bool operator<( const Callback1<FirstArgument>& self, const Callback1<FirstArgument>& other ){
return self.getEnvironment() < other.getEnvironment() ||
( !( other.getEnvironment() < self.getEnvironment() ) && self.getThunk() < other.getThunk() );
}
template<typename Functor>
class FunctorInvoke
{
public:
inline void operator()( Functor functor ){
functor();
}
};
typedef FunctorInvoke<Callback> CallbackInvoke;
template<typename Functor, typename FirstArgument>
class Functor1Invoke
{
FirstArgument m_firstArgument;
public:
Functor1Invoke( FirstArgument firstArgument ) : m_firstArgument( firstArgument ){
}
inline void operator()( Functor functor ){
functor( m_firstArgument );
}
};
typedef Callback1<bool> BoolImportCallback;
typedef Callback1<const BoolImportCallback&> BoolExportCallback;
typedef Callback1<int> IntImportCallback;
typedef Callback1<const IntImportCallback&> IntExportCallback;
typedef Callback1<float> FloatImportCallback;
typedef Callback1<const FloatImportCallback&> FloatExportCallback;
typedef Callback1<const char*> StringImportCallback;
typedef Callback1<const StringImportCallback&> StringExportCallback;
typedef Callback1<std::size_t> SizeImportCallback;
typedef Callback1<const SizeImportCallback&> 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<typename Environment, void( Environment::*member ) ( )>
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*>( 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<typename Environment, void( Environment::*member ) ( ) const>
class ConstMemberCaller
{
const Environment& m_environment;
public:
ConstMemberCaller( const Environment& environment ) : m_environment( environment ){
}
void* getEnvironment() const {
return const_cast<Environment*>( &m_environment );
}
static void thunk( void* environment ){
( ( *reinterpret_cast<const Environment*>( 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<typename Environment, typename FirstArgument, void( Environment::*member ) (FirstArgument)>
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*>( environment ) ).*member )( firstArgument );
}
operator Callback1<FirstArgument>( ) const
{
return Callback1<FirstArgument>( getEnvironment(), thunk );
}
};
/// \brief Forms a Callback from a const Environment reference and a const Environment member-function which takes one argument.
template<typename Environment, typename FirstArgument, void( Environment::*member ) (FirstArgument) const>
class ConstMemberCaller1
{
const Environment& m_environment;
public:
ConstMemberCaller1( const Environment& environment ) : m_environment( environment ){
}
void* getEnvironment() const {
return const_cast<Environment*>( &m_environment );
}
static void thunk( void* environment, FirstArgument firstArgument ){
( ( *reinterpret_cast<Environment*>( environment ) ).*member )( firstArgument );
}
operator Callback1<FirstArgument>( ) const
{
return Callback1<FirstArgument>( 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<typename Environment, void( *func ) (Environment&)>
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*>( 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<typename Environment, void( *func ) (const Environment&)>
class ConstReferenceCaller
{
const Environment& m_environment;
public:
ConstReferenceCaller( const Environment& environment ) : m_environment( environment ){
}
void* getEnvironment() const {
return const_cast<Environment*>( &m_environment );
}
static void thunk( void* environment ){
(func)( *reinterpret_cast<const Environment*>( 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<typename Environment, typename FirstArgument, void( *func ) ( Environment&, FirstArgument )>
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*>( environment ), firstArgument );
}
operator Callback1<FirstArgument>( ) const
{
return Callback1<FirstArgument>( 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<typename Environment, typename FirstArgument, void( *func ) ( const Environment&, FirstArgument )>
class ConstReferenceCaller1
{
const Environment& m_environment;
public:
ConstReferenceCaller1( const Environment& environment ) : m_environment( environment ){
}
void* getEnvironment() const {
return const_cast<Environment*>( &m_environment );
}
static void thunk( void* environment, FirstArgument firstArgument ){
(func)( *reinterpret_cast<const Environment*>( environment ), firstArgument );
}
operator Callback1<FirstArgument>( ) const
{
return Callback1<FirstArgument>( 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<typename Environment, void( *func ) (Environment*)>
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*>( 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<typename Environment, void( *func ) (const Environment*)>
class ConstPointerCaller
{
const Environment* m_environment;
public:
ConstPointerCaller( const Environment* environment ) : m_environment( environment ){
}
void* getEnvironment() const {
return const_cast<Environment*>( m_environment );
}
static void thunk( void* environment ){
(func)( reinterpret_cast<const Environment*>( 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<typename Environment, typename FirstArgument, void( *func ) ( Environment*, FirstArgument )>
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*>( environment ), firstArgument );
}
operator Callback1<FirstArgument>( ) const
{
return Callback1<FirstArgument>( 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<typename Environment, typename FirstArgument, void( *func ) ( const Environment*, FirstArgument )>
class ConstPointerCaller1
{
const Environment* m_environment;
public:
ConstPointerCaller1( const Environment* environment ) : m_environment( environment ){
}
void* getEnvironment() const {
return const_cast<Environment*>( m_environment );
}
static void thunk( void* environment, FirstArgument firstArgument ){
(func)( reinterpret_cast<const Environment*>( environment ), firstArgument );
}
operator Callback1<FirstArgument>( ) const
{
return Callback1<FirstArgument>( getEnvironment(), thunk );
}
};
/// \brief Forms a Callback from a free function which takes no arguments.
template<void( *func ) ( )>
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<typename FirstArgument, void( *func ) (FirstArgument)>
class FreeCaller1
{
public:
void* getEnvironment() const {
return 0;
}
static void thunk( void*, FirstArgument firstArgument ){
(func)( firstArgument );
}
operator Callback1<FirstArgument>( ) const
{
return Callback1<FirstArgument>( getEnvironment(), thunk );
}
};
/// \brief Constructs a Callback from a non-const \p functor with zero arguments.
///
/// \param Functor Must define \c operator()().
template<typename Functor>
inline Callback makeCallback( Functor& functor ){
return Callback( MemberCaller<Functor, &Functor::operator()>( functor ) );
}
/// \brief Constructs a Callback from a const \p functor with zero arguments.
///
/// \param Functor Must define const \c operator()().
template<typename Functor>
inline Callback makeCallback( const Functor& functor ){
return Callback( ConstMemberCaller<Functor, &Functor::operator()>( 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<typename Functor>
inline Callback1<typename Functor::first_argument_type> makeCallback1( Functor& functor ){
typedef typename Functor::first_argument_type FirstArgument;
return Callback1<FirstArgument>( MemberCaller1<Functor, FirstArgument, &Functor::operator()>( 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<typename Functor>
inline Callback1<typename Functor::first_argument_type> makeCallback1( const Functor& functor ){
typedef typename Functor::first_argument_type FirstArgument;
return Callback1<FirstArgument>( ConstMemberCaller1<Functor, FirstArgument, &Functor::operator()>( functor ) );
}
#endif