]> git.mxchange.org Git - simgear.git/commitdiff
cppbind: Automatic conversion of derived ghosts and some cleanup/fixes
authorThomas Geymayer <tomgey@gmail.com>
Tue, 27 Nov 2012 12:01:46 +0000 (13:01 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Tue, 27 Nov 2012 12:02:36 +0000 (13:02 +0100)
simgear/nasal/cppbind/Ghost.hxx
simgear/nasal/cppbind/NasalHash.cxx
simgear/nasal/cppbind/NasalHash.hxx
simgear/nasal/cppbind/cppbind_test.cxx
simgear/nasal/cppbind/from_nasal.cxx
simgear/nasal/cppbind/from_nasal.hxx
simgear/nasal/cppbind/from_nasal_detail.hxx

index 759b25ed9be4d2aa8ecc26f7995e463001639710..6fce4cbc74b1171172893f259f57887ded536a2c 100644 (file)
@@ -83,8 +83,9 @@ namespace nasal
   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
@@ -95,9 +96,25 @@ namespace nasal
       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();
     }
   };
 
@@ -107,8 +124,9 @@ namespace nasal
   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
@@ -118,6 +136,12 @@ namespace nasal
       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));
@@ -143,11 +167,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<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)
@@ -155,11 +198,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 +218,22 @@ namespace nasal
     };
   }
 
+  /**
+   * 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
    *
@@ -207,9 +273,11 @@ namespace 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;
 
@@ -281,6 +349,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
@@ -504,6 +573,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)
+        // 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>
@@ -511,11 +629,13 @@ namespace nasal
 
       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>
@@ -537,8 +657,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 +690,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<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
           );
 
@@ -609,7 +722,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 +744,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));
         }
       };
 
index 1595c266123ae88e6e21f06ce4a471cffc929f72..20fb2ec5c8909e762141eb7d26d3e0cd82ea4086 100644 (file)
@@ -33,7 +33,7 @@ namespace nasal
   }
 
   //----------------------------------------------------------------------------
-  Hash::Hash(const naRef& hash, naContext c):
+  Hash::Hash(naRef hash, naContext c):
     _hash(hash),
     _context(c)
   {
@@ -46,6 +46,14 @@ namespace nasal
     naHash_set(_hash, to_nasal(_context, name), ref);
   }
 
+  //----------------------------------------------------------------------------
+  naRef Hash::get(const std::string& name)
+  {
+    naRef result;
+    return naHash_get(_hash, to_nasal(_context, name), &result) ? result
+                                                                : naNil();
+  }
+
   //----------------------------------------------------------------------------
   Hash Hash::createHash(const std::string& name)
   {
index 0e48a9dd335523a326f4d6926d754c52388b5c25..4cc15642acd3fde349279b6d7cb09fa2c5b24dfe 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef SG_NASAL_HASH_HXX_
 #define SG_NASAL_HASH_HXX_
 
+#include "from_nasal.hxx"
 #include "to_nasal.hxx"
 
 namespace nasal
@@ -44,7 +45,7 @@ namespace nasal
        * @param hash  Existing Nasal Hash
        * @param c     Nasal context for creating new Nasal objects
        */
-      Hash(const naRef& hash, naContext c);
+      Hash(naRef hash, naContext c);
 
       /**
        * Set member
@@ -66,6 +67,25 @@ namespace nasal
         set(name, to_nasal(_context, val));
       }
 
+      /**
+       * Get member
+       *
+       * @param name    Member name
+       */
+      naRef get(const std::string& name);
+
+      /**
+       * Get member converted to given type
+       *
+       * @tparam T      Type to convert to (using from_nasal)
+       * @param name    Member name
+       */
+      template<class T>
+      T get(const std::string& name)
+      {
+        return from_nasal<T>(_context, get(name));
+      }
+
       /**
        * Create a new child hash (module)
        *
index 30d4a338611199752428940e55a65089055aedfb..4a2802ac660ca8e66d0bbbffa2ee514ae8f8d0d2 100644 (file)
@@ -15,7 +15,7 @@
 
 struct Base
 {
-  naRef member(naContext, int, naRef*) { return naNil(); }
+  naRef member(const nasal::CallContext&) { return naNil(); }
   virtual ~Base(){};
 };
 struct Derived:
@@ -36,7 +36,13 @@ struct DoubleDerived2:
 
 };
 
-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[])
 {
@@ -84,6 +90,9 @@ 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);
 
@@ -98,14 +107,11 @@ int main(int argc, char* argv[])
   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")
@@ -126,7 +132,29 @@ int main(int argc, char* argv[])
   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);
 
index 03c4dc2e6fb234a60aa2819ab760000ff482dd82..0cede8c1a98dc5e30e0ad06435d051066e822027 100644 (file)
@@ -47,14 +47,14 @@ namespace nasal
   }
 
   //----------------------------------------------------------------------------
-  std::string from_nasal(naContext c, naRef ref, std::string*)
+  std::string from_nasal_helper(naContext c, naRef ref, std::string*)
   {
     naRef na_str = naStringValue(c, ref);
     return std::string(naStr_data(na_str), naStr_len(na_str));
   }
 
   //----------------------------------------------------------------------------
-  Hash from_nasal(naContext c, naRef ref, Hash*)
+  Hash from_nasal_helper(naContext c, naRef ref, Hash*)
   {
     if( !naIsHash(ref) )
       throw bad_nasal_cast("Not a hash");
index d36d5826992e2ffdffd1ff12bccda24bfb47b20b..37b636594278dfb11e708dc212a91ceb94a90b44 100644 (file)
@@ -37,12 +37,12 @@ namespace nasal
    * @note  Every type which should be supported needs a function with the
    *        following signature declared:
    *
-   *        Type from_nasal(naContext, naRef, Type*)
+   *        Type from_nasal_helper(naContext, naRef, Type*)
    */
   template<class T>
   T from_nasal(naContext c, naRef ref)
   {
-    return from_nasal(c, ref, static_cast<T*>(0));
+    return from_nasal_helper(c, ref, static_cast<T*>(0));
   }
 
 } // namespace nasal
index 2a053e4d59df1d9ab489baa49934e340d8be44d2..48a8879ee9f7fcac814dec5d5dfafcd045482192 100644 (file)
@@ -63,15 +63,20 @@ namespace nasal
       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
@@ -80,7 +85,7 @@ namespace nasal
   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) )
@@ -92,11 +97,14 @@ namespace nasal
   /**
    * 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");
@@ -105,7 +113,12 @@ namespace nasal
     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;
   }