From beca1cbf96b2ca7908b2f50e5462b8208e802278 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Sat, 29 Dec 2012 17:47:07 +0100 Subject: [PATCH] Allow nasal::Ghost to only wrap classes by their shared pointers This removes support for exposing and managing classes by just raw pointers as this made lifetime management of instances from C++ to Nasal and especially the other way round nearly impossible. Always using smart pointers saves us from a lot of headaches. --- simgear/nasal/cppbind/Ghost.hxx | 244 +++++++++---------------- simgear/nasal/cppbind/cppbind_test.cxx | 18 +- simgear/structure/SGSharedPtr.hxx | 2 + 3 files changed, 91 insertions(+), 173 deletions(-) diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index 39b4f3c3..37cd749e 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -39,117 +40,6 @@ namespace nasal { - /** - * Traits for C++ classes exposed as Ghost. This is the basic template for - * raw types. - */ - template - struct GhostTypeTraits - { - /** Whether the class is passed by shared pointer or raw pointer */ - typedef boost::false_type::type is_shared; - - /** The raw class type (Without any shared pointer) */ - typedef T raw_type; - }; - - template - struct GhostTypeTraits > - { - typedef boost::true_type::type is_shared; - typedef T raw_type; - }; - -#ifdef OSG_REF_PTR - template - struct GhostTypeTraits > - { - typedef boost::true_type::type is_shared; - typedef T raw_type; - }; -#endif - -#ifdef SGSharedPtr_HXX - template - struct GhostTypeTraits > - { - typedef boost::true_type::type is_shared; - typedef T raw_type; - }; -#endif - - /** - * Policy for creating ghost instances from shared pointer objects. - */ - template - struct SharedPointerPolicy - { - typedef typename GhostTypeTraits::raw_type raw_type; - typedef T pointer; - typedef boost::false_type returns_dynamic_type; - - /** - * Create a shared pointer on the heap to handle the reference counting for - * the passed shared pointer while it is used in Nasal space. - */ - static T* createInstance(const T& ptr) - { - return ptr ? new T(ptr) : 0; - } - - static pointer getPtr(void* ptr) - { - if( ptr ) - return *static_cast(ptr); - else - return pointer(); - } - - static raw_type* getRawPtr(void* ptr) - { - if( ptr ) - return static_cast(ptr)->get(); - else - return 0; - } - - static raw_type* getRawPtr(const T& ptr) - { - return ptr.get(); - } - }; - - /** - * Policy for creating ghost instances as raw objects on the heap. - */ - template - struct RawPointerPolicy - { - typedef typename GhostTypeTraits::raw_type raw_type; - typedef raw_type* pointer; - typedef boost::true_type returns_dynamic_type; - - /** - * Create a new object instance on the heap - */ - static T* createInstance() - { - return new T(); - } - - static pointer getPtr(void* ptr) - { - BOOST_STATIC_ASSERT((boost::is_same::value)); - return static_cast(ptr); - } - - static raw_type* getRawPtr(void* ptr) - { - BOOST_STATIC_ASSERT((boost::is_same::value)); - return static_cast(ptr); - } - }; - namespace internal { /** @@ -217,6 +107,8 @@ namespace nasal return nasal::to_nasal(c, _parents); } }; + + BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type) } /** @@ -278,12 +170,14 @@ namespace nasal * * naRef myMember(naContext c, int argc, naRef* args); * } + * typedef boost::shared_ptr MyClassPtr; * * void exposeClasses() * { * // Register a nasal ghost type for MyClass. This needs to be done only - * // once before creating the first ghost instance. - * Ghost::init("MyClass") + * // once before creating the first ghost instance. The exposed class needs + * // to be wrapped inside a shared pointer, eg. boost::shared_ptr. + * Ghost::init("MyClass") * // Members can be exposed by getters and setters * .member("x", &MyClass::getX, &MyClass::setX) * // For readonly variables only pass a getter @@ -298,15 +192,13 @@ namespace nasal */ template class Ghost: - public internal::GhostMetadata, - protected boost::mpl::if_< typename GhostTypeTraits::is_shared, - SharedPointerPolicy, - RawPointerPolicy >::type + public internal::GhostMetadata { + BOOST_STATIC_ASSERT( internal::has_element_type::value ); + public: - typedef T value_type; - typedef typename GhostTypeTraits::raw_type raw_type; - typedef typename Ghost::pointer 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; @@ -361,22 +253,27 @@ namespace nasal * registers on its own before it can be used as base class. * * @tparam BaseGhost Type of base class already wrapped into Ghost class - * (Ghost) + * (Ghost) * * @code{cpp} - * Ghost::init("MyBase"); - * Ghost::init("MyClass") - * .bases >(); + * Ghost::init("MyBase"); + * Ghost::init("MyClass") + * .bases >(); * @endcode */ template - typename boost::enable_if_c - < boost::is_base_of::value - && boost::is_base_of::value, + typename boost::enable_if + < + boost::is_base_of, Ghost >::type& bases() { + BOOST_STATIC_ASSERT + (( + boost::is_base_of::value + )); + BaseGhost* base = BaseGhost::getSingletonPtr(); base->addDerived ( @@ -417,22 +314,27 @@ namespace nasal * Register a base class for this ghost. The base class needs to be * registers on its own before it can be used as base class. * - * @tparam Base Type of base class (Base as used in Ghost) + * @tparam Base Type of base class (Base as used in Ghost) * * @code{cpp} - * Ghost::init("MyBase"); - * Ghost::init("MyClass") - * .bases(); + * Ghost::init("MyBase"); + * Ghost::init("MyClass") + * .bases(); * @endcode */ template - typename boost::enable_if_c - < !boost::is_base_of::value - && boost::is_base_of::raw_type, raw_type>::value, + typename boost::disable_if + < + boost::is_base_of, Ghost >::type& bases() { + BOOST_STATIC_ASSERT + (( + boost::is_base_of::raw_type, raw_type>::value + )); + return bases< Ghost >(); } @@ -537,7 +439,7 @@ namespace nasal * naRef myMethod(naContext c, int argc, naRef* args); * } * - * Ghost::init("Test") + * Ghost::init("Test") * .method<&MyClass::myMethod>("myMethod"); * @endcode */ @@ -563,7 +465,7 @@ namespace nasal * class MyClass; * naRef myMethod(MyClass& obj, naContext c, int argc, naRef* args); * - * Ghost::init("Test") + * Ghost::init("Test") * .method_func<&myMethod>("myMethod"); * @endcode */ @@ -580,10 +482,11 @@ namespace nasal * * @param c Active Nasal context */ - static naRef create( naContext c ) - { - return makeGhost(c, Ghost::createInstance()); - } + // TODO check if default constructor exists +// static naRef create( naContext c ) +// { +// return makeGhost(c, createInstance()); +// } /** * Create a Nasal instance of this ghost. @@ -594,7 +497,7 @@ namespace nasal template static naRef create( naContext c, const A1& a1 ) { - return makeGhost(c, Ghost::createInstance(a1)); + return makeGhost(c, createInstance(a1)); } /** @@ -627,7 +530,7 @@ namespace nasal { // Check if it's a ghost and if it can be converted if( isBaseOf( naGhost_type(me) ) ) - return Ghost::getPtr( naGhost_ptr(me) ); + return getPtr( naGhost_ptr(me) ); // Now if it is derived from a ghost (hash with ghost in parent vector) else if( naIsHash(me) ) @@ -663,6 +566,36 @@ namespace nasal typedef std::vector DerivedList; DerivedList _derived_types; + /** + * Create a shared pointer on the heap to handle the reference counting + * for the passed shared pointer while it is used in Nasal space. + */ + static pointer* createInstance(const pointer& ptr) + { + return ptr ? new pointer(ptr) : 0; + } + + static pointer getPtr(void* ptr) + { + if( ptr ) + return *static_cast(ptr); + else + return pointer(); + } + + static raw_type* getRawPtr(void* ptr) + { + if( ptr ) + return static_cast(ptr)->get(); + else + return 0; + } + + static raw_type* getRawPtr(const pointer& ptr) + { + return ptr.get(); + } + void addDerived( const internal::GhostMetadata* derived_meta, const type_checker_t& derived_info ) { @@ -724,7 +657,7 @@ namespace nasal static raw_type& requireObject(naContext c, naRef me) { - raw_type* obj = Ghost::getRawPtr( fromNasal(c, me) ); + raw_type* obj = getRawPtr( fromNasal(c, me) ); naGhostType* ghost_type = naGhost_type(me); if( !obj ) @@ -800,20 +733,13 @@ namespace nasal static naRef makeGhost(naContext c, void *ptr) { - if( Ghost::getRawPtr(ptr) ) + if( getRawPtr(ptr) ) { - naGhostType* ghost_type = 0; - if( Ghost::returns_dynamic_type::value ) - // For pointer policies already returning instances of an object - // with the dynamic type of this Ghost's raw_type the type is always - // the same. - ghost_type = &getSingletonPtr()->_ghost_type; - else - // If wrapping eg. shared pointers the users passes an already - // existing instance of an object which will then be hold be a new - // shared pointer. We therefore have to check for the dynamic type - // of the object as it might differ from the passed static type. - ghost_type = getTypeFor( Ghost::getRawPtr(ptr) ); + // We are wrapping shared pointers to already existing objects which + // will then be hold be a new shared pointer. We therefore have to + // check for the dynamic type of the object as it might differ from + // the passed static type. + naGhostType* ghost_type = getTypeFor( getRawPtr(ptr) ); if( ghost_type ) return naNewGhost2(c, ghost_type, ptr); @@ -825,7 +751,7 @@ namespace nasal static void destroyGhost(void *ptr) { - delete static_cast(ptr); + delete static_cast(ptr); } /** @@ -852,7 +778,7 @@ namespace nasal if( member->second.func ) *out = nasal::to_nasal(c, member->second.func); else if( !member->second.getter.empty() ) - *out = member->second.getter(c, *Ghost::getRawPtr(g)); + *out = member->second.getter(c, *getRawPtr(g)); else return "Read-protected member"; @@ -873,7 +799,7 @@ namespace nasal if( member->second.setter.empty() ) naRuntimeError(c, "ghost: Write protected member: %s", key.c_str()); - member->second.setter(c, *Ghost::getRawPtr(g), val); + member->second.setter(c, *getRawPtr(g), val); } }; diff --git a/simgear/nasal/cppbind/cppbind_test.cxx b/simgear/nasal/cppbind/cppbind_test.cxx index 88d7d648..416d4a0e 100644 --- a/simgear/nasal/cppbind/cppbind_test.cxx +++ b/simgear/nasal/cppbind/cppbind_test.cxx @@ -111,31 +111,21 @@ int main(int argc, char* argv[]) Hash mod = hash.createHash("mod"); mod.set("parent", hash); - Ghost::init("Base") + Ghost::init("BasePtr") .method<&Base::member>("member") .member("str", &Base::getString, &Base::setString); - Ghost::init("Derived") - .bases() - .member("x", &Derived::getX, &Derived::setX) - .member("x_alternate", &f_derivedGetX) - .method_func<&member>("free_member"); - - naRef derived = Ghost::create(c); - VERIFY( naIsGhost(derived) ); - VERIFY( std::string("Derived") == naGhost_type(derived)->name ); - - Ghost::init("BasePtr"); Ghost::init("DerivedPtr") .bases() .member("x", &Derived::getX, &Derived::setX) + .member("x_alternate", &f_derivedGetX) .method_func<&member>("free_member"); Ghost::init("DoubleDerivedPtr") .bases(); Ghost::init("DoubleDerived2Ptr") - .bases(); + .bases< Ghost >(); BasePtr d( new Derived ); - derived = Ghost::create(c, d); + naRef derived = Ghost::create(c, d); VERIFY( naIsGhost(derived) ); VERIFY( std::string("DerivedPtr") == naGhost_type(derived)->name ); diff --git a/simgear/structure/SGSharedPtr.hxx b/simgear/structure/SGSharedPtr.hxx index b8553b06..3de62e6c 100644 --- a/simgear/structure/SGSharedPtr.hxx +++ b/simgear/structure/SGSharedPtr.hxx @@ -48,6 +48,8 @@ class SGWeakPtr; template class SGSharedPtr { public: + typedef T element_type; + SGSharedPtr(void) : _ptr(0) {} SGSharedPtr(T* ptr) : _ptr(ptr) -- 2.39.5