summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Blum2013-07-05 14:08:12 -0700
committerJosh Blum2013-07-05 14:08:12 -0700
commitbc8165bcc3a2703d8fd3d17925b6bcb55ddff6ef (patch)
treec90c0829a173381398bf6a28c8e5780f76de586f
parent1298bcd1e421ccfefafa78c6d33760818902f399 (diff)
downloadsandhi-bc8165bcc3a2703d8fd3d17925b6bcb55ddff6ef.tar.gz
sandhi-bc8165bcc3a2703d8fd3d17925b6bcb55ddff6ef.tar.bz2
sandhi-bc8165bcc3a2703d8fd3d17925b6bcb55ddff6ef.zip
gras: save callable work before we tear up more
m---------PMC0
m---------grextras0
-rw-r--r--include/gras/CMakeLists.txt2
-rw-r--r--include/gras/block.hpp9
-rw-r--r--include/gras/callable.hpp89
-rw-r--r--include/gras/detail/block.hpp39
-rw-r--r--include/gras/detail/callable.hpp113
-rw-r--r--tests/block_props_test.cpp2
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);
}