]> git.mxchange.org Git - simgear.git/commitdiff
Command-manager supports functors.
authorJames Turner <zakalawe@mac.com>
Sat, 9 Feb 2013 12:40:44 +0000 (12:40 +0000)
committerJames Turner <zakalawe@mac.com>
Sat, 9 Feb 2013 12:40:44 +0000 (12:40 +0000)
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.

simgear/structure/SGBinding.hxx
simgear/structure/commands.cxx
simgear/structure/commands.hxx
simgear/structure/state_machine_test.cxx

index 026da27078ac6af765c7105109fba62ef130fa3a..eb12f3d235b3c8b6052d2451cce4110ad3572347 100644 (file)
@@ -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;
 };
index 266cdb4ce3b0177b269e102295647a32515b262e..3a221321c3f1593238aab84d7e1dbb4223bd3556 100644 (file)
@@ -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;
 
index 09f1c1bcf132799814e12a2d27be2aa47c9fbe72..c03ef5dc1ca0a05ba56db0e509c1b607bb6e3f5f 100644 (file)
 
 #include <string>
 #include <map>
-#include <vector>
 
 #include <simgear/threads/SGThread.hxx>
 #include <simgear/math/sg_types.hxx>
-#include <simgear/props/props.hxx>
 
+// forward decls
+class SGPropertyNode;
+     
 /**
  * Manage commands.
  *
 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>(fun);
+   }
+
+   template< class ObjPtr, typename MemFn >
+   Command* make_functor( const ObjPtr& pObj, MemFn pMemFn )
+   {
+       return new MethodCommand<ObjPtr,MemFn>(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<typename FUNC>
+  void addCommand(const std::string& name, const FUNC* f)
+  { addCommand(name, make_functor(f)); }
+       
+  void addCommand (const std::string &name, Command* command);
+
+  template<class OBJ, typename METHOD>
+  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<std::string,command_t> command_map;
+  typedef std::map<std::string,Command*> command_map;
   command_map _commands;
 
   static SGMutex _instanceMutex;
index d1a4d26dcb2b0d60cdfed0dbd6b9f0d7101231f4..2d31d63d2014427f41dfeda7051084b6271f6d98 100644 (file)
@@ -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()