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.
* @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; }
/**
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;
};
}
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);
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;
#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.
*/
* 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.
*
* @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;
/**
private:
- typedef std::map<std::string,command_t> command_map;
+ typedef std::map<std::string,Command*> command_map;
command_map _commands;
static SGMutex _instanceMutex;
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)) { \
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"));
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"));
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()