Simplify Slot.hh

Replace CallbackHolder, FunctorHolder and SlotHolder with a (smaller) set of polymorphic classes.
SignalHolder now stores a (smart) pointer to the class.
This commit is contained in:
Pavel Labath 2011-05-02 15:10:42 +02:00
parent 4b47675441
commit 144d716a42
2 changed files with 71 additions and 255 deletions

View file

@ -22,6 +22,7 @@
#ifndef FBTK_SIGNAL_HH #ifndef FBTK_SIGNAL_HH
#define FBTK_SIGNAL_HH #define FBTK_SIGNAL_HH
#include "RefCount.hh"
#include "Slot.hh" #include "Slot.hh"
#include <list> #include <list>
#include <map> #include <map>
@ -49,7 +50,7 @@ public:
}; };
/// Do not use this type outside this class /// Do not use this type outside this class
typedef std::list<SlotHolder> SlotList; typedef std::list<RefCount<SlotBase> > SlotList;
typedef SlotList::iterator Iterator; typedef SlotList::iterator Iterator;
typedef Iterator SlotID; typedef Iterator SlotID;
@ -91,7 +92,7 @@ protected:
Iterator end() { return m_slots.end(); } Iterator end() { return m_slots.end(); }
/// Connect a slot to this signal. Must only be called by child classes. /// Connect a slot to this signal. Must only be called by child classes.
SlotID connect(const SlotHolder& slot) { SlotID connect(const RefCount<SlotBase>& slot) {
return m_slots.insert(m_slots.end(), slot); return m_slots.insert(m_slots.end(), slot);
} }
@ -111,16 +112,17 @@ template <typename ReturnType,
typename Arg1 = SigImpl::EmptyArg, typename Arg2 = SigImpl::EmptyArg, typename Arg3 = SigImpl::EmptyArg > typename Arg1 = SigImpl::EmptyArg, typename Arg2 = SigImpl::EmptyArg, typename Arg3 = SigImpl::EmptyArg >
class Signal: public SigImpl::SignalHolder { class Signal: public SigImpl::SignalHolder {
public: public:
typedef SigImpl::Slot3<ReturnType, Arg1, Arg2, Arg3> SlotType;
void emit(Arg1 arg1, Arg2 arg2, Arg3 arg3) { void emit(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
for ( Iterator it = begin(); it != end(); ++it ) { for ( Iterator it = begin(); it != end(); ++it ) {
static_cast<SlotType&>(*it)(arg1, arg2, arg3); static_cast<SigImpl::SlotBase3<ReturnType, Arg1, Arg2, Arg3> &>(**it)(arg1, arg2, arg3);
} }
} }
SlotID connect(const SlotType& slot) { template<typename Functor>
return SignalHolder::connect(slot); SlotID connect(const Functor& functor) {
return SignalHolder::connect(FbTk::RefCount<SigImpl::SlotBase>(
new SigImpl::Slot3<ReturnType, Arg1, Arg2, Arg3, Functor>(functor)
));
} }
}; };
@ -128,16 +130,17 @@ public:
template <typename ReturnType, typename Arg1, typename Arg2> template <typename ReturnType, typename Arg1, typename Arg2>
class Signal<ReturnType, Arg1, Arg2, SigImpl::EmptyArg>: public SigImpl::SignalHolder { class Signal<ReturnType, Arg1, Arg2, SigImpl::EmptyArg>: public SigImpl::SignalHolder {
public: public:
typedef SigImpl::Slot2<ReturnType, Arg1, Arg2> SlotType;
void emit(Arg1 arg1, Arg2 arg2) { void emit(Arg1 arg1, Arg2 arg2) {
for ( Iterator it = begin(); it != end(); ++it ) { for ( Iterator it = begin(); it != end(); ++it ) {
static_cast<SlotType&>(*it)(arg1, arg2); static_cast<SigImpl::SlotBase2<ReturnType, Arg1, Arg2> &>(**it)(arg1, arg2);
} }
} }
SlotID connect(const SlotType& slot) { template<typename Functor>
return SignalHolder::connect(slot); SlotID connect(const Functor& functor) {
return SignalHolder::connect(FbTk::RefCount<SigImpl::SlotBase>(
new SigImpl::Slot2<ReturnType, Arg1, Arg2, Functor>(functor)
));
} }
}; };
@ -145,16 +148,17 @@ public:
template <typename ReturnType, typename Arg1> template <typename ReturnType, typename Arg1>
class Signal<ReturnType, Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder { class Signal<ReturnType, Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder {
public: public:
typedef SigImpl::Slot1<ReturnType, Arg1> SlotType;
void emit(Arg1 arg) { void emit(Arg1 arg) {
for ( Iterator it = begin(); it != end(); ++it ) { for ( Iterator it = begin(); it != end(); ++it ) {
static_cast<SlotType&>(*it)(arg); static_cast<SigImpl::SlotBase1<ReturnType, Arg1> &>(**it)(arg);
} }
} }
SlotID connect(const SlotType& slot) { template<typename Functor>
return SignalHolder::connect(slot); SlotID connect(const Functor& functor) {
return SignalHolder::connect(FbTk::RefCount<SigImpl::SlotBase>(
new SigImpl::Slot1<ReturnType, Arg1, Functor>(functor)
));
} }
}; };
@ -162,16 +166,17 @@ public:
template <typename ReturnType> template <typename ReturnType>
class Signal<ReturnType, SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder { class Signal<ReturnType, SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder {
public: public:
typedef SigImpl::Slot0<ReturnType> SlotType;
void emit() { void emit() {
for ( Iterator it = begin(); it != end(); ++it ) { for ( Iterator it = begin(); it != end(); ++it ) {
static_cast<SlotType&>(*it)(); static_cast<SigImpl::SlotBase0<ReturnType> &>(**it)();
} }
} }
SlotID connect(const SlotType& slot) { template<typename Functor>
return SignalHolder::connect(slot); SlotID connect(const Functor& functor) {
return SignalHolder::connect(FbTk::RefCount<SigImpl::SlotBase>(
new SigImpl::Slot0<ReturnType, Functor>(functor)
));
} }
}; };

View file

@ -27,268 +27,79 @@ namespace FbTk {
/// \namespace Implementation details for signals, do not use anything in this namespace /// \namespace Implementation details for signals, do not use anything in this namespace
namespace SigImpl { namespace SigImpl {
class CallbackHolder; class SlotBase {
/// Placeholder type for typed callbacks
typedef void* (*CallbackFunc)(void *);
/// Clone function callback type for cloning typed callback holders
typedef CallbackHolder* (*CloneFunc)(CallbackHolder*);
/// Kill function callback type for destroying type specific information in
/// FunctorHolder
typedef void (*KillFunc)(CallbackHolder*);
/// Holds clone, functor callback, and the kill function for FunctorHolder.
class CallbackHolder {
public: public:
/** virtual ~SlotBase() {}
* @param callback The callback to call when a slot receives a signal. };
* @param clone The callback to use for cloning a type specific instance of
* this classinstance.
* @param kill The callback that knows how to free the memory in type
* specific instance of this class.
*/
CallbackHolder(CallbackFunc callback,
CloneFunc clone,
KillFunc kill):
m_callback(callback),
m_kill(kill),
m_clone(clone) { }
~CallbackHolder() { template<typename ReturnType>
(*m_kill)(this); class SlotBase0: public SlotBase {
} public:
virtual ReturnType operator()() = 0;
};
/// @return a clone of this instance template<typename ReturnType, typename Functor>
CallbackHolder* clone() { class Slot0: public SlotBase0<ReturnType> {
return (*m_clone)(this); public:
} virtual ReturnType operator()() { return m_functor(); }
/// \c Callback to \c Functor specific callback Slot0(Functor functor) : m_functor(functor) {}
CallbackFunc m_callback;
protected:
CallbackHolder& operator = (const CallbackHolder& other) {
if ( this == &other ) {
return *this;
}
m_callback = other.m_callback;
m_clone = other.m_clone;
m_kill = other.m_kill;
return *this;
}
CallbackHolder(const CallbackHolder& other) {
*this = other;
}
private: private:
/// This function is called to kill this instance Functor m_functor;
KillFunc m_kill;
/// Functions that knows how to clone a specific \c Functor type
CloneFunc m_clone;
}; };
template<typename ReturnType, typename Arg1>
/// Holds the functor and creates a clone callback for \c Functor specific type class SlotBase1: public SlotBase {
template <typename Functor>
class FunctorHolder: public CallbackHolder {
public: public:
/// This type. virtual ReturnType operator()(Arg1) = 0;
typedef FunctorHolder<Functor> Self;
/**
* @param functor The functor to be used when a signal is emitted.
* @param callback The callback to call when a signal is emitted.
*/
FunctorHolder(const Functor& functor, CallbackFunc callback):
CallbackHolder(callback, &clone, &kill),
m_functor(functor) {
}
/// Specific clone for this Functor type
static CallbackHolder* clone(CallbackHolder* self) {
return new Self( static_cast<Self&>(*self));
}
static void kill(CallbackHolder* self) {
// Destroy functor
static_cast<Self*>( self )->m_functor.~Functor();
}
Functor m_functor; ///< the functor to use when a signal is emitted.
}; };
template<typename ReturnType, typename Arg1, typename Functor>
class Slot1: public SlotBase1<ReturnType, Arg1> {
/// Callback with no arguments.
template <typename Functor, typename ReturnType >
struct Callback0 {
static ReturnType callback(CallbackHolder* base) {
static_cast< FunctorHolder<Functor>* >( base )->m_functor();
return ReturnType();
}
static CallbackFunc functionAddress() {
return reinterpret_cast<CallbackFunc>(&callback);
}
};
/// Callback with one argument
template <typename Functor, typename ReturnType, typename Arg1>
struct Callback1 {
typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1);
static ReturnType callback(CallbackHolder* base, Arg1 arg1) {
static_cast< FunctorHolder<Functor>* >( base )->m_functor(arg1);
return ReturnType();
}
static CallbackFunc functionAddress() {
return reinterpret_cast<CallbackFunc>(&callback);
}
};
/// Callback with two arguments
template <typename Functor, typename ReturnType,
typename Arg1, typename Arg2>
struct Callback2 {
typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1, Arg2);
static ReturnType callback(CallbackHolder* base, Arg1 arg1, Arg2 arg2) {
static_cast< FunctorHolder<Functor>* >( base )->m_functor(arg1, arg2);
return ReturnType();
}
static CallbackFunc functionAddress() {
return reinterpret_cast<CallbackFunc>(&callback);
}
};
/// Callback with three arguments
template <typename Functor, typename ReturnType,
typename Arg1, typename Arg2, typename Arg3>
struct Callback3 {
typedef ReturnType (Functor::* CallbackType)(CallbackHolder*, Arg1, Arg2, Arg3);
static ReturnType callback(CallbackHolder* base, Arg1 arg1, Arg2 arg2, Arg3 arg3) {
static_cast< FunctorHolder<Functor>* >( base )->m_functor( arg1, arg2, arg3 );
return ReturnType();
}
static CallbackFunc functionAddress() {
return reinterpret_cast<CallbackFunc>(&callback);
}
};
/// Holds callback holder and handles the copying of callback holders for the
/// \c Slots.
class SlotHolder {
public: public:
SlotHolder(const SlotHolder& other): virtual ReturnType operator()(Arg1 arg1) { return m_functor(arg1); }
m_holder( other.m_holder ? other.m_holder->clone() : 0 ) {
}
~SlotHolder() { Slot1(Functor functor) : m_functor(functor) {}
delete m_holder;
}
SlotHolder& operator = (const SlotHolder& other) { private:
if ( &other == this ) { Functor m_functor;
return *this;
}
delete m_holder;
if ( other.m_holder ) {
m_holder = other.m_holder->clone();
} else {
m_holder = 0;
}
return *this;
}
SlotHolder():m_holder( 0 ) { }
protected:
explicit SlotHolder(CallbackHolder* holder):
m_holder( holder ) {
}
CallbackHolder* m_holder;
}; };
/// Slot with no argument. template<typename ReturnType, typename Arg1, typename Arg2>
template <typename ReturnType> class SlotBase2: public SlotBase {
class Slot0: public SlotHolder {
public: public:
typedef ReturnType (*CallbackType)(CallbackHolder*); virtual ReturnType operator()(Arg1, Arg2) = 0;
template <typename Functor>
Slot0( const Functor& functor ):
SlotHolder( new FunctorHolder<Functor>
(functor, Callback0<Functor, ReturnType>::functionAddress())) {
}
void operator()() {
if (m_holder)
reinterpret_cast<CallbackType>(m_holder->m_callback)( m_holder );
}
}; };
/// Slot with one argument. template<typename ReturnType, typename Arg1, typename Arg2, typename Functor>
template <typename ReturnType, typename Arg1> class Slot2: public SlotBase2<ReturnType, Arg1, Arg2> {
class Slot1:public SlotHolder {
public: public:
typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1); virtual ReturnType operator()(Arg1 arg1, Arg2 arg2) { return m_functor(arg1, arg2); }
template <typename Functor> Slot2(Functor functor) : m_functor(functor) {}
Slot1( const Functor& functor ):
SlotHolder( new FunctorHolder<Functor>
(functor, Callback1<Functor, ReturnType, Arg1>::functionAddress())){
}
void operator()(Arg1 arg) {
if (m_holder)
reinterpret_cast<CallbackType>(m_holder->m_callback)(m_holder, arg);
}
private:
Functor m_functor;
}; };
/// Slot with two arguments template<typename ReturnType, typename Arg1, typename Arg2, typename Arg3>
template <typename ReturnType, typename Arg1, typename Arg2> class SlotBase3: public SlotBase {
class Slot2: public SlotHolder {
public: public:
typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1, Arg2); virtual ReturnType operator()(Arg1, Arg2, Arg3) = 0;
template <typename Functor> virtual ~SlotBase3() {}
Slot2( const Functor& functor ):
SlotHolder( new FunctorHolder<Functor>
(functor, Callback2<Functor, ReturnType, Arg1, Arg2>::functionAddress())){
}
void operator()(Arg1 arg1, Arg2 arg2) {
if (m_holder)
reinterpret_cast<CallbackType>(m_holder->m_callback)(m_holder, arg1, arg2);
}
}; };
/// Slot with three arguments template<typename ReturnType, typename Arg1, typename Arg2, typename Arg3, typename Functor>
template <typename ReturnType, typename Arg1, typename Arg2, typename Arg3> class Slot3: public SlotBase3<ReturnType, Arg1, Arg2, Arg3> {
class Slot3: public SlotHolder {
public: public:
typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1, Arg2, Arg3); virtual ReturnType operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3)
template <typename Functor> { return m_functor(arg1, arg2, arg3); }
Slot3( const Functor& functor ):
SlotHolder( new FunctorHolder<Functor>
(functor, Callback3<Functor, ReturnType, Arg1, Arg2, Arg3>::functionAddress())){
}
void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3) { Slot3(Functor functor) : m_functor(functor) {}
if (m_holder)
reinterpret_cast<CallbackType>(m_holder->m_callback) private:
( m_holder, arg1, arg2, arg3 ); Functor m_functor;
}
}; };
} // namespace SigImpl } // namespace SigImpl