summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorancarola <raffaele.ancarola@epfl.ch>2019-01-28 23:32:05 +0100
committerancarola <raffaele.ancarola@epfl.ch>2019-01-28 23:32:05 +0100
commit62d4db15ed7ff5fd0a1fbd019542f038e6891f7b (patch)
tree5157b7a480d4be94022481a2acea5a979c35a93f
parentListener pre-reconstruction (diff)
downloadflatland-62d4db15ed7ff5fd0a1fbd019542f038e6891f7b.tar.gz
flatland-62d4db15ed7ff5fd0a1fbd019542f038e6891f7b.zip
Experimental status of signal
-rw-r--r--engine/include/core/signal.hpp203
-rw-r--r--engine/signal.cpp102
2 files changed, 170 insertions, 135 deletions
diff --git a/engine/include/core/signal.hpp b/engine/include/core/signal.hpp
index 4a4345c..fbcd043 100644
--- a/engine/include/core/signal.hpp
+++ b/engine/include/core/signal.hpp
@@ -9,9 +9,37 @@
#include "object.hpp"
#include <functional>
#include <memory>
+#include <cstddef>
+#include <type_traits>
#include "priority.hpp"
#include "labelled.hpp"
+/*
+ * Some tools for variadic binding templates
+ */
+
+namespace helper
+{
+
+ template<int...> struct int_sequence {};
+
+ template<int N, int... Is> struct make_int_sequence
+ : make_int_sequence<N-1, N-1, Is...> {};
+ template<int... Is> struct make_int_sequence<0, Is...>
+ : int_sequence<Is...> {};
+
+ template<int>
+ struct placeholder_template {};
+}
+
+namespace std
+{
+ template<int N>
+ struct is_placeholder< helper::placeholder_template<N> >
+ : integral_constant<int, N+1> // the one is important
+ {};
+}
+
namespace flat
{
//class object;
@@ -19,80 +47,106 @@ namespace flat
namespace core
{
- class signal : virtual public labelled, virtual public prioritized
+ /*
+ * Signal class
+ */
+
+ struct abstract_signal : public labelled, public prioritized
+ {
+ abstract_signal(const std::string& id = "", priority_t prior = priority_t::none);
+
+ // virtual destructor, sure to call right class destructor
+ virtual ~abstract_signal() {}
+ };
+
+ template <class ...Args>
+ struct signal : public abstract_signal
{
- public:
+ std::tuple<Args...> args;
+
+ signal( Args&& ... args,
+ const std::string& id = "",
+ priority_t prior = priority_t::none)
- struct package
+ : abstract_signal(id, prior), args(std::forward<Args>(args)...)
{
- package(void *data) : data(data) {}
- template<class T>
- T * get() {
+ }
- return reinterpret_cast<T*>(data);
- }
+ /* Alias to flat::core::channel::emit() */
+ //bool emit(const std::string& channel) const;
+ };
- void * data;
- };
-
- object * sender;
- package m_package;
+ class abstract_listener
+ {
+ std::list<std::string> filters;
+
+ protected:
- signal( object * sender,
- const std::string& id = "",
- void * data = 0,
- priority_t prior = priority_t::none);
+ bool check_in_filters(const std::string&) const;
- /* Alias to flat::core::channel::emit() */
- bool emit(const std::string& channel) const;
+ bool match_filters(const abstract_signal *sig) const;
+
+ public:
+
+ abstract_listener(const std::initializer_list<std::string>& filters = {});
+ virtual ~abstract_listener();
+
+ void add_filter(const std::string&);
+ void remove_filter(const std::string&);
+
+ virtual void invoke(const abstract_signal&) = 0;
};
/* Listener class */
- class listener
+ template <class ...Args>
+ class listener : public abstract_listener
{
public:
- using callback = std::function<void(const object*, signal::package)>;
- using ptr = std::shared_ptr<listener>;
+ using callback = std::function<void(Args...)>;
+ using ptr = std::shared_ptr<listener<Args...>>;
- listener(callback m_callback, const std::initializer_list<std::string>& filters = {});
- ~listener();
+ listener(callback m_callback, const std::initializer_list<std::string>& filters = {})
+ : abstract_listener(filters), m_callback(m_callback)
+ {
- void add_filter(const std::string&);
- void remove_filter(const std::string&);
+ }
- bool connect(const std::string&);
- bool disconnect(const std::string&);
+ //bool connect(const std::string&);
+ //bool disconnect(const std::string&);
- void invoke(const signal&);
+ template<int ...Is>
+ void invoke(abstract_signal *sig, helper::int_sequence<Is...>)
+ {
+ signal<Args...>* pt = dynamic_cast<signal<Args...>*>(sig);
+
+ // check if the arguments and the filters match
+ if (pt && match_filters(sig))
+ m_callback(std::get<Is>(pt->args)...);
+ }
- /* Allow to safely bind a functor */
- template<typename R, typename T>
- static ptr create( R T::*mf,
- T& obj,
- const std::initializer_list<std::string>& filters = {}) {
- return std::make_shared<listener>(std::bind(mf, obj), filters);
+ // implement base class method
+ virtual bool invoke(abstract_signal* sig) override
+ {
+ return invoke(sig, helper::make_int_sequence<sizeof...(Args)>{});
}
private:
callback m_callback;
-
- std::list<std::string> filters;
-
- bool check_in_filters(const std::string&) const;
};
+
/* Channel class */
class channel : virtual public labelled, public std::enable_shared_from_this<channel>
{
/* Post processing signal stacking */
- queue<signal> stack;
+ queue<std::unique_ptr<abstract_signal>> stack;
/* Listeners list */
- std::list<std::weak_ptr<listener>> listeners;
+ std::list<std::weak_ptr<abstract_listener>> listeners;
/* Synchronous task checking for signals */
task::ptr checker;
@@ -103,7 +157,9 @@ namespace flat
bool mapped;
bool map();
-
+
+ bool connect(std::shared_ptr<abstract_listener> l);
+
public:
using ptr = std::shared_ptr<channel>;
@@ -124,14 +180,32 @@ namespace flat
// it does not have any sense to create a channel with the same name
channel(const channel&) = delete;
channel& operator=(const channel&) = delete;
-
- void emit(const signal&);
+
+ template<class ...Args>
+ void emit(const signal<Args...>& sig)
+ {
+ stack.insert(std::make_unique<abstract_signal>(sig));
+ npdebug("Emitted signal: ", sig.label, " ", this);
+ }
+
- bool connect(listener::ptr l);
- void disconnect(listener::ptr l);
+ template<class ...Args>
+ void disconnect(listener<Args...>::ptr l)
+ {
+ listeners.remove_if(
+ [l](std::weak_ptr<listener> p){
+
+ listener::ptr pt = p.lock();
+ return pt.get() == l.get();
+ });
+ }
- bool connect(listener* l);
- void disconnect(listener* l);
+ template<class ...Args>
+ void disconnect(listener<Args...>* l)
+ {
+ listener<Args...>::ptr pt(l);
+ disconnect<Args...>(pt);
+ }
/*
* Check for legacy
@@ -148,17 +222,40 @@ namespace flat
*/
bool start(priority_t task_priority = priority_t::none, job * _job = NULL);
+ /*
+ * Successfully stops the channel
+ * Any related job is then detached
+ */
void finalize();
- listener::ptr connect(listener::callback f,
- const std::initializer_list<std::string>& filters = {});
+ /*
+ * Connects any bound function to the channel and
+ * returns the corresponding listener
+ */
+ template<class ...Args>
+ listener<Args...>::ptr connect( listener<Args...>::callback f,
+ const std::initializer_list<std::string>& filters = {})
+ {
+ listener<Args...>::ptr lis = std::make_shared<listener<Args..>>(f, filters);
+
+ if (connect(static_pointer_cast<abstract_listener>(lis)))
+ return lis;
- template<typename R, typename T>
+ return nullptr;
+ }
+
+ /*
+ * Connect a class member function and returns the
+ * corresponding listener
+ */
+ template<typename R, typename T, class Args...>
inline listener::ptr connect(R T::*mf, T* obj,
const std::initializer_list<std::string>& filters = {})
{
- using namespace std::placeholders;
- return connect(std::bind(mf, obj, _1, _2), filters);
+ //using namespace std::placeholders;
+ //return connect<Args...>(std::bind(mf, obj, _1, _2), filters);
+ using namespace helper;
+ return connect<Args...>(std::bind(mf, obj, make_int_sequence<sizeof...(Args)>{}), filters);
}
/*
diff --git a/engine/signal.cpp b/engine/signal.cpp
index c5b5ad4..675bdc8 100644
--- a/engine/signal.cpp
+++ b/engine/signal.cpp
@@ -68,13 +68,7 @@ bool channel::map()
return mapped;
}
-void channel::emit(const signal& sig)
-{
- stack.insert(sig);
- npdebug("Emitted signal: ", sig.label, " ", this);
-}
-
-bool channel::connect(listener::ptr l)
+bool channel::connect(std::shared_ptr<abstract_listener> l)
{
/* Control not to double */
for (auto lis : listeners)
@@ -89,38 +83,6 @@ bool channel::connect(listener::ptr l)
return true;
}
-void channel::disconnect(listener::ptr l)
-{
- listeners.remove_if(
- [l](std::weak_ptr<listener> p){
-
- listener::ptr pt = p.lock();
- return pt.get() == l.get();
- });
-}
-
-bool channel::connect(listener* l)
-{
- listener::ptr pt(l);
- return connect(pt);
-}
-
-void channel::disconnect(listener* l)
-{
- listener::ptr pt(l);
- disconnect(pt);
-}
-
-listener::ptr channel::connect(listener::callback f, const std::initializer_list<std::string>& filters)
-{
- listener::ptr lis = std::make_shared<listener>(f, filters);
-
- if (connect(lis))
- return lis;
-
- return nullptr;
-}
-
bool channel::legit() const
{
return mapped;
@@ -150,19 +112,22 @@ void channel::check_and_call()
npdebug("Signal detected: ", label, " ", this)
- std::vector<std::weak_ptr<listener>> to_erase;
+ std::vector<std::weak_ptr<abstract_listener>> to_erase;
// TODO, maybe it exists pop
/* for each listener_s, catch signal */
for (auto l : listeners)
{
- listener::ptr pt;
+ std::shared_ptr<abstract_listener> pt;
if (pt = l.lock())
{
for (const auto& sig : stack)
- pt->invoke(sig);
+ {
+ // pass simple pointer
+ pt->invoke(sig.get());
+ }
}
else
to_erase.push_back(l);
@@ -170,7 +135,7 @@ void channel::check_and_call()
/* Erase invalidated listeners */
listeners.remove_if(
- [](std::weak_ptr<listener> e) { return e.expired(); });
+ [](std::weak_ptr<abstract_listener> e) { return e.expired(); });
stack.clear(); // TODO not so efficient
}
@@ -179,46 +144,40 @@ void channel::check_and_call()
/* signal class */
-signal::signal( object *sender,
- const std::string& id,
- void *data,
- priority_t priority)
+abstract_signal::abstract_signal(const std::string& id, priority_t priority)
: labelled(id, true),
prioritized(priority),
- sender(sender),
- m_package(package(data))
{
}
-bool signal::emit(const std::string& chan) const
+/*bool signal::emit(const std::string& chan) const
{
channel::ptr c = channel::find(chan);
if (!c)
return false;
- /* Finally emit in channel */
c->emit(*this);
return true;
-}
+}*/
/* listener_s class */
-listener::listener(callback m_callback, const std::initializer_list<std::string>& filters)
+abstract_listener::abstract_listener(const std::initializer_list<std::string>& filters)
- : m_callback(m_callback), filters(filters)
+ : filters(filters)
{
}
-listener::~listener()
+abstract_listener::~abstract_listener()
{
}
-bool listener::check_in_filters(const std::string& filter) const
+bool abstract_listener::check_in_filters(const std::string& filter) const
{
for (const auto& f : filters)
{
@@ -229,40 +188,19 @@ bool listener::check_in_filters(const std::string& filter) const
return false;
}
-void listener::add_filter(const std::string& f)
+void abstract_listener::add_filter(const std::string& f)
{
filters.push_back(f);
}
-void listener::remove_filter(const std::string& f)
+void abstract_listener::remove_filter(const std::string& f)
{
filters.remove(f);
}
-bool listener::connect(const std::string& chan)
-{
- channel::ptr c = channel::find(chan);
-
- if (!c)
- c->connect(this);
-
- return bool(c);
-}
-
-bool listener::disconnect(const std::string& chan)
-{
- channel::ptr c = channel::find(chan);
-
- if (!c)
- c->disconnect(this);
-
- return bool(c);
-}
-
-void listener::invoke(const signal& sig)
+bool abstract_listener::match_filters(const abstract_signal *sig) const
{
- if ( (!sig.label.empty() && check_in_filters(sig.label)) ||
- (sig.label.empty() && filters.empty()))
- m_callback(sig.sender, sig.m_package);
+ return (!sig.label.empty() && check_in_filters(sig.label)) ||
+ (sig.label.empty() && filters.empty());
}