#ifndef SIGNAL_SLOT_H
#define SIGNAL_SLOT_H
#include <vector>
#include <cstdio>
#include "Variant.h"
#include "Pointer.h"
#include "Containers.h"
#include "Namespace.h"
BEGIN_NAMESPACE
class Invokable
{
public:
virtual ~Invokable() {}
virtual void operator()(Variant& a_params) = 0;
};
template <typename Method>
class StaticFunctionCallback : public Invokable
{
public:
StaticFunctionCallback(Method a_method)
: m_method(a_method)
{
}
virtual void operator()(Variant& a_params)
{
(*m_method)(a_params);
}
private:
Method m_method;
};
template <class Class, typename Method>
class MethodCallback : public Invokable
{
public:
MethodCallback(Class* a_obj, Method a_method)
: m_object(a_obj)
, m_method(a_method)
{
}
MethodCallback(MethodCallback const& a_other)
{
m_object = a_other.m_object;
//m_object.addRef();
m_method = a_other.m_method;
}
MethodCallback& operator=(MethodCallback const& a_other)
{
m_object = a_other.m_object;
//m_object.addRef();
m_method = a_other.m_method;
return *this;
}
virtual void operator()(Variant& a_params)
{
(m_object->*m_method)(a_params);
}
private:
Class* m_object;
Method m_method;
};
class Slot
{
public:
/*
// rule of three
// How to handle copying of slot objects
// Also need to ensure the safety of the object and method this slot holds going out of scope or being deleted
// Really need object passed in to be a SharedPtr or something that will mean that this slot will know about it
// being deleted
Slot(Slot const& a_other);
Slot& operator=(Slot const & a_other)
{
a_other.swap(*this);
return *this;
}
void swap(Slot & a_other) {
std::swap(placementNewBuffer, a_other.placementNewBuffer);
std::swap(m_callback, a_other.m_callback);
std::swap(m_variant, a_other.m_variant);
}
*/
Slot() : m_callback(0)
{
}
~Slot(void)
{
}
/*
Slot(Slot const& a_other) {
memcpy(placementNewBuffer, a_other.placementNewBuffer, sizeof(placementNewBuffer));
m_callback = a_other.m_callback;
MethodCallback* cb = dynamic_cast<MethodCallback>(m_callback);
if (cb)
cb->m
m_variant = a_other.m_variant;
}
Slot& operator=(Slot const & a_other)
{
memcpy(placementNewBuffer, a_other.placementNewBuffer, sizeof(placementNewBuffer));
m_callback = a_other.m_callback;
m_variant = a_other.m_variant;
return *this;
}
*/
template <typename Method>
Slot(Method a_method, Variant a_v = Variant())
: m_callback(new(placementNewBuffer) StaticFunctionCallback<Method>(a_method)), m_variant(a_v)
{
STATIC_ASSERT(sizeof(StaticFunctionCallback<Method>) <= sizeof(placementNewBuffer), increaseBufferBize);
}
template <class Class, typename Method>
Slot(Class* object, Method a_method, Variant a_v = Variant())
: m_callback(new(placementNewBuffer) MethodCallback<Class,Method>(object, a_method)), m_variant(a_v)
{
STATIC_ASSERT(sizeof(MethodCallback<Class,Method>) <= sizeof(placementNewBuffer), increaseBufferBize);
}
// Need some kind of way to notify when object gets destroyed so that it can remove this slot
void operator()()
{
(*m_callback)(m_variant);
}
void operator()(Variant& a_params)
{
if (m_variant.isValid())
(*m_callback)(m_variant);
else
(*m_callback)(a_params);
}
template <typename T>
void operator()(const T& a_params)
{
Variant v(a_params);
(*this)(v);
}
private:
char placementNewBuffer[24]; // by trial and error, 24 was min to compile x64 using MSVC
Invokable *m_callback;
Variant m_variant;
};
class Signal
{
public:
// Because a Signal holds a list of Slots, the same needs to be
// thought through about the life time of objects and the places that hold references
Signal() : m_insideInvokation(false) {}
//~Signal() { m_connectionList.clear(); }
void addConnection(SharedPtr<Slot>& a_delegate) { m_connectionList.push_back(a_delegate); }
// Need some kind of callback or something that when a slot with an object has that object deleted,
// then the slot get destroyed, and when that happens it disconnects the slot from this signal
void disconnectAll() { m_connectionList.clear(); }
bool disconnectOne(SharedPtr<Slot>& a_delegate) { /* TODO */ return true; }
void operator()()
{
if (!m_insideInvokation) // prevent recursion
{
m_insideInvokation = true;
for (uint32_t i = 0; i < m_connectionList.size(); i++)
(*m_connectionList[i])();
m_insideInvokation = false;
}
}
void operator()(Variant& a_param)
{
if (!m_insideInvokation) // prevent recursion
{
m_insideInvokation = true;
for (uint32_t i = 0; i < m_connectionList.size(); i++)
(*m_connectionList[i])(a_param);
m_insideInvokation = false;
}
}
private:
Signal(Signal const& a_other);
Signal& operator=(Signal const & a_other);
bool m_insideInvokation;
Vector<SharedPtr<Slot> > m_connectionList;
};
//typedef Signal Event;
typedef Slot Delegate;
static inline void connect(Signal& a_signal, Slot& a_slot)
{
SharedPtr<Slot> slot(new Slot(a_slot));
a_signal.addConnection(slot);
}
template <class Class, typename Method>
static inline void connect(Signal& a_signal, Class *a_object, Method a_method, Variant a_v = Variant())
{
SharedPtr<Slot> slot(new Slot(a_object, a_method, a_v));
a_signal.addConnection(slot);
}
END_NAMESPACE
#endif // SIGNAL_SLOT_H