summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNao Pross <naopross@thearcway.org>2019-02-02 22:49:46 +0100
committerNao Pross <naopross@thearcway.org>2019-02-02 22:49:46 +0100
commit02acb58b46192660b9a1ba337c037770801e847e (patch)
tree2a6e63da483498d63aaeab1e0b62b86daee002e8
parentFix all template errors, it compiles! (but doesn't work yet) (diff)
downloadflatland-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.hpp99
-rw-r--r--engine/signal.cpp31
-rw-r--r--engine/task.cpp7
-rw-r--r--test/signal_test.cpp21
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