X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fnasal%2Fcppbind%2FGhost.hxx;h=d2a5d22c9906b80610750537961cb6f4720706ad;hb=46442ef50c5a2b7c8e41e5c025f86c1cd35e6e15;hp=288c5113e5b3aff5b61dbd75b04693d9aaeb94fd;hpb=9f31addfa5d7dc97a886c432c3a435f0c8356563;p=simgear.git diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index 288c5113..d2a5d22c 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -83,8 +84,9 @@ namespace nasal template struct SharedPointerPolicy { - typedef typename GhostTypeTraits::raw_type raw_type; - typedef boost::false_type returns_dynamic_type; + typedef typename GhostTypeTraits::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 @@ -95,9 +97,25 @@ namespace nasal return new T(ptr); } + static pointer getPtr(void* ptr) + { + if( ptr ) + return *static_cast(ptr); + else + return pointer(); + } + static raw_type* getRawPtr(void* ptr) { - return static_cast(ptr)->get(); + if( ptr ) + return static_cast(ptr)->get(); + else + return 0; + } + + static raw_type* getRawPtr(const T& ptr) + { + return ptr.get(); } }; @@ -107,8 +125,9 @@ namespace nasal template struct RawPointerPolicy { - typedef typename GhostTypeTraits::raw_type raw_type; - typedef boost::true_type returns_dynamic_type; + typedef typename GhostTypeTraits::raw_type raw_type; + typedef raw_type* pointer; + typedef boost::true_type returns_dynamic_type; /** * Create a new object instance on the heap @@ -118,6 +137,12 @@ namespace nasal return new T(); } + static pointer getPtr(void* ptr) + { + BOOST_STATIC_ASSERT((boost::is_same::value)); + return static_cast(ptr); + } + static raw_type* getRawPtr(void* ptr) { BOOST_STATIC_ASSERT((boost::is_same::value)); @@ -143,11 +168,30 @@ namespace nasal _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 _base_classes; - std::vector _parents; + + typedef std::vector DerivedList; + + const std::string _name; + naGhostType _ghost_type; + DerivedList _derived_classes; + std::vector _parents; explicit GhostMetadata(const std::string& name): _name(name) @@ -155,11 +199,18 @@ namespace nasal } - // 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) { @@ -168,6 +219,52 @@ namespace nasal }; } + /** + * Context passed to a function/method being called from Nasal + */ + struct CallContext + { + CallContext(naContext c, size_t argc, naRef* args): + c(c), + argc(argc), + args(args) + {} + + /** + * Get the argument with given index if it exists. Otherwise returns the + * passed default value. + * + * @tparam T Type of argument (converted using ::from_nasal) + * @param index Index of requested argument + * @param def Default value returned if too few arguments available + */ + template + T getArg(size_t index, const T& def = T()) const + { + if( index >= argc ) + return def; + + return from_nasal(c, args[index]); + } + + /** + * Get the argument with given index. Raises a Nasal runtime error if there + * are to few arguments available. + */ + template + T requireArg(size_t index) const + { + if( index >= argc ) + naRuntimeError(c, "Missing required arg #%d", index); + + return from_nasal(c, args[index]); + } + + naContext c; + size_t argc; + naRef *args; + }; + /** * Class for exposing C++ objects to Nasal * @@ -207,9 +304,11 @@ namespace nasal RawPointerPolicy >::type { public: - typedef typename GhostTypeTraits::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::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 getter_t; typedef boost::function setter_t; @@ -281,6 +380,7 @@ namespace nasal 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 @@ -358,12 +458,13 @@ namespace nasal template Ghost& member( const std::string& field, Var (raw_type::*getter)() const, - void (raw_type::*setter)(Var) = 0 ) + void (raw_type::*setter)(typename boost::call_traits::param_type) = 0 ) { member_t m; if( getter ) { - naRef (*to_nasal_)(naContext, Var) = &nasal::to_nasal; + typedef typename boost::call_traits::param_type param_type; + naRef (*to_nasal_)(naContext, param_type) = &nasal::to_nasal; // Getter signature: naRef(naContext, raw_type&) m.getter = boost::bind(to_nasal_, _1, boost::bind(getter, _2)); @@ -504,6 +605,55 @@ namespace nasal 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) + else if( naIsHash(me) ) + { + naRef na_parents = naHash_cget(me, const_cast("parents")); + if( !naIsVector(na_parents) ) + { + SG_LOG(SG_NASAL, SG_DEBUG, "Missing 'parents' vector for ghost"); + return pointer(); + } + + typedef std::vector naRefs; + naRefs parents = from_nasal(c, na_parents); + for( naRefs::const_iterator parent = parents.begin(); + parent != parents.end(); + ++parent ) + { + pointer ptr = fromNasal(c, *parent); + if( ptr ) + return ptr; + } + } + + return pointer(); + } + private: template @@ -511,11 +661,13 @@ namespace nasal typedef naGhostType* (*type_checker_t)(const raw_type*); typedef std::vector 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 @@ -537,8 +689,8 @@ namespace nasal // 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 = @@ -570,24 +722,17 @@ namespace nasal 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(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 ); @@ -609,7 +754,7 @@ namespace nasal */ 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)); } }; @@ -631,7 +776,7 @@ namespace nasal */ 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)); } }; @@ -655,6 +800,9 @@ namespace nasal static naRef makeGhost(naContext c, void *ptr) { + if( !Ghost::getRawPtr(ptr) ) + return naNil(); + naGhostType* ghost_type = 0; if( Ghost::returns_dynamic_type::value ) // For pointer policies already returning instances of an object with