Canvas/C++ bindings: automatically detect dynamic type of polymorphic exposed classes
This commit is contained in:
@@ -84,6 +84,7 @@ namespace nasal
|
|||||||
struct SharedPointerPolicy
|
struct SharedPointerPolicy
|
||||||
{
|
{
|
||||||
typedef typename GhostTypeTraits<T>::raw_type raw_type;
|
typedef typename GhostTypeTraits<T>::raw_type raw_type;
|
||||||
|
typedef boost::false_type returns_dynamic_type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a shared pointer on the heap to handle the reference counting for
|
* Create a shared pointer on the heap to handle the reference counting for
|
||||||
@@ -107,6 +108,7 @@ namespace nasal
|
|||||||
struct RawPointerPolicy
|
struct RawPointerPolicy
|
||||||
{
|
{
|
||||||
typedef typename GhostTypeTraits<T>::raw_type raw_type;
|
typedef typename GhostTypeTraits<T>::raw_type raw_type;
|
||||||
|
typedef boost::true_type returns_dynamic_type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new object instance on the heap
|
* Create a new object instance on the heap
|
||||||
@@ -243,10 +245,14 @@ namespace nasal
|
|||||||
/**
|
/**
|
||||||
* Register a new ghost type.
|
* Register a new ghost type.
|
||||||
*
|
*
|
||||||
|
* @note Only intialize each ghost type once!
|
||||||
|
*
|
||||||
* @param name Descriptive name of the ghost type.
|
* @param name Descriptive name of the ghost type.
|
||||||
*/
|
*/
|
||||||
static Ghost& init(const std::string& name)
|
static Ghost& init(const std::string& name)
|
||||||
{
|
{
|
||||||
|
assert( !getSingletonPtr() );
|
||||||
|
|
||||||
getSingletonHolder().reset( new Ghost(name) );
|
getSingletonHolder().reset( new Ghost(name) );
|
||||||
return *getSingletonPtr();
|
return *getSingletonPtr();
|
||||||
}
|
}
|
||||||
@@ -273,7 +279,7 @@ namespace nasal
|
|||||||
bases()
|
bases()
|
||||||
{
|
{
|
||||||
BaseGhost* base = BaseGhost::getSingletonPtr();
|
BaseGhost* base = BaseGhost::getSingletonPtr();
|
||||||
//addBaseClass( base );
|
base->addDerived( &getTypeFor<BaseGhost> );
|
||||||
|
|
||||||
// Replace any getter that is not available in the current class.
|
// Replace any getter that is not available in the current class.
|
||||||
// TODO check if this is the correct behavior of function overriding
|
// TODO check if this is the correct behavior of function overriding
|
||||||
@@ -490,6 +496,62 @@ namespace nasal
|
|||||||
template<class>
|
template<class>
|
||||||
friend class Ghost;
|
friend class Ghost;
|
||||||
|
|
||||||
|
typedef naGhostType* (*type_checker_t)(const raw_type*);
|
||||||
|
typedef std::vector<type_checker_t> DerivedList;
|
||||||
|
DerivedList _derived_classes;
|
||||||
|
|
||||||
|
void addDerived(const type_checker_t& derived_info)
|
||||||
|
{
|
||||||
|
_derived_classes.push_back(derived_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BaseGhost>
|
||||||
|
static
|
||||||
|
typename boost::enable_if
|
||||||
|
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
||||||
|
naGhostType*
|
||||||
|
>::type
|
||||||
|
getTypeFor(const typename BaseGhost::raw_type* base)
|
||||||
|
{
|
||||||
|
// Check first if passed pointer can by converted to instance of class
|
||||||
|
// this ghost wraps.
|
||||||
|
if( !boost::is_same
|
||||||
|
< typename BaseGhost::raw_type,
|
||||||
|
Ghost::raw_type
|
||||||
|
>::value
|
||||||
|
&& dynamic_cast<const Ghost::raw_type*>(base) != base )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Now check if we can further downcast to one of our derived classes.
|
||||||
|
naGhostType* ghost_type = 0;
|
||||||
|
for( typename DerivedList::reverse_iterator
|
||||||
|
derived = getSingletonPtr()->_derived_classes.rbegin();
|
||||||
|
derived != getSingletonPtr()->_derived_classes.rend();
|
||||||
|
++derived )
|
||||||
|
{
|
||||||
|
ghost_type = (*derived)( static_cast<const Ghost::raw_type*>(base) );
|
||||||
|
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 &getSingletonPtr()->_ghost_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BaseGhost>
|
||||||
|
static
|
||||||
|
typename boost::disable_if
|
||||||
|
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
||||||
|
naGhostType*
|
||||||
|
>::type
|
||||||
|
getTypeFor(const typename BaseGhost::raw_type* base)
|
||||||
|
{
|
||||||
|
// For non polymorphic classes there is no possibility to get the actual
|
||||||
|
// dynamic type, therefore we can only use its static type.
|
||||||
|
return &BaseGhost::getSingletonPtr()->_ghost_type;
|
||||||
|
}
|
||||||
|
|
||||||
static Ghost* getSingletonPtr()
|
static Ghost* getSingletonPtr()
|
||||||
{
|
{
|
||||||
return getSingletonHolder().get();
|
return getSingletonHolder().get();
|
||||||
@@ -580,7 +642,23 @@ namespace nasal
|
|||||||
|
|
||||||
static naRef makeGhost(naContext c, void *ptr)
|
static naRef makeGhost(naContext c, void *ptr)
|
||||||
{
|
{
|
||||||
return naNewGhost2(c, &getSingletonPtr()->_ghost_type, 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>( Ghost::getRawPtr(ptr) );
|
||||||
|
|
||||||
|
if( !ghost_type )
|
||||||
|
return naNil();
|
||||||
|
|
||||||
|
return naNewGhost2(c, ghost_type, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroyGhost(void *ptr)
|
static void destroyGhost(void *ptr)
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
#include "Ghost.hxx"
|
#include "Ghost.hxx"
|
||||||
#include "NasalHash.hxx"
|
#include "NasalHash.hxx"
|
||||||
|
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#define VERIFY(a) \
|
#define VERIFY(a) \
|
||||||
if( !(a) ) \
|
if( !(a) ) \
|
||||||
{ \
|
{ \
|
||||||
std::cerr << "failed:" << #a << std::endl; \
|
std::cerr << "failed: line " << __LINE__ << ": " << #a << std::endl; \
|
||||||
return 1; \
|
return 1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Base
|
struct Base
|
||||||
{
|
{
|
||||||
naRef member(naContext, int, naRef*) { return naNil(); }
|
naRef member(naContext, int, naRef*) { return naNil(); }
|
||||||
|
virtual ~Base(){};
|
||||||
};
|
};
|
||||||
struct Derived:
|
struct Derived:
|
||||||
public Base
|
public Base
|
||||||
@@ -22,6 +25,16 @@ struct Derived:
|
|||||||
int getX() const { return _x; }
|
int getX() const { return _x; }
|
||||||
void setX(int x) { _x = x; }
|
void setX(int x) { _x = x; }
|
||||||
};
|
};
|
||||||
|
struct DoubleDerived:
|
||||||
|
public Derived
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
struct DoubleDerived2:
|
||||||
|
public Derived
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
naRef member(Derived&, naContext, int, naRef*) { return naNil(); }
|
naRef member(Derived&, naContext, int, naRef*) { return naNil(); }
|
||||||
|
|
||||||
@@ -83,6 +96,36 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
naRef derived = Ghost<Derived>::create(c);
|
naRef derived = Ghost<Derived>::create(c);
|
||||||
VERIFY( naIsGhost(derived) );
|
VERIFY( naIsGhost(derived) );
|
||||||
|
VERIFY( std::string("Derived") == naGhost_type(derived)->name );
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<Base> BasePtr;
|
||||||
|
typedef boost::shared_ptr<Derived> DerivedPtr;
|
||||||
|
typedef boost::shared_ptr<DoubleDerived> DoubleDerivedPtr;
|
||||||
|
typedef boost::shared_ptr<DoubleDerived2> DoubleDerived2Ptr;
|
||||||
|
|
||||||
|
Ghost<BasePtr>::init("BasePtr");
|
||||||
|
Ghost<DerivedPtr>::init("DerivedPtr")
|
||||||
|
.bases<BasePtr>();
|
||||||
|
Ghost<DoubleDerivedPtr>::init("DoubleDerivedPtr")
|
||||||
|
.bases<DerivedPtr>();
|
||||||
|
Ghost<DoubleDerived2Ptr>::init("DoubleDerived2Ptr")
|
||||||
|
.bases<DerivedPtr>();
|
||||||
|
|
||||||
|
BasePtr d( new Derived );
|
||||||
|
derived = Ghost<BasePtr>::create(c, d);
|
||||||
|
VERIFY( naIsGhost(derived) );
|
||||||
|
VERIFY( std::string("DerivedPtr") == naGhost_type(derived)->name );
|
||||||
|
|
||||||
|
BasePtr d2( new DoubleDerived );
|
||||||
|
derived = Ghost<BasePtr>::create(c, d2);
|
||||||
|
VERIFY( naIsGhost(derived) );
|
||||||
|
VERIFY( std::string("DoubleDerivedPtr") == naGhost_type(derived)->name );
|
||||||
|
|
||||||
|
BasePtr d3( new DoubleDerived2 );
|
||||||
|
derived = Ghost<BasePtr>::create(c, d3);
|
||||||
|
VERIFY( naIsGhost(derived) );
|
||||||
|
VERIFY( std::string("DoubleDerived2Ptr") == naGhost_type(derived)->name );
|
||||||
|
|
||||||
// TODO actuall do something with the ghosts...
|
// TODO actuall do something with the ghosts...
|
||||||
|
|
||||||
naFreeContext(c);
|
naFreeContext(c);
|
||||||
|
|||||||
Reference in New Issue
Block a user