diff options
-rw-r--r-- | include/gras/callable.hpp | 2 | ||||
-rw-r--r-- | include/gras/detail/callable.hpp | 45 | ||||
-rw-r--r-- | lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/callable.cpp | 45 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/callable_test.cpp | 53 |
6 files changed, 128 insertions, 19 deletions
diff --git a/include/gras/callable.hpp b/include/gras/callable.hpp index 07c6034..6b2a3b6 100644 --- a/include/gras/callable.hpp +++ b/include/gras/callable.hpp @@ -79,7 +79,7 @@ struct GRAS_API Callable ******************************************************************/ 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; + void *_call_registry; }; } //namespace gras diff --git a/include/gras/detail/callable.hpp b/include/gras/detail/callable.hpp index 86b741d..5e7854a 100644 --- a/include/gras/detail/callable.hpp +++ b/include/gras/detail/callable.hpp @@ -8,15 +8,15 @@ namespace gras { -struct GRAS_API CallableRegistry +struct GRAS_API CallableRegistryEntry { - CallableRegistry(void); - virtual ~CallableRegistry(void); + CallableRegistryEntry(void); + virtual ~CallableRegistryEntry(void); virtual PMCC call(const std::vector<PMCC> &args) = 0; }; template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1> -class CallableRegistryImpl : public CallableRegistry +class CallableRegistryEntryImpl : public CallableRegistryEntry { public: @@ -24,10 +24,10 @@ public: 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): + CallableRegistryEntryImpl(ClassType *obj, Fcn0 fcn0, Fcn1 fcn1 = NULL, Fcn2 fcn2 = NULL): _obj(obj), _fcn0(fcn0), _fcn1(fcn1), _fcn2(fcn2) {} - virtual ~CallableRegistryImpl(void){} + virtual ~CallableRegistryEntryImpl(void){} PMCC call(const std::vector<PMCC> &args) { @@ -42,35 +42,40 @@ private: Fcn0 _fcn0; Fcn1 _fcn1; Fcn2 _fcn2; }; -template <typename ClassType, typename ReturnType> void Callable::register_call(const std::string &key, ReturnType(ClassType::*fcn)(void)) +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); + void *fr = new CallableRegistryEntryImpl<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 &)) +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); + void *fr = new CallableRegistryEntryImpl<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 &)) +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); + void *fr = new CallableRegistryEntryImpl<ClassType, ReturnType, Arg0, Arg1>(obj, NULL, NULL, fcn); _register_call(key, fr); } -template <typename ReturnType> ReturnType Callable::call(const std::string &key) +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) +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)); @@ -78,7 +83,8 @@ template <typename ReturnType, typename Arg0> ReturnType Callable::call(const st 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) +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)); @@ -87,20 +93,23 @@ template <typename ReturnType, typename Arg0, typename Arg1> ReturnType Callable return r.safe_as<ReturnType>(); } -inline void Callable::call(const std::string &key) +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) +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) +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)); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index ab5d886..38216b3 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -41,6 +41,7 @@ list(APPEND GRAS_SOURCES ${apology_sources}) ######################################################################## list(APPEND GRAS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/debug.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/callable.cpp ${CMAKE_CURRENT_SOURCE_DIR}/element.cpp ${CMAKE_CURRENT_SOURCE_DIR}/element_uid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sbuffer.cpp diff --git a/lib/callable.cpp b/lib/callable.cpp new file mode 100644 index 0000000..a6417bb --- /dev/null +++ b/lib/callable.cpp @@ -0,0 +1,45 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#include <gras/callable.hpp> +#include <boost/shared_ptr.hpp> +#include <stdexcept> +#include <map> + +using namespace gras; + +typedef std::map<std::string, boost::shared_ptr<CallableRegistryEntry> > CallableRegistry; + +Callable::Callable(void) +{ + _call_registry = new CallableRegistry(); +} + +Callable::~Callable(void) +{ + CallableRegistry *cr = reinterpret_cast<CallableRegistry *>(_call_registry); + delete cr; +} + +void Callable::_register_call(const std::string &key, void *entry) +{ + CallableRegistry *cr = reinterpret_cast<CallableRegistry *>(_call_registry); + (*cr)[key].reset(reinterpret_cast<CallableRegistryEntry *>(entry)); +} + +PMCC Callable::_handle_call(const std::string &key, const std::vector<PMCC> &args) +{ + CallableRegistry *cr = reinterpret_cast<CallableRegistry *>(_call_registry); + boost::shared_ptr<CallableRegistryEntry> entry = (*cr)[key]; + if (not entry) throw std::invalid_argument("Callable: no method registered for key: " + key); + return entry->call(args); +} + +CallableRegistryEntry::CallableRegistryEntry(void) +{ + //NOP +} + +CallableRegistryEntry::~CallableRegistryEntry(void) +{ + //NOP +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bc3815e..bb3f3c8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,6 +14,7 @@ if (NOT Boost_FOUND) endif() set(test_sources + callable_test.cpp chrono_time_test.cpp block_props_test.cpp serialize_tags_test.cpp diff --git a/tests/callable_test.cpp b/tests/callable_test.cpp new file mode 100644 index 0000000..1753f79 --- /dev/null +++ b/tests/callable_test.cpp @@ -0,0 +1,53 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#include <boost/test/unit_test.hpp> +#include <iostream> + +#include <gras/callable.hpp> + + +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); + } + + int foo(void) + { + return 42; + } + + int bar(const std::string &a0) + { + return a0.size(); + } + + int baz(const std::string &a0, const bool &a1) + { + return a1?a0.size():-1; + } + + void example_setter(const long &) + { + + } +}; + +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)); + + size_t my_bar = my_class.call<size_t>("bar", "hello"); + BOOST_CHECK_EQUAL(my_bar, size_t(5)); + + signed my_baz = my_class.call<signed>("baz", "hello", false); + BOOST_CHECK_EQUAL(my_baz, signed(-1)); + + //my_class.call("example_setter", 123); +} |