Newer
Older
Import / applications / HighwayDash / ports / Framework / Delegates / SignalSlot.h
#ifndef SIGNAL_SLOT_H
#define SIGNAL_SLOT_H


// compile with:
//         g++ -std=c++11 SignalSlot.cpp Test.cpp Variant.cpp main.cpp -o test


#include <vector>
#include <cstdio>
#include <functional>
#include <memory>
#include <utility>
#include <tuple>
#include "Variant.h"
#include "Pointer.h"
//#include "Containers.h"


#include "Namespace.h"
BEGIN_NAMESPACE


//#define slot_ptr        shared_ptr // weak_ptr // shared_ptr
//#define signal_ptr      shared_ptr // weak_ptr
#define slot_ptr        shared_ptr
#define signal_ptr      weak_ptr


template <typename ... Params>
class TSlot
{
public:
	template <typename Function, typename ... Ts>
	//TSlot(Function a_func, Ts... args)
    //  : m_callback(a_func), m_args(args...)
	TSlot(Function a_func, Variant a_v = Variant())
      : m_callback(a_func), m_variant(a_v), m_args(a_v)
	{
	}

    // Objects need to be passed by shared_ptr to properly manage the references to them
	template <class Class, typename Method>
	TSlot(std::slot_ptr<Class> object, Method a_method, Variant a_v = Variant())
      : m_callback(std::bind(a_method, object, std::placeholders::_1)), m_variant(a_v), m_args(a_v)
	{
	}

	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);
	}

/*
    template <typename ...Ts>
    void operator()(Ts ...args) {
        m_callback(args...);
    }
*/
private:
    std::function<void(Params...)> m_callback;
//    std::tuple<Params...>          m_args;
    std::tuple<Variant>            m_args;
	Variant m_variant;
};


template <typename ... Params>
class TSignal
{
public:
	TSignal() : m_insideInvokation(false) {}

	void addConnection(std::signal_ptr<TSlot<Params...> > a_delegate)    { m_connectionList.push_back(a_delegate); }

	void disconnectAll()                                               { m_connectionList.clear(); }

    template <typename ...Ts>
	void operator()(Ts ... args)
	{
		if (!m_insideInvokation) // prevent recursion
		{
			m_insideInvokation = true;
			for (auto s : m_connectionList) {
                if (auto slot = s.lock())
				    (*slot)(args...);
                else
                    printf("couldn't get weak ptr\n");
            }
			m_insideInvokation = false;
		}
	}

private:
    TSignal(TSignal const& a_other) = delete;
    TSignal& operator=(TSignal const & a_other) = delete;
	bool m_insideInvokation;
    std::vector<std::signal_ptr<TSlot<Params... > > > m_connectionList; // weak_ptr needed here
};


typedef TSignal<Variant&>    Signal;
typedef TSlot<Variant&>      Slot;

// These names may be more familiar to others
typedef Signal               Event;
typedef Slot                 Delegate;


template <class Class, typename Method, typename ... Params>
static inline void connect(TSignal<Params...> & a_signal, std::slot_ptr<Class> a_object, Method a_method, Variant a_v = Variant())
{
	a_signal.addConnection(std::make_shared<TSlot<Params...> >(a_object, a_method, a_v));
}


template <typename ... Params>
static inline void connect(TSignal<Params...> & a_signal, TSlot<Params...>& a_slot)
{
	a_signal.addConnection(std::make_shared<TSlot<Params...> >(a_slot));
}


END_NAMESPACE


#endif // SIGNAL_SLOT_H