diff options
author | Josh Blum | 2013-07-05 14:08:12 -0700 |
---|---|---|
committer | Josh Blum | 2013-07-05 14:08:12 -0700 |
commit | bc8165bcc3a2703d8fd3d17925b6bcb55ddff6ef (patch) | |
tree | c90c0829a173381398bf6a28c8e5780f76de586f | |
parent | 1298bcd1e421ccfefafa78c6d33760818902f399 (diff) | |
download | sandhi-bc8165bcc3a2703d8fd3d17925b6bcb55ddff6ef.tar.gz sandhi-bc8165bcc3a2703d8fd3d17925b6bcb55ddff6ef.tar.bz2 sandhi-bc8165bcc3a2703d8fd3d17925b6bcb55ddff6ef.zip |
gras: save callable work before we tear up more
m--------- | PMC | 0 | ||||
m--------- | grextras | 0 | ||||
-rw-r--r-- | include/gras/CMakeLists.txt | 2 | ||||
-rw-r--r-- | include/gras/block.hpp | 9 | ||||
-rw-r--r-- | include/gras/callable.hpp | 89 | ||||
-rw-r--r-- | include/gras/detail/block.hpp | 39 | ||||
-rw-r--r-- | include/gras/detail/callable.hpp | 113 | ||||
-rw-r--r-- | tests/block_props_test.cpp | 2 |
8 files changed, 240 insertions, 14 deletions
diff --git a/PMC b/PMC -Subproject 8b452d920f64e7cf7d0ebbd5181aed4508fa3c2 +Subproject 53d848db2bae3e3bd6bf73ef1ca34bf8d777a9c diff --git a/grextras b/grextras -Subproject b6d5eb07a59c7849ad50a19ff05a1570f7aea67 +Subproject 79583e7fd6302ea4555c476dcfd9ab4c55a5fff diff --git a/include/gras/CMakeLists.txt b/include/gras/CMakeLists.txt index d432747..38cb233 100644 --- a/include/gras/CMakeLists.txt +++ b/include/gras/CMakeLists.txt @@ -4,6 +4,7 @@ install(FILES exception.i + callable.hpp chrono.hpp block.hpp block_config.hpp @@ -34,6 +35,7 @@ install(FILES install(FILES + detail/callable.hpp detail/block.hpp detail/chrono.hpp detail/element.hpp diff --git a/include/gras/block.hpp b/include/gras/block.hpp index ba9a64a..9ea609a 100644 --- a/include/gras/block.hpp +++ b/include/gras/block.hpp @@ -174,6 +174,15 @@ struct GRAS_API Block : Element 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 &); + + template <typename ClassType> void register_call(const std::string &key, void(ClassType::*fcn)(void)); + template <typename ClassType, typename Arg0> void register_call(const std::string &key, void(ClassType::*fcn)(const Arg0 &)); + template <typename ClassType, typename Arg0, typename Arg1> void register_call(const std::string &key, void(ClassType::*fcn)(const Arg0 &, const Arg1 &)); + + void call(const std::string &key); + template <typename Arg0> void call(const std::string &key, const Arg0 &); + template <typename Arg0, typename Arg1> void call(const std::string &key, const Arg0 &, const Arg1 &); + /*! * Register property getter method into the property interface. * Call register_getter() from the contructor of the block. diff --git a/include/gras/callable.hpp b/include/gras/callable.hpp new file mode 100644 index 0000000..07c6034 --- /dev/null +++ b/include/gras/callable.hpp @@ -0,0 +1,89 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#ifndef INCLUDED_GRAS_CALLABLE_HPP +#define INCLUDED_GRAS_CALLABLE_HPP + +#include <gras/gras.hpp> +#include <PMC/PMC.hpp> +#include <string> +#include <vector> + +namespace gras +{ + +/*! + * The callable interface allows subclasses to export public methods, + * but without actually exporting traditional library symbols. + * + * Callable handles the template magic so you don't have to: + * - registering subclass methods is simple and easy on the user. + * - users call registered methods with natural code aesthetics. + * + * Register a method (in the constructor of MyClass): + * this->register_call("set_foo", &MyClass::set_foo); + * + * Call a method on a instance of MyClass: + * my_class->call("set_foo", new_foo_val); + */ +struct GRAS_API Callable +{ + //! Default constructor + Callable(void); + + //! Destructor (virtual for subclasses) + virtual ~Callable(void); + + /******************************************************************* + * Register API - don't look here, template magic, not helpful + ******************************************************************/ + 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 Arg0> + void register_call(const std::string &key, void(ClassType::*fcn)(const Arg0 &)); + + template <typename ClassType, typename Arg0, typename Arg1> + void register_call(const std::string &key, void(ClassType::*fcn)(const Arg0 &, const Arg1 &)); + + /******************************************************************* + * Call API - don't look here, template magic, not helpful + ******************************************************************/ + template <typename ReturnType> + ReturnType 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 Arg0, typename Arg1> + void call(const std::string &key, const Arg0 &, const Arg1 &); + + /******************************************************************* + * Private registration hooks + ******************************************************************/ + void _register_call(const std::string &, void *); + virtual PMCC _handle_call(const std::string &, const std::vector<PMCC> &); + std::map<std::string, void *> _call_registry; +}; + +} //namespace gras + +#include <gras/detail/callable.hpp> + +#endif /*INCLUDED_GRAS_CALLABLE_HPP*/ diff --git a/include/gras/detail/block.hpp b/include/gras/detail/block.hpp index fcd52e1..e098797 100644 --- a/include/gras/detail/block.hpp +++ b/include/gras/detail/block.hpp @@ -19,16 +19,13 @@ template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1> class FunctionRegistryImpl : public FunctionRegistry { public: - FunctionRegistryImpl( - ClassType *obj, - ReturnType(ClassType::*fcn0)(void), - ReturnType(ClassType::*fcn1)(const Arg0 &) = NULL, - ReturnType(ClassType::*fcn2)(const Arg0 &, const Arg1 &) = NULL - ): - _obj(obj), - _fcn0(fcn0), - _fcn1(fcn1), - _fcn2(fcn2) + + typedef ReturnType(ClassType::*Fcn0)(void); + typedef ReturnType(ClassType::*Fcn1)(const Arg0 &); + typedef ReturnType(ClassType::*Fcn2)(const Arg0 &, const Arg1 &); + + FunctionRegistryImpl(ClassType *obj, Fcn0 fcn0, Fcn1 fcn1 = NULL, Fcn2 fcn2 = NULL): + _obj(obj), _fcn0(fcn0), _fcn1(fcn1), _fcn2(fcn2) {} virtual ~FunctionRegistryImpl(void){} @@ -42,9 +39,7 @@ public: private: ClassType *_obj; - ReturnType(ClassType::*_fcn0)(void); - ReturnType(ClassType::*_fcn1)(const Arg0 &); - ReturnType(ClassType::*_fcn2)(const Arg0 &, const Arg1 &); + Fcn0 _fcn0; Fcn1 _fcn1; Fcn2 _fcn2; }; template <typename ClassType, typename ReturnType> void Block::register_call(const std::string &key, ReturnType(ClassType::*fcn)(void)) @@ -92,8 +87,26 @@ template <typename ReturnType, typename Arg0, typename Arg1> ReturnType Block::c return r.safe_as<ReturnType>(); } +inline void Block::call(const std::string &key) +{ + std::vector<PMCC> args; + _handle_function_access(key, args); +} +template <typename Arg0> void Block::call(const std::string &key, const Arg0 &a0) +{ + std::vector<PMCC> args; + args.push_back(PMC_M(a0)); + _handle_function_access(key, args); +} +template <typename Arg0, typename Arg1> void Block::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)); + _handle_function_access(key, args); +} struct GRAS_API PropertyRegistry { diff --git a/include/gras/detail/callable.hpp b/include/gras/detail/callable.hpp new file mode 100644 index 0000000..86b741d --- /dev/null +++ b/include/gras/detail/callable.hpp @@ -0,0 +1,113 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#ifndef INCLUDED_GRAS_DETAIL_CALLABLE_HPP +#define INCLUDED_GRAS_DETAIL_CALLABLE_HPP + +#include <typeinfo> + +namespace gras +{ + +struct GRAS_API CallableRegistry +{ + CallableRegistry(void); + virtual ~CallableRegistry(void); + virtual PMCC call(const std::vector<PMCC> &args) = 0; +}; + +template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1> +class CallableRegistryImpl : public CallableRegistry +{ +public: + + typedef ReturnType(ClassType::*Fcn0)(void); + typedef ReturnType(ClassType::*Fcn1)(const Arg0 &); + typedef ReturnType(ClassType::*Fcn2)(const Arg0 &, const Arg1 &); + + CallableRegistryImpl(ClassType *obj, Fcn0 fcn0, Fcn1 fcn1 = NULL, Fcn2 fcn2 = NULL): + _obj(obj), _fcn0(fcn0), _fcn1(fcn1), _fcn2(fcn2) + {} + virtual ~CallableRegistryImpl(void){} + + PMCC call(const std::vector<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 + } + +private: + ClassType *_obj; + Fcn0 _fcn0; Fcn1 _fcn1; Fcn2 _fcn2; +}; + +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 CallableRegistryImpl<ClassType, ReturnType, int, int>(obj, fcn); + _register_call(key, fr); +} + +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 CallableRegistryImpl<ClassType, ReturnType, Arg0, int>(obj, NULL, fcn); + _register_call(key, fr); +} + +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 CallableRegistryImpl<ClassType, ReturnType, Arg0, Arg1>(obj, NULL, NULL, fcn); + _register_call(key, fr); +} + +template <typename ReturnType> ReturnType Callable::call(const std::string &key) +{ + std::vector<PMCC> args; + PMCC r = _handle_call(key, args); + return r.safe_as<ReturnType>(); +} + +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 r = _handle_call(key, args); + return r.safe_as<ReturnType>(); +} + +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 r = _handle_call(key, args); + return r.safe_as<ReturnType>(); +} + +inline void Callable::call(const std::string &key) +{ + std::vector<PMCC> args; + _handle_call(key, args); +} + +template <typename Arg0> void Callable::call(const std::string &key, const Arg0 &a0) +{ + std::vector<PMCC> args; + args.push_back(PMC_M(a0)); + _handle_call(key, args); +} + +template <typename Arg0, typename Arg1> void 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)); + _handle_call(key, args); +} + +} //namespace gras + +#endif /*INCLUDED_GRAS_DETAIL_CALLABLE_HPP*/ diff --git a/tests/block_props_test.cpp b/tests/block_props_test.cpp index ad1c5e2..91afd24 100644 --- a/tests/block_props_test.cpp +++ b/tests/block_props_test.cpp @@ -116,5 +116,5 @@ BOOST_AUTO_TEST_CASE(test_property_newshit) signed my_baz = my_block.call<signed>("baz", "hello", false); BOOST_CHECK_EQUAL(my_baz, signed(-1)); - //my_block.call<int>("example_setter", 123); + //my_block.call("example_setter", 123); } |