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
|
#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)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
277
src/FbTk/Slot.hh
277
src/FbTk/Slot.hh
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue