From a8e96997cb3f576ccf6c289ef13c2e2912531912 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Thu, 29 May 2014 14:14:52 +0200 Subject: [PATCH] nasal::Hash: add iterators. --- simgear/nasal/cppbind/NasalHash.cxx | 66 +++++++++-- simgear/nasal/cppbind/NasalHash.hxx | 156 +++++++++++++++++++++++-- simgear/nasal/cppbind/cppbind_test.cxx | 9 ++ 3 files changed, 215 insertions(+), 16 deletions(-) diff --git a/simgear/nasal/cppbind/NasalHash.cxx b/simgear/nasal/cppbind/NasalHash.cxx index 7cd99468..71afefe0 100644 --- a/simgear/nasal/cppbind/NasalHash.cxx +++ b/simgear/nasal/cppbind/NasalHash.cxx @@ -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 Hash::keys() const { - naRef keys = naNewVector(_context); - naHash_keys(keys, _hash); - return from_nasal >(_context, keys); + return from_nasal >(_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 diff --git a/simgear/nasal/cppbind/NasalHash.hxx b/simgear/nasal/cppbind/NasalHash.hxx index e330428e..aaf673dd 100644 --- a/simgear/nasal/cppbind/NasalHash.hxx +++ b/simgear/nasal/cppbind/NasalHash.hxx @@ -23,6 +23,7 @@ #include "to_nasal.hxx" #include +#include namespace nasal { @@ -34,12 +35,20 @@ namespace nasal { public: + template class Entry; + template class Iterator; + + typedef Entry reference; + typedef Entry const_reference; + typedef Iterator iterator; + typedef Iterator 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 - T get(const std::string& name) + template + T get(const Key& name) const { + BOOST_STATIC_ASSERT(( boost::is_convertible::value + || boost::is_convertible::value + )); + return from_nasal(_context, get(name)); } @@ -93,16 +118,26 @@ namespace nasal * * @tparam Sig Function signature * @param name Member name + * @param key Member key */ - template + template typename boost::enable_if< boost::is_function, boost::function >::type - get(const std::string& name) + get(const Key& name) const { + BOOST_STATIC_ASSERT(( boost::is_convertible::value + || boost::is_convertible::value + )); + return from_nasal_helper(_context, get(name), static_cast(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 + 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(_hash->_context, _key); + } + + template + T getValue() const + { + if( !_hash || naIsNil(_key) ) + return T(); + + return _hash->get(_key); + } + + private: + HashPtr _hash; + naRef _key; + + }; + + /// Hash iterator + template + class Iterator: + public boost::iterator_facade< + Iterator, + Entry, + boost::bidirectional_traversal_tag, + Entry + > + { + public: + typedef typename Entry::HashPtr HashPtr; + typedef Entry 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 + Iterator( Iterator 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 friend class Iterator; + + HashPtr _hash; + int _index; + + template + bool equal(Iterator 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* ) { - nasal::Hash hash = from_nasal_helper(c, ref, static_cast(0)); std::vector const& keys = hash.keys(); diff --git a/simgear/nasal/cppbind/cppbind_test.cxx b/simgear/nasal/cppbind/cppbind_test.cxx index 2af6877b..03ef4d83 100644 --- a/simgear/nasal/cppbind/cppbind_test.cxx +++ b/simgear/nasal/cppbind/cppbind_test.cxx @@ -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(it->getKey()) == it->getValue() ) + + Hash::iterator it1, it2; + Hash::const_iterator it3 = it1, it4(it2); + it1 = it2; + it3 = it2; + r = to_nasal(c, hash); VERIFY( naIsHash(r) ); -- 2.39.5