From 30d7196cd4a04269dfcfea252dba318ddaf0e702 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Mon, 12 May 2014 23:44:12 +0300 Subject: [PATCH] Listener object is better than 3 lambdas + handle --- include/library/command.hpp | 49 +++++++++++++--- include/library/keyboard-mapper.hpp | 45 +++++++++++++-- src/library/command.cpp | 108 ++++++++++++++++++------------------ src/library/keyboard-mapper.cpp | 107 +++++++++++++++++------------------ 4 files changed, 188 insertions(+), 121 deletions(-) diff --git a/include/library/command.hpp b/include/library/command.hpp index 6cb8e227..1fb32883 100644 --- a/include/library/command.hpp +++ b/include/library/command.hpp @@ -10,10 +10,35 @@ namespace command { +class set; class base; class factory_base; /** + * Set add/drop listener. + */ +class set_listener +{ +public: +/** + * Dtor. + */ + virtual ~set_listener(); +/** + * New item in set. + */ + virtual void create(set& s, const std::string& name, factory_base& cmd) = 0; +/** + * Deleted item from set. + */ + virtual void destroy(set& s, const std::string& name) = 0; +/** + * Destroyed the entiere set. + */ + virtual void kill(set& s) = 0; +}; + +/** * A set of commands. */ class set @@ -38,20 +63,15 @@ public: /** * Add a notification callback and call ccb on all. * - * Parameter ccb: The create callback function. - * Parameter dcb: The destroy callback function. - * Parameter tcb: The terminate callback function. - * Returns: Callback handle. + * Parameter listener: The listener to add. */ - uint64_t add_callback(std::function ccb, - std::function dcb, std::function tcb) - throw(std::bad_alloc); + void add_callback(set_listener& listener) throw(std::bad_alloc); /** * Drop a notification callback and call dcb on all. * - * Parameter handle: The handle of callback to drop. + * Parameter listener: The listener to drop. */ - void drop_callback(uint64_t handle) throw(); + void drop_callback(set_listener& listener) throw(); /** * Obtain list of all commands so far. */ @@ -121,6 +141,17 @@ public: */ void set_oom_panic(void (*fn)()); private: + class listener : public set_listener + { + public: + listener(group& _grp); + ~listener(); + void create(set& s, const std::string& name, factory_base& cmd); + void destroy(set& s, const std::string& name); + void kill(set& s); + private: + group& grp; + } _listener; std::set command_stack; std::map> aliases; std::ostream* output; diff --git a/include/library/keyboard-mapper.hpp b/include/library/keyboard-mapper.hpp index 9c4d2a4a..f9166451 100644 --- a/include/library/keyboard-mapper.hpp +++ b/include/library/keyboard-mapper.hpp @@ -74,6 +74,32 @@ struct keyspec }; class invbind_set; +class invbind_info; + +/** + * Set add/drop listener. + */ +class set_listener +{ +public: +/** + * Dtor. + */ + virtual ~set_listener(); +/** + * New item in set. + */ + virtual void create(invbind_set& s, const std::string& name, invbind_info& ibinfo) = 0; +/** + * Deleted item from set. + */ + virtual void destroy(invbind_set& s, const std::string& name) = 0; +/** + * Destroyed the entiere set. + */ + virtual void kill(invbind_set& s) = 0; +}; + /** * Keyboard mapper. Maps keyboard keys into commands. @@ -215,6 +241,17 @@ private: key* _key; unsigned subkey; }; + class listener : public set_listener + { + public: + listener(mapper& _grp); + ~listener(); + void create(invbind_set& s, const std::string& name, invbind_info& ibinfo); + void destroy(invbind_set& s, const std::string& name); + void kill(invbind_set& s); + private: + mapper& grp; + } _listener; void change_command(const keyspec& spec, const std::string& old, const std::string& newc); void on_key_event(modifier_set& mods, key& key, event& event); void on_key_event_subkey(modifier_set& mods, key& key, unsigned skey, bool polarity); @@ -224,7 +261,7 @@ private: std::map ckeys; std::map bindings; std::set listening; - std::map invbind_set_cbs; + std::set invbind_set_cbs; keyboard& kbd; command::group& domain; bool dtor_running; @@ -257,13 +294,11 @@ public: /** * Add a callback on new invese bind. */ - uint64_t add_callback(std::function ccb, - std::function dcb, - std::function tcb) throw(std::bad_alloc); + void add_callback(set_listener& listener) throw(std::bad_alloc); /** * Drop a callback on new inverse bind. */ - void drop_callback(uint64_t handle); + void drop_callback(set_listener& listener); }; /** diff --git a/src/library/command.cpp b/src/library/command.cpp index 0d943aed..2926d493 100644 --- a/src/library/command.cpp +++ b/src/library/command.cpp @@ -65,13 +65,6 @@ namespace exit(1); } - struct set_callbacks - { - std::function ccb; - std::function dcb; - std::function tcb; - }; - threads::rlock* global_lock; threads::rlock& get_cmd_lock() { @@ -81,21 +74,24 @@ namespace struct set_internal { - std::map callbacks; - integer_pool pool; + std::set callbacks; std::map commands; }; struct group_internal { std::map commands; - std::map set_handles; + std::set set_handles; }; typedef stateobject::type set_internal_t; typedef stateobject::type group_internal_t; } +set_listener::~set_listener() +{ +} + void factory_base::_factory_base(set& _set, const std::string& cmd) throw(std::bad_alloc) { threads::arlock h(get_cmd_lock()); @@ -161,10 +157,10 @@ set::~set() throw() //Call all DCBs on all factories. for(auto i : state->commands) for(auto j : state->callbacks) - j.second.dcb(*this, i.first); + j->destroy(*this, i.first); //Call all TCBs. for(auto j : state->callbacks) - j.second.tcb(*this); + j->kill(*this); //Notify all factories that base set died. for(auto i : state->commands) i.second->set_died(); @@ -183,7 +179,7 @@ void set::do_register(const std::string& name, factory_base& cmd) throw(std::bad state.commands[name] = &cmd; //Call all CCBs on this. for(auto i : state.callbacks) - i.second.ccb(*this, name, cmd); + i->create(*this, name, cmd); } void set::do_unregister(const std::string& name, factory_base& cmd) throw(std::bad_alloc) @@ -195,43 +191,30 @@ void set::do_unregister(const std::string& name, factory_base& cmd) throw(std::b state->commands.erase(name); //Call all DCBs on this. for(auto i : state->callbacks) - i.second.dcb(*this, name); + i->destroy(*this, name); } -uint64_t set::add_callback(std::function ccb, - std::function dcb, std::function tcb) +void set::add_callback(set_listener& listener) throw(std::bad_alloc) { threads::arlock h(get_cmd_lock()); auto& state = set_internal_t::get(this); - set_callbacks cb; - cb.ccb = ccb; - cb.dcb = dcb; - cb.tcb = tcb; - uint64_t i = state.pool(); - try { - state.callbacks[i] = cb; - } catch(...) { - state.pool(i); - throw; - } + state.callbacks.insert(&listener); //To avoid races, call CCBs on all factories for this. for(auto j : state.commands) - ccb(*this, j.first, *j.second); - return i; + listener.create(*this, j.first, *j.second); } -void set::drop_callback(uint64_t handle) throw() +void set::drop_callback(set_listener& listener) throw() { threads::arlock h(get_cmd_lock()); auto state = set_internal_t::get_soft(this); if(!state) return; - if(state->callbacks.count(handle)) { + if(state->callbacks.count(&listener)) { //To avoid races, call DCBs on all factories for this. for(auto j : state->commands) - state->callbacks[handle].dcb(*this, j.first); - state->callbacks.erase(handle); - state->pool(handle); + listener.destroy(*this, j.first); + state->callbacks.erase(&listener); } } @@ -244,6 +227,7 @@ std::map set::get_commands() } group::group() throw(std::bad_alloc) + : _listener(*this) { oom_panic_routine = default_oom_panic; output = &std::cerr; @@ -264,7 +248,7 @@ group::~group() throw() //Drop all callbacks. for(auto i : state->set_handles) - i.first->drop_callback(i.second); + i->drop_callback(_listener); //We assume all bases that need destroying have already been destroyed. group_internal_t::clear(this); } @@ -441,23 +425,10 @@ void group::add_set(set& s) throw(std::bad_alloc) { threads::arlock h(get_cmd_lock()); auto& state = group_internal_t::get(this); - if(state.set_handles.count(&s)) - return; - state.set_handles[&s] = 0xFFFFFFFFFFFFFFFF; + if(state.set_handles.count(&s)) return; try { - state.set_handles[&s] = s.add_callback( - [this](set& s, const std::string& name, factory_base& cmd) { - cmd.make(*this); - }, [this](set& s, const std::string& name) { - auto state = group_internal_t::get_soft(this); - if(!state) return; - state->commands.erase(name); - }, [this](set& s) { - auto state = group_internal_t::get_soft(this); - if(!state) return; - state->set_handles.erase(&s); - } - ); + state.set_handles.insert(&s); + s.add_callback(_listener); } catch(...) { state.set_handles.erase(&s); } @@ -468,10 +439,39 @@ void group::drop_set(set& s) throw() threads::arlock h(get_cmd_lock()); auto state = group_internal_t::get_soft(this); if(!state) return; - if(!state->set_handles.count(&s)) - return; //Drop the callback. This unregisters all. - s.drop_callback(state->set_handles[&s]); + s.drop_callback(_listener); + state->set_handles.erase(&s); +} + +group::listener::listener(group& _grp) + : grp(_grp) +{ +} + +group::listener::~listener() +{ +} + +void group::listener::create(set& s, const std::string& name, factory_base& cmd) +{ + threads::arlock h(get_cmd_lock()); + cmd.make(grp); +} + +void group::listener::destroy(set& s, const std::string& name) +{ + threads::arlock h(get_cmd_lock()); + auto state = group_internal_t::get_soft(&grp); + if(!state) return; + state->commands.erase(name); +} + +void group::listener::kill(set& s) +{ + threads::arlock h(get_cmd_lock()); + auto state = group_internal_t::get_soft(&grp); + if(!state) return; state->set_handles.erase(&s); } diff --git a/src/library/keyboard-mapper.cpp b/src/library/keyboard-mapper.cpp index 3b78c5f5..6dcf6134 100644 --- a/src/library/keyboard-mapper.cpp +++ b/src/library/keyboard-mapper.cpp @@ -16,22 +16,19 @@ namespace return *global_lock; } - struct set_callbacks - { - std::function ccb; - std::function dcb; - std::function tcb; - }; - struct set_internal { std::map invbinds; - std::map callbacks; - integer_pool pool; + std::set callbacks; }; typedef stateobject::type set_internal_t; } + +set_listener::~set_listener() +{ +} + std::string mapper::fixup_command_polarity(std::string cmd, bool polarity) throw(std::bad_alloc) { if(cmd == "" || cmd == "*") @@ -166,7 +163,7 @@ keyboard& mapper::get_keyboard() throw() } mapper::mapper(keyboard& _kbd, command::group& _domain) throw(std::bad_alloc) - : kbd(_kbd), domain(_domain) + : _listener(*this), kbd(_kbd), domain(_domain) { register_queue::do_ready(*this, true); register_queue::do_ready(*this, true); @@ -178,6 +175,8 @@ mapper::~mapper() throw() threads::arlock u(get_keymap_lock()); for(auto i : ibinds) i.second->mapper_died(); + for(auto i : invbind_set_cbs) + i->drop_callback(_listener); register_queue::do_ready(*this, false); register_queue::do_ready(*this, false); } @@ -412,21 +411,10 @@ std::list mapper::get_controllerkeys_kbdkey(key* kbdkey) void mapper::add_invbind_set(invbind_set& set) { threads::arlock u(get_keymap_lock()); - if(invbind_set_cbs.count(&set)) - return; - invbind_set_cbs[&set] = 0xFFFFFFFFFFFFFFFF; + if(invbind_set_cbs.count(&set)) return; try { - invbind_set_cbs[&set] = set.add_callback( - [this](invbind_set& s, const std::string& name, invbind_info& ib) { - ib.make(*this); - }, [this](invbind_set& s, const std::string& name) { - if(dtor_running) return; - ibinds.erase(name); - }, [this](invbind_set& s) { - if(dtor_running) return; - this->invbind_set_cbs.erase(&s); - } - ); + invbind_set_cbs.insert(&set); + set.add_callback(_listener); } catch(...) { invbind_set_cbs.erase(&set); } @@ -434,14 +422,41 @@ void mapper::add_invbind_set(invbind_set& set) void mapper::drop_invbind_set(invbind_set& set) { - threads::arlock u(get_keymap_lock()); - if(!invbind_set_cbs.count(&set)) - return; + threads::arlock h(get_keymap_lock()); //Drop the callback. This unregisters all. - set.drop_callback(invbind_set_cbs[&set]); + set.drop_callback(_listener); invbind_set_cbs.erase(&set); } +mapper::listener::listener(mapper& _grp) + : grp(_grp) +{ +} + +mapper::listener::~listener() +{ +} + +void mapper::listener::create(invbind_set& s, const std::string& name, invbind_info& ibinfo) +{ + threads::arlock h(get_keymap_lock()); + ibinfo.make(grp); +} + +void mapper::listener::destroy(invbind_set& s, const std::string& name) +{ + threads::arlock h(get_keymap_lock()); + if(grp.dtor_running) return; + grp.ibinds.erase(name); +} + +void mapper::listener::kill(invbind_set& s) +{ + threads::arlock h(get_keymap_lock()); + if(grp.dtor_running) return; + grp.invbind_set_cbs.erase(&s); +} + invbind::invbind(mapper& kmapper, const std::string& _command, const std::string& _name, bool dynamic) throw(std::bad_alloc) : _mapper(&kmapper), cmd(_command), oname(_name) @@ -533,10 +548,10 @@ invbind_set::~invbind_set() //Call all DCBs on all factories. for(auto i : state->invbinds) for(auto j : state->callbacks) - j.second.dcb(*this, i.first); + j->destroy(*this, i.first); //Call all TCBs. for(auto j : state->callbacks) - j.second.tcb(*this); + j->kill(*this); //Notify all factories that base set died. for(auto i : state->invbinds) i.second->set_died(); @@ -555,7 +570,7 @@ void invbind_set::do_register(const std::string& name, invbind_info& info) state.invbinds[name] = &info; //Call all CCBs on this. for(auto i : state.callbacks) - i.second.ccb(*this, name, info); + i->create(*this, name, info); } void invbind_set::do_unregister(const std::string& name, invbind_info& info) @@ -567,43 +582,29 @@ void invbind_set::do_unregister(const std::string& name, invbind_info& info) state->invbinds.erase(name); //Call all DCBs on this. for(auto i : state->callbacks) - i.second.dcb(*this, name); + i->destroy(*this, name); } -uint64_t invbind_set::add_callback(std::function ccb, - std::function dcb, - std::function tcb) throw(std::bad_alloc) +void invbind_set::add_callback(set_listener& listener) throw(std::bad_alloc) { threads::arlock u(get_keymap_lock()); auto& state = set_internal_t::get(this); - set_callbacks cb; - cb.ccb = ccb; - cb.dcb = dcb; - cb.tcb = tcb; - uint64_t i = state.pool(); - try { - state.callbacks[i] = cb; - } catch(...) { - state.pool(i); - throw; - } + state.callbacks.insert(&listener); //To avoid races, call CCBs on all factories for this. for(auto j : state.invbinds) - ccb(*this, j.first, *j.second); - return i; + listener.create(*this, j.first, *j.second); } -void invbind_set::drop_callback(uint64_t handle) +void invbind_set::drop_callback(set_listener& listener) { threads::arlock u(get_keymap_lock()); auto state = set_internal_t::get_soft(this); if(!state) return; - if(state->callbacks.count(handle)) { + if(state->callbacks.count(&listener)) { //To avoid races, call DCBs on all factories for this. for(auto j : state->invbinds) - state->callbacks[handle].dcb(*this, j.first); - state->callbacks.erase(handle); - state->pool(handle); + listener.destroy(*this, j.first); + state->callbacks.erase(&listener); } } -- 2.11.4.GIT