diff options
author | Mathias Stearn <redbeard0531@gmail.com> | 2022-03-29 13:41:27 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-03-29 15:23:17 +0000 |
commit | 07ba0f5fb79b855f9abc260ac35126c30b362e29 (patch) | |
tree | 92943ce777d133e7a38284d1764cdf66c362a296 | |
parent | 0fa0170045ccab649621111ec86c80e798bcac23 (diff) | |
download | mongo-07ba0f5fb79b855f9abc260ac35126c30b362e29.tar.gz |
SERVER-54358 enable for (auto [name, elem] : someBsonObj) {...}
-rw-r--r-- | src/mongo/bson/bson_obj_test.cpp | 10 | ||||
-rw-r--r-- | src/mongo/bson/bsonelement.h | 28 | ||||
-rw-r--r-- | src/mongo/bson/bsonobj.h | 6 |
3 files changed, 44 insertions, 0 deletions
diff --git a/src/mongo/bson/bson_obj_test.cpp b/src/mongo/bson/bson_obj_test.cpp index 049fab19d52..3745f77f135 100644 --- a/src/mongo/bson/bson_obj_test.cpp +++ b/src/mongo/bson/bson_obj_test.cpp @@ -621,6 +621,16 @@ TEST(Looping, Cpp11Auto) { ASSERT_EQUALS(count, 1 + 2 + 3); } +TEST(Looping, Cpp17StructuredBindings) { + int count = 0; + for (auto [name, e] : BSON("a" << 1 << "a" << 2 << "a" << 3)) { + ASSERT_EQUALS(name, "a"); + count += e.Int(); + } + + ASSERT_EQUALS(count, 1 + 2 + 3); +} + TEST(BSONObj, getFields) { auto e = BSON("a" << 1 << "b" << 2 << "c" << 3 << "d" << 4 << "e" << 5 << "f" << 6); std::array<StringData, 3> fieldNames{"c", "d", "f"}; diff --git a/src/mongo/bson/bsonelement.h b/src/mongo/bson/bsonelement.h index 722ea0937b3..a0cf82dcf02 100644 --- a/src/mongo/bson/bsonelement.h +++ b/src/mongo/bson/bsonelement.h @@ -901,6 +901,24 @@ public: private: /** + * This is to enable structured bindings for BSONElement, it should not be used explicitly. + * When used in a structed binding, BSONElement behaves as-if it is a + * std::pair<StringData, BSONElement>. + * + * Example: + * for (auto [name, elem] : someBsonObj) {...} + */ + template <size_t I> + friend auto get(const BSONElement& elem) { + static_assert(I <= 1); + if constexpr (I == 0) { + return elem.fieldNameStringData(); + } else if constexpr (I == 1) { + return elem; + } + } + + /** * Get a string's value. Also gives you start of the real data for an embedded object. * You must assure data is of an appropriate type first, like the type check in * valueStringDataSafe(). You should use the string's size when performing any operations @@ -1227,3 +1245,13 @@ inline BSONElement::BSONElement() { totalSize = 1; } } // namespace mongo + +// These template specializations in namespace std are required in order to support structured +// bindings using the "tuple protocol". +namespace std { +template <> +struct tuple_size<mongo::BSONElement> : std::integral_constant<size_t, 2> {}; +template <size_t I> +struct tuple_element<I, mongo::BSONElement> + : std::tuple_element<I, std::pair<mongo::StringData, mongo::BSONElement>> {}; +} // namespace std diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h index 10c6483e70d..2f1e511704d 100644 --- a/src/mongo/bson/bsonobj.h +++ b/src/mongo/bson/bsonobj.h @@ -662,6 +662,12 @@ public: * for (BSONElement elem : BSON("a" << 1 << "b" << 2)) { * ... // Do something with elem * } + * + * You can also loop over a bson object as-if it were a map<StringData, BSONElement>: + * + * for (auto [fieldName, elem] : BSON("a" << 1 << "b" << 2)) { + * ... // Do something with fieldName and elem + * } */ iterator begin() const; iterator end() const; |