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
#define FBTK_SIGNAL_HH
#include "RefCount.hh"
#include "Slot.hh"
#include <list>
#include <map>
@ -49,7 +50,7 @@ public:
};
/// Do not use this type outside this class
typedef std::list<SlotHolder> SlotList;
typedef std::list<RefCount<SlotBase> > SlotList;
typedef SlotList::iterator Iterator;
typedef Iterator SlotID;
@ -91,7 +92,7 @@ protected:
Iterator end() { return m_slots.end(); }
/// 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);
}
@ -111,16 +112,17 @@ template <typename ReturnType,
typename Arg1 = SigImpl::EmptyArg, typename Arg2 = SigImpl::EmptyArg, typename Arg3 = SigImpl::EmptyArg >
class Signal: public SigImpl::SignalHolder {
public:
typedef SigImpl::Slot3<ReturnType, Arg1, Arg2, Arg3> SlotType;
void emit(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
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) {
return SignalHolder::connect(slot);
template<typename Functor>
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>
class Signal<ReturnType, Arg1, Arg2, SigImpl::EmptyArg>: public SigImpl::SignalHolder {
public:
typedef SigImpl::Slot2<ReturnType, Arg1, Arg2> SlotType;
void emit(Arg1 arg1, Arg2 arg2) {
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) {
return SignalHolder::connect(slot);
template<typename Functor>
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>
class Signal<ReturnType, Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder {
public:
typedef SigImpl::Slot1<ReturnType, Arg1> SlotType;
void emit(Arg1 arg) {
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) {
return SignalHolder::connect(slot);
template<typename Functor>
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>
class Signal<ReturnType, SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder {
public:
typedef SigImpl::Slot0<ReturnType> SlotType;
void emit() {
for ( Iterator it = begin(); it != end(); ++it ) {
static_cast<SlotType&>(*it)();
static_cast<SigImpl::SlotBase0<ReturnType> &>(**it)();
}
}
SlotID connect(const SlotType& slot) {
return SignalHolder::connect(slot);
template<typename Functor>
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 SigImpl {
class CallbackHolder;
/// 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 {
class SlotBase {
public:
/**
* @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) { }
virtual ~SlotBase() {}
};
~CallbackHolder() {
(*m_kill)(this);
}
template<typename ReturnType>
class SlotBase0: public SlotBase {
public:
virtual ReturnType operator()() = 0;
};
/// @return a clone of this instance
CallbackHolder* clone() {
return (*m_clone)(this);
}
template<typename ReturnType, typename Functor>
class Slot0: public SlotBase0<ReturnType> {
public:
virtual ReturnType operator()() { return m_functor(); }
/// \c Callback to \c Functor specific callback
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;
}
Slot0(Functor functor) : m_functor(functor) {}
private:
/// This function is called to kill this instance
KillFunc m_kill;
/// Functions that knows how to clone a specific \c Functor type
CloneFunc m_clone;
Functor m_functor;
};
/// Holds the functor and creates a clone callback for \c Functor specific type
template <typename Functor>
class FunctorHolder: public CallbackHolder {
template<typename ReturnType, typename Arg1>
class SlotBase1: public SlotBase {
public:
/// This type.
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.
virtual ReturnType operator()(Arg1) = 0;
};
/// 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 {
template<typename ReturnType, typename Arg1, typename Functor>
class Slot1: public SlotBase1<ReturnType, Arg1> {
public:
SlotHolder(const SlotHolder& other):
m_holder( other.m_holder ? other.m_holder->clone() : 0 ) {
}
virtual ReturnType operator()(Arg1 arg1) { return m_functor(arg1); }
~SlotHolder() {
delete m_holder;
}
Slot1(Functor functor) : m_functor(functor) {}
SlotHolder& operator = (const SlotHolder& other) {
if ( &other == this ) {
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;
private:
Functor m_functor;
};
/// Slot with no argument.
template <typename ReturnType>
class Slot0: public SlotHolder {
template<typename ReturnType, typename Arg1, typename Arg2>
class SlotBase2: public SlotBase {
public:
typedef ReturnType (*CallbackType)(CallbackHolder*);
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 );
}
virtual ReturnType operator()(Arg1, Arg2) = 0;
};
/// Slot with one argument.
template <typename ReturnType, typename Arg1>
class Slot1:public SlotHolder {
template<typename ReturnType, typename Arg1, typename Arg2, typename Functor>
class Slot2: public SlotBase2<ReturnType, Arg1, Arg2> {
public:
typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1);
virtual ReturnType operator()(Arg1 arg1, Arg2 arg2) { return m_functor(arg1, arg2); }
template <typename 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);
}
Slot2(Functor functor) : m_functor(functor) {}
private:
Functor m_functor;
};
/// Slot with two arguments
template <typename ReturnType, typename Arg1, typename Arg2>
class Slot2: public SlotHolder {
template<typename ReturnType, typename Arg1, typename Arg2, typename Arg3>
class SlotBase3: public SlotBase {
public:
typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1, Arg2);
template <typename Functor>
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);
}
virtual ReturnType operator()(Arg1, Arg2, Arg3) = 0;
virtual ~SlotBase3() {}
};
/// Slot with three arguments
template <typename ReturnType, typename Arg1, typename Arg2, typename Arg3>
class Slot3: public SlotHolder {
template<typename ReturnType, typename Arg1, typename Arg2, typename Arg3, typename Functor>
class Slot3: public SlotBase3<ReturnType, Arg1, Arg2, Arg3> {
public:
typedef ReturnType (*CallbackType)(CallbackHolder*, Arg1, Arg2, Arg3);
template <typename Functor>
Slot3( const Functor& functor ):
SlotHolder( new FunctorHolder<Functor>
(functor, Callback3<Functor, ReturnType, Arg1, Arg2, Arg3>::functionAddress())){
virtual ReturnType operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3)
{ return m_functor(arg1, arg2, arg3); }
}
Slot3(Functor functor) : m_functor(functor) {}
void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
if (m_holder)
reinterpret_cast<CallbackType>(m_holder->m_callback)
( m_holder, arg1, arg2, arg3 );
}
private:
Functor m_functor;
};
} // namespace SigImpl