diff options
-rw-r--r-- | include/gras/callable.hpp | 37 | ||||
-rw-r--r-- | include/gras/detail/callable.hpp | 255 | ||||
-rw-r--r-- | lib/callable.cpp | 2 | ||||
-rw-r--r-- | tests/callable_test.cpp | 109 |
4 files changed, 322 insertions, 81 deletions
diff --git a/include/gras/callable.hpp b/include/gras/callable.hpp index 6b2a3b6..32d6d17 100644 --- a/include/gras/callable.hpp +++ b/include/gras/callable.hpp @@ -39,46 +39,59 @@ struct GRAS_API Callable template <typename ClassType, typename ReturnType> void register_call(const std::string &key, ReturnType(ClassType::*fcn)(void)); - template <typename ClassType, typename ReturnType, typename Arg0> - void register_call(const std::string &key, ReturnType(ClassType::*fcn)(const Arg0 &)); - - template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1> - void register_call(const std::string &key, ReturnType(ClassType::*fcn)(const Arg0 &, const Arg1 &)); - template <typename ClassType> void register_call(const std::string &key, void(ClassType::*fcn)(void)); + template <typename ClassType, typename ReturnType, typename Arg0> + void register_call(const std::string &key, ReturnType(ClassType::*fcn)(const Arg0 &)); + template <typename ClassType, typename Arg0> void register_call(const std::string &key, void(ClassType::*fcn)(const Arg0 &)); + template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1> + void register_call(const std::string &key, ReturnType(ClassType::*fcn)(const Arg0 &, const Arg1 &)); + template <typename ClassType, typename Arg0, typename Arg1> void register_call(const std::string &key, void(ClassType::*fcn)(const Arg0 &, const Arg1 &)); + template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1, typename Arg2> + void register_call(const std::string &key, ReturnType(ClassType::*fcn)(const Arg0 &, const Arg1 &, const Arg2 &)); + + template <typename ClassType, typename Arg0, typename Arg1, typename Arg2> + void register_call(const std::string &key, void(ClassType::*fcn)(const Arg0 &, const Arg1 &, const Arg2 &)); + /******************************************************************* * Call API - don't look here, template magic, not helpful ******************************************************************/ template <typename ReturnType> ReturnType call(const std::string &key); + inline + void call(const std::string &key); + template <typename ReturnType, typename Arg0> ReturnType call(const std::string &key, const Arg0 &); - template <typename ReturnType, typename Arg0, typename Arg1> - ReturnType call(const std::string &key, const Arg0 &, const Arg1 &); - - void call(const std::string &key); - template <typename Arg0> void call(const std::string &key, const Arg0 &); + template <typename ReturnType, typename Arg0, typename Arg1> + ReturnType call(const std::string &key, const Arg0 &, const Arg1 &); + template <typename Arg0, typename Arg1> void call(const std::string &key, const Arg0 &, const Arg1 &); + template <typename ReturnType, typename Arg0, typename Arg1, typename Arg2> + ReturnType call(const std::string &key, const Arg0 &, const Arg1 &, const Arg2 &); + + template <typename Arg0, typename Arg1, typename Arg2> + void call(const std::string &key, const Arg0 &, const Arg1 &, const Arg2 &); + /******************************************************************* * Private registration hooks ******************************************************************/ void _register_call(const std::string &, void *); - virtual PMCC _handle_call(const std::string &, const std::vector<PMCC> &); + virtual PMCC _handle_call(const std::string &, const PMCC *); void *_call_registry; }; diff --git a/include/gras/detail/callable.hpp b/include/gras/detail/callable.hpp index 5e7854a..23e3ab6 100644 --- a/include/gras/detail/callable.hpp +++ b/include/gras/detail/callable.hpp @@ -8,112 +8,277 @@ namespace gras { +/*********************************************************************** + * Registration entry base class + **********************************************************************/ struct GRAS_API CallableRegistryEntry { CallableRegistryEntry(void); virtual ~CallableRegistryEntry(void); - virtual PMCC call(const std::vector<PMCC> &args) = 0; + virtual PMCC call(const PMCC *args) = 0; }; -template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1> -class CallableRegistryEntryImpl : public CallableRegistryEntry +/*********************************************************************** + * Registration for return with 0 args + **********************************************************************/ +template <typename ClassType, typename ReturnType> +struct CallableRegistryEntryImpl0 : CallableRegistryEntry { -public: - - typedef ReturnType(ClassType::*Fcn0)(void); - typedef ReturnType(ClassType::*Fcn1)(const Arg0 &); - typedef ReturnType(ClassType::*Fcn2)(const Arg0 &, const Arg1 &); - - CallableRegistryEntryImpl(ClassType *obj, Fcn0 fcn0, Fcn1 fcn1 = NULL, Fcn2 fcn2 = NULL): - _obj(obj), _fcn0(fcn0), _fcn1(fcn1), _fcn2(fcn2) - {} - virtual ~CallableRegistryEntryImpl(void){} - - PMCC call(const std::vector<PMCC> &args) + typedef ReturnType(ClassType::*Fcn)(void); + CallableRegistryEntryImpl0(ClassType *obj, Fcn fcn): + _obj(obj), _fcn(fcn){} + PMCC call(const PMCC *args) { - if (_fcn0) return PMC_M((_obj->*_fcn0)()); - if (_fcn1) return PMC_M((_obj->*_fcn1)(args[0].safe_as<Arg0>())); - if (_fcn2) return PMC_M((_obj->*_fcn2)(args[0].safe_as<Arg0>(), args[1].safe_as<Arg1>())); - return PMCC();//should not get here + return PMC_M((_obj->*_fcn)()); } - -private: - ClassType *_obj; - Fcn0 _fcn0; Fcn1 _fcn1; Fcn2 _fcn2; + ClassType *_obj; Fcn _fcn; }; template <typename ClassType, typename ReturnType> void Callable::register_call(const std::string &key, ReturnType(ClassType::*fcn)(void)) { ClassType *obj = dynamic_cast<ClassType *>(this); - void *fr = new CallableRegistryEntryImpl<ClassType, ReturnType, int, int>(obj, fcn); + void *fr = new CallableRegistryEntryImpl0<ClassType, ReturnType>(obj, fcn); _register_call(key, fr); } +template <typename ClassType> +struct CallableRegistryEntryImplVoid0 : CallableRegistryEntry +{ + typedef void(ClassType::*Fcn)(void); + CallableRegistryEntryImplVoid0(ClassType *obj, Fcn fcn): + _obj(obj), _fcn(fcn){} + PMCC call(const PMCC *args) + { + (_obj->*_fcn)(); return PMCC(); + } + ClassType *_obj; Fcn _fcn; +}; + +template <typename ClassType> +void Callable::register_call(const std::string &key, void(ClassType::*fcn)(void)) +{ + ClassType *obj = dynamic_cast<ClassType *>(this); + void *fr = new CallableRegistryEntryImplVoid0<ClassType>(obj, fcn); + _register_call(key, fr); +} + +/*********************************************************************** + * Registration for return with 1 args + **********************************************************************/ +template <typename ClassType, typename ReturnType, typename Arg0> +struct CallableRegistryEntryImpl1 : CallableRegistryEntry +{ + typedef ReturnType(ClassType::*Fcn)(const Arg0 &); + CallableRegistryEntryImpl1(ClassType *obj, Fcn fcn): + _obj(obj), _fcn(fcn){} + PMCC call(const PMCC *args) + { + return PMC_M((_obj->*_fcn)(args[0].safe_as<Arg0>())); + } + ClassType *_obj; Fcn _fcn; +}; + template <typename ClassType, typename ReturnType, typename Arg0> void Callable::register_call(const std::string &key, ReturnType(ClassType::*fcn)(const Arg0 &)) { ClassType *obj = dynamic_cast<ClassType *>(this); - void *fr = new CallableRegistryEntryImpl<ClassType, ReturnType, Arg0, int>(obj, NULL, fcn); + void *fr = new CallableRegistryEntryImpl1<ClassType, ReturnType, Arg0>(obj, fcn); + _register_call(key, fr); +} + +template <typename ClassType, typename Arg0> +struct CallableRegistryEntryImplVoid1 : CallableRegistryEntry +{ + typedef void(ClassType::*Fcn)(const Arg0 &); + CallableRegistryEntryImplVoid1(ClassType *obj, Fcn fcn): + _obj(obj), _fcn(fcn){} + PMCC call(const PMCC *args) + { + (_obj->*_fcn)(args[0].safe_as<Arg0>()); return PMCC(); + } + ClassType *_obj; Fcn _fcn; +}; + +template <typename ClassType, typename Arg0> +void Callable::register_call(const std::string &key, void(ClassType::*fcn)(const Arg0 &)) +{ + ClassType *obj = dynamic_cast<ClassType *>(this); + void *fr = new CallableRegistryEntryImplVoid1<ClassType, Arg0>(obj, fcn); _register_call(key, fr); } +/*********************************************************************** + * Registration for return with 2 args + **********************************************************************/ +template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1> +struct CallableRegistryEntryImpl2 : CallableRegistryEntry +{ + typedef ReturnType(ClassType::*Fcn)(const Arg0 &, const Arg1 &); + CallableRegistryEntryImpl2(ClassType *obj, Fcn fcn): + _obj(obj), _fcn(fcn){} + PMCC call(const PMCC *args) + { + return PMC_M((_obj->*_fcn)(args[0].safe_as<Arg0>(), args[1].safe_as<Arg1>())); + } + ClassType *_obj; Fcn _fcn; +}; + template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1> void Callable::register_call(const std::string &key, ReturnType(ClassType::*fcn)(const Arg0 &, const Arg1 &)) { ClassType *obj = dynamic_cast<ClassType *>(this); - void *fr = new CallableRegistryEntryImpl<ClassType, ReturnType, Arg0, Arg1>(obj, NULL, NULL, fcn); + void *fr = new CallableRegistryEntryImpl2<ClassType, ReturnType, Arg0, Arg1>(obj, fcn); _register_call(key, fr); } +template <typename ClassType, typename Arg0, typename Arg1> +struct CallableRegistryEntryImplVoid2 : CallableRegistryEntry +{ + typedef void(ClassType::*Fcn)(const Arg0 &, const Arg1 &); + CallableRegistryEntryImplVoid2(ClassType *obj, Fcn fcn): + _obj(obj), _fcn(fcn){} + PMCC call(const PMCC *args) + { + (_obj->*_fcn)(args[0].safe_as<Arg0>(), args[1].safe_as<Arg1>()); return PMCC(); + } + ClassType *_obj; Fcn _fcn; +}; + +template <typename ClassType, typename Arg0, typename Arg1> +void Callable::register_call(const std::string &key, void(ClassType::*fcn)(const Arg0 &, const Arg1 &)) +{ + ClassType *obj = dynamic_cast<ClassType *>(this); + void *fr = new CallableRegistryEntryImplVoid2<ClassType, Arg0, Arg1>(obj, fcn); + _register_call(key, fr); +} + +/*********************************************************************** + * Registration for return with 3 args + **********************************************************************/ +template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1, typename Arg2> +struct CallableRegistryEntryImpl3 : CallableRegistryEntry +{ + typedef ReturnType(ClassType::*Fcn)(const Arg0 &, const Arg1 &, const Arg2 &); + CallableRegistryEntryImpl3(ClassType *obj, Fcn fcn): + _obj(obj), _fcn(fcn){} + PMCC call(const PMCC *args) + { + return PMC_M((_obj->*_fcn)(args[0].safe_as<Arg0>(), args[1].safe_as<Arg1>(), args[2].safe_as<Arg2>())); + } + ClassType *_obj; Fcn _fcn; +}; + +template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1, typename Arg2> +void Callable::register_call(const std::string &key, ReturnType(ClassType::*fcn)(const Arg0 &, const Arg1 &, const Arg2 &)) +{ + ClassType *obj = dynamic_cast<ClassType *>(this); + void *fr = new CallableRegistryEntryImpl3<ClassType, ReturnType, Arg0, Arg1, Arg2>(obj, fcn); + _register_call(key, fr); +} + +template <typename ClassType, typename Arg0, typename Arg1, typename Arg2> +struct CallableRegistryEntryImplVoid3 : CallableRegistryEntry +{ + typedef void(ClassType::*Fcn)(const Arg0 &, const Arg1 &, const Arg2 &); + CallableRegistryEntryImplVoid3(ClassType *obj, Fcn fcn): + _obj(obj), _fcn(fcn){} + PMCC call(const PMCC *args) + { + (_obj->*_fcn)(args[0].safe_as<Arg0>(), args[1].safe_as<Arg1>(), args[2].safe_as<Arg2>()); return PMCC(); + } + ClassType *_obj; Fcn _fcn; +}; + +template <typename ClassType, typename Arg0, typename Arg1, typename Arg2> +void Callable::register_call(const std::string &key, void(ClassType::*fcn)(const Arg0 &, const Arg1 &, const Arg2 &)) +{ + ClassType *obj = dynamic_cast<ClassType *>(this); + void *fr = new CallableRegistryEntryImplVoid3<ClassType, Arg0, Arg1, Arg2>(obj, fcn); + _register_call(key, fr); +} + +/*********************************************************************** + * Call implementations with 0 args + **********************************************************************/ template <typename ReturnType> ReturnType Callable::call(const std::string &key) { - std::vector<PMCC> args; + PMCC args[0]; PMCC r = _handle_call(key, args); return r.safe_as<ReturnType>(); } +inline +void Callable::call(const std::string &key) +{ + PMCC args[0]; + _handle_call(key, args); +} + +/*********************************************************************** + * Call implementations with 1 args + **********************************************************************/ template <typename ReturnType, typename Arg0> ReturnType Callable::call(const std::string &key, const Arg0 &a0) { - std::vector<PMCC> args; - args.push_back(PMC_M(a0)); + PMCC args[1]; + args[0] = PMC_M(a0); PMCC r = _handle_call(key, args); return r.safe_as<ReturnType>(); } +template <typename Arg0> +void Callable::call(const std::string &key, const Arg0 &a0) +{ + PMCC args[1]; + args[0] = PMC_M(a0); + _handle_call(key, args); +} + +/*********************************************************************** + * Call implementations with 2 args + **********************************************************************/ template <typename ReturnType, typename Arg0, typename Arg1> ReturnType Callable::call(const std::string &key, const Arg0 &a0, const Arg1 &a1) { - std::vector<PMCC> args; - args.push_back(PMC_M(a0)); - args.push_back(PMC_M(a1)); + PMCC args[2]; + args[0] = PMC_M(a0); + args[1] = PMC_M(a1); PMCC r = _handle_call(key, args); return r.safe_as<ReturnType>(); } -inline -void Callable::call(const std::string &key) +template <typename Arg0, typename Arg1> +void Callable::call(const std::string &key, const Arg0 &a0, const Arg1 &a1) { - std::vector<PMCC> args; + PMCC args[2]; + args[0] = PMC_M(a0); + args[1] = PMC_M(a1); _handle_call(key, args); } -template <typename Arg0> -void Callable::call(const std::string &key, const Arg0 &a0) +/*********************************************************************** + * Call implementations with 3 args + **********************************************************************/ +template <typename ReturnType, typename Arg0, typename Arg1, typename Arg2> +ReturnType Callable::call(const std::string &key, const Arg0 &a0, const Arg1 &a1, const Arg2 &a2) { - std::vector<PMCC> args; - args.push_back(PMC_M(a0)); - _handle_call(key, args); + PMCC args[3]; + args[0] = PMC_M(a0); + args[1] = PMC_M(a1); + args[2] = PMC_M(a2); + PMCC r = _handle_call(key, args); + return r.safe_as<ReturnType>(); } -template <typename Arg0, typename Arg1> -void Callable::call(const std::string &key, const Arg0 &a0, const Arg1 &a1) +template <typename Arg0, typename Arg1, typename Arg2> +void Callable::call(const std::string &key, const Arg0 &a0, const Arg1 &a1, const Arg2 &a2) { - std::vector<PMCC> args; - args.push_back(PMC_M(a0)); - args.push_back(PMC_M(a1)); + PMCC args[3]; + args[0] = PMC_M(a0); + args[1] = PMC_M(a1); + args[2] = PMC_M(a2); _handle_call(key, args); } diff --git a/lib/callable.cpp b/lib/callable.cpp index a6417bb..6014974 100644 --- a/lib/callable.cpp +++ b/lib/callable.cpp @@ -26,7 +26,7 @@ void Callable::_register_call(const std::string &key, void *entry) (*cr)[key].reset(reinterpret_cast<CallableRegistryEntry *>(entry)); } -PMCC Callable::_handle_call(const std::string &key, const std::vector<PMCC> &args) +PMCC Callable::_handle_call(const std::string &key, const PMCC *args) { CallableRegistry *cr = reinterpret_cast<CallableRegistry *>(_call_registry); boost::shared_ptr<CallableRegistryEntry> entry = (*cr)[key]; diff --git a/tests/callable_test.cpp b/tests/callable_test.cpp index 1753f79..684a820 100644 --- a/tests/callable_test.cpp +++ b/tests/callable_test.cpp @@ -10,44 +10,107 @@ struct MyClass : gras::Callable { MyClass(void) { - this->register_call("foo", &MyClass::foo); - this->register_call("bar", &MyClass::bar); - this->register_call("baz", &MyClass::baz); - //this->register_call("example_setter", &MyClass::example_setter); + count = 0; + this->register_call("test_args0_with_return", &MyClass::test_args0_with_return); + this->register_call("test_args1_with_return", &MyClass::test_args1_with_return); + this->register_call("test_args2_with_return", &MyClass::test_args2_with_return); + this->register_call("test_args3_with_return", &MyClass::test_args3_with_return); + this->register_call("test_args0_with_no_return", &MyClass::test_args0_with_no_return); + this->register_call("test_args1_with_no_return", &MyClass::test_args1_with_no_return); + this->register_call("test_args2_with_no_return", &MyClass::test_args2_with_no_return); + this->register_call("test_args3_with_no_return", &MyClass::test_args3_with_no_return); } - int foo(void) + int test_args0_with_return(void) { - return 42; + return count; } - int bar(const std::string &a0) + int test_args1_with_return(const int &a0) { - return a0.size(); + return a0; } - int baz(const std::string &a0, const bool &a1) + int test_args2_with_return(const int &a0, const std::string &a1) { - return a1?a0.size():-1; + return a0 + a1.size(); } - void example_setter(const long &) + int test_args3_with_return(const int &a0, const std::string &a1, const bool &a3) { - + return a3? a0 + a1.size() : 0; } -}; -BOOST_AUTO_TEST_CASE(test_property_newshit) -{ - MyClass my_class; - size_t my_foo = my_class.call<size_t>("foo"); - BOOST_CHECK_EQUAL(my_foo, size_t(42)); + void test_args0_with_no_return(void) + { + count++; + } + + void test_args1_with_no_return(const int &a0) + { + count = a0; + } + + void test_args2_with_no_return(const int &a0, const std::string &a1) + { + count = a0 + a1.size(); + } - size_t my_bar = my_class.call<size_t>("bar", "hello"); - BOOST_CHECK_EQUAL(my_bar, size_t(5)); + void test_args3_with_no_return(const int &a0, const std::string &a1, const bool &a2) + { + if (a2) count = a0 + a1.size(); + else count = 0; + } - signed my_baz = my_class.call<signed>("baz", "hello", false); - BOOST_CHECK_EQUAL(my_baz, signed(-1)); + int count; +}; - //my_class.call("example_setter", 123); +BOOST_AUTO_TEST_CASE(test_registered_methods) +{ + MyClass my_class; + { + size_t ret = my_class.call<size_t>("test_args0_with_return"); + BOOST_CHECK_EQUAL(ret, size_t(0)); + } + { + size_t ret = my_class.call<size_t>("test_args1_with_return", 42); + BOOST_CHECK_EQUAL(ret, size_t(42)); + } + { + size_t ret = my_class.call<size_t>("test_args2_with_return", 1, "OK"); + BOOST_CHECK_EQUAL(ret, size_t(3)); + } + { + size_t ret = my_class.call<size_t>("test_args3_with_return", 1, "OK", true); + BOOST_CHECK_EQUAL(ret, size_t(3)); + } + { + size_t ret = my_class.call<size_t>("test_args3_with_return", 1, "OK", false); + BOOST_CHECK_EQUAL(ret, size_t(0)); + } + { + my_class.call("test_args0_with_no_return"); //this adds 1 to count + size_t ret = my_class.call<size_t>("test_args0_with_return"); + BOOST_CHECK_EQUAL(ret, size_t(1)); + } + { + my_class.call("test_args1_with_no_return", 42); + size_t ret = my_class.call<size_t>("test_args0_with_return"); + BOOST_CHECK_EQUAL(ret, size_t(42)); + } + { + my_class.call("test_args2_with_no_return", 1, "OK"); + size_t ret = my_class.call<size_t>("test_args0_with_return"); + BOOST_CHECK_EQUAL(ret, size_t(3)); + } + { + my_class.call("test_args3_with_no_return", 1, "OK", true); + size_t ret = my_class.call<size_t>("test_args0_with_return"); + BOOST_CHECK_EQUAL(ret, size_t(3)); + } + { + my_class.call("test_args3_with_no_return", 1, "OK", false); + size_t ret = my_class.call<size_t>("test_args0_with_return"); + BOOST_CHECK_EQUAL(ret, size_t(0)); + } } |