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:
parent
4b47675441
commit
144d716a42
2 changed files with 71 additions and 255 deletions
|
@ -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)
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
275
src/FbTk/Slot.hh
275
src/FbTk/Slot.hh
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue