How To Write A Wrapper Over Functions And Member Functions That Executes Some Code Before And After The Wrapped Function?
Solution 1:
In this case, you can write a Functor class that wraps over your function, and then overload boost::python::detail::get_signature to accept your Functor!
UPDATE: Added support for member functions too!
Example:
#include<boost/shared_ptr.hpp>#include<boost/python.hpp>#include<boost/python/signature.hpp>#include<boost/mpl/vector.hpp>#include<iostream>#include<string>#include<sstream>static boost::shared_ptr<std::ostringstream> test_stream_data;
std::ostringstream& test_stream(){
if (!test_stream_data) {
test_stream_data.reset(new std::ostringstream);
}
return *test_stream_data;
}
std::string get_value_and_clear_test_stream(){
std::string result;
if (test_stream_data) {
result = test_stream_data->str();
}
test_stream_data.reset(new std::ostringstream);
return result;
}
std::string func(int a, double b){
std::ostringstream oss;
oss << "func(a=" << a << ", b=" << b << ")";
std::string result = oss.str();
test_stream() << "- In " << result << std::endl;
return result;
}
classMyClass
{
public:
MyClass(std::string p_name)
: m_name(p_name)
{
test_stream() << "- In MyClass::MyClass(p_name=\"" << p_name << "\")" << std::endl;
}
MyClass(MyClass const& p_another)
: m_name(p_another.m_name)
{
test_stream()
<< "- In MyClass::MyClass(p_another=MyClass(\""
<< p_another.m_name << "\"))" << std::endl;
}
~MyClass()
{
test_stream() << "- In MyClass(\"" << this->m_name << "\")::~MyClass()" << std::endl;
}
boost::shared_ptr<MyClass> clone_and_change(std::string p_new_name){
test_stream()
<< "- In MyClass(\"" << this->m_name << "\").clone_and_change(p_new_name=\""
<< p_new_name << "\")" << std::endl;
boost::shared_ptr<MyClass> result(new MyClass(*this));
result->m_name = p_new_name;
return result;
}
std::string get_name(){
test_stream() << "- In MyClass(\"" << this->m_name << "\").get_name()" << std::endl;
returnthis->m_name;
}
std::string m_name;
};
structScopePreAndPostActions
{
ScopePreAndPostActions()
{
test_stream() << "[Before action...]" << std::endl;
}
~ScopePreAndPostActions()
{
test_stream() << "[After action...]" << std::endl;
}
};
template <classFuncType_>
structFuncWrapper;
// You can code-generate specializations for other arities...template <classR_, classA0_, classA1_>
structFuncWrapper<R_ (A0_, A1_)>
{
typedefR_(*func_type)(A0_, A1_);
typedeftypename boost::add_const<typename boost::add_reference<typename A0_>::type>::type AC0_;
typedeftypename boost::add_const<typename boost::add_reference<typename A1_>::type>::type AC1_;
func_type m_wrapped_func;
FuncWrapper(func_type p_wrapped_func)
: m_wrapped_func(p_wrapped_func)
{
}
R_ operator()(AC0_ p0, AC1_ p1){
ScopePreAndPostActions actions_guard;
returnthis->m_wrapped_func(p0, p1);
}
};
template <
classR_,
classC_,
classA0_=void,
class A1_=void,
class A2_=void// ...
>
struct MemberFuncWrapper;
template <classR_, classC_, classA0_>
structMemberFuncWrapper<R_, C_, A0_>
{
typedefR_(C_::*member_func_type)(A0_);
typedeftypename boost::add_const<typename boost::add_reference<typename A0_>::type>::type AC0_;
member_func_type m_wrapped_method;
MemberFuncWrapper(member_func_type p_wrapped_method)
: m_wrapped_method(p_wrapped_method)
{
}
R_ operator()(C_* p_self, AC0_ p0){
ScopePreAndPostActions actions_guard;
return (p_self->*(this->m_wrapped_method))(p0);
returnR_();
}
};
namespace boost { namespace python { namespace detail {
// You can code-generate specializations for other arities...template <classR_, classP0_, classP1_>
inline boost::mpl::vector<R_, P0_, P1_>
get_signature(FuncWrapper<R_ (P0_, P1_)>, void* = 0){
return boost::mpl::vector<R_, P0_, P1_>();
}
template <classR_, classC_, classP0_>
inline boost::mpl::vector<R_, C_*, P0_>
get_signature(MemberFuncWrapper<R_, C_, P0_>, void* = 0){
return boost::mpl::vector<R_, C_*, P0_>();
}
} } }
// -------------------------------------------------------------------template <classFuncPtr_>
voidmake_wrapper(FuncPtr_);
// You can code-generate specializations for other arities...template <classR_, classA0_, classA1_>
FuncWrapper<R_(A0_, A1_)> make_wrapper(R_ (*p_wrapped_func)(A0_, A1_)){
returnFuncWrapper<R_ (A0_, A1_)>(p_wrapped_func);
}
template <classR_, classC_, classA0_>
MemberFuncWrapper<R_, C_, A0_> make_wrapper(R_ (C_::*p_wrapped_method)(A0_)){
returnMemberFuncWrapper<R_, C_, A0_>(p_wrapped_method);
}
template <classR_, classC_, classA0_, classA1_>
MemberFuncWrapper<R_, C_, A0_, A1_> make_wrapper(R_ (C_::*p_wrapped_method)(A0_, A1_)){
returnMemberFuncWrapper<R_, C_, A0_, A1_>(p_wrapped_method);
}
usingnamespace boost::python;
voidRegisterTestWrapper(){
def("GetValueAndClearTestStream", &get_value_and_clear_test_stream);
def("TestFunc", &func);
def(
"TestWrappedFunctor",
make_wrapper(&func)
);
{
class_< MyClass, shared_ptr<MyClass>, boost::noncopyable > c("MyClass", init<std::string>());
c.def("CloneAndChange", &MyClass::clone_and_change);
c.def("GetName", &MyClass::get_name);
c.def("WrappedCloneAndChange", make_wrapper(&MyClass::clone_and_change));
}
}
And on python:
import unittest
from _test_wrapper import GetValueAndClearTestStream, TestFunc, TestWrappedFunctor, MyClass
classTest(unittest.TestCase):
defsetUp(self):
GetValueAndClearTestStream()
deftestWrapper(self):
self.assertEqual(TestFunc(69, 1.618), 'func(a=69, b=1.618)')
self.assertEqual(GetValueAndClearTestStream(), '- In func(a=69, b=1.618)\n')
self.assertEqual(TestWrappedFunctor(69, 1.618), 'func(a=69, b=1.618)')
self.assertEqual(
GetValueAndClearTestStream(),
(
'[Before action...]\n''- In func(a=69, b=1.618)\n''[After action...]\n'
),
)
deftestWrappedMemberFunction(self):
from textwrap import dedent
x = MyClass("xx")
y = x.WrappedCloneAndChange("yy")
z = y.WrappedCloneAndChange("zz")
self.assertEqual(x.GetName(), "xx")
self.assertEqual(y.GetName(), "yy")
self.assertEqual(z.GetName(), "zz")
self.assertEqual(
GetValueAndClearTestStream(),
dedent('''\
- In MyClass::MyClass(p_name="xx")
[Before action...]
- In MyClass("xx").clone_and_change(p_new_name="yy")
- In MyClass::MyClass(p_another=MyClass("xx"))
[After action...]
[Before action...]
- In MyClass("yy").clone_and_change(p_new_name="zz")
- In MyClass::MyClass(p_another=MyClass("yy"))
[After action...]
- In MyClass("xx").get_name()
- In MyClass("yy").get_name()
- In MyClass("zz").get_name()
'''),
)
Solution 2:
Have you looked at the function wrapping technique described by Stroustrup in his "Wrapping C++ Member Function Calls" paper? There's also a SO response here that demonstrates how to implement it in a concise manner. Basically you'd implement a template that overloads operator->()
. Within that operator
's implementation you'd construct a temporary object before your actual function call. The temporary object's constructor and destructor take care of invoking your "pre-" and "post-" code before and after your actual function call, respectively.
Post a Comment for "How To Write A Wrapper Over Functions And Member Functions That Executes Some Code Before And After The Wrapped Function?"