From bdba377cfd20ba7a2971053a527823e84644e243 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Sat, 2 Feb 2019 16:24:04 +0100 Subject: Update signal_test, fix a few bugs (but doesn't compile yet) Change: signal_test is now a specific test for signal.cpp instead of a general test. --- configure.py | 6 +- engine/include/core/priority.hpp | 2 +- engine/include/core/signal.hpp | 77 +++++++++++++++------- engine/signal.cpp | 19 +----- test/signal_test.cpp | 138 ++++++++++++++------------------------- 5 files changed, 109 insertions(+), 133 deletions(-) diff --git a/configure.py b/configure.py index f0d34f5..0a489bb 100755 --- a/configure.py +++ b/configure.py @@ -107,7 +107,11 @@ with open("build.ninja", "w") as bf: # add tests add_specific_test(bf, "task_test.cpp", ["engine/task.cpp"]) - add_test(bf, "signal_test.cpp", "build/libflatland.so") + add_specific_test(bf, "signal_test.cpp", [ + "engine/task.cpp", + "engine/labelled.cpp", + "engine/signal.cpp", + ]) print("default build/test/signal_test", file=bf) diff --git a/engine/include/core/priority.hpp b/engine/include/core/priority.hpp index 5519327..071b23c 100644 --- a/engine/include/core/priority.hpp +++ b/engine/include/core/priority.hpp @@ -45,7 +45,7 @@ namespace flat { if (auto r = rhs.lock()) { // if both valid, check their priority // in case they are the same, left is prioritized - operator()(l.get(), r.get()); + return 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 fd7d575..865b48b 100644 --- a/engine/include/core/signal.hpp +++ b/engine/include/core/signal.hpp @@ -2,15 +2,13 @@ #include "task.hpp" #include "types.hpp" -#include "object.hpp" #include "priority.hpp" #include "labelled.hpp" #include "debug.hpp" #include #include -#include -#include +#include #include #include #include @@ -23,7 +21,7 @@ namespace flat::core { /* forward decls */ - template + template class listener; namespace helper @@ -37,8 +35,9 @@ namespace flat::core class signal : public prioritized { public: - signal(const signal& other) = delete; + // signal(const signal& other) = delete; signal& operator=(const signal& other) = delete; + virtual ~signal() {} protected: signal(priority_t p) : prioritized(p) {} @@ -58,9 +57,13 @@ namespace flat::core friend class listener; public: - signal(Args&&... args, priority_t p = priority_t::none) - : std::tuple(std::forward(args)...), - helper::signal(p) {} + constexpr signal(Args& ...args) + : std::tuple((args)...), + helper::signal(priority_t::none) {} + + constexpr signal(Args&& ...args) + : std::tuple(std::move(args)...), + helper::signal(priority_t::none) {} }; @@ -80,9 +83,10 @@ namespace flat::core protected: listener() {} + virtual ~listener() {} public: - virtual bool invoke(std::shared_ptr s) = 0; + virtual bool invoke(std::shared_ptr s) const = 0; }; } @@ -91,19 +95,28 @@ namespace flat::core * 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 - class listener : public helper::listener + template + class listener : public helper::listener { public: using callback = typename std::function; using ptr = typename std::shared_ptr>; listener() = delete; - listener(F&& f) : m_callback(std::move(f)) {} + listener(callback f) : m_callback(f) {} // attempt to call m_callback with s as argument // m_callback is called only if the signature matches - bool invoke(std::shared_ptr s) override; + bool invoke(std::shared_ptr s) const override + { + const signal *p = dynamic_cast *>(s.get()); + + if (p != nullptr) + std::apply(m_callback, *p); + + // return true if p was called + return (p != nullptr); + } private: callback m_callback; @@ -119,7 +132,7 @@ namespace flat::core { private: // this is a set because sets do not allow identical elements - std::set> m_listeners; + std::list> m_listeners; queue> m_signals; /// task to call @@ -135,38 +148,52 @@ namespace flat::core // 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 - void emit(const signal& sig) + void emit(const signal sig) { // insert signal and decay it to a non-template // unique_ptr - m_signals.insert(std::make_unique(sig)); + m_signals.insert(std::make_shared(sig)); } /// for each signal accumulated, call each listener void broadcast(); /// connect a standalone function - template - std::shared_ptr> connect(listener::callback f) + template + std::shared_ptr> _connect(std::function f) { auto lis_ptr = std::make_shared>(f); // insert listener and decay it to a non-template // weak_ptr - m_listeners.insert(lis_ptr); + m_listeners.push_back( + static_cast>(lis_ptr) + ); return lis_ptr; } + template + std::shared_ptr> connect(R (*f)(Args...)) + { + return _connect(static_cast>( + [=](Args ...args) -> R { + return f((args)...); + }) + ); + } + /// connect a member function - template - std::shared_ptr> connect(R T::*mf, T& obj) + template + std::shared_ptr> connect(R (T::*mf)(Args ...args), T* obj) { - return connect([mf](Args&& ...args) -> R { - return (mf(args),...); - }); + return _connect(static_cast>( + [=](Args ...args) -> R { + return (obj->*mf)((args)...); + }) + ); } }; } diff --git a/engine/signal.cpp b/engine/signal.cpp index 362fbdf..86861d9 100644 --- a/engine/signal.cpp +++ b/engine/signal.cpp @@ -1,26 +1,11 @@ #include "core/signal.hpp" #include "object.hpp" -#include #include "flatland.hpp" - #include "debug.hpp" -using namespace flat::core; - -/* listener */ - -template -bool listener::invoke(std::shared_ptr s) -{ - const signal *p = dynamic_cast *>(s.get()); - - if (p != nullptr) - std::apply(m_callback, *p); - - // return true if p was called - return (p != nullptr); -} +#include +using namespace flat::core; /* channel */ diff --git a/test/signal_test.cpp b/test/signal_test.cpp index 3b3fab2..b234672 100644 --- a/test/signal_test.cpp +++ b/test/signal_test.cpp @@ -1,126 +1,86 @@ #include "core/signal.hpp" #include "core/task.hpp" -#include "object.hpp" -#include "window.hpp" -#include "flatland.hpp" -#include "exceptions/forcequit.hpp" - #include "debug.hpp" -using namespace std; -using namespace flat; -using namespace flat::core; - +#include -class sender : public object -{ - const char *m_message; - channel::ptr m_chan; -public: - - sender(const char * message, channel::ptr chan) : m_message(message), m_chan(chan) - { - } +using namespace flat::core; - void send() - { - signal msg(m_message); - m_chan->emit(m_msg); - } -}; -void function_listener(const char *msg) -{ - cout << "Funzione: " << msg << endl; +void got_signal(int x, double y) { + npdebug("got signal with x=", x, " and y=", y); } -class c_listener + +class test_emitter { - std::shared_ptr> lis; +private: + channel& m_chan; public: + test_emitter(channel& ch) : m_chan(ch) {} - c_listener(channel::ptr chan) - { - m_lis = chan->connect(&c_listener::method_listener, this); + void send_str(const std::string& msg) { + m_chan.emit(signal(msg)); + npdebug("emitted signal with msg=", msg); } - void method_listener(const char *msg) - { - cout << "Metodo: " << msg << endl; + void send_num(int n) { + m_chan.emit(signal(n)); + npdebug("emitted signal with n=", n); } }; -/* Objects definition */ - -channel::ptr alpha; -sender * m_sender; -c_listener * m_listener; -std::shared_ptr> f_listener; -int steps = 0; - -void lifeloop() +class test_listener { - if (!(steps % 10)) - cout << "Step: " << steps << endl; - - if (!(steps % 40)) - m_sender->send(); +private: + template + using listener_of = typename std::shared_ptr>; - if (++steps > 200) - { - signal quit("quit"); + listener_of str_lis; + listener_of num_lis; - // quit request - flat::core_channel().emit(quit); +public: + test_listener(channel& ch) { + str_lis = ch.connect(&test_listener::got_string, this); + num_lis = ch.connect(&test_listener::got_number, this); } - if (steps > 205) - throw flat::ForceQuit("Too many steps"); -} - -int main() -{ - FlatWindow win(600, 900, "Test 3"); - flat_status status; - - npdebug("Initializing channel alpha") - - alpha = channel::create("alpha"); - - if (alpha == nullptr) - { - cout << "Could not create channel alpha" << endl; - return -1; + void got_string(const std::string& msg) { + npdebug("got signal with msg=", msg); } - // create sender - m_sender = new sender("Ciao", alpha); - m_listener = new c_listener(alpha); - - // Connect listener to alpha channel - f_listener = alpha->connect(&function_listener); + void got_number(int n) { + npdebug("got signal with n=", n); + } +}; - // bind counter task - task::ptr looptask = flat::main_job().delegate_task(lifeloop); - init_flatland(&win, status, 60); +int main() { + // create a job to propagate signals + job broadcaster; + + // create a channel + channel chan(broadcaster); - npdebug("Deleting m_sender") - delete m_sender; + // test with a function + chan.connect(got_signal); + chan.emit(signal(100, 293.0)); - npdebug("Deleting m_listener") - delete m_listener; + // call job to propagate signals + broadcaster(); - alpha = nullptr; // out of scope - f_listener = nullptr; + // test with members + test_emitter e(chan); + test_listener l(chan); - npdebug("alpha use count: ", alpha.use_count()) - npdebug("f_listener use count: ", f_listener.use_count()) + e.send_str("hello world!"); + e.send_num(42); - npdebug("Exiting") + // call job to propagate signals + broadcaster(); return 0; } -- cgit v1.2.1