template<class T>
struct SharedPointerPolicy
{
- typedef typename GhostTypeTraits<T>::raw_type raw_type;
- typedef boost::false_type returns_dynamic_type;
+ typedef typename GhostTypeTraits<T>::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
return new T(ptr);
}
+ static pointer getPtr(void* ptr)
+ {
+ if( ptr )
+ return *static_cast<T*>(ptr);
+ else
+ return pointer();
+ }
+
static raw_type* getRawPtr(void* ptr)
{
- return static_cast<T*>(ptr)->get();
+ if( ptr )
+ return static_cast<T*>(ptr)->get();
+ else
+ return 0;
+ }
+
+ static raw_type* getRawPtr(const T& ptr)
+ {
+ return ptr.get();
}
};
template<class T>
struct RawPointerPolicy
{
- typedef typename GhostTypeTraits<T>::raw_type raw_type;
- typedef boost::true_type returns_dynamic_type;
+ typedef typename GhostTypeTraits<T>::raw_type raw_type;
+ typedef raw_type* pointer;
+ typedef boost::true_type returns_dynamic_type;
/**
* Create a new object instance on the heap
return new T();
}
+ static pointer getPtr(void* ptr)
+ {
+ BOOST_STATIC_ASSERT((boost::is_same<pointer, T*>::value));
+ return static_cast<T*>(ptr);
+ }
+
static raw_type* getRawPtr(void* ptr)
{
BOOST_STATIC_ASSERT((boost::is_same<raw_type, T>::value));
_parents.push_back(parent);
}
+ bool isBaseOf(naGhostType* ghost_type) const
+ {
+ if( ghost_type == &_ghost_type )
+ return true;
+
+ for( DerivedList::const_iterator derived = _derived_classes.begin();
+ derived != _derived_classes.end();
+ ++derived )
+ {
+ if( (*derived)->isBaseOf(ghost_type) )
+ return true;
+ }
+
+ return false;
+ }
+
protected:
- const std::string _name;
- naGhostType _ghost_type;
- // std::vector<GhostMetadata*> _base_classes;
- std::vector<naRef> _parents;
+
+ typedef std::vector<const GhostMetadata*> DerivedList;
+
+ const std::string _name;
+ naGhostType _ghost_type;
+ DerivedList _derived_classes;
+ std::vector<naRef> _parents;
explicit GhostMetadata(const std::string& name):
_name(name)
}
- // void addBaseClass(GhostMetadata* base)
- // {
- // assert(base);
- // _base_classes.push_back(base);
- // }
+ void addDerived(const GhostMetadata* derived)
+ {
+ assert(derived);
+ _derived_classes.push_back(derived);
+
+ SG_LOG
+ (
+ SG_NASAL,
+ SG_INFO,
+ "Ghost::addDerived: " <<_ghost_type.name << " -> " << derived->_name
+ );
+ }
naRef getParents(naContext c)
{
};
}
+ /**
+ * Context passed to a function/method being called from Nasal
+ */
+ struct CallContext
+ {
+ CallContext(naContext c, int argc, naRef* args):
+ c(c),
+ argc(argc),
+ args(args)
+ {}
+
+ naContext c;
+ int argc;
+ naRef *args;
+ };
+
/**
* Class for exposing C++ objects to Nasal
*
RawPointerPolicy<T> >::type
{
public:
- typedef typename GhostTypeTraits<T>::raw_type raw_type;
- typedef naRef (raw_type::*member_func_t)(naContext, int, naRef*);
- typedef naRef (*free_func_t)(raw_type&, naContext, int, naRef*);
+ typedef T value_type;
+ typedef typename GhostTypeTraits<T>::raw_type raw_type;
+ typedef typename Ghost::pointer pointer;
+ typedef naRef (raw_type::*member_func_t)(const CallContext&);
+ typedef naRef (*free_func_t)(raw_type&, const CallContext&);
typedef boost::function<naRef(naContext, raw_type&)> getter_t;
typedef boost::function<void(naContext, raw_type&, naRef)> setter_t;
BaseGhost* base = BaseGhost::getSingletonPtr();
base->addDerived
(
+ this,
// Both ways of retrieving the address of a static member function
// should be legal but not all compilers know this.
// g++-4.4.7+ has been tested to work with both versions
return create(c);
}
+ static bool isBaseOf(naGhostType* ghost_type)
+ {
+ if( !ghost_type )
+ return false;
+
+ return getSingletonPtr()->GhostMetadata::isBaseOf(ghost_type);
+ }
+
+ static bool isBaseOf(naRef obj)
+ {
+ return isBaseOf( naGhost_type(obj) );
+ }
+
+ /**
+ * Convert Nasal object to C++ object. To get a valid object the passed
+ * 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)
+ {
+ // Check if it's a ghost and if it can be converted
+ if( isBaseOf( naGhost_type(me) ) )
+ return Ghost::getPtr( naGhost_ptr(me) );
+
+ // Now if it is derived from a ghost (hash with ghost in parent vector)
+ // TODO handle recursive parents
+ else if( naIsHash(me) )
+ {
+ naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
+ if( !naIsVector(na_parents) )
+ {
+ SG_LOG(SG_NASAL, SG_DEBUG, "Missing 'parents' vector for ghost");
+ return pointer();
+ }
+
+ typedef std::vector<naRef> naRefs;
+ naRefs parents = from_nasal<naRefs>(c, na_parents);
+ for( naRefs::const_iterator parent = parents.begin();
+ parent != parents.end();
+ ++parent )
+ {
+ if( isBaseOf(naGhost_type(*parent)) )
+ return Ghost::getPtr( naGhost_ptr(*parent) );
+ }
+ }
+
+ return pointer();
+ }
+
private:
template<class>
typedef naGhostType* (*type_checker_t)(const raw_type*);
typedef std::vector<type_checker_t> DerivedList;
- DerivedList _derived_classes;
+ DerivedList _derived_types;
- void addDerived(const type_checker_t& derived_info)
+ void addDerived( const internal::GhostMetadata* derived_meta,
+ const type_checker_t& derived_info )
{
- _derived_classes.push_back(derived_info);
+ GhostMetadata::addDerived(derived_meta);
+ _derived_types.push_back(derived_info);
}
template<class BaseGhost>
// Now check if we can further downcast to one of our derived classes.
for( typename DerivedList::reverse_iterator
- derived = getSingletonPtr()->_derived_classes.rbegin();
- derived != getSingletonPtr()->_derived_classes.rend();
+ derived = getSingletonPtr()->_derived_types.rbegin();
+ derived != getSingletonPtr()->_derived_types.rend();
++derived )
{
naGhostType* ghost_type =
return getSingletonHolder().get();
}
- // TODO integrate with from_nasal template to be able to cast objects
- // passed as function argument.
- static raw_type* from_nasal(naRef me)
- {
- if( naGhost_type(me) != &getSingletonPtr()->_ghost_type )
- return 0;
-
- return Ghost::getRawPtr( static_cast<T*>(naGhost_ptr(me)) );
- }
-
static raw_type& requireObject(naContext c, naRef me)
{
- raw_type* obj = Ghost::from_nasal(me);
+ raw_type* obj = Ghost::getRawPtr( fromNasal(c, me) );
+ naGhostType* ghost_type = naGhost_type(me);
+
if( !obj )
naRuntimeError
(
c,
- "method called on object of wrong type: '%s' expected",
+ "method called on object of wrong type: is '%s' expected '%s'",
+ ghost_type ? ghost_type->name : "unknown",
getSingletonPtr()->_ghost_type.name
);
*/
static naRef call(naContext c, naRef me, int argc, naRef* args)
{
- return (requireObject(c, me).*func)(c, argc, args);
+ return (requireObject(c, me).*func)(CallContext(c, argc, args));
}
};
*/
static naRef call(naContext c, naRef me, int argc, naRef* args)
{
- return func(requireObject(c, me), c, argc, args);
+ return func(requireObject(c, me), CallContext(c, argc, args));
}
};
struct Base
{
- naRef member(naContext, int, naRef*) { return naNil(); }
+ naRef member(const nasal::CallContext&) { return naNil(); }
virtual ~Base(){};
};
struct Derived:
};
-naRef member(Derived&, naContext, int, naRef*) { return naNil(); }
+typedef boost::shared_ptr<Base> BasePtr;
+typedef boost::shared_ptr<Derived> DerivedPtr;
+typedef boost::shared_ptr<DoubleDerived> DoubleDerivedPtr;
+typedef boost::shared_ptr<DoubleDerived2> DoubleDerived2Ptr;
+
+naRef member(Derived&, const nasal::CallContext&) { return naNil(); }
+naRef member(DerivedPtr&, const nasal::CallContext&) { return naNil(); }
int main(int argc, char* argv[])
{
r = to_nasal(c, hash);
VERIFY( naIsHash(r) );
+ VERIFY( hash.get<std::string>("name") == "my-name" );
+ VERIFY( naIsString(hash.get("name")) );
+
Hash mod = hash.createHash("mod");
mod.set("parent", hash);
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>();
+ .bases<BasePtr>()
+ .member("x", &Derived::getX, &Derived::setX)
+ .method_func<&member>("free_member");
Ghost<DoubleDerivedPtr>::init("DoubleDerivedPtr")
.bases<DerivedPtr>();
Ghost<DoubleDerived2Ptr>::init("DoubleDerived2Ptr")
VERIFY( naIsGhost(derived) );
VERIFY( std::string("DoubleDerived2Ptr") == naGhost_type(derived)->name );
- // TODO actuall do something with the ghosts...
+ VERIFY( Ghost<BasePtr>::isBaseOf(derived) );
+ VERIFY( Ghost<DerivedPtr>::isBaseOf(derived) );
+ VERIFY( Ghost<DoubleDerived2Ptr>::isBaseOf(derived) );
+
+ VERIFY( Ghost<BasePtr>::fromNasal(c, derived) == d3 );
+ VERIFY( Ghost<BasePtr>::fromNasal(c, derived) != d2 );
+ VERIFY( Ghost<DerivedPtr>::fromNasal(c, derived)
+ == boost::dynamic_pointer_cast<Derived>(d3) );
+ VERIFY( Ghost<DoubleDerived2Ptr>::fromNasal(c, derived)
+ == boost::dynamic_pointer_cast<DoubleDerived2>(d3) );
+ VERIFY( !Ghost<DoubleDerivedPtr>::fromNasal(c, derived) );
+
+ // Check converting to Ghost if using Nasal hashes with actual ghost inside
+ // the hashes parents vector
+ std::vector<naRef> parents;
+ parents.push_back(hash.get_naRef());
+ parents.push_back(derived);
+
+ Hash obj(c);
+ obj.set("parents", parents);
+ VERIFY( Ghost<BasePtr>::fromNasal(c, obj.get_naRef()) == d3 );
+
+ // TODO actually do something with the ghosts...
naFreeContext(c);
std::string _msg;
};
+ /**
+ * Simple pass through for unified handling also of naRef.
+ */
+ inline naRef from_nasal_helper(naContext, naRef ref, naRef*) { return ref; }
+
/**
* Convert Nasal string to std::string
*/
- std::string from_nasal(naContext c, naRef ref, std::string*);
+ std::string from_nasal_helper(naContext c, naRef ref, std::string*);
/**
* Convert a Nasal hash to a nasal::Hash
*/
- Hash from_nasal(naContext c, naRef ref, Hash*);
+ Hash from_nasal_helper(naContext c, naRef ref, Hash*);
/**
* Convert a Nasal number to a C++ numeric type
typename boost::enable_if< boost::is_arithmetic<T>,
T
>::type
- from_nasal(naContext c, naRef ref, T*)
+ from_nasal_helper(naContext c, naRef ref, T*)
{
naRef num = naNumValue(ref);
if( !naIsNum(num) )
/**
* Convert a Nasal vector to a std::vector
*/
- template<class Vector, class T>
- typename boost::enable_if< boost::is_same<Vector, std::vector<T> >,
+ template<class Vector>
+ typename boost::enable_if< boost::is_same
+ < Vector,
+ std::vector<typename Vector::value_type>
+ >,
Vector
>::type
- from_nasal(naContext c, naRef ref, Vector*)
+ from_nasal_helper(naContext c, naRef ref, Vector*)
{
if( !naIsVector(ref) )
throw bad_nasal_cast("Not a vector");
Vector vec(size);
for(int i = 0; i < size; ++i)
- vec[i] = from_nasal<T>(c, naVec_get(ref, i));
+ vec[i] = from_nasal_helper
+ (
+ c,
+ naVec_get(ref, i),
+ static_cast<typename Vector::value_type*>(0)
+ );
return vec;
}