X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fnasal%2Fcppbind%2FGhost.hxx;h=d2a5d22c9906b80610750537961cb6f4720706ad;hb=46442ef50c5a2b7c8e41e5c025f86c1cd35e6e15;hp=c679f6440c69a244f532dbce68e4450c3675ff64;hpb=392ba18ff7295f2622ae3a052049c76e9d760e26;p=simgear.git diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index c679f644..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,11 +304,13 @@ 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 boost::function getter_t; - typedef boost::function setter_t; + 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; /** * A ghost member. Can consist either of getter and/or setter functions @@ -279,7 +378,21 @@ namespace nasal bases() { BaseGhost* base = BaseGhost::getSingletonPtr(); - base->addDerived( &getTypeFor ); + 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 +#if defined(GCC_VERSION) && GCC_VERSION < 40407 + // The old version of g++ used on Jenkins (16.11.2012) only compiles + // this version. + &getTypeFor +#else + // VS (2008, 2010, ... ?) only allow this version. + &Ghost::getTypeFor +#endif + ); // Replace any getter that is not available in the current class. // TODO check if this is the correct behavior of function overriding @@ -345,14 +458,15 @@ 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*) + // Getter signature: naRef(naContext, raw_type&) m.getter = boost::bind(to_nasal_, _1, boost::bind(getter, _2)); } @@ -360,7 +474,7 @@ namespace nasal { Var (*from_nasal_)(naContext, naRef) = &nasal::from_nasal; - // Setter signature: void(naContext, raw_type*, naRef) + // Setter signature: void(naContext, raw_type&, naRef) m.setter = boost::bind(setter, _2, boost::bind(from_nasal_, _1, _3)); } @@ -491,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 @@ -498,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 @@ -517,19 +682,19 @@ namespace nasal // this ghost wraps. if( !boost::is_same < typename BaseGhost::raw_type, - Ghost::raw_type + typename Ghost::raw_type >::value - && dynamic_cast(base) != base ) + && dynamic_cast(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 = getSingletonPtr()->_derived_types.rbegin(); + derived != getSingletonPtr()->_derived_types.rend(); ++derived ) { - ghost_type = (*derived)( static_cast(base) ); + naGhostType* ghost_type = + (*derived)( static_cast(base) ); if( ghost_type ) return ghost_type; } @@ -557,28 +722,21 @@ 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) + static raw_type& requireObject(naContext c, naRef me) { - if( naGhost_type(me) != &getSingletonPtr()->_ghost_type ) - return 0; - - return Ghost::getRawPtr( static_cast(naGhost_ptr(me)) ); - } + raw_type* obj = Ghost::getRawPtr( fromNasal(c, me) ); + naGhostType* ghost_type = naGhost_type(me); - static raw_type* requireObject(naContext c, naRef me) - { - raw_type* obj = Ghost::from_nasal(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 ); - return obj; + return *obj; } /** @@ -596,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)); } }; @@ -618,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)); } }; @@ -642,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 @@ -690,7 +851,7 @@ namespace nasal if( member->second.func ) *out = nasal::to_nasal(c, member->second.func); else if( !member->second.getter.empty() ) - *out = member->second.getter(c, Ghost::getRawPtr(g)); + *out = member->second.getter(c, *Ghost::getRawPtr(g)); else return "Read-protected member"; @@ -711,7 +872,7 @@ namespace nasal if( member->second.setter.empty() ) naRuntimeError(c, "ghost: Write protected member: %s", key.c_str()); - member->second.setter(c, Ghost::getRawPtr(g), val); + member->second.setter(c, *Ghost::getRawPtr(g), val); } };