]> git.mxchange.org Git - simgear.git/commitdiff
nasal::Hash: add iterators.
authorThomas Geymayer <tomgey@gmail.com>
Thu, 29 May 2014 12:14:52 +0000 (14:14 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Thu, 29 May 2014 12:14:52 +0000 (14:14 +0200)
simgear/nasal/cppbind/NasalHash.cxx
simgear/nasal/cppbind/NasalHash.hxx
simgear/nasal/cppbind/cppbind_test.cxx

index 7cd99468ca283fcf94f8f95e68de5484bdb564a4..71afefe0301ff0a305456abd6743953ce14fb5c1 100644 (file)
@@ -26,8 +26,9 @@ namespace nasal
 
   //----------------------------------------------------------------------------
   Hash::Hash(naContext c):
-    _hash( naNewHash(c) ),
-    _context(c)
+    _hash(naNewHash(c)),
+    _context(c),
+    _keys(naNil())
   {
 
   }
@@ -35,31 +36,66 @@ namespace nasal
   //----------------------------------------------------------------------------
   Hash::Hash(naRef hash, naContext c):
     _hash(hash),
-    _context(c)
+    _context(c),
+    _keys(naNil())
   {
     assert( naIsHash(_hash) );
   }
 
+  //----------------------------------------------------------------------------
+  Hash::iterator Hash::begin()
+  {
+    return iterator(this, 0);
+  }
+
+  //----------------------------------------------------------------------------
+  Hash::iterator Hash::end()
+  {
+    return iterator(this, size());
+  }
+
+  //----------------------------------------------------------------------------
+  Hash::const_iterator Hash::begin() const
+  {
+    return const_iterator(this, 0);
+  }
+
+  //----------------------------------------------------------------------------
+  Hash::const_iterator Hash::end() const
+  {
+    return const_iterator(this, size());
+  }
+
   //----------------------------------------------------------------------------
   void Hash::set(const std::string& name, naRef ref)
   {
     naHash_set(_hash, to_nasal(_context, name), ref);
+    _keys = naNil();
   }
 
   //----------------------------------------------------------------------------
-  naRef Hash::get(const std::string& name)
+  naRef Hash::get(naRef key) const
   {
     naRef result;
-    return naHash_get(_hash, to_nasal(_context, name), &result) ? result
-                                                                : naNil();
+    return naHash_get(_hash, key, &result) ? result : naNil();
+  }
+
+  //----------------------------------------------------------------------------
+  naRef Hash::get(const std::string& name) const
+  {
+    return get( to_nasal(_context, name) );
+  }
+
+  //----------------------------------------------------------------------------
+  int Hash::size() const
+  {
+    return naVec_size(get_naRefKeys());
   }
 
   //----------------------------------------------------------------------------
   std::vector<std::string> Hash::keys() const
   {
-    naRef keys = naNewVector(_context);
-    naHash_keys(keys, _hash);
-    return from_nasal<std::vector<std::string> >(_context, keys);
+    return from_nasal<std::vector<std::string> >(_context, get_naRefKeys());
   }
 
   //----------------------------------------------------------------------------
@@ -82,4 +118,16 @@ namespace nasal
     return _hash;
   }
 
+  //----------------------------------------------------------------------------
+  naRef Hash::get_naRefKeys() const
+  {
+    if( naIsNil(_keys) && naIsHash(_hash) )
+    {
+      _keys = naNewVector(_context);
+      naHash_keys(_keys, _hash);
+    }
+
+    return _keys;
+  }
+
 } // namespace nasal
index e330428eb96fbcd7449014985821d8874719d8f8..aaf673dd2b7b219db4c3bc463398fac856a5aef3 100644 (file)
@@ -23,6 +23,7 @@
 #include "to_nasal.hxx"
 
 #include <simgear/structure/map.hxx>
+#include <boost/iterator/iterator_facade.hpp>
 
 namespace nasal
 {
@@ -34,12 +35,20 @@ namespace nasal
   {
     public:
 
+      template<bool> class Entry;
+      template<bool> class Iterator;
+
+      typedef Entry<false>      reference;
+      typedef Entry<true>       const_reference;
+      typedef Iterator<false>   iterator;
+      typedef Iterator<true>    const_iterator;
+
       /**
        * Create a new Nasal Hash
        *
        * @param c   Nasal context for creating the hash
        */
-      Hash(naContext c);
+      explicit Hash(naContext c);
 
       /**
        * Initialize from an existing Nasal Hash
@@ -49,6 +58,11 @@ namespace nasal
        */
       Hash(naRef hash, naContext c);
 
+      iterator begin();
+      iterator end();
+      const_iterator begin() const;
+      const_iterator end() const;
+
       /**
        * Set member
        *
@@ -69,12 +83,19 @@ namespace nasal
         set(name, to_nasal(_context, val));
       }
 
+      /**
+       * Get member
+       *
+       * @param key    Member key
+       */
+      naRef get(naRef key) const;
+
       /**
        * Get member
        *
        * @param name    Member name
        */
-      naRef get(const std::string& name);
+      naRef get(const std::string& name) const;
 
       /**
        * Get member converted to given type
@@ -82,9 +103,13 @@ namespace nasal
        * @tparam T      Type to convert to (using from_nasal)
        * @param name    Member name
        */
-      template<class T>
-      T get(const std::string& name)
+      template<class T, class Key>
+      T get(const Key& name) const
       {
+        BOOST_STATIC_ASSERT(( boost::is_convertible<Key, naRef>::value
+                           || boost::is_convertible<Key, std::string>::value
+                           ));
+
         return from_nasal<T>(_context, get(name));
       }
 
@@ -93,16 +118,26 @@ namespace nasal
        *
        * @tparam Sig    Function signature
        * @param name    Member name
+       * @param key     Member key
        */
-      template<class Sig>
+      template<class Sig, class Key>
       typename boost::enable_if< boost::is_function<Sig>,
                                  boost::function<Sig>
                                >::type
-      get(const std::string& name)
+      get(const Key& name) const
       {
+        BOOST_STATIC_ASSERT(( boost::is_convertible<Key, naRef>::value
+                           || boost::is_convertible<Key, std::string>::value
+                           ));
+
         return from_nasal_helper(_context, get(name), static_cast<Sig*>(0));
       }
 
+      /**
+       * Returns the number of entries in the hash
+       */
+      int size() const;
+
       /**
        * Get a list of all keys
        */
@@ -127,11 +162,119 @@ namespace nasal
        */
       naRef get_naRef() const;
 
+      /**
+       * Get Nasal vector of keys
+       */
+      naRef get_naRefKeys() const;
+
+      /// Hash entry
+      template<bool is_const>
+      class Entry
+      {
+        public:
+          typedef typename boost::mpl::if_c<
+            is_const,
+            Hash const*,
+            Hash*
+          >::type HashPtr;
+
+          Entry(HashPtr hash, naRef key):
+            _hash(hash),
+            _key(key)
+          {
+            assert(hash);
+            assert(!naIsNil(key));
+          }
+
+          std::string getKey() const
+          {
+            if( !_hash || naIsNil(_key) )
+              return std::string();
+
+            return from_nasal<std::string>(_hash->_context, _key);
+          }
+
+          template<class T>
+          T getValue() const
+          {
+            if( !_hash || naIsNil(_key) )
+              return T();
+
+            return _hash->get<T>(_key);
+          }
+
+        private:
+          HashPtr _hash;
+          naRef _key;
+
+      };
+
+      /// Hash iterator
+      template<bool is_const>
+      class Iterator:
+        public boost::iterator_facade<
+          Iterator<is_const>,
+          Entry<is_const>,
+          boost::bidirectional_traversal_tag,
+          Entry<is_const>
+        >
+      {
+        public:
+          typedef typename Entry<is_const>::HashPtr HashPtr;
+          typedef Entry<is_const>                   value_type;
+
+          Iterator():
+            _hash(NULL),
+            _index(0)
+          {}
+
+          Iterator(HashPtr hash, int index):
+            _hash(hash),
+            _index(index)
+          {}
+
+          /**
+           * Convert from iterator to const_iterator or copy within same type
+           */
+          template<bool is_other_const>
+          Iterator( Iterator<is_other_const> const& other,
+                    typename boost::enable_if_c< is_const || !is_other_const,
+                                                 void*
+                                               >::type = NULL ):
+            _hash(other._hash),
+            _index(other._index)
+          {}
+
+        private:
+          friend class boost::iterator_core_access;
+          template <bool> friend class Iterator;
+
+          HashPtr _hash;
+          int _index;
+
+          template<bool is_other_const>
+          bool equal(Iterator<is_other_const> const& other) const
+          {
+            return _hash == other._hash
+                && _index == other._index;
+          }
+
+          void increment() { ++_index; }
+          void decrement() { --_index; }
+
+          value_type dereference() const
+          {
+            return value_type(_hash, naVec_get(_hash->get_naRefKeys(), _index));
+          }
+      };
+
     protected:
 
       naRef _hash;
       naContext _context;
 
+      mutable naRef _keys; //< Store vector of keys (for iterators)
+
   };
 
 } // namespace nasal
@@ -142,7 +285,6 @@ from_nasal_helper( naContext c,
                    naRef ref,
                    const simgear::Map<std::string, Value>* )
 {
-
   nasal::Hash hash = from_nasal_helper(c, ref, static_cast<nasal::Hash*>(0));
   std::vector<std::string> const& keys = hash.keys();
 
index 2af6877bca58a601a4e32a02a340af6ee2a9dc6e..03ef4d830a3b9656263627c62c2f810d3848cd5c 100644 (file)
@@ -175,6 +175,15 @@ int main(int argc, char* argv[])
   hash.set("string", std::string("blub"));
   hash.set("func", &f_freeFunction);
 
+  VERIFY( hash.size() == 5 )
+  for(Hash::const_iterator it = hash.begin(); it != hash.end(); ++it)
+    VERIFY( hash.get<std::string>(it->getKey()) == it->getValue<std::string>() )
+
+  Hash::iterator it1, it2;
+  Hash::const_iterator it3 = it1, it4(it2);
+  it1 = it2;
+  it3 = it2;
+
   r = to_nasal(c, hash);
   VERIFY( naIsHash(r) );