summaryrefslogtreecommitdiff
path: root/src/mongo/bson
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2017-12-19 13:23:11 -0500
committerMathias Stearn <mathias@10gen.com>2018-07-23 16:56:06 -0400
commite64cf49efa5410aafdbf1a837070563abcf41fb2 (patch)
tree284efc541391aab2982d5dcda1f6094689e2afb6 /src/mongo/bson
parentdeb1161a6c3feb0497c9af4c7b72b01c6d4bdb97 (diff)
downloadmongo-e64cf49efa5410aafdbf1a837070563abcf41fb2.tar.gz
SERVER-32302 Introduce BSONObjStlIterator as a proper stl-style iterator
(cherry picked from commit 1497899f237dd60ad7313913c38c3f07fe168f2b)
Diffstat (limited to 'src/mongo/bson')
-rw-r--r--src/mongo/bson/bsonelement.h1
-rw-r--r--src/mongo/bson/bsonobj.h119
-rw-r--r--src/mongo/bson/mutable/mutable_bson_test.cpp2
-rw-r--r--src/mongo/bson/util/bson_check.h3
4 files changed, 97 insertions, 28 deletions
diff --git a/src/mongo/bson/bsonelement.h b/src/mongo/bson/bsonelement.h
index 0c84387f2ad..7c427f38004 100644
--- a/src/mongo/bson/bsonelement.h
+++ b/src/mongo/bson/bsonelement.h
@@ -702,6 +702,7 @@ private:
mutable int totalSize; /* caches the computed size */
friend class BSONObjIterator;
+ friend class BSONObjStlIterator;
friend class BSONObj;
const BSONElement& chk(BSONType t) const {
if (t != type()) {
diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h
index 6898c63a840..7cd2a50870a 100644
--- a/src/mongo/bson/bsonobj.h
+++ b/src/mongo/bson/bsonobj.h
@@ -52,6 +52,8 @@
namespace mongo {
+class BSONObjStlIterator;
+
/**
C++ representation of a "BSON" object -- that is, an extended JSON-style
object in a binary representation.
@@ -516,7 +518,9 @@ public:
void elems(std::list<BSONElement>&) const;
friend class BSONObjIterator;
- typedef BSONObjIterator iterator;
+ friend class BSONObjStlIterator;
+ typedef BSONObjStlIterator iterator;
+ typedef BSONObjStlIterator const_iterator;
/**
* These enable range-based for loops over BSONObjs:
@@ -525,8 +529,8 @@ public:
* ... // Do something with elem
* }
*/
- BSONObjIterator begin() const;
- BSONObjIterator end() const;
+ iterator begin() const;
+ iterator end() const;
void appendSelfToBufBuilder(BufBuilder& b) const {
verify(objsize());
@@ -580,18 +584,89 @@ struct BSONArray : BSONObj {
explicit BSONArray(const BSONObj& obj) : BSONObj(obj) {}
};
-/** iterator for a BSONObj
+/**
+ * An stl-compatible forward iterator over the elements of a BSONObj.
+ *
+ * The BSONObj must stay in scope for the duration of the iterator's execution.
+ */
+class BSONObjStlIterator {
+public:
+ using iterator_category = std::forward_iterator_tag;
+ using difference_type = ptrdiff_t;
+ using value_type = BSONElement;
+ using pointer = const BSONElement*;
+ using reference = const BSONElement&;
+
+ /**
+ * All default constructed iterators are equal to each other.
+ * They are in a dereferencable state, and return an EOO BSONElement.
+ * They must not be incremented.
+ */
+ BSONObjStlIterator() = default;
+
+ /**
+ * Constructs an iterator pointing to the first element in obj or EOO if it is empty.
+ */
+ explicit BSONObjStlIterator(const BSONObj& obj) : BSONObjStlIterator(obj.firstElement()) {}
- Note each BSONObj ends with an EOO element: so you will get more() on an empty
- object, although next().eoo() will be true.
+ /**
+ * Returns an iterator pointing to the EOO element in obj.
+ */
+ static BSONObjStlIterator endOf(const BSONObj& obj) {
+ auto eooElem = BSONElement();
+ eooElem.data = (obj.objdata() + obj.objsize() - 1);
+ dassert(eooElem.eoo()); // This is checked in the BSONObj constructor.
+ return BSONObjStlIterator(eooElem);
+ }
- The BSONObj must stay in scope for the duration of the iterator's execution.
+ /** pre-increment */
+ BSONObjStlIterator& operator++() {
+ dassert(!_cur.eoo());
+ *this = BSONObjStlIterator(BSONElement(_cur.rawdata() + _curSize));
+ return *this;
+ }
- 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.
-*/
+ /** post-increment */
+ BSONObjStlIterator operator++(int) {
+ BSONObjStlIterator oldPos = *this;
+ ++*this;
+ return oldPos;
+ }
+
+ const BSONElement& operator*() const {
+ return _cur;
+ }
+ const BSONElement* operator->() const {
+ return &_cur;
+ }
+
+ bool operator==(const BSONObjStlIterator& other) {
+ return _cur.rawdata() == other._cur.rawdata();
+ }
+ bool operator!=(const BSONObjStlIterator& other) {
+ return !(*this == other);
+ }
+
+private:
+ explicit BSONObjStlIterator(BSONElement elem)
+ : _cur(elem),
+ // Make sure the lazy size fields are filled in.
+ _curSize(_cur.size()) {}
+
+ BSONElement _cur;
+ int _curSize = 0; // TODO consider removing if we make the size cache in BSONElement eager.
+};
+
+/**
+ * Non-STL iterator for a BSONObj
+ *
+ * For simple loops over BSONObj, do this instead: for (auto&& elem : obj) { ... }
+ *
+ * Note each BSONObj ends with an EOO element: so you will get moreWithEOO() on an empty
+ * object, although more() will be false and next().eoo() will be true.
+ *
+ * The BSONObj must stay in scope for the duration of the iterator's execution.
+ */
class BSONObjIterator {
public:
/** Create an iterator for a BSON object.
@@ -611,12 +686,6 @@ public:
_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;
@@ -733,11 +802,11 @@ public:
BSONArrayIteratorSorted(const BSONArray& array);
};
-inline BSONObjIterator BSONObj::begin() const {
- return BSONObjIterator(*this);
+inline BSONObj::iterator BSONObj::begin() const {
+ return BSONObj::iterator(*this);
}
-inline BSONObjIterator BSONObj::end() const {
- return BSONObjIterator::endOf(*this);
+inline BSONObj::iterator BSONObj::end() const {
+ return BSONObj::iterator::endOf(*this);
}
/**
@@ -780,9 +849,7 @@ template <size_t N>
inline void BSONObj::getFields(const std::array<StringData, N>& fieldNames,
std::array<BSONElement, N>* fields) const {
std::bitset<N> foundFields;
- auto iter = this->begin();
- while (iter.more() && !foundFields.all()) {
- auto el = iter.next();
+ for (auto&& el : *this) {
auto fieldName = el.fieldNameStringData();
for (std::size_t i = 0; i < N; ++i) {
if (!foundFields.test(i) && (fieldNames[i] == fieldName)) {
@@ -791,6 +858,8 @@ inline void BSONObj::getFields(const std::array<StringData, N>& fieldNames,
break;
}
}
+ if (foundFields.all())
+ break;
}
}
} // namespace mongo
diff --git a/src/mongo/bson/mutable/mutable_bson_test.cpp b/src/mongo/bson/mutable/mutable_bson_test.cpp
index 8b832f13f6c..031a09b0128 100644
--- a/src/mongo/bson/mutable/mutable_bson_test.cpp
+++ b/src/mongo/bson/mutable/mutable_bson_test.cpp
@@ -1456,7 +1456,7 @@ TEST(Document, SetValueBSONElementFieldNameHandling) {
static const char inJson2[] = "{ b : 5 }";
mongo::BSONObj inObj2 = mongo::fromjson(inJson2);
- mongo::BSONObjIterator iterator = inObj2.begin();
+ mongo::BSONObjIterator iterator(inObj2);
ASSERT_TRUE(iterator.more());
const mongo::BSONElement b = iterator.next();
diff --git a/src/mongo/bson/util/bson_check.h b/src/mongo/bson/util/bson_check.h
index edfff37b5a0..953279a751d 100644
--- a/src/mongo/bson/util/bson_check.h
+++ b/src/mongo/bson/util/bson_check.h
@@ -49,8 +49,7 @@ Status bsonCheckOnlyHasFieldsImpl(StringData objectName,
const BSONObj& obj,
const Condition& allowed) {
StringMap<bool> seenFields;
- for (BSONObj::iterator iter(obj); iter.more();) {
- const BSONElement e = iter.next();
+ for (auto&& e : obj) {
const auto name = e.fieldNameStringData();
if (!allowed(name)) {