diff options
author | ancarola <raffaele.ancarola@epfl.ch> | 2019-01-23 19:43:09 +0100 |
---|---|---|
committer | ancarola <raffaele.ancarola@epfl.ch> | 2019-01-23 19:43:09 +0100 |
commit | 40a2e6ae3d17e271f9eaa07a53d934fc5d5457db (patch) | |
tree | 0da332dbff1d621306d5bfc4d1e54fccb795a206 /engine | |
parent | Task debugging (diff) | |
download | flatland-40a2e6ae3d17e271f9eaa07a53d934fc5d5457db.tar.gz flatland-40a2e6ae3d17e271f9eaa07a53d934fc5d5457db.zip |
Labelled, signal
Diffstat (limited to 'engine')
-rw-r--r-- | engine/include/core/labelled.hpp | 26 | ||||
-rw-r--r-- | engine/include/core/object.hpp | 38 | ||||
-rw-r--r-- | engine/include/core/signal.hpp | 60 | ||||
-rw-r--r-- | engine/include/flatland.h | 20 | ||||
-rw-r--r-- | engine/labelled.cpp | 19 | ||||
-rw-r--r-- | engine/object.cpp | 62 | ||||
-rw-r--r-- | engine/signal.cpp | 126 |
7 files changed, 178 insertions, 173 deletions
diff --git a/engine/include/core/labelled.hpp b/engine/include/core/labelled.hpp new file mode 100644 index 0000000..7363e8d --- /dev/null +++ b/engine/include/core/labelled.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include <list> +#include <vector> +#include <string> +#include <initializer_list> + +#include "types.hpp" + +namespace flat +{ + namespace core + { + class labelled; + } +} + +struct flat::core::labelled +{ + const std::string label; + + labelled(const std::string& label = ""); + + static std::string random_label(uint8_t length = 8); +}; + diff --git a/engine/include/core/object.hpp b/engine/include/core/object.hpp index 1992d2a..cd5da5e 100644 --- a/engine/include/core/object.hpp +++ b/engine/include/core/object.hpp @@ -1,42 +1,12 @@ #pragma once -#include <list> -#include <vector> -#include <string> -#include <initializer_list> - -#include "types.hpp" - namespace flat { namespace core { - class object; + struct object + { + // it exists + }; } } - -class flat::core::object -{ - std::string id; - - /* Common list of objects */ - static std::list<object*> all_objects; - -public: - - object(); - ~object(); - - void set_id(const std::string&); - - const std::string& get_id() const; - - /* Static accessors to allObject */ - - static bool is_allocated(object*); - - static std::vector<object*>& get_by_id(const std::string& id, std::vector<object*>&); - - static std::string random_id(uint8_t length = 8); -}; - diff --git a/engine/include/core/signal.hpp b/engine/include/core/signal.hpp index 2393bc7..4270aa5 100644 --- a/engine/include/core/signal.hpp +++ b/engine/include/core/signal.hpp @@ -8,73 +8,92 @@ #include "task.hpp" #include "types.h" #include <functional> +#include <memory> #include "priority.hpp" +#include "labelled.hpp" namespace flat { namespace core { - class signal : virtual public object, public prioritized + class signal : virtual public labelled, virtual public prioritized { public: object * sender; - void * data; // TODO, avoid this void pointer + package m_package; priority_t prior; signal( object * sender, const std::string& id = "", - void * data, + void * data = 0, priority_t prior = priority_t::none); /* Alias to flat::core::channel::emit() */ bool emit(const std::string& channel) const; + + struct package + { + package(void *data) : data(data) {} + + template<class T> + T * get() { + + return dynamic_cast<T>(data); + } + + void * data; + }; }; /* Channel class */ - class channel : virtual public object + class channel : virtual public labelled { /* Post processing signal stacking */ queue<signal> stack; /* Listeners list */ - std::list<listener*> listeners; + std::list<std::weak_ptr<listener>> listeners; /* Synchronous task checking for signals */ - task * checker; + task::ptr checker; /* Channel mapping */ - static std::map<std::string, channel*> channels; + static std::map<std::string, std::weak_ptr<channel>> channels; public: channel(const std::string& id = "", priority_t task_priority = priority_t::none); ~channel(); + + void start(); + bool map(); void emit(const signal&); - void connect(const listener*); - void disconnect(const listener*); + bool connect(listener::ptr l); + void disconnect(listener::ptr l); - static channel * find_channel(const std::string&); + static ptr find(const std::string&); + + static ptr create(const string& id, priority_t prior); - void post_processing(); + void check_and_call(); + + typedef shared_ptr<channel> ptr; }; /* Listener class */ - class listener : virtual public object + class listener { - std::list<std::string> filters; bool check_in_filters(const std::string&) const; callback_t m_callback; - - channel * parent; public: @@ -93,14 +112,15 @@ namespace flat /* Allow to safely bind e functor */ template<class T> - static listener create( const (T::*method(const object*, void*))& fct, - T* ptr, - const std::initializer_list<std::string>& filters = {}) + static ptr make( const (T::*method(const object*, void*))& fct, + T* obj, + const std::initializer_list<std::string>& filters = {}) { - return listener(std::bind(fct, ptr), filters); + return new listener(std::bind(fct, ptr), filters); } - typedef std::function<void(const object*, void*)> callback_t; + typedef std::function<void(const object*, signal::package)> callback_t; + typedef shared_ptr<listener> ptr; }; } diff --git a/engine/include/flatland.h b/engine/include/flatland.h index 27d2d12..c5f3eb5 100644 --- a/engine/include/flatland.h +++ b/engine/include/flatland.h @@ -1,6 +1,8 @@ #ifndef __FLATLAND_H__ #define __FLATLAND_H__ +namespace flat { + class FlatWindow; typedef void (*gameloop)(float); @@ -38,11 +40,21 @@ struct flat_status int init_flatland(FlatWindow*, gameloop, const flat_status&, float fps = 60); void quit_flatland(); -/* Core channel */ +namespace core { + + class job; + class task; + class channel; +} + +/* Engine channels */ -class SignalChannel; +channel& core_chan(); +channel& error_chan(); -SignalChannel * getCoreChannel(); +/* Main job access */ + +job& game_job(); /* Window and status accessors */ @@ -58,4 +70,6 @@ void load_flatland_status(const flat_status&); extern float flatland_dt; +} + #endif diff --git a/engine/labelled.cpp b/engine/labelled.cpp new file mode 100644 index 0000000..ede43d6 --- /dev/null +++ b/engine/labelled.cpp @@ -0,0 +1,19 @@ +#include "core/labelled.hpp" + +#include <stdlib.h> + +using namespace std; +using namespace flat::core; + +labelled::labelled(const std::string& label) : label(label) {} + +string labelled::random_id(uint8_t length) { + + string out; + + for (uint8_t i = 0; i < length; ++i) + out += (char)(rand() % 93 + 33); + + return out; +} + diff --git a/engine/object.cpp b/engine/object.cpp deleted file mode 100644 index 7134061..0000000 --- a/engine/object.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "core/object.hpp" - -#include <stdlib.h> - -using namespace std; -using namespace flat::core; - -list<object*> object::all_objects; - -object::object() -{ - /* Collect this object */ - object::all_objects.push_back(this); -} - -object::~object() -{ - /* Eliminate this object reference */ - object::all_objects.remove(this); -} - -void object::set_id(const string& id) -{ - this->id = id; -} - -const string& object::get_id() const -{ - return id; -} - -string object::random_id(uint8_t length) { - - string out; - - for (uint8_t i = 0; i < length; ++i) - out += (char)(rand() % 93 + 33); - - return out; -} - -bool object::is_allocated(object *obj) -{ - for (object * o : object::all_objects) - { - if (o == obj) - return true; - } - - return false; -} - -vector<object*>& object::get_by_id(const string& id, vector<object*>& l) -{ - for (object * obj : object::all_objects) - { - if (id == obj->get_id()) - l.push_back(obj); - } - - return l; -} diff --git a/engine/signal.cpp b/engine/signal.cpp index 5eac3eb..2af4a68 100644 --- a/engine/signal.cpp +++ b/engine/signal.cpp @@ -1,5 +1,6 @@ #include "core/signal.hpp" #include <functional> +#include "flatland.h" using namespace std; using namespace flat::core; @@ -7,30 +8,27 @@ using namespace flat::core; map<string, channel*> channel::channels; channel::channel(const string& id, priority_t prior) + : labelled(id.empty() ? object::random_id(): id) { - channel * other = find_channel(id); - - if (!other) - //TODO throw exception - ; - - /* Initialize task, post-process, fifth priority */ - checker = new task( bind(&channel::post_processing, this), - prior); - - string ID = (id.empty()) ? object::random_id() : id; +} - set_id(ID); +channel::~channel() +{ + // by default it should be there + channels.erase(label); +} - channels.insert(pair<string, channel*>(ID, this)); +void channel::start() +{ + // Initialize task + checker = flat::game_job().delegate_task<channel>(&channel::check_and_call, this, prior); } -channel::~channel() +bool channel::map() { - channels.erase(get_id()); + channel * other = find_channel(label); - /* Finalize task */ - delete checker; + return other ? false : channels.insert(pair<string, channel*>(label, this)); } void channel::emit(const signal& sig) @@ -38,52 +36,77 @@ void channel::emit(const signal& sig) stack.insert(sig); } -void channel::connect(const listener* l) +bool channel::connect(listener::ptr l) { /* Control not to double */ for (auto lis : listeners) { - if (lis == l) - return; + if (lis.get() == l.get()) + return false; } listeners.push_back(l); + return true; } -void channel::disconnect(const listener* l) +void channel::disconnect(listener::ptr l) { listeners.remove(l); } +channel::ptr channel::create(const string& id, priority_t prior) +{ + ptr out = std::make_ptr(new channel(id, prior)); + + if (!out.map()) + return nullptr; + + out.start(); + + return out; +} -channel * channel::find_channel(const string& id) +channel::ptr channel::find(const string& id) { if (id.empty()) - return 0; + return nullptr; auto it = channels.find(id); - return (it == channels.end()) ? 0 : (*it).second; + return (it == channels.end()) ? nullptr : (*it).second.lock(); } -void channel::post_processing() +void channel::check_and_call() { if (!stack.empty()) { + vector<weak_ptr<listener>> to_erase; + // TODO, maybe it exists pop /* for each listener_s, catch signal */ - for (const auto& signal : stack) + + for (auto l : listeners) { - for (auto l : listeners) - l->invoke(signal); + listener::ptr pt; + + if (pt = l.lock()) + { + for (const auto& sig : stack) + l->invoke(sig); + } + else + to_erase.push_back(l); } + + /* Erase invalidated listeners */ + for (auto e : to_erase) + listeners.remove(e); - stack.clear(); + stack.clear(); // TODO not so efficient } } - /* signal class */ signal::signal( object *sender, @@ -91,40 +114,39 @@ signal::signal( object *sender, void *data, priority_t priority) - : sender(sender), data(data), priority(priority) + : labelled(id), + sender(sender), + m_package(package(data)), + priority(priority) { - set_id(id); } -bool signal::emit(const string& channel) const +bool signal::emit(const string& chan) const { - channel * chan = channel::find_channel(channel); + channel::ptr c = channel::find(chan); - if (!chan) + if (!c) return false; /* Finally emit in channel */ - chan->emit(*this); + c->emit(*this); return true; } - /* listener_s class */ listener::listener( callback_t m_callback, const initializer_list<string>& filters) - : m_callback(m_callback), filters(filters), parent(0) + : m_callback(m_callback), filters(filters) { } listener::~listener() { - if (parent != 0) - parent->disconnect(this); } bool listener::check_in_filters(const string& filter) const @@ -150,32 +172,28 @@ void listener::remove_filter(const string& f) bool listener::connect(const string& chan) { - channel * c = channel::find_channel(chan); + channel::ptr c = channel::find(chan); if (!c) c->connect(this); - parent = c; - - return c != 0; + return c; } -bool listener_s::disconnect(const string& chan) +bool listener::disconnect(const string& chan) { - channel * c = channel::find_channel(chan); + channel::ptr c = channel::find_channel(chan); if (!c) - c->connect(this); - - parent = 0; + c->disconnect(this); - return c != 0; + return c; } -void listener::invoke(const signal&) +void listener::invoke(const signal& sig) { - if ( (!sig.get_id().empty() && check_in_filters(sig.get_id())) || - (sig.get_id().empty() && filters.empty())) - m_callback(sig.sender); + if ( (!sig.label.empty() && check_in_filters(sig.label)) || + (sig.label.empty() && filters.empty())) + m_callback(sig.sender, sig.m_package); } |