summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Stearn <redbeard0531@gmail.com>2022-03-29 13:41:27 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-03-29 15:23:17 +0000
commit07ba0f5fb79b855f9abc260ac35126c30b362e29 (patch)
tree92943ce777d133e7a38284d1764cdf66c362a296
parent0fa0170045ccab649621111ec86c80e798bcac23 (diff)
downloadmongo-07ba0f5fb79b855f9abc260ac35126c30b362e29.tar.gz
SERVER-54358 enable for (auto [name, elem] : someBsonObj) {...}
-rw-r--r--src/mongo/bson/bson_obj_test.cpp10
-rw-r--r--src/mongo/bson/bsonelement.h28
-rw-r--r--src/mongo/bson/bsonobj.h6
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;