diff options
author | Nao Pross <naopross@thearcway.org> | 2019-02-02 22:49:46 +0100 |
---|---|---|
committer | Nao Pross <naopross@thearcway.org> | 2019-02-02 22:49:46 +0100 |
commit | 02acb58b46192660b9a1ba337c037770801e847e (patch) | |
tree | 2a6e63da483498d63aaeab1e0b62b86daee002e8 | |
parent | Fix all template errors, it compiles! (but doesn't work yet) (diff) | |
download | flatland-02acb58b46192660b9a1ba337c037770801e847e.tar.gz flatland-02acb58b46192660b9a1ba337c037770801e847e.zip |
Finish signal, it compiles signal_test and works(!!)
But the whole library doesn't compile yet
-rw-r--r-- | engine/include/core/signal.hpp | 99 | ||||
-rw-r--r-- | engine/signal.cpp | 31 | ||||
-rw-r--r-- | engine/task.cpp | 7 | ||||
-rw-r--r-- | test/signal_test.cpp | 21 |
4 files changed, 101 insertions, 57 deletions
diff --git a/engine/include/core/signal.hpp b/engine/include/core/signal.hpp index 7b5ac3b..a820880 100644 --- a/engine/include/core/signal.hpp +++ b/engine/include/core/signal.hpp @@ -7,12 +7,11 @@ #include "debug.hpp" #include <map> -#include <list> #include <tuple> +#include <list> #include <functional> #include <memory> #include <cstddef> -#include <type_traits> namespace flat::core @@ -41,7 +40,7 @@ namespace flat::core /* class signal<...Args> * - * is a specialized tuple that contains function arguments (...Args) + * is a tuple wrapper that contains function arguments (...Args) * that are later used to call a callback stored in a listener. */ template <typename ...Args> @@ -49,8 +48,18 @@ namespace flat::core { const std::tuple<Args...> args; - explicit constexpr signal(Args... _args) - : args(std::move(_args)...) {} + /// copy constructor + explicit constexpr signal(const Args&... _args) + : args(_args...) {} + + /// move constructor + explicit constexpr signal(Args&&... _args) + : args(std::forward<Args>(_args)...) {} + + // TODO: if needed add copy constructor and move constructor + // not needed yet + // explicit constexpr signal(const signal<Args...>& other) + // : helper::signal(), args(other.args) {} }; @@ -62,7 +71,7 @@ namespace flat::core * pointer type. To make anything with it must be first downcasted to a * core::listener<Args...> */ - class listener + class listener : public std::enable_shared_from_this<listener> { protected: explicit listener() {} @@ -83,21 +92,31 @@ namespace flat::core { public: using callback = typename std::function<void(Args...)>; - using ptr = typename std::shared_ptr<listener<Args...>>; explicit listener(callback f) : m_callback(f) {} + + // TODO: remove + ~listener() { + npdebug("deleted listener ", this); + } // 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) const override { + // TODO: shared dynamic pointer cast const signal<Args...> *p = dynamic_cast<const signal<Args...> *>(s.get()); - if (p != nullptr) - std::apply(m_callback, p->args); + // if dynamic cast fails + if (p == nullptr) { + npdebug("invoked listener ", this, " with non-matching signal ", s); + return false; + } + + npdebug("invoked listener ", this, " with signal ", p); + std::apply(m_callback, p->args); - // return true if p was called - return (p != nullptr); + return true; } private: @@ -119,6 +138,25 @@ namespace flat::core /// task to call std::shared_ptr<task> m_broadcast; + + /// connect a closure / lambda (this is a helper), see others below + template<typename R, typename ...Args> + std::shared_ptr<listener<Args...>> _connect(std::function<R(Args...)> f) + { + auto lis_ptr = std::make_shared<listener<Args...>>(f); + + // insert pointer + m_listeners.push_front( + // decay shared_ptr to weak_ptr + // TODO: static weak + static_cast<std::weak_ptr<helper::listener>>( + // decay listener to helper::listener + std::static_pointer_cast<helper::listener>(lis_ptr) + ) + ); + + return lis_ptr; + } public: using ptr = std::shared_ptr<channel>; @@ -128,30 +166,24 @@ namespace flat::core /// add a signal to the queue/stack of signals (m_signals) template<class ...Args> - void emit(const signal<Args...> sig) + void emit(const signal<Args...>& sig) { - // insert signal and decay it to a non-template - // unique_ptr<helper::signal> - m_signals.insert(std::make_shared<helper::signal>(sig)); - } + // create a shared_ptr + auto p = std::make_shared<signal<Args...>>(sig) - /// for each signal accumulated, call each listener - void broadcast(); + npdebug("emitted signal ", p); - /// connect a standalone function - template<typename R, typename ...Args> - std::shared_ptr<listener<Args...>> _connect(std::function<R(Args...)> f) - { - auto lis_ptr = std::make_shared<listener<Args...>>(f); - // insert listener and decay it to a non-template - // weak_ptr<helper::listener> - m_listeners.push_back( - static_cast<std::weak_ptr<helper::listener>>(lis_ptr) + // insert pointer + m_signals.insert( + // decay signal to helper::signal + std::static_pointer_cast<helper::signal>(p) ); - - return lis_ptr; } + /// for each signal accumulated, call each listener + void broadcast(); + + /// connect a function template<typename R, typename ...Args> std::shared_ptr<listener<Args...>> connect(R (*f)(Args...)) { @@ -175,12 +207,3 @@ namespace flat::core }; } - -namespace std -{ - template<typename... Args> - struct tuple_size<flat::core::signal<Args...>> - { - constexpr static std::size_t value = (0 + ... + sizeof(Args)); - }; -} diff --git a/engine/signal.cpp b/engine/signal.cpp index 86861d9..244e1b7 100644 --- a/engine/signal.cpp +++ b/engine/signal.cpp @@ -16,18 +16,35 @@ channel::channel(job& broadcaster) void channel::broadcast() { - std::vector<std::weak_ptr<helper::listener>> to_erase; + npdebug("broadcasting signals from channel ", this); + std::list<std::weak_ptr<helper::listener>> to_erase; for (const auto& sig : m_signals) { - for (auto l : m_listeners) { - // check that is not expired - std::shared_ptr<helper::listener> pt; + bool invoked = false; - if ((pt = l.lock())) { - pt->invoke(sig); + for (const auto& l : m_listeners) { + if (std::shared_ptr<helper::listener> pt = l.lock()) { + if (pt->invoke(sig)) + invoked = true; } else { - to_erase.push_back(l); + npdebug("found an expired listener"); + to_erase.push_front(l); } } + + if (!invoked) { + npdebug("signal ", sig, " was ignored (not invoked)"); + } } + + // TODO: check if this works + for (const auto& l : to_erase) { + // because weak_ptr do not have operator== + m_listeners.remove_if([&](const auto& v) { + return std::owner_less<std::weak_ptr<helper::listener>>()(l, v); + }); + } + + // release all accumulated signals + m_signals.clear(); } diff --git a/engine/task.cpp b/engine/task.cpp index 6f0c466..d82c107 100644 --- a/engine/task.cpp +++ b/engine/task.cpp @@ -21,7 +21,7 @@ namespace flat { auto shared = std::make_shared<task>(f, p); insert(shared); - npdebug("Task number: ", this->size()); + npdebug("delgated job: ", shared); return shared; } @@ -38,9 +38,12 @@ namespace flat { for (auto tp : *this) { // check that the task has not expired if (std::shared_ptr<task> t = tp.lock()) { + npdebug("invoked job ", t); std::invoke(*t); - } else + } else { to_erase.push_back(tp); + npdebug("found an expired job"); + } } // delete expired tasks diff --git a/test/signal_test.cpp b/test/signal_test.cpp index b234672..99e6747 100644 --- a/test/signal_test.cpp +++ b/test/signal_test.cpp @@ -21,14 +21,14 @@ private: public: test_emitter(channel& ch) : m_chan(ch) {} - void send_str(const std::string& msg) { + void send_str(std::string msg) { + npdebug("emitting signal with msg=", msg); m_chan.emit(signal(msg)); - npdebug("emitted signal with msg=", msg); } void send_num(int n) { + npdebug("emitting signal with n=", n); m_chan.emit(signal(n)); - npdebug("emitted signal with n=", n); } }; @@ -39,16 +39,16 @@ private: template<typename T> using listener_of = typename std::shared_ptr<listener<T>>; - listener_of<const std::string&> str_lis; + listener_of<std::string> str_lis; listener_of<int> num_lis; public: - test_listener(channel& ch) { - str_lis = ch.connect(&test_listener::got_string, this); - num_lis = ch.connect(&test_listener::got_number, this); - } + test_listener(channel& ch) + : str_lis(ch.connect(&test_listener::got_string, this)), + num_lis(ch.connect(&test_listener::got_number, this)) + {} - void got_string(const std::string& msg) { + void got_string(std::string msg) { npdebug("got signal with msg=", msg); } @@ -66,7 +66,8 @@ int main() { channel chan(broadcaster); // test with a function - chan.connect(got_signal); + auto fun_lis = chan.connect(got_signal); + npdebug("emitting signal with x=100, y=293.0"); chan.emit(signal(100, 293.0)); // call job to propagate signals |