From: James Turner Date: Sat, 9 Feb 2013 12:40:44 +0000 (+0000) Subject: Command-manager supports functors. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=b0063f8db67066c1ad4d9481c33b4627a1c51d3b;p=simgear.git Command-manager supports functors. Will be used to support native Nasal commands, which was tricky with pure function pointers before. Can also be used to avoid some trampoline functions in the code, but this can happen gradually. --- diff --git a/simgear/structure/SGBinding.hxx b/simgear/structure/SGBinding.hxx index 026da270..eb12f3d2 100644 --- a/simgear/structure/SGBinding.hxx +++ b/simgear/structure/SGBinding.hxx @@ -73,7 +73,7 @@ public: * @return The command associated with this binding, or 0 if none * is present. */ - SGCommandMgr::command_t getCommand () const { return _command; } + SGCommandMgr::Command* getCommand () const { return _command; } /** @@ -120,7 +120,7 @@ private: SGBinding (const SGBinding &binding); std::string _command_name; - mutable SGCommandMgr::command_t _command; + mutable SGCommandMgr::Command* _command; mutable SGPropertyNode_ptr _arg; mutable SGPropertyNode_ptr _setting; }; diff --git a/simgear/structure/commands.cxx b/simgear/structure/commands.cxx index 266cdb4c..3a221321 100644 --- a/simgear/structure/commands.cxx +++ b/simgear/structure/commands.cxx @@ -52,12 +52,15 @@ SGCommandMgr::instance() } void -SGCommandMgr::addCommand (const std::string &name, command_t command) +SGCommandMgr::addCommand (const std::string &name, Command* command) { + if (_commands.find(name) != _commands.end()) + throw sg_exception("duplicate command name:" + name); + _commands[name] = command; } -SGCommandMgr::command_t +SGCommandMgr::Command* SGCommandMgr::getCommand (const std::string &name) const { const command_map::const_iterator it = _commands.find(name); @@ -80,7 +83,7 @@ SGCommandMgr::getCommandNames () const bool SGCommandMgr::execute (const std::string &name, const SGPropertyNode * arg) const { - command_t command = getCommand(name); + Command* command = getCommand(name); if (command == 0) return false; diff --git a/simgear/structure/commands.hxx b/simgear/structure/commands.hxx index 09f1c1bc..c03ef5dc 100644 --- a/simgear/structure/commands.hxx +++ b/simgear/structure/commands.hxx @@ -15,12 +15,13 @@ #include #include -#include #include #include -#include +// forward decls +class SGPropertyNode; + /** * Manage commands. * @@ -34,13 +35,65 @@ class SGCommandMgr { public: + /** + * Command functor object + */ + class Command + { + public: + virtual ~Command() { } + virtual bool operator()(const SGPropertyNode * arg) = 0; + }; - /** - * Type for a command function. - */ +private: + template< typename Fun > + class FunctionCommand : public Command + { + public: + FunctionCommand( const Fun* fun ) + : f_(fun) {} + + virtual bool operator()(const SGPropertyNode * arg) { return (*f_)(arg); } + private: + Fun* f_; + }; + + template< class ObjPtr, typename MemFn > + class MethodCommand : public Command + { + public: + MethodCommand( const ObjPtr& pObj, MemFn pMemFn ) : + pObj_(pObj), pMemFn_(pMemFn) {} + + virtual bool operator()(const SGPropertyNode * arg) + { + return ((*pObj_).*pMemFn_)(arg); + } + private: + ObjPtr pObj_; + MemFn pMemFn_; + }; + + /** + * Helper template functions. + */ + + template< typename Fun > + Command* make_functor( const Fun* fun ) + { + return new FunctionCommand(fun); + } + + template< class ObjPtr, typename MemFn > + Command* make_functor( const ObjPtr& pObj, MemFn pMemFn ) + { + return new MethodCommand(pObj, pMemFn ); + } + +public: + typedef bool (*command_t) (const SGPropertyNode * arg); - /** * Destructor. */ @@ -60,9 +113,18 @@ public: * a bool result. The argument is always a const pointer to * an SGPropertyNode (which may contain multiple values). */ - virtual void addCommand (const std::string &name, command_t command); - - + template + void addCommand(const std::string& name, const FUNC* f) + { addCommand(name, make_functor(f)); } + + void addCommand (const std::string &name, Command* command); + + template + void addCommand(const std::string& name, const OBJ& o, METHOD m) + { + addCommand(name, make_functor(o,m)); + } + /** * Look up an existing command. * @@ -70,7 +132,7 @@ public: * @return A pointer to the command, or 0 if there is no registered * command with the name specified. */ - virtual command_t getCommand (const std::string &name) const; + virtual Command* getCommand (const std::string &name) const; /** @@ -103,7 +165,7 @@ protected: private: - typedef std::map command_map; + typedef std::map command_map; command_map _commands; static SGMutex _instanceMutex; diff --git a/simgear/structure/state_machine_test.cxx b/simgear/structure/state_machine_test.cxx index d1a4d26d..2d31d63d 100644 --- a/simgear/structure/state_machine_test.cxx +++ b/simgear/structure/state_machine_test.cxx @@ -43,13 +43,19 @@ public: bool _state; }; -static int dummy_cmd_state = 0; - -bool dummyCommand(const SGPropertyNode* arg) +class DummyThing { - ++dummy_cmd_state; - return true; -} +public: + DummyThing() : dummy_cmd_state(0) { } + + bool someCommand(const SGPropertyNode* arg) + { + dummy_cmd_state++; + return true; + } + + int dummy_cmd_state; +}; #define COMPARE(a, b) \ if ((a) != (b)) { \ @@ -171,7 +177,8 @@ void testNoSourcesTransition() void testBindings() { SGCommandMgr* cmdMgr = SGCommandMgr::instance(); - cmdMgr->addCommand("dummy", dummyCommand); + DummyThing thing; + cmdMgr->addCommand("dummy", &thing, &DummyThing::someCommand); BUILD_MACHINE_1(); t2->addBinding(new SGBinding("dummy")); @@ -186,20 +193,20 @@ void testBindings() sm->update(1.0); trigger1->_state = false; COMPARE(sm->state()->name(), "b"); - COMPARE(dummy_cmd_state, 1); // exit state A + COMPARE(thing.dummy_cmd_state, 1); // exit state A trigger2->_state = true; sm->update(1.0); trigger2->_state = false; - COMPARE(dummy_cmd_state, 3); // fire transition 2, enter state C + COMPARE(thing.dummy_cmd_state, 3); // fire transition 2, enter state C - dummy_cmd_state = 0; + thing.dummy_cmd_state = 0; sm->changeToState(stateA); - COMPARE(dummy_cmd_state, 1); // enter state A + COMPARE(thing.dummy_cmd_state, 1); // enter state A trigger1->_state = true; sm->update(1.0); trigger1->_state = false; - COMPARE(dummy_cmd_state, 2); // exit state A + COMPARE(thing.dummy_cmd_state, 2); // exit state A //////////////////////// t3->addBinding(new SGBinding("dummy")); @@ -207,11 +214,11 @@ void testBindings() t3->addBinding(new SGBinding("dummy")); sm->changeToStateName("b"); - dummy_cmd_state = 0; + thing.dummy_cmd_state = 0; trigger3->_state = true; sm->update(1.0); trigger3->_state = false; - COMPARE(dummy_cmd_state, 4); // three transition bindings, enter A + COMPARE(thing.dummy_cmd_state, 4); // three transition bindings, enter A } void testParse()