From: Thomas Geymayer Date: Sat, 22 Mar 2014 11:31:03 +0000 (+0100) Subject: cppbind: allow calling methods with 'me' object from C++. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=13a3ea3503cfcf835305bd0e8f53fbe4b1d2f1cc;p=simgear.git cppbind: allow calling methods with 'me' object from C++. --- diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index a1d82b32..b186a186 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -542,6 +542,11 @@ namespace nasal return method(name, boost::bind(method_invoker, func, _1, _2)); } + // Build dependency for CMake, gcc, etc. +#define SG_DONT_DO_ANYTHING +# include +#undef SG_DONT_DO_ANYTHING + #define BOOST_PP_ITERATION_LIMITS (0, 9) #define BOOST_PP_FILENAME_1 #include BOOST_PP_ITERATE() @@ -732,7 +737,7 @@ namespace nasal ( c, "method called on object of wrong type: is '%s' expected '%s'", - ghost_type ? ghost_type->name : "unknown", + naIsNil(me) ? "nil" : (ghost_type ? ghost_type->name : "unknown"), _ghost_type.name ); diff --git a/simgear/nasal/cppbind/NasalHash.cxx b/simgear/nasal/cppbind/NasalHash.cxx index 20fb2ec5..d1dd3be3 100644 --- a/simgear/nasal/cppbind/NasalHash.cxx +++ b/simgear/nasal/cppbind/NasalHash.cxx @@ -69,7 +69,7 @@ namespace nasal } //---------------------------------------------------------------------------- - const naRef Hash::get_naRef() const + naRef Hash::get_naRef() const { return _hash; } diff --git a/simgear/nasal/cppbind/NasalHash.hxx b/simgear/nasal/cppbind/NasalHash.hxx index 914d2640..e1de133d 100644 --- a/simgear/nasal/cppbind/NasalHash.hxx +++ b/simgear/nasal/cppbind/NasalHash.hxx @@ -118,7 +118,7 @@ namespace nasal /** * Get Nasal representation of Hash */ - const naRef get_naRef() const; + naRef get_naRef() const; protected: diff --git a/simgear/nasal/cppbind/cppbind_test.cxx b/simgear/nasal/cppbind/cppbind_test.cxx index a152a722..d8f24612 100644 --- a/simgear/nasal/cppbind/cppbind_test.cxx +++ b/simgear/nasal/cppbind/cppbind_test.cxx @@ -38,6 +38,8 @@ struct Base std::string var; const std::string& getVar() const { return var; } void setVar(const std::string v) { var = v; } + + unsigned long getThis() const { return (unsigned long)this; } }; void baseVoidFunc(Base& b) {} @@ -173,6 +175,19 @@ int main(int argc, char* argv[]) VERIFY( fma ); VERIFY( fma("test", 3, .5) == "test" ); + typedef boost::function naRefMemFunc; + naRefMemFunc fmem = hash.get("func"); + VERIFY( fmem ); + naRef ret = fmem(hash.get_naRef()), + hash_ref = hash.get_naRef(); + VERIFY( memcmp(&ret, &hash_ref, sizeof(naRef)) == 0 ); + + // Check if nasal::Me gets passed as self/me and remaining arguments are + // passed on to function + typedef boost::function MeIntFunc; + MeIntFunc fmeint = hash.get("func"); + VERIFY( fmeint(naNil(), 5) == 5 ); + //---------------------------------------------------------------------------- // Test exposing classes to Nasal //---------------------------------------------------------------------------- @@ -190,7 +205,8 @@ int main(int argc, char* argv[]) .method("void_c", &baseConstVoidFunc) .method("int2args", &baseFunc2Args) .method("bool2args", &Base::test2Args) - .method("str_ptr", &testPtr); + .method("str_ptr", &testPtr) + .method("this", &Base::getThis); Ghost::init("DerivedPtr") .bases() .member("x", &Derived::getX, &Derived::setX) @@ -216,6 +232,17 @@ int main(int argc, char* argv[]) VERIFY( naIsGhost(derived) ); VERIFY( std::string("DerivedPtr") == naGhost_type(derived)->name ); + // Get member function from ghost... + naRef thisGetter = naNil(); + VERIFY( naMember_get(c, derived, to_nasal(c, "this"), &thisGetter) ); + VERIFY( naIsFunc(thisGetter) ); + + // ...and check if it really gets passed the correct instance + typedef boost::function MemFunc; + MemFunc fGetThis = from_nasal(c, thisGetter); + VERIFY( fGetThis ); + VERIFY( fGetThis(derived) == (unsigned long)d.get() ); + BasePtr d2( new DoubleDerived ); derived = to_nasal(c, d2); VERIFY( naIsGhost(derived) ); @@ -292,8 +319,6 @@ int main(int argc, char* argv[]) VERIFY( objects[1] == d2 ); VERIFY( objects[2] == d3 ); - // TODO actually do something with the ghosts... - //---------------------------------------------------------------------------- // Test nasal::CallContext //---------------------------------------------------------------------------- diff --git a/simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx b/simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx index e72adbf7..6b788122 100644 --- a/simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx +++ b/simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx @@ -2,6 +2,7 @@ # error Nasal cppbind - do not include this file! #endif +#ifndef SG_DONT_DO_ANYTHING #define n BOOST_PP_ITERATION() #ifndef SG_BOOST_FUNCTION_FROM_NASAL_FWD @@ -12,14 +13,12 @@ template< class Ret - BOOST_PP_COMMA_IF(n) - BOOST_PP_ENUM_PARAMS(n, class A) + BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) > typename boost::disable_if, Ret>::type - callNasalFunction( const ObjectHolder* holder - BOOST_PP_COMMA_IF(n) - BOOST_PP_ENUM(n, SG_CALL_TRAITS_PARAM, 0) - ) + callNasalMethod( const ObjectHolder* holder, + Me self + BOOST_PP_ENUM_TRAILING(n, SG_CALL_TRAITS_PARAM, 0) ) { naContext ctx = naNewContext(); naRef args[] = { @@ -28,33 +27,43 @@ const int num_args = sizeof(args)/sizeof(args[0]); naRef result = - naCallMethod(holder->get_naRef(), naNil(), num_args, args, naNil()); + naCallMethodCtx(ctx, holder->get_naRef(), self, num_args, args, naNil()); + + const char* error = naGetError(ctx); + std::string error_str(error ? error : ""); + + Ret r = Ret(); + if( !error ) + r = from_nasal_helper(ctx, result, static_cast(0)); - Ret r = from_nasal_helper(ctx, result, static_cast(0)); naFreeContext(ctx); + if( error ) + throw std::runtime_error(error_str); + return r; } template< class Ret - BOOST_PP_COMMA_IF(n) - BOOST_PP_ENUM_PARAMS(n, class A) + BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) > typename boost::enable_if, Ret>::type - callNasalFunction( const ObjectHolder* holder - BOOST_PP_COMMA_IF(n) - BOOST_PP_ENUM(n, SG_CALL_TRAITS_PARAM, 0) - ) + callNasalMethod( const ObjectHolder* holder, + Me self + BOOST_PP_ENUM_TRAILING(n, SG_CALL_TRAITS_PARAM, 0) ) { - naContext ctx = naNewContext(); - naRef args[] = { - BOOST_PP_ENUM(n, SG_CALL_ARG, 0) - }; - const int num_args = sizeof(args)/sizeof(args[0]); - - naCallMethod(holder->get_naRef(), naNil(), num_args, args, naNil()); - naFreeContext(ctx); + callNasalMethod< + naRef // do not do any conversion and just ignore the return value + // TODO warn if something different to nil is returned? + BOOST_PP_COMMA_IF(n) + BOOST_PP_ENUM_PARAMS(n, A) + > + ( + holder, + self + BOOST_PP_ENUM_TRAILING_PARAMS(n, a) + ); } # undef SG_CALL_TRAITS_PARAM @@ -63,10 +72,13 @@ template< class Ret - BOOST_PP_COMMA_IF(n) - BOOST_PP_ENUM_PARAMS(n, class A) + BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) > - boost::function + typename boost::disable_if< + // free function if first argument is not nasal::Me or no argument at all + boost::is_same, + boost::function + >::type boostFunctionFromNasal(naRef code, Ret (*)(BOOST_PP_ENUM_PARAMS(n, A))) #ifdef SG_BOOST_FUNCTION_FROM_NASAL_FWD ; @@ -74,12 +86,43 @@ { return boost::bind ( - &callNasalFunction, - ObjectHolder::makeShared(code) + &callNasalMethod, + ObjectHolder::makeShared(code), + boost::bind(naNil) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(n), _) ); } #endif +#if n > 0 + template< + class Ret + BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) + > + typename boost::enable_if< + // method if type of first argument is nasal::Me + boost::is_same, + boost::function + >::type + boostFunctionFromNasal(naRef code, Ret (*)(BOOST_PP_ENUM_PARAMS(n, A))) +#ifdef SG_BOOST_FUNCTION_FROM_NASAL_FWD + ; +#else + { + return boost::bind + ( + &callNasalMethod< + Ret + BOOST_PP_COMMA_IF(BOOST_PP_DEC(n)) + BOOST_PP_ENUM_SHIFTED_PARAMS(n, A) + >, + ObjectHolder::makeShared(code), + BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(n), _) + ); + } +#endif +#endif + #undef n +#endif // SG_DONT_DO_ANYTHING diff --git a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx index cb7aee01..0769fc64 100644 --- a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx +++ b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx @@ -31,7 +31,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -71,6 +74,21 @@ namespace nasal std::string _msg; }; + /** + * Wrap a naRef to indicate it references the self/me object in Nasal method + * calls. + */ + struct Me + { + naRef _ref; + + Me(naRef ref): + _ref(ref) + {} + + operator naRef() { return _ref; } + }; + /** * Simple pass through for unified handling also of naRef. */ @@ -193,7 +211,14 @@ namespace nasal // Helpers for wrapping calls to Nasal functions into boost::function namespace detail { -#define BOOST_PP_ITERATION_LIMITS (0, 9) + // Dummy include to add a build dependency on this file for gcc/CMake/etc. +#define SG_DONT_DO_ANYTHING +# include +#undef SG_DONT_DO_ANYTHING + + // Now the actual include (we are limited to 8 arguments (+me) here because + // boost::bind has an upper limit of 9) +#define BOOST_PP_ITERATION_LIMITS (0, 8) #define BOOST_PP_FILENAME_1 #include BOOST_PP_ITERATE() } diff --git a/simgear/nasal/cppbind/detail/functor_templates.hxx b/simgear/nasal/cppbind/detail/functor_templates.hxx index 59e9a0fb..e17b7d49 100644 --- a/simgear/nasal/cppbind/detail/functor_templates.hxx +++ b/simgear/nasal/cppbind/detail/functor_templates.hxx @@ -2,10 +2,11 @@ # error Nasal cppbind - do not include this file! #endif +#ifndef SG_DONT_DO_ANYTHING #define n BOOST_PP_ITERATION() #define SG_GHOST_FUNC_TYPE\ - boost::function + boost::function /** * Bind any callable entity accepting an instance of raw_type and an arbitrary @@ -13,8 +14,7 @@ */ template< class Ret - BOOST_PP_COMMA_IF(n) - BOOST_PP_ENUM_PARAMS(n, class A) + BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) > Ghost& method(const std::string& name, const SG_GHOST_FUNC_TYPE& func) { @@ -36,8 +36,7 @@ ( boost::bind( func, _1 - BOOST_PP_COMMA_IF(n) - BOOST_PP_ENUM(n, SG_GHOST_REQUIRE_ARG, 0) + BOOST_PP_ENUM_TRAILING(n, SG_GHOST_REQUIRE_ARG, 0) )) ); @@ -50,8 +49,7 @@ */\ template<\ class Ret\ - BOOST_PP_COMMA_IF(n)\ - BOOST_PP_ENUM_PARAMS(n, class A)\ + BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)\ >\ Ghost& method\ (\ @@ -61,8 +59,7 @@ {\ return method<\ Ret\ - BOOST_PP_COMMA_IF(n)\ - BOOST_PP_ENUM_PARAMS(n,A)\ + BOOST_PP_ENUM_TRAILING_PARAMS(n,A)\ >(name, SG_GHOST_FUNC_TYPE(fn));\ } @@ -83,13 +80,12 @@ template< class Ret, class Type - BOOST_PP_COMMA_IF(n) - BOOST_PP_ENUM_PARAMS(n, class A) + BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) > Ghost& method ( const std::string& name, - Ret (*fn)(Type BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,A)) + Ret (*fn)(Type BOOST_PP_ENUM_TRAILING_PARAMS(n,A)) ) { BOOST_STATIC_ASSERT @@ -102,3 +98,4 @@ #undef n #undef SG_GHOST_TYPEDEF_FUNC_TYPE +#endif // SG_DONT_DO_ANYTHING