return p.lock().get();
}
+namespace osg
+{
+ template<class T>
+ inline T* get_pointer(observer_ptr<T> const& p)
+ {
+ ref_ptr<T> ref;
+ p.lock(ref);
+ return ref.get();
+ }
+}
+
template<class T>
-inline T* get_pointer(osg::observer_ptr<T> const& p)
+inline typename boost::enable_if<
+ boost::is_pointer<T>,
+ T
+>::type
+get_pointer(T ptr)
{
- osg::ref_ptr<T> ref;
- p.lock(ref);
- return ref.get();
+ return ptr;
}
// Both ways of retrieving the address of a static member function
if( !holder )
throw std::runtime_error("holder has expired");
+ // Keep reference for duration of call to prevent expiring
+ // TODO not needed for strong referenced ghost
+ strong_ref ref = fromNasal<strong_ref>(c, me);
+ if( !ref )
+ {
+ 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_strong.name
+ );
+ }
+
return holder->_method
(
- requireObject(c, me),
+ *get_pointer(ref),
CallContext(c, argc, args)
);
}
if( !ghost_type )
return naNil();
- return naNewGhost2(c, ghost_type, new RefType(ref_ptr));
+ return naNewGhost2( c,
+ ghost_type,
+ shared_ptr_storage<RefType>::ref(ref_ptr) );
}
/**
* Nasal objects has to be derived class of the target class (Either
* derived in C++ or in Nasal using a 'parents' vector)
*/
- 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)
+ template<class Type>
+ static Type fromNasal(naContext c, naRef me)
{
bool is_weak = false;
if( isBaseOf(naGhost_type(me), is_weak) )
{
void* ghost = naGhost_ptr(me);
- return is_weak ? getPtr<RefType, true>(ghost)
- : getPtr<RefType, false>(ghost);
+ return is_weak ? getPtr<Type, true>(ghost)
+ : getPtr<Type, false>(ghost);
}
// Now if it is derived from a ghost (hash with ghost in parent vector)
{
naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
if( !naIsVector(na_parents) )
- return RefType();
+ return Type();
typedef std::vector<naRef> naRefs;
naRefs parents = from_nasal<naRefs>(c, na_parents);
parent != parents.end();
++parent )
{
- RefType ptr = fromNasal<RefType>(c, *parent);
+ Type ptr = fromNasal<Type>(c, *parent);
if( get_pointer(ptr) )
return ptr;
}
}
- return RefType();
+ return Type();
}
static bool isBaseOf(naRef obj)
>::type
getPtr(void* ptr)
{
+ typedef shared_ptr_storage<strong_ref> storage_type;
if( ptr )
- return RefPtr(*static_cast<strong_ref*>(ptr));
+ return storage_type::template get<RefPtr>(
+ static_cast<typename storage_type::storage_type*>(ptr)
+ );
else
return RefPtr();
}
>::type
getPtr(void* ptr)
{
+ typedef shared_ptr_storage<weak_ref> storage_type;
if( ptr )
- return RefPtr(*static_cast<weak_ref*>(ptr));
+ return storage_type::template get<RefPtr>(
+ static_cast<typename storage_type::storage_type*>(ptr)
+ );
else
return RefPtr();
}
return getSingletonHolder().get();
}
- static raw_type& requireObject(naContext c, naRef 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_strong.name
- );
- }
-
- return *obj;
- }
-
template<class Ret>
getter_t to_getter(Ret (raw_type::*getter)() const)
{
_ghost_type_strong.destroy =
SG_GET_TEMPLATE_MEMBER(Ghost, queueDestroy<strong_ref>);
_ghost_type_strong.name = _name_strong.c_str();
- _ghost_type_strong.get_member =
- SG_GET_TEMPLATE_MEMBER(Ghost, getMember<false>);
- _ghost_type_strong.set_member =
- SG_GET_TEMPLATE_MEMBER(Ghost, setMember<false>);
+ _ghost_type_strong.get_member = &Ghost::getMemberStrong;
+ _ghost_type_strong.set_member = &Ghost::setMemberStrong;
_ghost_type_weak.destroy =
SG_GET_TEMPLATE_MEMBER(Ghost, queueDestroy<weak_ref>);
if( supports_weak_ref<T>::value )
{
- _ghost_type_weak.get_member =
- SG_GET_TEMPLATE_MEMBER(Ghost, getMember<true>);
- _ghost_type_weak.set_member =
- SG_GET_TEMPLATE_MEMBER(Ghost, setMember<true>);
+ _ghost_type_weak.get_member = &Ghost::getMemberWeak;
+ _ghost_type_weak.set_member = &Ghost::setMemberWeak;
}
else
{
template<class Type>
static void destroy(void *ptr)
{
- delete static_cast<Type*>(ptr);
+ typedef shared_ptr_storage<Type> storage_type;
+ storage_type::unref(
+ static_cast<typename storage_type::storage_type*>(ptr)
+ );
}
template<class Type>
_destroy_list.push_back( DestroyList::value_type(&destroy<Type>, ptr) );
}
+ static void raiseErrorExpired(naContext c, const char* str)
+ {
+ Ghost* ghost_info = getSingletonPtr();
+ naRuntimeError(
+ c,
+ "Ghost::%s: ghost has expired '%s'",
+ str,
+ ghost_info ? ghost_info->_name_strong.c_str() : "unknown"
+ );
+ }
+
/**
* Callback for retrieving a ghost member.
*/
return "";
}
- template<bool is_weak>
- static const char* getMember( naContext c,
- void* ghost,
- naRef key,
- naRef* out )
+ static const char*
+ getMemberWeak(naContext c, void* ghost, naRef key, naRef* out)
+ {
+ // Keep a strong reference while retrieving member, to prevent deleting
+ // object in between.
+ strong_ref ref = getPtr<strong_ref, true>(ghost);
+ if( !ref )
+ raiseErrorExpired(c, "getMember");
+
+ return getMemberImpl(c, *get_pointer(ref), key, out);
+ }
+
+ static const char*
+ getMemberStrong(naContext c, void* ghost, naRef key, naRef* out)
{
- strong_ref const& ptr = getPtr<strong_ref, is_weak>(ghost);
- return getMemberImpl(c, *get_pointer(ptr), key, out);
+ // Just get a raw pointer as we are keeping a strong reference as ghost
+ // anyhow.
+ raw_type* ptr = getPtr<raw_type*, false>(ghost);
+ return getMemberImpl(c, *ptr, key, out);
}
/**
member->second.setter(obj, c, val);
}
- template<bool is_weak>
- static void setMember( naContext c,
- void* ghost,
- naRef field,
- naRef val )
+ static void
+ setMemberWeak(naContext c, void* ghost, naRef field, naRef val)
{
- strong_ref const& ptr = getPtr<strong_ref, is_weak>(ghost);
- return setMemberImpl(c, *get_pointer(ptr), field, val);
+ // Keep a strong reference while retrieving member, to prevent deleting
+ // object in between.
+ strong_ref ref = getPtr<strong_ref, true>(ghost);
+ if( !ref )
+ raiseErrorExpired(c, "setMember");
+
+ setMemberImpl(c, *get_pointer(ref), field, val);
+ }
+
+ static void
+ setMemberStrong(naContext c, void* ghost, naRef field, naRef val)
+ {
+ // Just get a raw pointer as we are keeping a strong reference as ghost
+ // anyhow.
+ raw_type* ptr = getPtr<raw_type*, false>(ghost);
+ setMemberImpl(c, *ptr, field, val);
}
};
}
/**
- * Convert any pointer to a SGReference based object to a ghost.
+ * Convert any pointer to a SGReferenced based object to a ghost.
*/
template<class T>
typename boost::enable_if_c<
}
/**
- * Convert nasal ghosts/hashes to pointer (of a SGReference based ghost).
+ * Convert nasal ghosts/hashes to pointer (of a SGReferenced based ghost).
*/
template<class T>
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>::template fromNasal<TypeRef>(c, ref).release();
+ return nasal::Ghost<TypeRef>::template fromNasal<T>(c, ref);
+}
+
+/**
+ * Convert any pointer to a osg::Referenced based object to a ghost.
+ */
+template<class T>
+typename boost::enable_if<
+ boost::is_base_of<osg::Referenced, T>,
+ naRef
+>::type
+to_nasal_helper(naContext c, T* ptr)
+{
+ return nasal::Ghost<osg::ref_ptr<T> >::makeGhost(c, osg::ref_ptr<T>(ptr));
+}
+
+/**
+ * Convert nasal ghosts/hashes to pointer (of a osg::Referenced based ghost).
+ */
+template<class T>
+typename boost::enable_if<
+ boost::is_base_of<osg::Referenced, typename boost::remove_pointer<T>::type>,
+ T
+>::type
+from_nasal_helper(naContext c, naRef ref, const T*)
+{
+ typedef osg::ref_ptr<typename boost::remove_pointer<T>::type> TypeRef;
+ return nasal::Ghost<TypeRef>::template fromNasal<T>(c, ref);
}
#endif /* SG_NASAL_GHOST_HXX_ */
#include <BoostTestTargetConfig.h>
#include "Ghost.hxx"
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
class Base1:
public virtual SGVirtualWeakReferenced
CHECK_PTR_TRAIT_TYPE(weak, weak_ref, weak)\
CHECK_PTR_TRAIT(DerivedPtr, DerivedWeakPtr)
+CHECK_PTR_TRAIT(boost::shared_ptr<Base1>, boost::weak_ptr<Base1>)
#undef CHECK_PTR_TRAIT
#undef CHECK_PTR_TRAIT_TYPE
BOOST_REQUIRE( !weak.lock() );
}
+
+#define CHECK_PTR_STORAGE_TRAIT_TYPE(ptr_t, storage)\
+ BOOST_STATIC_ASSERT((boost::is_same<\
+ nasal::shared_ptr_storage<ptr_t>::storage_type,\
+ storage\
+ >::value));
+
+CHECK_PTR_STORAGE_TRAIT_TYPE(DerivedPtr, Derived)
+CHECK_PTR_STORAGE_TRAIT_TYPE(DerivedWeakPtr, DerivedWeakPtr)
+
+typedef boost::shared_ptr<Derived> BoostDerivedPtr;
+CHECK_PTR_STORAGE_TRAIT_TYPE(BoostDerivedPtr, BoostDerivedPtr)
+
+typedef boost::weak_ptr<Derived> BoostDerivedWeakPtr;
+CHECK_PTR_STORAGE_TRAIT_TYPE(BoostDerivedWeakPtr, BoostDerivedWeakPtr)
+
+#undef CHECK_PTR_STORAGE_TRAIT_TYPE
+
+BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<Base1Ptr>::is_intrusive::value));
+BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<Base2Ptr>::is_intrusive::value));
+BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<DerivedPtr>::is_intrusive::value));
+BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<DerivedWeakPtr>::is_intrusive::value));
+BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<SGReferencedPtr>::is_intrusive::value));
+
+BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<boost::shared_ptr<Derived> >::is_intrusive::value));
+BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<boost::weak_ptr<Derived> >::is_intrusive::value));
+
+BOOST_AUTO_TEST_CASE( storage_traits )
+{
+ DerivedPtr d = new Derived();
+
+ Derived* d_raw = nasal::shared_ptr_storage<DerivedPtr>::ref(d);
+ BOOST_REQUIRE_EQUAL(d_raw, d.get());
+ BOOST_REQUIRE_EQUAL(d.getNumRefs(), 2);
+
+ DerivedWeakPtr* d_weak = nasal::shared_ptr_storage<DerivedWeakPtr>::ref(d);
+ BOOST_REQUIRE_EQUAL(
+ nasal::shared_ptr_storage<DerivedWeakPtr>::get<Derived*>(d_weak),
+ d_raw
+ );
+
+ d.reset();
+ BOOST_REQUIRE_EQUAL(Derived::count(d_raw), 1);
+
+ nasal::shared_ptr_storage<DerivedPtr>::unref(d_raw);
+ BOOST_REQUIRE(d_weak->expired());
+
+ nasal::shared_ptr_storage<DerivedWeakPtr>::unref(d_weak);
+}
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/is_base_of.hpp>
+#include <boost/utility/enable_if.hpp>
// Forward declarations
+class SGReferenced;
class SGWeakReferenced;
template<class T> class SGSharedPtr;
template<class T> class SGWeakPtr;
}
namespace osg
{
+ class Referenced;
template<class T> class ref_ptr;
template<class T> class observer_ptr;
public boost::integral_constant<bool, false>
{};
-#define SG_MAKE_SHARED_PTR_TRAIT(ref, weak)\
+#define SG_MAKE_SHARED_PTR_TRAIT(strong, weak, intrusive)\
template<class T>\
- struct shared_ptr_traits<ref<T> >\
+ struct shared_ptr_traits<strong<T> >\
{\
- typedef ref<T> strong_ref;\
- typedef weak<T> weak_ref;\
- typedef T element_type;\
+ typedef strong<T> strong_ref;\
+ typedef weak<T> weak_ref;\
+ typedef T element_type;\
typedef boost::integral_constant<bool, true> is_strong;\
+ typedef boost::integral_constant<bool, intrusive> is_intrusive;\
};\
template<class T>\
struct shared_ptr_traits<weak<T> >\
{\
- typedef ref<T> strong_ref;\
- typedef weak<T> weak_ref;\
- typedef T element_type;\
+ typedef strong<T> strong_ref;\
+ typedef weak<T> weak_ref;\
+ typedef T element_type;\
typedef boost::integral_constant<bool, false> is_strong;\
+ typedef boost::integral_constant<bool, intrusive> is_intrusive;\
};\
template<class T>\
- struct is_strong_ref<ref<T> >:\
+ struct is_strong_ref<strong<T> >:\
public boost::integral_constant<bool, true>\
{};\
template<class 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)
+ SG_MAKE_SHARED_PTR_TRAIT(SGSharedPtr, SGWeakPtr, true)
+ SG_MAKE_SHARED_PTR_TRAIT(osg::ref_ptr, osg::observer_ptr, true)
+ SG_MAKE_SHARED_PTR_TRAIT(boost::shared_ptr, boost::weak_ptr, false)
#undef SG_MAKE_SHARED_PTR_TRAIT
>
{};
+ template<class T>
+ struct shared_ptr_storage
+ {
+ typedef T storage_type;
+ typedef typename T::element_type element_type;
+ typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
+ typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
+
+ template<class U>
+ static storage_type* ref(U ptr)
+ {
+ return new storage_type(ptr);
+ }
+ static void unref(storage_type* ptr)
+ {
+ delete ptr;
+ }
+
+ template<class U>
+ static
+ typename boost::enable_if<
+ boost::is_same<U, element_type*>,
+ element_type*
+ >::type
+ get(storage_type* ptr)
+ {
+ return get_pointer(*ptr);
+ }
+ template<class U>
+ static
+ typename boost::enable_if_c<
+ boost::is_same<U, strong_ref>::value
+ || (boost::is_same<U, weak_ref>::value && supports_weak_ref<U>::value),
+ U
+ >::type
+ get(storage_type* ptr)
+ {
+ return U(*ptr);
+ }
+ template<class U>
+ static
+ typename boost::enable_if_c<
+ boost::is_same<U, weak_ref>::value
+ && !supports_weak_ref<U>::value,
+ U
+ >::type
+ get(storage_type* ptr)
+ {
+ return U();
+ }
+ };
+
+ namespace internal
+ {
+ template<class T>
+ struct intrusive_ptr_storage
+ {
+ typedef typename T::element_type storage_type;
+ typedef typename T::element_type element_type;
+ typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
+ typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
+
+ template<class U>
+ static
+ typename boost::enable_if<
+ boost::is_same<U, element_type*>,
+ element_type*
+ >::type
+ get(storage_type* ptr)
+ {
+ return ptr;
+ }
+ template<class U>
+ static
+ typename boost::enable_if_c<
+ boost::is_same<U, strong_ref>::value
+ || (boost::is_same<U, weak_ref>::value && supports_weak_ref<U>::value),
+ U
+ >::type
+ get(storage_type* ptr)
+ {
+ return U(ptr);
+ }
+ template<class U>
+ static
+ typename boost::enable_if_c<
+ boost::is_same<U, weak_ref>::value
+ && !supports_weak_ref<U>::value,
+ U
+ >::type
+ get(storage_type* ptr)
+ {
+ return U();
+ }
+ };
+ }
+
+ template<class T>
+ struct shared_ptr_storage<SGSharedPtr<T> >:
+ public internal::intrusive_ptr_storage<SGSharedPtr<T> >
+ {
+ typedef T storage_type;
+ typedef T element_type;
+
+ static storage_type* ref(element_type* ptr)
+ {
+ T::get(ptr);
+ return ptr;
+ }
+ static void unref(storage_type* ptr)
+ {
+ if( !T::put(ptr) )
+ delete ptr;
+ }
+ };
+
+ template<class T>
+ struct shared_ptr_storage<osg::ref_ptr<T> >:
+ public internal::intrusive_ptr_storage<osg::ref_ptr<T> >
+ {
+ typedef T storage_type;
+ typedef T element_type;
+
+
+ static storage_type* ref(element_type* ptr)
+ {
+ ptr->ref();
+ return ptr;
+ }
+ static void unref(storage_type* ptr)
+ {
+ ptr->unref();
+ }
+ };
+
} // namespace nasal
#endif /* SG_NASAL_TRAITS_HXX_ */