summaryrefslogtreecommitdiff
path: root/src/mongo/bson
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2015-02-13 15:55:47 -0500
committerMathias Stearn <mathias@10gen.com>2015-03-27 14:32:37 -0400
commitcfce87ebbb36f2acf63eb5a29f6aec95a55e3866 (patch)
tree1af4e2f8311205526f838b9ebaffc448dcb2ad06 /src/mongo/bson
parentcafa5d7815509e5ce4fa65f4def89cf18e087bcf (diff)
downloadmongo-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.cpp21
-rw-r--r--src/mongo/bson/bsonobj.cpp4
-rw-r--r--src/mongo/bson/bsonobj.h84
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))
}