summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNao Pross <naopross@thearcway.org>2019-02-01 21:49:57 +0100
committerNao Pross <naopross@thearcway.org>2019-02-01 21:49:57 +0100
commit6d568f45f3db041c8726eca2aa48b0f1bc3c105c (patch)
tree161242504354db301da31e789f8a6b6b71c8507f
parentdasf (diff)
downloadflatland-6d568f45f3db041c8726eca2aa48b0f1bc3c105c.tar.gz
flatland-6d568f45f3db041c8726eca2aa48b0f1bc3c105c.zip
Rewrite signal.hpp and signal.cpp to NOT use std::sequence(s)
Its a f*cking mess right now.
-rw-r--r--engine/include/core/priority.hpp16
-rw-r--r--engine/include/core/signal.hpp367
-rw-r--r--engine/signal.cpp198
m---------lib/libwsdl20
4 files changed, 141 insertions, 440 deletions
diff --git a/engine/include/core/priority.hpp b/engine/include/core/priority.hpp
index ae4a6db..5519327 100644
--- a/engine/include/core/priority.hpp
+++ b/engine/include/core/priority.hpp
@@ -28,12 +28,24 @@ namespace flat {
return lhs.priority < rhs.priority;
}
- bool operator()(const std::weak_ptr<prioritized> lhs, const std::weak_ptr<prioritized> rhs) {
+ bool operator()(const prioritized * const lhs, const prioritized * const rhs) {
+ return lhs->priority < rhs->priority;
+ }
+
+ bool operator()(const std::unique_ptr<const prioritized> lhs,
+ const std::unique_ptr<const prioritized> rhs)
+ {
+ return operator()(lhs.get(), rhs.get());
+ }
+
+ bool operator()(const std::weak_ptr<const prioritized> lhs,
+ const std::weak_ptr<prioritized> rhs)
+ {
if (auto l = lhs.lock()) {
if (auto r = rhs.lock()) {
// if both valid, check their priority
// in case they are the same, left is prioritized
- return l->priority < r->priority;
+ operator()(l.get(), r.get());
} else {
// if right is expired, left is prioritized
return true;
diff --git a/engine/include/core/signal.hpp b/engine/include/core/signal.hpp
index 2ead34a..fd7d575 100644
--- a/engine/include/core/signal.hpp
+++ b/engine/include/core/signal.hpp
@@ -1,328 +1,173 @@
#pragma once
+#include "task.hpp"
+#include "types.hpp"
+#include "object.hpp"
+#include "priority.hpp"
+#include "labelled.hpp"
+#include "debug.hpp"
+
#include <map>
#include <list>
#include <set>
#include <initializer_list>
-#include "task.hpp"
-#include "types.hpp"
-#include "object.hpp"
#include <functional>
#include <memory>
#include <cstddef>
#include <type_traits>
-#include "priority.hpp"
-#include "labelled.hpp"
-
-#include "debug.hpp" // debug header
/*
* 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<std::size_t>
- struct placeholder_template {};
-}
-
-namespace std
+namespace flat::core
{
- template<size_t N>
- struct is_placeholder< helper::placeholder_template<N> >
- : integral_constant<size_t, N+1> // the one is important
- {};
-}
+ /* forward decls */
+ template<typename F, typename ...Args>
+ class listener;
-namespace flat
-{
- //class object;
-
- namespace core
+ namespace helper
{
+ /* class helper::signal
+ *
+ * is a non constructible, non copyable object used only as abstract
+ * pointer type. To make anything with it must be first downcasted to a
+ * core::signal<Args...>
+ */
+ class signal : public prioritized
+ {
+ public:
+ signal(const signal& other) = delete;
+ signal& operator=(const signal& other) = delete;
- /*
- * Signal class
- */
+ protected:
+ signal(priority_t p) : prioritized(p) {}
+ };
+ }
- struct abstract_signal : public labelled, public prioritized
+ /* class signal<...Args>
+ *
+ * is a specialized tuple that contains funnction arguments (...Args)
+ * that are later used to calll a callback stored in a listener.
+ */
+ template <typename ...Args>
+ class signal : private std::tuple<Args...>, public helper::signal
{
- abstract_signal(const std::string& id = "", priority_t prior = priority_t::none);
-
- // virtual destructor, sure to call right class destructor
- virtual ~abstract_signal() {}
+ private:
+ /// listener with the same signature is allowed to peek
+ friend class listener<Args...>;
+
+ public:
+ signal(Args&&... args, priority_t p = priority_t::none)
+ : std::tuple<Args...>(std::forward<Args>(args)...),
+ helper::signal(p) {}
};
- template <class ...Args>
- struct signal : public abstract_signal
- {
-
- std::tuple<Args...> args;
-
- signal( Args ... args,
- const std::string& id = "",
- priority_t prior = priority_t::none)
-
- : abstract_signal(id, prior),
- args(std::forward<Args>(args)...)
- {
-
- }
-
- /* Alias to flat::core::channel::emit() */
- //bool emit(const std::string& channel) const;
- };
- class abstract_listener
+ namespace helper
{
- std::list<std::string> filters;
-
- protected:
-
- bool check_in_filters(const std::string&) const;
-
- bool match_filters(const abstract_signal *sig) const;
-
- public:
-
- abstract_listener(const std::initializer_list<std::string>& filters = {});
- virtual ~abstract_listener();
+ /* class helper::listener
+ *
+ * is a non constructible, non copyable object used only as abstract
+ * pointer type. To make anything with it must be first downcasted to a
+ * core::listener<Args...>
+ */
+ class listener
+ {
+ private:
+ listener(const signal& other) = delete;
+ listener& operator=(const listener& other) = delete;
- void add_filter(const std::string&);
- void remove_filter(const std::string&);
+ protected:
+ listener() {}
- virtual bool invoke(const abstract_signal *) = 0;
- };
+ public:
+ virtual bool invoke(std::shared_ptr<const helper::signal> s) = 0;
+ };
+ }
- /* Listener class */
- template <class ...Args>
- class listener : public abstract_listener
+ /* class listener<F, ...Args>
+ *
+ * is an object holding a callback, that can be only called by passing
+ * a signal<...Args> object, which contains the arguments for the callback.
+ */
+ template <typename F, typename ...Args>
+ class listener : public helper::listener
{
-
public:
-
using callback = typename std::function<void(Args...)>;
using ptr = typename std::shared_ptr<listener<Args...>>;
- listener(callback m_callback, const std::initializer_list<std::string>& filters = {})
- : abstract_listener(filters), m_callback(m_callback)
- {
-
- }
-
- //bool connect(const std::string&);
- //bool disconnect(const std::string&);
-
- template<std::size_t ...Is>
- void invoke(const abstract_signal * sig, std::index_sequence<Is...>)
- {
- const signal<Args...> * pt = dynamic_cast<const signal<Args...>*>(sig);
+ listener() = delete;
+ listener(F&& f) : m_callback(std::move(f)) {}
- // check if the arguments and the filters match
- if (pt && match_filters(sig))
- m_callback(std::get<Is>(pt->args)...);
- }
-
- // implement base class method
- virtual bool invoke(const abstract_signal * sig) override
- {
- return invoke(sig, std::make_index_sequence<sizeof...(Args)>{});
- }
+ // attempt to call m_callback with s as argument
+ // m_callback is called only if the signature matches
+ bool invoke(std::shared_ptr<const helper::signal> s) override;
private:
-
callback m_callback;
};
- /* Channel class */
+ /* class channel
+ *
+ * is an object type through which signals are emitted.
+ * and is an object type through which listener get their signals.
+ */
class channel : virtual public labelled, public std::enable_shared_from_this<channel>
{
- /* Post processing signal stacking */
- queue<std::unique_ptr<abstract_signal>> stack;
-
- /* Listeners list */
- std::list<std::weak_ptr<abstract_listener>> listeners;
-
- /* Synchronous task checking for signals */
- task::ptr checker;
-
- /* Channel mapping */
- static std::map<std::string, std::weak_ptr<channel>> channels;
-
- bool mapped;
-
- bool map();
-
- bool connect(std::shared_ptr<abstract_listener> l);
-
- /*
- * Connects any bound function to the channel and
- * returns the corresponding listener
- */
- template<class ...Args>
- std::shared_ptr<listener<Args...>> _connect(std::function<void(Args...)> f,
- const std::initializer_list<std::string>& filters = {})
- {
- std::shared_ptr<listener<Args...>> lis =
- std::make_shared<listener<Args...>>(f, filters);
-
- if (connect(std::static_pointer_cast<abstract_listener>(lis)))
- return lis;
+ private:
+ // this is a set because sets do not allow identical elements
+ std::set<std::weak_ptr<helper::listener>> m_listeners;
+ queue<std::shared_ptr<helper::signal>> m_signals;
- return nullptr;
- }
+ /// task to call
+ std::shared_ptr<task> m_broadcast;
public:
-
using ptr = std::shared_ptr<channel>;
- /*
- * Constructs a new channel and try to bind it the specified job
- * If no job is specified, then flat::main_job will be taken
- *
- * Note: Remember to check for channel legacy with legit() member function
- * A channel is legit if and only if there's no other channel
- * corresponding to the same label name
- * In general, a channel must be UNIQUE with its label
- */
- channel(const std::string& id = "");
- ~channel();
+ // TODO: channel() that binds to main_job
+ channel(job& broadcaster);
// do not allow to copy a channel
- // it does not have any sense to create a channel with the same name
+ // it does not make sense to create a channel with the same name
channel(const channel&) = delete;
channel& operator=(const channel&) = delete;
+ /// add a signal to the queue/stack of signals (m_signals)
template<class ...Args>
void emit(const signal<Args...>& sig)
{
- stack.insert(std::make_unique<abstract_signal>(sig));
- npdebug("Emitted signal: ", sig.label, " ", this);
+ // insert signal and decay it to a non-template
+ // unique_ptr<helper::signal>
+ m_signals.insert(std::make_unique<helper::signal>(sig));
}
-
- template<class ...Args>
- void disconnect(typename listener<Args...>::ptr l)
- {
- listeners.remove_if(
- [l](std::weak_ptr<abstract_listener> p){
-
- typename listener<Args...>::ptr pt = p.lock();
- return pt.get() == l.get();
- });
- }
+ /// for each signal accumulated, call each listener
+ void broadcast();
- template<class ...Args>
- void disconnect(listener<Args...>* l)
+ /// connect a standalone function
+ template<typename F, typename ...Args>
+ std::shared_ptr<listener<F, Args...>> connect(listener<F, Args...>::callback f)
{
- typename listener<Args...>::ptr pt(l);
- disconnect<Args...>(pt);
- }
-
- /*
- * Check for legacy
- *
- * Note: Channels are mapped by their label.
- * A channel is legit if and only if there's no other channel
- * corresponding to the same label name.
- */
- bool legit() const;
-
- /*
- * It tries binding the channel task and make the channel legit
- * In case of success, true is returned, otherwise false
- */
- bool start(priority_t task_priority = priority_t::none, job * _job = NULL);
+ auto lis_ptr = std::make_shared<listener<Args...>>(f);
+ // insert listener and decay it to a non-template
+ // weak_ptr<helper::listener>
+ m_listeners.insert(lis_ptr);
- /*
- * Successfully stops the channel
- * Any related job is then detached
- */
- void finalize();
-
- /*
- * Connect a function and returns the
- * corresponding listener, placeholder form
- */
- template<typename R, class ...Args, std::size_t ...Is>
- std::shared_ptr<listener<Args...>> p_connect(R (*mf)(Args...), std::index_sequence<Is...>, const std::initializer_list<std::string>& filters = {})
- {
- //using namespace std::placeholders;
- //return connect<Args...>(std::bind(mf, obj, _1, _2), filters);
- //using namespace helper;
- auto b = std::bind(mf, helper::placeholder_template<Is>{}...);
- return _connect(b, filters);
+ return lis_ptr;
}
- /*
- * Connect a function and returns the
- * corresponding listener
- */
- template<typename R, class ...Args>
- std::shared_ptr<listener<Args...>> connect(R (*mf)(Args...), const std::initializer_list<std::string>& filters = {})
+ /// connect a member function
+ template<typename R, typename T, typename F, typename ...Args>
+ std::shared_ptr<listener<F, Args...>> connect(R T::*mf, T& obj)
{
- //using namespace std::placeholders;
- //return connect<Args...>(std::bind(mf, obj, _1, _2), filters);
- //using namespace helper;
- return p_connect(mf, std::make_index_sequence<sizeof...(Args)>{}, filters);
+ return connect([mf](Args&& ...args) -> R {
+ return (mf(args),...);
+ });
}
-
- /*
- * Connect a class member function and returns the
- * corresponding listener, placeholder form
- */
- template<typename R, typename T, class ...Args, size_t ...Is>
- std::shared_ptr<listener<Args...>> c_connect(R (T::*mf)(Args...), T* obj, std::index_sequence<Is...>, const std::initializer_list<std::string>& filters = {})
- {
- //using namespace std::placeholders;
- //return connect<Args...>(std::bind(mf, obj, _1, _2), filters);
- //using namespace helper;
- auto b = std::bind(mf, obj, helper::placeholder_template<Is>{}...);
- return _connect(b, filters);
- }
-
- /*
- * Connect a class member function and returns the
- * corresponding listener
- */
- template<typename R, typename T, class ...Args>
- std::shared_ptr<listener<Args...>> connect(R (T::*mf)(Args...), T* obj, const std::initializer_list<std::string>& filters = {})
- {
- //using namespace std::placeholders;
- //return connect<Args...>(std::bind(mf, obj, _1, _2), filters);
- //using namespace helper;
- return c_connect(mf, obj, std::make_index_sequence<sizeof...(Args)>{}, filters);
- }
-
- /*
- * Find channel by its name
- */
- static ptr find(const std::string&);
-
- /*
- * Safer than constructor
- * It constructs a new channel checking whether it is legit or not.
- * It returns a nullptr if the legacy is not verified.
- *
- * Note: Channels are mapped by their label.
- * A channel is legit if and only if there's no other channel
- * corresponding to the same label name.
- */
- static ptr create(const std::string& id, priority_t prior = priority_t::none, job * _job = NULL);
-
- void check_and_call();
};
-
-
- }
}
diff --git a/engine/signal.cpp b/engine/signal.cpp
index 941d641..362fbdf 100644
--- a/engine/signal.cpp
+++ b/engine/signal.cpp
@@ -7,198 +7,42 @@
using namespace flat::core;
-std::map<std::string, std::weak_ptr<channel>> channel::channels;
+/* listener */
-channel::channel(const std::string& id) : labelled(id), mapped(false)
+template<typename F, typename ...Args>
+bool listener<F, Args ...>::invoke(std::shared_ptr<const helper::signal> s)
{
-}
-
-channel::~channel()
-{
- // by default it should be there
- if (mapped)
- channels.erase(label);
-}
-
-bool channel::start(priority_t prior, job * _job)
-{
- npdebug("Trying to map channel: ", label);
-
- if (map())
- checker.reset(); // force count to zero, it should remove task too
- else
- return false;
-
- npdebug("Starting channel: ", label);
+ const signal<Args...> *p = dynamic_cast<const signal<Args...> *>(s.get());
- // take main job if no job is specified
- if (!_job)
- _job = &flat::main_job();
+ if (p != nullptr)
+ std::apply(m_callback, *p);
- // Initialize task
- checker = _job->delegate_task(&channel::check_and_call, this, prior);
-
- return true;
+ // return true if p was called
+ return (p != nullptr);
}
-void channel::finalize()
-{
- npdebug("Finalizing channel: ", label)
-
- if (mapped) {
- channels.erase(label);
- checker.reset();
- }
-}
+/* channel */
-bool channel::map()
+channel::channel(job& broadcaster)
{
- if (!mapped) {
-
- channel::ptr other = channel::find(label);
-
- if (!other) {
-
- channels.insert(std::pair<std::string, std::weak_ptr<channel>>(label, weak_from_this()));
- mapped = true;
- }
- }
-
- return mapped;
+ m_broadcast = broadcaster.delegate_task(&channel::broadcast, this);
}
-bool channel::connect(std::shared_ptr<abstract_listener> l)
+void channel::broadcast()
{
- /* Control not to double */
- for (auto lis : listeners)
- {
- auto pt = lis.lock();
-
- if (pt.get() == l.get())
- return false;
- }
-
- listeners.push_back(l);
- return true;
-}
-
-bool channel::legit() const
-{
- return mapped;
-}
-
-channel::ptr channel::create(const std::string& id, priority_t prior, job * _job)
-{
- ptr out = std::make_shared<channel>(id);
-
- // do not create a non-legit channel
- return out->start(prior, _job) ? out : nullptr;
-}
-
-channel::ptr channel::find(const std::string& id)
-{
- if (id.empty())
- return nullptr;
-
- auto it = channels.find(id);
-
- return (it == channels.end()) ? nullptr : (*it).second.lock();
-}
-
-void channel::check_and_call()
-{
- if (!stack.empty()) {
-
- npdebug("Signal detected: ", label, " ", this)
-
- std::vector<std::weak_ptr<abstract_listener>> to_erase;
+ std::vector<std::weak_ptr<helper::listener>> to_erase;
- // TODO, maybe it exists pop
- /* for each listener_s, catch signal */
+ for (const auto& sig : m_signals) {
+ for (auto l : m_listeners) {
+ // check that is not expired
+ std::shared_ptr<helper::listener> pt;
- for (auto l : listeners)
- {
- std::shared_ptr<abstract_listener> pt;
-
- if (pt = l.lock())
- {
- for (const auto& sig : stack)
- {
- // pass simple pointer
- pt->invoke(sig.get());
- }
- }
- else
+ if ((pt = l.lock())) {
+ pt->invoke(sig);
+ } else {
to_erase.push_back(l);
+ }
}
-
- /* Erase invalidated listeners */
- listeners.remove_if(
- [](std::weak_ptr<abstract_listener> e) { return e.expired(); });
-
- stack.clear(); // TODO not so efficient
- }
-}
-
-
-/* signal class */
-
-abstract_signal::abstract_signal(const std::string& id, priority_t priority)
-
- : labelled(id, true),
- prioritized(priority) {}
-
-/*bool signal::emit(const std::string& chan) const
-{
- channel::ptr c = channel::find(chan);
-
- if (!c)
- return false;
-
- c->emit(*this);
-
- return true;
-}*/
-
-
-/* listener_s class */
-
-abstract_listener::abstract_listener(const std::initializer_list<std::string>& filters)
-
- : filters(filters)
-{
-
-}
-
-abstract_listener::~abstract_listener()
-{
-}
-
-bool abstract_listener::check_in_filters(const std::string& filter) const
-{
- for (const auto& f : filters)
- {
- if (filter == f)
- return true;
}
-
- return false;
-}
-
-void abstract_listener::add_filter(const std::string& f)
-{
- filters.push_back(f);
-}
-
-void abstract_listener::remove_filter(const std::string& f)
-{
- filters.remove(f);
}
-
-bool abstract_listener::match_filters(const abstract_signal *sig) const
-{
- return (!sig->label.empty() && check_in_filters(sig->label)) ||
- (sig->label.empty() && filters.empty());
-}
-
diff --git a/lib/libwsdl2 b/lib/libwsdl2
-Subproject 736ec71fce673d5aa88228b96acfe6c6862a223
+Subproject 71b593ebd1a015a4cb9bfe0eebafc78d897ff28