summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Blum2013-07-04 19:46:58 -0700
committerJosh Blum2013-07-04 19:46:58 -0700
commit1298bcd1e421ccfefafa78c6d33760818902f399 (patch)
treee4c57bbcf98f9e7502850e5ab481ba7b9d4c11fc
parentfbec0c405a1fec4e8ee82d065fdc657cdd333f52 (diff)
downloadsandhi-1298bcd1e421ccfefafa78c6d33760818902f399.tar.gz
sandhi-1298bcd1e421ccfefafa78c6d33760818902f399.tar.bz2
sandhi-1298bcd1e421ccfefafa78c6d33760818902f399.zip
gras: function registry is more flexible
-rw-r--r--include/gras/block.hpp13
-rw-r--r--include/gras/detail/block.hpp87
-rw-r--r--lib/block_props.cpp15
-rw-r--r--lib/gras_impl/block_data.hpp2
-rw-r--r--tests/block_props_test.cpp50
5 files changed, 167 insertions, 0 deletions
diff --git a/include/gras/block.hpp b/include/gras/block.hpp
index f2f1b2b..ba9a64a 100644
--- a/include/gras/block.hpp
+++ b/include/gras/block.hpp
@@ -166,6 +166,14 @@ struct GRAS_API Block : Element
* Provides polymorphic, thread-safe access to block properties.
******************************************************************/
+ 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 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 &);
+
/*!
* Register property getter method into the property interface.
* Call register_getter() from the contructor of the block.
@@ -430,6 +438,11 @@ struct GRAS_API Block : Element
/*******************************************************************
* private implementation guts for overloads and template support
******************************************************************/
+
+ void _register_function(const std::string &, void *);
+ virtual PMCC _handle_function_access(const std::string &, const std::vector<PMCC> &);
+
+
virtual PMCC _handle_prop_access(const std::string &, const PMCC &, const bool);
void _register_getter(const std::string &, void *);
void _register_setter(const std::string &, void *);
diff --git a/include/gras/detail/block.hpp b/include/gras/detail/block.hpp
index 9dccb22..fcd52e1 100644
--- a/include/gras/detail/block.hpp
+++ b/include/gras/detail/block.hpp
@@ -8,6 +8,93 @@
namespace gras
{
+struct GRAS_API FunctionRegistry
+{
+ FunctionRegistry(void);
+ virtual ~FunctionRegistry(void);
+ virtual PMCC call(const std::vector<PMCC> &args) = 0;
+};
+
+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)
+ {}
+ virtual ~FunctionRegistryImpl(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;
+ ReturnType(ClassType::*_fcn0)(void);
+ ReturnType(ClassType::*_fcn1)(const Arg0 &);
+ ReturnType(ClassType::*_fcn2)(const Arg0 &, const Arg1 &);
+};
+
+template <typename ClassType, typename ReturnType> void Block::register_call(const std::string &key, ReturnType(ClassType::*fcn)(void))
+{
+ ClassType *obj = dynamic_cast<ClassType *>(this);
+ void *fr = new FunctionRegistryImpl<ClassType, ReturnType, int, int>(obj, fcn);
+ _register_function(key, fr);
+}
+
+template <typename ClassType, typename ReturnType, typename Arg0> void Block::register_call(const std::string &key, ReturnType(ClassType::*fcn)(const Arg0 &))
+{
+ ClassType *obj = dynamic_cast<ClassType *>(this);
+ void *fr = new FunctionRegistryImpl<ClassType, ReturnType, Arg0, int>(obj, NULL, fcn);
+ _register_function(key, fr);
+}
+
+template <typename ClassType, typename ReturnType, typename Arg0, typename Arg1> void Block::register_call(const std::string &key, ReturnType(ClassType::*fcn)(const Arg0 &, const Arg1 &))
+{
+ ClassType *obj = dynamic_cast<ClassType *>(this);
+ void *fr = new FunctionRegistryImpl<ClassType, ReturnType, Arg0, Arg1>(obj, NULL, NULL, fcn);
+ _register_function(key, fr);
+}
+
+template <typename ReturnType> ReturnType Block::call(const std::string &key)
+{
+ std::vector<PMCC> args;
+ PMCC r = _handle_function_access(key, args);
+ return r.safe_as<ReturnType>();
+}
+
+template <typename ReturnType, typename Arg0> ReturnType Block::call(const std::string &key, const Arg0 &a0)
+{
+ std::vector<PMCC> args;
+ args.push_back(PMC_M(a0));
+ PMCC r = _handle_function_access(key, args);
+ return r.safe_as<ReturnType>();
+}
+
+template <typename ReturnType, typename Arg0, typename Arg1> ReturnType 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));
+ PMCC r = _handle_function_access(key, args);
+ return r.safe_as<ReturnType>();
+}
+
+
+
+
struct GRAS_API PropertyRegistry
{
PropertyRegistry(void);
diff --git a/lib/block_props.cpp b/lib/block_props.cpp
index ae687be..fc4c755 100644
--- a/lib/block_props.cpp
+++ b/lib/block_props.cpp
@@ -5,6 +5,9 @@
using namespace gras;
+FunctionRegistry::FunctionRegistry(void){}
+FunctionRegistry::~FunctionRegistry(void){}
+
PropertyRegistry::PropertyRegistry(void){}
PropertyRegistry::~PropertyRegistry(void){}
@@ -113,3 +116,15 @@ PMCC Block::_get_property(const std::string &key)
{
return prop_access_dispatcher((*this)->block_actor, key, PMCC(), false);
}
+
+
+void Block::_register_function(const std::string &key, void *fr)
+{
+ (*this)->block_data->function_registry[key].reset(reinterpret_cast<FunctionRegistry *>(fr));
+}
+
+PMCC Block::_handle_function_access(const std::string &key, const std::vector<PMCC> &args)
+{
+ //TODO this is testing -- needs to call actor instead
+ return (*this)->block_data->function_registry[key]->call(args);
+}
diff --git a/lib/gras_impl/block_data.hpp b/lib/gras_impl/block_data.hpp
index cbc657e..664ee5a 100644
--- a/lib/gras_impl/block_data.hpp
+++ b/lib/gras_impl/block_data.hpp
@@ -18,6 +18,7 @@
namespace gras
{
+typedef boost::shared_ptr<FunctionRegistry> FunctionRegistrySptr;
typedef boost::shared_ptr<PropertyRegistry> PropertyRegistrySptr;
struct PropertyRegistryPair
{
@@ -82,6 +83,7 @@ struct BlockData
//property stuff
std::map<std::string, PropertyRegistryPair> property_registry;
+ std::map<std::string, FunctionRegistrySptr> function_registry;
BlockStats stats;
};
diff --git a/tests/block_props_test.cpp b/tests/block_props_test.cpp
index f53a1c3..ad1c5e2 100644
--- a/tests/block_props_test.cpp
+++ b/tests/block_props_test.cpp
@@ -68,3 +68,53 @@ BOOST_AUTO_TEST_CASE(test_property_errors)
//wrong type for property
BOOST_CHECK_THROW(my_block.set("foo", "a string"), std::exception);
}
+
+struct MyBlockNewShit : gras::Block
+{
+ MyBlockNewShit(void):
+ gras::Block("MyBlockNewShit")
+ {
+ this->register_call("foo", &MyBlockNewShit::foo);
+ this->register_call("bar", &MyBlockNewShit::bar);
+ this->register_call("baz", &MyBlockNewShit::baz);
+ //this->register_call("example_setter", &MyBlockNewShit::example_setter);
+ }
+
+ //dummy work
+ void work(const InputItems &, const OutputItems &){}
+
+ 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)
+{
+ MyBlockNewShit my_block;
+ size_t my_foo = my_block.call<size_t>("foo");
+ BOOST_CHECK_EQUAL(my_foo, size_t(42));
+
+ size_t my_bar = my_block.call<size_t>("bar", "hello");
+ BOOST_CHECK_EQUAL(my_bar, size_t(5));
+
+ signed my_baz = my_block.call<signed>("baz", "hello", false);
+ BOOST_CHECK_EQUAL(my_baz, signed(-1));
+
+ //my_block.call<int>("example_setter", 123);
+}