]> git.mxchange.org Git - simgear.git/commitdiff
cppbind::Ghost: safely use strong and weak references.
authorThomas Geymayer <tomgey@gmail.com>
Tue, 3 Jun 2014 07:55:32 +0000 (09:55 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Tue, 3 Jun 2014 16:40:01 +0000 (18:40 +0200)
Allow using strong and weak references within the same
class hierarchy and seemlessly convert between them -
from and to Nasal.

simgear/nasal/cppbind/CMakeLists.txt
simgear/nasal/cppbind/Ghost.hxx
simgear/nasal/cppbind/cppbind_test.cxx
simgear/nasal/cppbind/cppbind_test_ghost.cxx [new file with mode: 0644]
simgear/nasal/cppbind/detail/nasal_traits.hxx

index 4dba88f4440132c11d686b67d13c794822e38e72..952411d728dc987f1424a841470781ba200fb9de 100644 (file)
@@ -34,4 +34,9 @@ if(ENABLE_TESTS)
   add_executable(test_cppbind cppbind_test.cxx)
   add_test(cppbind ${EXECUTABLE_OUTPUT_PATH}/test_cppbind)
   target_link_libraries(test_cppbind ${TEST_LIBS})
-endif(ENABLE_TESTS)
\ No newline at end of file
+endif(ENABLE_TESTS)
+
+add_boost_test(cppbind_ghost
+  SOURCES cppbind_test_ghost.cxx
+  LIBRARIES ${TEST_LIBS}
+)
\ No newline at end of file
index 7c8f03d1082026fc529354065b2789d519dd7513..3cefc8de93b3724135f1ec73a46582341e6327a1 100644 (file)
@@ -50,12 +50,19 @@ inline T* get_pointer(SGWeakPtr<T> const& p)
   return p.lock().get();
 }
 
+template<class T>
+inline T* get_pointer(osg::observer_ptr<T> const& p)
+{
+  osg::ref_ptr<T> ref;
+  p.lock(ref);
+  return ref.get();
+}
+
 /**
  * Bindings between C++ and the Nasal scripting language
  */
 namespace nasal
 {
-
   namespace internal
   {
     /**
@@ -74,16 +81,25 @@ namespace nasal
           _parents.push_back(parent);
         }
 
-        bool isBaseOf(naGhostType* ghost_type) const
+        bool isBaseOf(naGhostType* ghost_type, bool& is_weak) const
         {
-          if( ghost_type == _ghost_type_ptr )
+          if( ghost_type == _ghost_type_strong_ptr )
+          {
+            is_weak = false;
             return true;
+          }
+
+          if( ghost_type == _ghost_type_weak_ptr )
+          {
+            is_weak = true;
+            return true;
+          }
 
           for( DerivedList::const_iterator derived = _derived_classes.begin();
                                            derived != _derived_classes.end();
                                          ++derived )
           {
-            if( (*derived)->isBaseOf(ghost_type) )
+            if( (*derived)->isBaseOf(ghost_type, is_weak) )
               return true;
           }
 
@@ -94,15 +110,20 @@ namespace nasal
 
         typedef std::vector<const GhostMetadata*> DerivedList;
 
-        const std::string   _name;
-        const naGhostType  *_ghost_type_ptr;
+        const std::string   _name_strong,
+                            _name_weak;
+        const naGhostType  *_ghost_type_strong_ptr,
+                           *_ghost_type_weak_ptr;
         DerivedList         _derived_classes;
         std::vector<naRef>  _parents;
 
         GhostMetadata( const std::string& name,
-                       const naGhostType* ghost_type ):
-          _name(name),
-          _ghost_type_ptr(ghost_type)
+                       const naGhostType* ghost_type_strong,
+                       const naGhostType* ghost_type_weak ):
+          _name_strong(name),
+          _name_weak(name + " (weak ref)"),
+          _ghost_type_strong_ptr(ghost_type_strong),
+          _ghost_type_weak_ptr(ghost_type_weak)
         {
 
         }
@@ -116,7 +137,8 @@ namespace nasal
           (
             SG_NASAL,
             SG_INFO,
-            "Ghost::addDerived: " << _name << " -> " << derived->_name
+            "Ghost::addDerived: " << _name_strong << " -> "
+                                  << derived->_name_strong
           );
         }
 
@@ -210,11 +232,15 @@ namespace nasal
   class Ghost:
     public internal::GhostMetadata
   {
-      BOOST_STATIC_ASSERT( internal::has_element_type<T>::value );
+      BOOST_STATIC_ASSERT_MSG(
+        (shared_ptr_traits<T>::is_strong::value),
+        "Shared pointer required for Ghost! (no weak pointer!)"
+      );
 
     public:
       typedef typename T::element_type                              raw_type;
-      typedef T                                                     pointer;
+      typedef typename shared_ptr_traits<T>::strong_ref             strong_ref;
+      typedef typename shared_ptr_traits<T>::weak_ref               weak_ref;
       typedef naRef (raw_type::*member_func_t)(const CallContext&);
       typedef naRef (*free_func_t)(raw_type&, const CallContext&);
       typedef boost::function<naRef(raw_type&, naContext)>          getter_t;
@@ -761,44 +787,35 @@ namespace nasal
 #define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
 #include BOOST_PP_ITERATE()
 
-      // TODO use variadic template when supporting C++11
-      // TODO check if default constructor exists
-//      static naRef create( naContext c )
-//      {
-//        return makeGhost(c, createInstance());
-//      }
-
       /**
-       * Create a Nasal instance of this ghost.
-       *
-       * @param c   Active Nasal context
-       * @param a1  Parameter used for creating new instance
-       */
-      template<class A1>
-      static naRef create( naContext c, const A1& a1 )
-      {
-        return makeGhost(c, createInstance(a1));
-      }
-
-      /**
-       * Nasal callback for creating a new instance of this ghost.
+       * 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 naRef f_create(naContext c, naRef me, int argc, naRef* args)
+      template<class RefType>
+      static
+      typename boost::enable_if_c<
+           boost::is_same<RefType, strong_ref>::value
+        || boost::is_same<RefType, weak_ref>::value,
+        naRef
+      >::type
+      makeGhost(naContext c, RefType const& ref_ptr)
       {
-        return create(c);
-      }
+        strong_ref ref(ref_ptr);
+        raw_type* ptr = get_pointer(ref_ptr);
+        if( !ptr )
+          return naNil();
+
+        // 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<Ghost>(ptr, shared_ptr_traits<RefType>::is_strong::value);
 
-      static bool isBaseOf(naGhostType* ghost_type)
-      {
         if( !ghost_type )
-          return false;
-
-        return getSingletonPtr()->GhostMetadata::isBaseOf(ghost_type);
-      }
+          return naNil();
 
-      static bool isBaseOf(naRef obj)
-      {
-        return isBaseOf( naGhost_type(obj) );
+        return naNewGhost2(c, ghost_type, new RefType(ref_ptr));
       }
 
       /**
@@ -806,18 +823,31 @@ namespace nasal
        * Nasal objects has to be derived class of the target class (Either
        * derived in C++ or in Nasal using a 'parents' vector)
        */
-      static pointer fromNasal(naContext c, naRef me)
+      template<class RefType>
+      static
+      typename boost::enable_if_c<
+           boost::is_same<RefType, strong_ref>::value
+        || boost::is_same<RefType, weak_ref>::value,
+        RefType
+      >::type
+      fromNasal(naContext c, naRef me)
       {
+        bool is_weak = false;
+
         // Check if it's a ghost and if it can be converted
-        if( isBaseOf( naGhost_type(me) ) )
-          return getPtr( naGhost_ptr(me) );
+        if( isBaseOf(naGhost_type(me), is_weak) )
+        {
+          void* ghost = naGhost_ptr(me);
+          return is_weak ? getPtr<RefType, true>(ghost)
+                         : getPtr<RefType, false>(ghost);
+        }
 
         // Now if it is derived from a ghost (hash with ghost in parent vector)
         else if( naIsHash(me) )
         {
           naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
           if( !naIsVector(na_parents) )
-            return pointer();
+            return RefType();
 
           typedef std::vector<naRef> naRefs;
           naRefs parents = from_nasal<naRefs>(c, na_parents);
@@ -825,13 +855,19 @@ namespace nasal
                                       parent != parents.end();
                                     ++parent )
           {
-            pointer ptr = fromNasal(c, *parent);
+            RefType ptr = fromNasal<RefType>(c, *parent);
             if( get_pointer(ptr) )
               return ptr;
           }
         }
 
-        return pointer();
+        return RefType();
+      }
+
+      static bool isBaseOf(naRef obj)
+      {
+        bool is_weak;
+        return isBaseOf(naGhost_type(obj), is_weak);
       }
 
     private:
@@ -839,47 +875,70 @@ namespace nasal
       template<class>
       friend class Ghost;
 
-      static naGhostType _ghost_type;
+      static naGhostType _ghost_type_strong, //!< Stored as shared pointer
+                         _ghost_type_weak;   //!< Stored as weak shared pointer
 
-      typedef naGhostType* (*type_checker_t)(const raw_type*);
+      typedef naGhostType* (*type_checker_t)(const raw_type*, bool);
       typedef std::vector<type_checker_t> 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)
+      static bool isBaseOf(naGhostType* ghost_type, bool& is_weak)
       {
-        return get_pointer(ptr) ? new pointer(ptr) : 0;
+        if( !ghost_type || !getSingletonPtr() )
+          return false;
+
+        return getSingletonPtr()->GhostMetadata::isBaseOf(ghost_type, is_weak);
       }
 
-      static pointer getPtr(void* ptr)
+      static bool isBaseOf(naRef obj, bool& is_weak)
+      {
+        return isBaseOf(naGhost_type(obj), is_weak);
+      }
+
+      template<class RefPtr, bool is_weak>
+      static
+      typename boost::enable_if_c<
+        !is_weak,
+        RefPtr
+      >::type
+      getPtr(void* ptr)
       {
         if( ptr )
-          return *static_cast<pointer*>(ptr);
+          return RefPtr(*static_cast<strong_ref*>(ptr));
         else
-          return pointer();
+          return RefPtr();
       }
 
-      static raw_type* getRawPtr(void* ptr)
+      template<class RefPtr, bool is_weak>
+      static
+      typename boost::enable_if_c<
+        is_weak && supports_weak_ref<T>::value,
+        RefPtr
+      >::type
+      getPtr(void* ptr)
       {
         if( ptr )
-          return get_pointer(*static_cast<pointer*>(ptr));
+          return RefPtr(*static_cast<weak_ref*>(ptr));
         else
-          return 0;
+          return RefPtr();
       }
 
-      static raw_type* getRawPtr(const pointer& ptr)
+      template<class RefPtr, bool is_weak>
+      static
+      typename boost::enable_if_c<
+        is_weak && !supports_weak_ref<T>::value,
+        RefPtr
+      >::type
+      getPtr(void* ptr)
       {
-        return get_pointer(ptr);
+        return RefPtr();
       }
 
       void addDerived( const internal::GhostMetadata* derived_meta,
-                       const type_checker_t& derived_info )
+                       type_checker_t derived_type_checker )
       {
         GhostMetadata::addDerived(derived_meta);
-        _derived_types.push_back(derived_info);
+        _derived_types.push_back(derived_type_checker);
       }
 
       template<class BaseGhost>
@@ -888,7 +947,7 @@ namespace nasal
         < boost::is_polymorphic<typename BaseGhost::raw_type>,
           naGhostType*
         >::type
-      getTypeFor(const typename BaseGhost::raw_type* base)
+      getTypeFor(const typename BaseGhost::raw_type* base, bool strong)
       {
         // Check first if passed pointer can by converted to instance of class
         // this ghost wraps.
@@ -917,14 +976,20 @@ namespace nasal
              ++derived )
         {
           naGhostType* ghost_type =
-            (*derived)( static_cast<const typename Ghost::raw_type*>(base) );
+            (*derived)(
+              static_cast<const typename Ghost::raw_type*>(base),
+              strong
+            );
+
           if( ghost_type )
             return ghost_type;
         }
 
         // If base is not an instance of any derived class, this class has to
         // be the dynamic type.
-        return &_ghost_type;
+        return strong
+             ? &_ghost_type_strong
+             : &_ghost_type_weak;
       }
 
       template<class BaseGhost>
@@ -933,11 +998,13 @@ namespace nasal
         < boost::is_polymorphic<typename BaseGhost::raw_type>,
           naGhostType*
         >::type
-      getTypeFor(const typename BaseGhost::raw_type* base)
+      getTypeFor(const typename BaseGhost::raw_type* base, bool strong)
       {
         // For non polymorphic classes there is no possibility to get the actual
         // dynamic type, therefore we can only use its static type.
-        return &BaseGhost::_ghost_type;
+        return strong
+             ? &BaseGhost::_ghost_type_strong
+             : &BaseGhost::_ghost_type_weak;
       }
 
       static Ghost* getSingletonPtr()
@@ -947,17 +1014,19 @@ namespace nasal
 
       static raw_type& requireObject(naContext c, naRef me)
       {
-        raw_type* obj = getRawPtr( fromNasal(c, me) );
-        naGhostType* ghost_type = naGhost_type(me);
+        raw_type* obj = get_pointer( fromNasal<strong_ref>(c, me) );
 
         if( !obj )
+        {
+          naGhostType* ghost_type = naGhost_type(me);
           naRuntimeError
           (
             c,
             "method called on object of wrong type: is '%s' expected '%s'",
             naIsNil(me) ? "nil" : (ghost_type ? ghost_type->name : "unknown"),
-            _ghost_type.name
+            _ghost_type_strong.name
           );
+        }
 
         return *obj;
       }
@@ -1084,12 +1153,21 @@ namespace nasal
       fallback_setter_t _fallback_setter;
 
       explicit Ghost(const std::string& name):
-        GhostMetadata(name, &_ghost_type)
+        GhostMetadata( name,
+                       &_ghost_type_strong,
+                       supports_weak_ref<T>::value ? &_ghost_type_weak : NULL )
       {
-        _ghost_type.destroy = &destroyGhost;
-        _ghost_type.name = _name.c_str();
-        _ghost_type.get_member = &getMember;
-        _ghost_type.set_member = &setMember;
+        _ghost_type_strong.destroy = &destroy<strong_ref>;
+        _ghost_type_strong.name = _name_strong.c_str();
+        _ghost_type_strong.get_member = &getMember<false>;
+        _ghost_type_strong.set_member = &setMember<false>;
+
+        _ghost_type_weak.destroy = &destroy<weak_ref>;
+        _ghost_type_weak.name = _name_weak.c_str();
+
+        bool can_weak = supports_weak_ref<T>::value;
+        _ghost_type_weak.get_member = can_weak ? &getMember<true> : 0;
+        _ghost_type_weak.set_member = can_weak ? &setMember<true> : 0;
       }
 
       static GhostPtr& getSingletonHolder()
@@ -1098,33 +1176,19 @@ namespace nasal
         return instance;
       }
 
-      static naRef makeGhost(naContext c, void *ptr)
+      template<class Type>
+      static void destroy(void *ptr)
       {
-        if( 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<Ghost>( getRawPtr(ptr) );
-
-          if( ghost_type )
-            return naNewGhost2(c, ghost_type, ptr);
-        }
-
-        destroyGhost(ptr);
-        return naNil();
-      }
-
-      static void destroyGhost(void *ptr)
-      {
-        delete static_cast<pointer*>(ptr);
+        delete static_cast<Type*>(ptr);
       }
 
       /**
        * Callback for retrieving a ghost member.
        */
-      static const char* getMember(naContext c, void* g, naRef key, naRef* out)
+      static const char* getMember( naContext c,
+                                    raw_type& obj,
+                                    naRef key,
+                                    naRef* out )
       {
         const std::string key_str = nasal::from_nasal<std::string>(c, key);
         // TODO merge instance parents with static class parents
@@ -1144,23 +1208,36 @@ namespace nasal
         {
           fallback_getter_t fallback_get = getSingletonPtr()->_fallback_getter;
           if(    !fallback_get
-              || !fallback_get(*getRawPtr(g), c, key_str, *out) )
+              || !fallback_get(obj, c, key_str, *out) )
             return 0;
         }
         else if( member->second.func )
           *out = member->second.func->get_naRef(c);
         else if( !member->second.getter.empty() )
-          *out = member->second.getter(*getRawPtr(g), c);
+          *out = member->second.getter(obj, c);
         else
           return "Read-protected member";
 
         return "";
       }
 
+      template<bool is_weak>
+      static const char* getMember( naContext c,
+                                    void* ghost,
+                                    naRef key,
+                                    naRef* out )
+      {
+        strong_ref const& ptr = getPtr<strong_ref, is_weak>(ghost);
+        return getMember(c, *get_pointer(ptr), key, out);
+      }
+
       /**
        * Callback for writing to a ghost member.
        */
-      static void setMember(naContext c, void* g, naRef field, naRef val)
+      static void setMember( naContext c,
+                             raw_type& obj,
+                             naRef field,
+                             naRef val )
       {
         const std::string key = nasal::from_nasal<std::string>(c, field);
         const MemberMap& members = getSingletonPtr()->_members;
@@ -1171,7 +1248,7 @@ namespace nasal
           fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
           if( !fallback_set )
             naRuntimeError(c, "ghost: No such member: %s", key.c_str());
-          else if( !fallback_set(*getRawPtr(g), c, key, val) )
+          else if( !fallback_set(obj, c, key, val) )
             naRuntimeError(c, "ghost: Failed to write (_set: %s)", key.c_str());
         }
         else if( member->second.setter.empty() )
@@ -1179,12 +1256,24 @@ namespace nasal
         else if( member->second.func )
           naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
         else
-          member->second.setter(*getRawPtr(g), c, val);
+          member->second.setter(obj, c, val);
+      }
+
+      template<bool is_weak>
+      static void setMember( naContext c,
+                             void* ghost,
+                             naRef field,
+                             naRef val )
+      {
+        strong_ref const& ptr = getPtr<strong_ref, is_weak>(ghost);
+        return setMember(c, *get_pointer(ptr), field, val);
       }
   };
 
   template<class T>
-  naGhostType Ghost<T>::_ghost_type;
+  naGhostType Ghost<T>::_ghost_type_strong;
+  template<class T>
+  naGhostType Ghost<T>::_ghost_type_weak;
 
 } // namespace nasal
 
@@ -1201,7 +1290,8 @@ typename boost::enable_if<
 >::type
 to_nasal_helper(naContext c, T ptr)
 {
-  return nasal::Ghost<T>::create(c, ptr);
+  typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
+  return nasal::Ghost<strong_ref>::makeGhost(c, ptr);
 }
 
 /**
@@ -1216,7 +1306,8 @@ typename boost::enable_if<
 >::type
 from_nasal_helper(naContext c, naRef ref, const T*)
 {
-  return nasal::Ghost<T>::fromNasal(c, ref);
+  typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
+  return nasal::Ghost<strong_ref>::template fromNasal<T>(c, ref);
 }
 
 /**
@@ -1230,7 +1321,7 @@ typename boost::enable_if_c<
 >::type
 to_nasal_helper(naContext c, T* ptr)
 {
-  return nasal::Ghost<SGSharedPtr<T> >::create(c, SGSharedPtr<T>(ptr));
+  return nasal::Ghost<SGSharedPtr<T> >::makeGhost(c, SGSharedPtr<T>(ptr));
 }
 
 /**
@@ -1251,7 +1342,7 @@ typename boost::enable_if_c<
 from_nasal_helper(naContext c, naRef ref, const T*)
 {
   typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
-  return nasal::Ghost<TypeRef>::fromNasal(c, ref).release();
+  return nasal::Ghost<TypeRef>::template fromNasal<TypeRef>(c, ref).release();
 }
 
 #endif /* SG_NASAL_GHOST_HXX_ */
index 03ef4d830a3b9656263627c62c2f810d3848cd5c..154aa1b1581a1e64b2d124a73d5ba51664241416 100644 (file)
@@ -269,7 +269,6 @@ int main(int argc, char* argv[])
     .member("base", &DoubleDerived2::getBase)
     .method("doIt", &DoubleDerived2::doSomeBaseWork);
 
-  Ghost<DerivedWeakPtr>::init("DerivedWeakPtr");
   Ghost<SGRefBasedPtr>::init("SGRefBasedPtr");
   Ghost<SGWeakRefBasedPtr>::init("SGWeakRefBasedPtr");
 
@@ -372,9 +371,9 @@ int main(int argc, char* argv[])
   VERIFY( from_nasal<BasePtr>(c, derived_obj.get_naRef()) == d3 );
 
   std::vector<naRef> nasal_objects;
-  nasal_objects.push_back( Ghost<BasePtr>::create(c, d) );
-  nasal_objects.push_back( Ghost<BasePtr>::create(c, d2) );
-  nasal_objects.push_back( Ghost<BasePtr>::create(c, d3) );
+  nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d) );
+  nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d2) );
+  nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d3) );
   naRef obj_vec = to_nasal(c, nasal_objects);
 
   std::vector<BasePtr> objects = from_nasal<std::vector<BasePtr> >(c, obj_vec);
diff --git a/simgear/nasal/cppbind/cppbind_test_ghost.cxx b/simgear/nasal/cppbind/cppbind_test_ghost.cxx
new file mode 100644 (file)
index 0000000..2394dfe
--- /dev/null
@@ -0,0 +1,88 @@
+#define BOOST_TEST_MODULE cppbind
+#include <BoostTestTargetConfig.h>
+
+#include "Ghost.hxx"
+
+class Base1:
+  public virtual SGVirtualWeakReferenced
+{};
+
+class Base2:
+  public virtual SGVirtualWeakReferenced
+{};
+
+class Derived:
+  public Base1,
+  public Base2
+{};
+
+typedef SGSharedPtr<Base1> Base1Ptr;
+typedef SGSharedPtr<Base2> Base2Ptr;
+typedef SGSharedPtr<Derived> DerivedPtr;
+typedef SGWeakPtr<Derived> DerivedWeakPtr;
+
+typedef SGSharedPtr<SGReferenced> SGReferencedPtr;
+
+// Check if shared_ptr_traits give correct types for strong and weak shared
+// pointer
+#define CHECK_PTR_TRAIT_TYPE(ptr_t, type_name, type)\
+  BOOST_STATIC_ASSERT((boost::is_same<\
+    nasal::shared_ptr_traits<ptr_t>::type_name,\
+    type\
+  >::value));
+
+#define CHECK_PTR_TRAIT(ref, weak)\
+  CHECK_PTR_TRAIT_TYPE(ref, strong_ref, ref)\
+  CHECK_PTR_TRAIT_TYPE(weak, weak_ref, weak)\
+
+CHECK_PTR_TRAIT(DerivedPtr, DerivedWeakPtr)
+
+#undef CHECK_PTR_TRAIT
+#undef CHECK_PTR_TRAIT_TYPE
+
+BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<Base1Ptr>::value));
+BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<Base2Ptr>::value));
+BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<DerivedPtr>::value));
+BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<DerivedWeakPtr>::value));
+BOOST_STATIC_ASSERT((!nasal::supports_weak_ref<SGReferencedPtr>::value));
+
+BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion )
+{
+  nasal::Ghost<Base1Ptr>::init("Base1");
+  nasal::Ghost<Base2Ptr>::init("Base2");
+  nasal::Ghost<DerivedPtr>::init("Derived")
+    .bases<Base1Ptr>()
+    .bases<Base2Ptr>();
+
+  naContext c = naNewContext();
+
+  DerivedPtr d = new Derived();
+  DerivedWeakPtr weak(d);
+
+  // store weak pointer and extract strong pointer
+  naRef na_d = nasal::to_nasal(c, DerivedWeakPtr(d));
+  BOOST_REQUIRE( naIsGhost(na_d) );
+  BOOST_CHECK_EQUAL( nasal::from_nasal<Base1Ptr>(c, na_d), d );
+  BOOST_CHECK_EQUAL( nasal::from_nasal<Base2Ptr>(c, na_d), d );
+  BOOST_CHECK_EQUAL( nasal::from_nasal<DerivedPtr>(c, na_d), d );
+
+  d.reset();
+  BOOST_REQUIRE( !nasal::from_nasal<DerivedPtr>(c, na_d) );
+
+  // store strong pointer and extract weak pointer
+  d.reset(new Derived);
+  na_d = nasal::to_nasal(c, d);
+  BOOST_REQUIRE( naIsGhost(na_d) );
+
+  weak = nasal::from_nasal<DerivedWeakPtr>(c, na_d);
+  BOOST_CHECK_EQUAL( weak.lock(), d );
+
+  d.reset();
+  BOOST_REQUIRE( nasal::from_nasal<DerivedPtr>(c, na_d) );
+  BOOST_REQUIRE( weak.lock() );
+
+  naFreeContext(c);
+  naGC();
+
+  BOOST_REQUIRE( !weak.lock() );
+}
index 2e216305f921163952b8ec44d542658c9ec23a72..b37c5114adf3fa3f6f1a1923a441007c66f5a333 100644 (file)
 #ifndef SG_NASAL_TRAITS_HXX_
 #define SG_NASAL_TRAITS_HXX_
 
+#include <simgear/structure/SGSharedPtr.hxx>
+#include <simgear/structure/SGWeakPtr.hxx>
+
+#include <osg/ref_ptr>
+#include <osg/observer_ptr>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
 #include <boost/type_traits/integral_constant.hpp>
+#include <boost/type_traits/is_base_of.hpp>
 
 namespace nasal
 {
@@ -54,5 +64,63 @@ namespace nasal
 
 #undef SG_MAKE_TRAIT
 
+  template<class T>
+  struct shared_ptr_traits;
+
+  template<class T>
+  struct is_strong_ref:
+    public boost::integral_constant<bool, false>
+  {};
+
+  template<class T>
+  struct is_weak_ref:
+    public boost::integral_constant<bool, false>
+  {};
+
+#define SG_MAKE_SHARED_PTR_TRAIT(ref, weak)\
+  template<class T>\
+  struct shared_ptr_traits<ref<T> >\
+  {\
+    typedef ref<T>  strong_ref;\
+    typedef weak<T> weak_ref;\
+    typedef T       element_type;\
+    typedef boost::integral_constant<bool, true> is_strong;\
+  };\
+  template<class T>\
+  struct shared_ptr_traits<weak<T> >\
+  {\
+    typedef ref<T>  strong_ref;\
+    typedef weak<T> weak_ref;\
+    typedef T       element_type;\
+    typedef boost::integral_constant<bool, false> is_strong;\
+  };\
+  template<class T>\
+  struct is_strong_ref<ref<T> >:\
+    public boost::integral_constant<bool, true>\
+  {};\
+  template<class T>\
+  struct is_weak_ref<weak<T> >:\
+    public boost::integral_constant<bool, true>\
+  {};
+
+  SG_MAKE_SHARED_PTR_TRAIT(SGSharedPtr, SGWeakPtr)
+  SG_MAKE_SHARED_PTR_TRAIT(osg::ref_ptr, osg::observer_ptr)
+  SG_MAKE_SHARED_PTR_TRAIT(boost::shared_ptr, boost::weak_ptr)
+
+#undef SG_MAKE_SHARED_PTR_TRAIT
+
+  template<class T>
+  struct supports_weak_ref:
+    public boost::integral_constant<bool, true>
+  {};
+
+  template<class T>
+  struct supports_weak_ref<SGSharedPtr<T> >:
+    public boost::integral_constant<
+      bool,
+      boost::is_base_of<SGWeakReferenced, T>::value
+    >
+  {};
+
 } // namespace nasal
 #endif /* SG_NASAL_TRAITS_HXX_ */