From 530de4d809a438d3b3dd4fff665233e1d74ef6ed Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Sat, 2 Mar 2013 00:13:06 +0100 Subject: [PATCH] cppbind: Prepare for improved bindings. - Improved Nasal/C++ bindings will follow. For now just test if all compilers are happy with intended approach. - Add to_nasal overload for std::map. --- simgear/nasal/cppbind/Ghost.hxx | 87 ++++++++++++++++++++++++-- simgear/nasal/cppbind/cppbind_test.cxx | 27 +++++++- simgear/nasal/cppbind/to_nasal.hxx | 59 +++++++++++++---- 3 files changed, 157 insertions(+), 16 deletions(-) diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index 9c2de3a3..88133e9d 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -197,12 +197,14 @@ namespace nasal BOOST_STATIC_ASSERT( internal::has_element_type::value ); public: - typedef typename T::element_type raw_type; - typedef T pointer; + typedef typename T::element_type raw_type; + typedef T pointer; typedef naRef (raw_type::*member_func_t)(const CallContext&); typedef naRef (*free_func_t)(raw_type&, const CallContext&); - typedef boost::function getter_t; - typedef boost::function setter_t; + typedef boost::function getter_t; + typedef boost::function setter_t; + typedef boost::function method_t; + typedef boost::shared_ptr method_ptr; /** * A ghost member. Can consist either of getter and/or setter functions @@ -466,6 +468,83 @@ namespace nasal return *this; } + /** + * Invoke a method which returns a value and convert it to Nasal. + */ + template + static + typename boost::disable_if, naRef>::type + method_invoker + ( + const boost::function& func, + raw_type& obj, + const CallContext& ctx + ) + { + typedef typename boost::call_traits::param_type param_type; + naRef (*to_nasal_)(naContext, param_type) = &nasal::to_nasal; + + return to_nasal_(ctx.c, func(obj, ctx)); + }; + + /** + * Invoke a method which returns void and "convert" it to nil. + */ + template + static + typename boost::enable_if, naRef>::type + method_invoker + ( + const boost::function& func, + raw_type& obj, + const CallContext& ctx + ) + { + func(obj, ctx); + return naNil(); + }; + + /** + * Bind any callable entity as method callable from Nasal + * + * Does not really register method yet!!! + */ + template + Ghost& method + ( + const std::string& name, + const boost::function& func + ) + { +// _members[name].func.reset +// ( + new method_t( boost::bind(method_invoker, func, _1, _2) ); +// ); + return *this; + } + + template + struct method_raw + { + typedef boost::function type; + }; + + /** + * Bind member function as method callable from Nasal + * + * Does not really register method yet!!! + */ + template + Ghost& method( const std::string& name, + Ret (raw_type::*fn)() const ) + { + return method + ( + name, + typename method_raw::type(boost::bind(fn, _1)) + ); + } + /** * Register a free function as member function. The object instance is * passed as additional first argument. diff --git a/simgear/nasal/cppbind/cppbind_test.cxx b/simgear/nasal/cppbind/cppbind_test.cxx index 18a282ce..cd80244b 100644 --- a/simgear/nasal/cppbind/cppbind_test.cxx +++ b/simgear/nasal/cppbind/cppbind_test.cxx @@ -23,11 +23,16 @@ struct Base std::string getString() const { return ""; } void setString(const std::string&) {} + void constVoidFunc() const {} std::string var; const std::string& getVar() const { return var; } void setVar(const std::string v) { var = v; } }; + +void baseVoidFunc(Base& b) {} +void baseConstVoidFunc(const Base& b) {} + struct Derived: public Base { @@ -51,6 +56,11 @@ typedef boost::shared_ptr DerivedPtr; typedef boost::shared_ptr DoubleDerivedPtr; typedef boost::shared_ptr DoubleDerived2Ptr; +naRef to_nasal(naContext c, const BasePtr& base) +{ + return nasal::Ghost::create(c, base); +} + naRef member(Derived&, const nasal::CallContext&) { return naNil(); } naRef f_derivedGetX(naContext c, const Derived& d) { @@ -140,9 +150,12 @@ int main(int argc, char* argv[]) Ghost::init("BasePtr") .method<&Base::member>("member") .member("str", &Base::getString, &Base::setString) + .method("str_m", &Base::getString) + .method("void", &Base::constVoidFunc) .member("var_r", &Base::getVar) .member("var_w", &Base::setVar) - .member("var", &Base::getVar, &Base::setVar); + .member("var", &Base::getVar, &Base::setVar) + /*.method("void", &baseVoidFunc)*/; Ghost::init("DerivedPtr") .bases() .member("x", &Derived::getX, &Derived::setX) @@ -180,6 +193,18 @@ int main(int argc, char* argv[]) == boost::dynamic_pointer_cast(d3) ); VERIFY( !Ghost::fromNasal(c, derived) ); + std::map instances; + VERIFY( naIsHash(to_nasal(c, instances)) ); + + std::map instances_d; + VERIFY( naIsHash(to_nasal(c, instances_d)) ); + + std::map int_map; + VERIFY( naIsHash(to_nasal(c, int_map)) ); + + std::map > int_vector_map; + VERIFY( naIsHash(to_nasal(c, int_vector_map)) ); + // Check converting to Ghost if using Nasal hashes with actual ghost inside // the hashes parents vector std::vector parents; diff --git a/simgear/nasal/cppbind/to_nasal.hxx b/simgear/nasal/cppbind/to_nasal.hxx index 20d989c6..c6a80863 100644 --- a/simgear/nasal/cppbind/to_nasal.hxx +++ b/simgear/nasal/cppbind/to_nasal.hxx @@ -25,8 +25,10 @@ #include #include +#include #include +#include #include #include @@ -74,18 +76,24 @@ namespace nasal return naNum(num); } + /** + * Convert a 2d vector to Nasal vector with 2 elements + */ + template + typename boost::enable_if, naRef>::type + to_nasal(naContext c, const Vec2& vec); + + /** + * Convert a std::map to a Nasal Hash + */ + template + naRef to_nasal(naContext c, const std::map& map); + /** * Convert a fixed size array to a Nasal vector */ template - naRef to_nasal(naContext c, const T(&array)[N]) - { - naRef ret = naNewVector(c); - naVec_setsize(c, ret, N); - for(size_t i = 0; i < N; ++i) - naVec_set(ret, i, to_nasal(c, array[i])); - return ret; - } + naRef to_nasal(naContext c, const T(&array)[N]); /** * Convert std::vector to Nasal vector @@ -108,9 +116,7 @@ namespace nasal return ret; } - /** - * Convert a 2d vector to Nasal vector with 2 elements - */ + //---------------------------------------------------------------------------- template typename boost::enable_if, naRef>::type to_nasal(naContext c, const Vec2& vec) @@ -121,6 +127,37 @@ namespace nasal return to_nasal(c, nasal_vec); } + //---------------------------------------------------------------------------- + template + naRef to_nasal(naContext c, const std::map& map) + { + naRef hash = naNewHash(c); + + typedef typename boost::call_traits::param_type param_type; + typedef typename std::map::const_iterator map_iterator; + + for( map_iterator it = map.begin(); it != map.end(); ++it ) + naHash_set + ( + hash, + to_nasal(c, it->first), + to_nasal(c, static_cast(it->second)) + ); + + return hash; + } + + //---------------------------------------------------------------------------- + template + naRef to_nasal(naContext c, const T(&array)[N]) + { + naRef ret = naNewVector(c); + naVec_setsize(c, ret, N); + for(size_t i = 0; i < N; ++i) + naVec_set(ret, i, to_nasal(c, array[i])); + return ret; + } + } // namespace nasal #endif /* SG_TO_NASAL_HXX_ */