cppbind::Ghost: safely use strong and weak references.
Allow using strong and weak references within the same class hierarchy and seemlessly convert between them - from and to Nasal.
This commit is contained in:
@@ -35,3 +35,8 @@ if(ENABLE_TESTS)
|
|||||||
add_test(cppbind ${EXECUTABLE_OUTPUT_PATH}/test_cppbind)
|
add_test(cppbind ${EXECUTABLE_OUTPUT_PATH}/test_cppbind)
|
||||||
target_link_libraries(test_cppbind ${TEST_LIBS})
|
target_link_libraries(test_cppbind ${TEST_LIBS})
|
||||||
endif(ENABLE_TESTS)
|
endif(ENABLE_TESTS)
|
||||||
|
|
||||||
|
add_boost_test(cppbind_ghost
|
||||||
|
SOURCES cppbind_test_ghost.cxx
|
||||||
|
LIBRARIES ${TEST_LIBS}
|
||||||
|
)
|
||||||
+202
-111
@@ -50,12 +50,19 @@ inline T* get_pointer(SGWeakPtr<T> const& p)
|
|||||||
return p.lock().get();
|
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
|
* Bindings between C++ and the Nasal scripting language
|
||||||
*/
|
*/
|
||||||
namespace nasal
|
namespace nasal
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace internal
|
namespace internal
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -74,16 +81,25 @@ namespace nasal
|
|||||||
_parents.push_back(parent);
|
_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;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ghost_type == _ghost_type_weak_ptr )
|
||||||
|
{
|
||||||
|
is_weak = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
for( DerivedList::const_iterator derived = _derived_classes.begin();
|
for( DerivedList::const_iterator derived = _derived_classes.begin();
|
||||||
derived != _derived_classes.end();
|
derived != _derived_classes.end();
|
||||||
++derived )
|
++derived )
|
||||||
{
|
{
|
||||||
if( (*derived)->isBaseOf(ghost_type) )
|
if( (*derived)->isBaseOf(ghost_type, is_weak) )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,15 +110,20 @@ namespace nasal
|
|||||||
|
|
||||||
typedef std::vector<const GhostMetadata*> DerivedList;
|
typedef std::vector<const GhostMetadata*> DerivedList;
|
||||||
|
|
||||||
const std::string _name;
|
const std::string _name_strong,
|
||||||
const naGhostType *_ghost_type_ptr;
|
_name_weak;
|
||||||
|
const naGhostType *_ghost_type_strong_ptr,
|
||||||
|
*_ghost_type_weak_ptr;
|
||||||
DerivedList _derived_classes;
|
DerivedList _derived_classes;
|
||||||
std::vector<naRef> _parents;
|
std::vector<naRef> _parents;
|
||||||
|
|
||||||
GhostMetadata( const std::string& name,
|
GhostMetadata( const std::string& name,
|
||||||
const naGhostType* ghost_type ):
|
const naGhostType* ghost_type_strong,
|
||||||
_name(name),
|
const naGhostType* ghost_type_weak ):
|
||||||
_ghost_type_ptr(ghost_type)
|
_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_NASAL,
|
||||||
SG_INFO,
|
SG_INFO,
|
||||||
"Ghost::addDerived: " << _name << " -> " << derived->_name
|
"Ghost::addDerived: " << _name_strong << " -> "
|
||||||
|
<< derived->_name_strong
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,11 +232,15 @@ namespace nasal
|
|||||||
class Ghost:
|
class Ghost:
|
||||||
public internal::GhostMetadata
|
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:
|
public:
|
||||||
typedef typename T::element_type raw_type;
|
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 (raw_type::*member_func_t)(const CallContext&);
|
||||||
typedef naRef (*free_func_t)(raw_type&, const CallContext&);
|
typedef naRef (*free_func_t)(raw_type&, const CallContext&);
|
||||||
typedef boost::function<naRef(raw_type&, naContext)> getter_t;
|
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>
|
#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
|
||||||
#include BOOST_PP_ITERATE()
|
#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.
|
* Create a shared pointer on the heap to handle the reference counting
|
||||||
*
|
* for the passed shared pointer while it is used in Nasal space.
|
||||||
* @param c Active Nasal context
|
|
||||||
* @param a1 Parameter used for creating new instance
|
|
||||||
*/
|
*/
|
||||||
template<class A1>
|
template<class RefType>
|
||||||
static naRef create( naContext c, const A1& a1 )
|
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 makeGhost(c, createInstance(a1));
|
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
|
||||||
* Nasal callback for creating a new instance of this ghost.
|
// 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
|
||||||
static naRef f_create(naContext c, naRef me, int argc, naRef* args)
|
// the passed static type.
|
||||||
{
|
naGhostType* ghost_type =
|
||||||
return create(c);
|
getTypeFor<Ghost>(ptr, shared_ptr_traits<RefType>::is_strong::value);
|
||||||
}
|
|
||||||
|
|
||||||
static bool isBaseOf(naGhostType* ghost_type)
|
|
||||||
{
|
|
||||||
if( !ghost_type )
|
if( !ghost_type )
|
||||||
return false;
|
return naNil();
|
||||||
|
|
||||||
return getSingletonPtr()->GhostMetadata::isBaseOf(ghost_type);
|
return naNewGhost2(c, ghost_type, new RefType(ref_ptr));
|
||||||
}
|
|
||||||
|
|
||||||
static bool isBaseOf(naRef obj)
|
|
||||||
{
|
|
||||||
return isBaseOf( naGhost_type(obj) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -806,18 +823,31 @@ namespace nasal
|
|||||||
* Nasal objects has to be derived class of the target class (Either
|
* Nasal objects has to be derived class of the target class (Either
|
||||||
* derived in C++ or in Nasal using a 'parents' vector)
|
* 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
|
// Check if it's a ghost and if it can be converted
|
||||||
if( isBaseOf( naGhost_type(me) ) )
|
if( isBaseOf(naGhost_type(me), is_weak) )
|
||||||
return getPtr( naGhost_ptr(me) );
|
{
|
||||||
|
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)
|
// Now if it is derived from a ghost (hash with ghost in parent vector)
|
||||||
else if( naIsHash(me) )
|
else if( naIsHash(me) )
|
||||||
{
|
{
|
||||||
naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
|
naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
|
||||||
if( !naIsVector(na_parents) )
|
if( !naIsVector(na_parents) )
|
||||||
return pointer();
|
return RefType();
|
||||||
|
|
||||||
typedef std::vector<naRef> naRefs;
|
typedef std::vector<naRef> naRefs;
|
||||||
naRefs parents = from_nasal<naRefs>(c, na_parents);
|
naRefs parents = from_nasal<naRefs>(c, na_parents);
|
||||||
@@ -825,13 +855,19 @@ namespace nasal
|
|||||||
parent != parents.end();
|
parent != parents.end();
|
||||||
++parent )
|
++parent )
|
||||||
{
|
{
|
||||||
pointer ptr = fromNasal(c, *parent);
|
RefType ptr = fromNasal<RefType>(c, *parent);
|
||||||
if( get_pointer(ptr) )
|
if( get_pointer(ptr) )
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pointer();
|
return RefType();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isBaseOf(naRef obj)
|
||||||
|
{
|
||||||
|
bool is_weak;
|
||||||
|
return isBaseOf(naGhost_type(obj), is_weak);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -839,47 +875,70 @@ namespace nasal
|
|||||||
template<class>
|
template<class>
|
||||||
friend class Ghost;
|
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;
|
typedef std::vector<type_checker_t> DerivedList;
|
||||||
DerivedList _derived_types;
|
DerivedList _derived_types;
|
||||||
|
|
||||||
/**
|
static bool isBaseOf(naGhostType* ghost_type, bool& is_weak)
|
||||||
* 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 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 )
|
if( ptr )
|
||||||
return *static_cast<pointer*>(ptr);
|
return RefPtr(*static_cast<strong_ref*>(ptr));
|
||||||
else
|
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 )
|
if( ptr )
|
||||||
return get_pointer(*static_cast<pointer*>(ptr));
|
return RefPtr(*static_cast<weak_ref*>(ptr));
|
||||||
else
|
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,
|
void addDerived( const internal::GhostMetadata* derived_meta,
|
||||||
const type_checker_t& derived_info )
|
type_checker_t derived_type_checker )
|
||||||
{
|
{
|
||||||
GhostMetadata::addDerived(derived_meta);
|
GhostMetadata::addDerived(derived_meta);
|
||||||
_derived_types.push_back(derived_info);
|
_derived_types.push_back(derived_type_checker);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BaseGhost>
|
template<class BaseGhost>
|
||||||
@@ -888,7 +947,7 @@ namespace nasal
|
|||||||
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
||||||
naGhostType*
|
naGhostType*
|
||||||
>::type
|
>::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
|
// Check first if passed pointer can by converted to instance of class
|
||||||
// this ghost wraps.
|
// this ghost wraps.
|
||||||
@@ -917,14 +976,20 @@ namespace nasal
|
|||||||
++derived )
|
++derived )
|
||||||
{
|
{
|
||||||
naGhostType* ghost_type =
|
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 )
|
if( ghost_type )
|
||||||
return ghost_type;
|
return ghost_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If base is not an instance of any derived class, this class has to
|
// If base is not an instance of any derived class, this class has to
|
||||||
// be the dynamic type.
|
// be the dynamic type.
|
||||||
return &_ghost_type;
|
return strong
|
||||||
|
? &_ghost_type_strong
|
||||||
|
: &_ghost_type_weak;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BaseGhost>
|
template<class BaseGhost>
|
||||||
@@ -933,11 +998,13 @@ namespace nasal
|
|||||||
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
||||||
naGhostType*
|
naGhostType*
|
||||||
>::type
|
>::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
|
// For non polymorphic classes there is no possibility to get the actual
|
||||||
// dynamic type, therefore we can only use its static type.
|
// 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()
|
static Ghost* getSingletonPtr()
|
||||||
@@ -947,17 +1014,19 @@ namespace nasal
|
|||||||
|
|
||||||
static raw_type& requireObject(naContext c, naRef me)
|
static raw_type& requireObject(naContext c, naRef me)
|
||||||
{
|
{
|
||||||
raw_type* obj = getRawPtr( fromNasal(c, me) );
|
raw_type* obj = get_pointer( fromNasal<strong_ref>(c, me) );
|
||||||
naGhostType* ghost_type = naGhost_type(me);
|
|
||||||
|
|
||||||
if( !obj )
|
if( !obj )
|
||||||
|
{
|
||||||
|
naGhostType* ghost_type = naGhost_type(me);
|
||||||
naRuntimeError
|
naRuntimeError
|
||||||
(
|
(
|
||||||
c,
|
c,
|
||||||
"method called on object of wrong type: is '%s' expected '%s'",
|
"method called on object of wrong type: is '%s' expected '%s'",
|
||||||
naIsNil(me) ? "nil" : (ghost_type ? ghost_type->name : "unknown"),
|
naIsNil(me) ? "nil" : (ghost_type ? ghost_type->name : "unknown"),
|
||||||
_ghost_type.name
|
_ghost_type_strong.name
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return *obj;
|
return *obj;
|
||||||
}
|
}
|
||||||
@@ -1084,12 +1153,21 @@ namespace nasal
|
|||||||
fallback_setter_t _fallback_setter;
|
fallback_setter_t _fallback_setter;
|
||||||
|
|
||||||
explicit Ghost(const std::string& name):
|
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_strong.destroy = &destroy<strong_ref>;
|
||||||
_ghost_type.name = _name.c_str();
|
_ghost_type_strong.name = _name_strong.c_str();
|
||||||
_ghost_type.get_member = &getMember;
|
_ghost_type_strong.get_member = &getMember<false>;
|
||||||
_ghost_type.set_member = &setMember;
|
_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()
|
static GhostPtr& getSingletonHolder()
|
||||||
@@ -1098,33 +1176,19 @@ namespace nasal
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
static naRef makeGhost(naContext c, void *ptr)
|
template<class Type>
|
||||||
|
static void destroy(void *ptr)
|
||||||
{
|
{
|
||||||
if( getRawPtr(ptr) )
|
delete static_cast<Type*>(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for retrieving a ghost member.
|
* 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);
|
const std::string key_str = nasal::from_nasal<std::string>(c, key);
|
||||||
// TODO merge instance parents with static class parents
|
// TODO merge instance parents with static class parents
|
||||||
@@ -1144,23 +1208,36 @@ namespace nasal
|
|||||||
{
|
{
|
||||||
fallback_getter_t fallback_get = getSingletonPtr()->_fallback_getter;
|
fallback_getter_t fallback_get = getSingletonPtr()->_fallback_getter;
|
||||||
if( !fallback_get
|
if( !fallback_get
|
||||||
|| !fallback_get(*getRawPtr(g), c, key_str, *out) )
|
|| !fallback_get(obj, c, key_str, *out) )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if( member->second.func )
|
else if( member->second.func )
|
||||||
*out = member->second.func->get_naRef(c);
|
*out = member->second.func->get_naRef(c);
|
||||||
else if( !member->second.getter.empty() )
|
else if( !member->second.getter.empty() )
|
||||||
*out = member->second.getter(*getRawPtr(g), c);
|
*out = member->second.getter(obj, c);
|
||||||
else
|
else
|
||||||
return "Read-protected member";
|
return "Read-protected member";
|
||||||
|
|
||||||
return "";
|
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.
|
* 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 std::string key = nasal::from_nasal<std::string>(c, field);
|
||||||
const MemberMap& members = getSingletonPtr()->_members;
|
const MemberMap& members = getSingletonPtr()->_members;
|
||||||
@@ -1171,7 +1248,7 @@ namespace nasal
|
|||||||
fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
|
fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
|
||||||
if( !fallback_set )
|
if( !fallback_set )
|
||||||
naRuntimeError(c, "ghost: No such member: %s", key.c_str());
|
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());
|
naRuntimeError(c, "ghost: Failed to write (_set: %s)", key.c_str());
|
||||||
}
|
}
|
||||||
else if( member->second.setter.empty() )
|
else if( member->second.setter.empty() )
|
||||||
@@ -1179,12 +1256,24 @@ namespace nasal
|
|||||||
else if( member->second.func )
|
else if( member->second.func )
|
||||||
naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
|
naRuntimeError(c, "ghost: Write to function: %s", key.c_str());
|
||||||
else
|
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>
|
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
|
} // namespace nasal
|
||||||
|
|
||||||
@@ -1201,7 +1290,8 @@ typename boost::enable_if<
|
|||||||
>::type
|
>::type
|
||||||
to_nasal_helper(naContext c, T ptr)
|
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
|
>::type
|
||||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
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
|
>::type
|
||||||
to_nasal_helper(naContext c, T* ptr)
|
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*)
|
from_nasal_helper(naContext c, naRef ref, const T*)
|
||||||
{
|
{
|
||||||
typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
|
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_ */
|
#endif /* SG_NASAL_GHOST_HXX_ */
|
||||||
|
|||||||
@@ -269,7 +269,6 @@ int main(int argc, char* argv[])
|
|||||||
.member("base", &DoubleDerived2::getBase)
|
.member("base", &DoubleDerived2::getBase)
|
||||||
.method("doIt", &DoubleDerived2::doSomeBaseWork);
|
.method("doIt", &DoubleDerived2::doSomeBaseWork);
|
||||||
|
|
||||||
Ghost<DerivedWeakPtr>::init("DerivedWeakPtr");
|
|
||||||
Ghost<SGRefBasedPtr>::init("SGRefBasedPtr");
|
Ghost<SGRefBasedPtr>::init("SGRefBasedPtr");
|
||||||
Ghost<SGWeakRefBasedPtr>::init("SGWeakRefBasedPtr");
|
Ghost<SGWeakRefBasedPtr>::init("SGWeakRefBasedPtr");
|
||||||
|
|
||||||
@@ -372,9 +371,9 @@ int main(int argc, char* argv[])
|
|||||||
VERIFY( from_nasal<BasePtr>(c, derived_obj.get_naRef()) == d3 );
|
VERIFY( from_nasal<BasePtr>(c, derived_obj.get_naRef()) == d3 );
|
||||||
|
|
||||||
std::vector<naRef> nasal_objects;
|
std::vector<naRef> nasal_objects;
|
||||||
nasal_objects.push_back( Ghost<BasePtr>::create(c, d) );
|
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d) );
|
||||||
nasal_objects.push_back( Ghost<BasePtr>::create(c, d2) );
|
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d2) );
|
||||||
nasal_objects.push_back( Ghost<BasePtr>::create(c, d3) );
|
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d3) );
|
||||||
naRef obj_vec = to_nasal(c, nasal_objects);
|
naRef obj_vec = to_nasal(c, nasal_objects);
|
||||||
|
|
||||||
std::vector<BasePtr> objects = from_nasal<std::vector<BasePtr> >(c, obj_vec);
|
std::vector<BasePtr> objects = from_nasal<std::vector<BasePtr> >(c, obj_vec);
|
||||||
|
|||||||
@@ -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() );
|
||||||
|
}
|
||||||
@@ -20,7 +20,17 @@
|
|||||||
#ifndef SG_NASAL_TRAITS_HXX_
|
#ifndef SG_NASAL_TRAITS_HXX_
|
||||||
#define 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/integral_constant.hpp>
|
||||||
|
#include <boost/type_traits/is_base_of.hpp>
|
||||||
|
|
||||||
namespace nasal
|
namespace nasal
|
||||||
{
|
{
|
||||||
@@ -54,5 +64,63 @@ namespace nasal
|
|||||||
|
|
||||||
#undef SG_MAKE_TRAIT
|
#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
|
} // namespace nasal
|
||||||
#endif /* SG_NASAL_TRAITS_HXX_ */
|
#endif /* SG_NASAL_TRAITS_HXX_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user