diff options
author | Mathias Stearn <mathias@10gen.com> | 2015-02-13 15:55:47 -0500 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2015-03-27 14:32:37 -0400 |
commit | cfce87ebbb36f2acf63eb5a29f6aec95a55e3866 (patch) | |
tree | 1af4e2f8311205526f838b9ebaffc448dcb2ad06 /src/mongo/bson | |
parent | cafa5d7815509e5ce4fa65f4def89cf18e087bcf (diff) | |
download | mongo-cfce87ebbb36f2acf63eb5a29f6aec95a55e3866.tar.gz |
Support C++11 range-based for loops over BSONObj
Diffstat (limited to 'src/mongo/bson')
-rw-r--r-- | src/mongo/bson/bson_obj_test.cpp | 21 | ||||
-rw-r--r-- | src/mongo/bson/bsonobj.cpp | 4 | ||||
-rw-r--r-- | src/mongo/bson/bsonobj.h | 84 |
3 files changed, 70 insertions, 39 deletions
diff --git a/src/mongo/bson/bson_obj_test.cpp b/src/mongo/bson/bson_obj_test.cpp index 443700f037d..6befb751760 100644 --- a/src/mongo/bson/bson_obj_test.cpp +++ b/src/mongo/bson/bson_obj_test.cpp @@ -31,6 +31,7 @@ #include "mongo/unittest/unittest.h" namespace { + using namespace mongo; TEST(BSONObjToString, EmptyArray) { const char text[] = "{ x: [] }"; @@ -182,4 +183,24 @@ namespace { } } + TEST(Looping, Cpp11Basic) { + int count = 0; + for (BSONElement e : BSON("a" << 1 << "a" << 2 << "a" << 3)) { + ASSERT_EQUALS( e.fieldNameStringData() , "a" ); + count += e.Int(); + } + + ASSERT_EQUALS( count , 1 + 2 + 3 ); + } + + TEST(Looping, Cpp11Auto) { + int count = 0; + for (auto e : BSON("a" << 1 << "a" << 2 << "a" << 3)) { + ASSERT_EQUALS( e.fieldNameStringData() , "a" ); + count += e.Int(); + } + + ASSERT_EQUALS( count , 1 + 2 + 3 ); + } + } // unnamed namespace diff --git a/src/mongo/bson/bsonobj.cpp b/src/mongo/bson/bsonobj.cpp index b9e76532fe0..59f5c077897 100644 --- a/src/mongo/bson/bsonobj.cpp +++ b/src/mongo/bson/bsonobj.cpp @@ -86,10 +86,6 @@ namespace mongo { return copy(); } - BSONObjIterator BSONObj::begin() const { - return BSONObjIterator(*this); - } - string BSONObj::jsonString( JsonStringFormat format, int pretty, bool isArray ) const { if ( isEmpty() ) return isArray ? "[]" : "{}"; diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h index 3a5d8a086a0..d138658edb6 100644 --- a/src/mongo/bson/bsonobj.h +++ b/src/mongo/bson/bsonobj.h @@ -29,7 +29,6 @@ #pragma once -#include <boost/preprocessor/cat.hpp> // like the ## operator but works with __LINE__ #include <boost/scoped_array.hpp> #include <list> #include <set> @@ -510,13 +509,15 @@ namespace mongo { friend class BSONObjIterator; typedef BSONObjIterator iterator; - /** use something like this: - for( BSONObj::iterator i = myObj.begin(); i.more(); ) { - BSONElement e = i.next(); - ... - } - */ + /** + * These enable range-based for loops over BSONObjs: + * + * for (BSONElement elem : BSON("a" << 1 << "b" << 2)) { + * ... // Do something with elem + * } + */ BSONObjIterator begin() const; + BSONObjIterator end() const; void appendSelfToBufBuilder(BufBuilder& b) const { verify( objsize() ); @@ -595,14 +596,16 @@ namespace mongo { The BSONObj must stay in scope for the duration of the iterator's execution. - todo: we may want to make a more stl-like iterator interface for this - with things like begin() and end() + todo: Finish making this an STL-compatible iterator. + Need iterator_catagory et al (maybe inherit from std::iterator). + Need operator-> + operator* should return a const reference not a value. */ class BSONObjIterator { public: /** Create an iterator for a BSON object. */ - BSONObjIterator(const BSONObj& jso) { + explicit BSONObjIterator(const BSONObj& jso) { int sz = jso.objsize(); if ( MONGO_unlikely(sz == 0) ) { _pos = _theend = 0; @@ -617,6 +620,12 @@ namespace mongo { _theend = end - 1; } + static BSONObjIterator endOf(const BSONObj& obj) { + BSONObjIterator end(obj); + end._pos = end._theend; + return end; + } + /** @return true if more elements exist to be enumerated. */ bool more() { return _pos < _theend; } @@ -640,20 +649,41 @@ namespace mongo { return e; } + BSONElement next() { verify( _pos <= _theend ); BSONElement e(_pos); _pos += e.size(); return e; } - void operator++() { next(); } - void operator++(int) { next(); } + + /** pre-increment */ + BSONObjIterator& operator++() { + next(); + return *this; + } + + /** post-increment */ + BSONObjIterator operator++(int) { + BSONObjIterator oldPos = *this; + next(); + return oldPos; + } BSONElement operator*() { verify( _pos <= _theend ); return BSONElement(_pos); } + bool operator==(const BSONObjIterator& other) { + dassert(_theend == other._theend); + return _pos == other._pos; + } + + bool operator!=(const BSONObjIterator& other) { + return !(*this == other); + } + private: const char* _pos; const char* _theend; @@ -704,30 +734,14 @@ namespace mongo { BSONArrayIteratorSorted( const BSONArray &array ); }; - /** Similar to BOOST_FOREACH - * - * because the iterator is defined outside of the for, you must use {} around - * the surrounding scope. Don't do this: - * - * if (foo) - * BSONForEach(e, obj) - * doSomething(e); - * - * but this is OK: - * - * if (foo) { - * BSONForEach(e, obj) - * doSomething(e); - * } + inline BSONObjIterator BSONObj::begin() const { return BSONObjIterator(*this); } + inline BSONObjIterator BSONObj::end() const { return BSONObjIterator::endOf(*this); } + + /** + * Similar to BOOST_FOREACH * + * DEPRECATED: Use range-based for loops now. */ - -#define BSONForEach(e, obj) \ - BSONObjIterator BOOST_PP_CAT(it_,__LINE__)(obj); \ - for ( BSONElement e; \ - (BOOST_PP_CAT(it_,__LINE__).more() ? \ - (e = BOOST_PP_CAT(it_,__LINE__).next(), true) : \ - false) ; \ - /*nothing*/ ) +#define BSONForEach(elemName, obj) for (BSONElement elemName : (obj)) } |