summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSpencer T Brody <spencer@mongodb.com>2020-04-29 01:04:04 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-04-30 22:58:41 +0000
commita6dbdff35b3367f110fca078980cc46c3752446e (patch)
tree0ab321b402c5e18a138f6779073c19904d2ac07f
parentd43a9f044f9a25980c467f8b7922ad691f517803 (diff)
downloadmongo-a6dbdff35b3367f110fca078980cc46c3752446e.tar.gz
SERVER-45591 Fix is_really_copy_constructible and add more tests.
-rw-r--r--src/mongo/util/future_impl.h26
-rw-r--r--src/mongo/util/future_test_future_move_only.cpp91
2 files changed, 97 insertions, 20 deletions
diff --git a/src/mongo/util/future_impl.h b/src/mongo/util/future_impl.h
index b4f223d4fd1..ed0e17296df 100644
--- a/src/mongo/util/future_impl.h
+++ b/src/mongo/util/future_impl.h
@@ -52,20 +52,6 @@
namespace mongo {
-namespace {
-// std::is_copy_constructible incorrectly returns true for containers of move-only types, so we use
-// our own modified version instead. Note this version is brittle at the moment, since it determines
-// whether or not the type is a container by the presense of a value_type field. After we switch to
-// C++20 we can use the Container concept for this instread.
-template <typename T, typename = void>
-struct is_really_copy_constructible : std::is_copy_constructible<T> {};
-template <typename T>
-struct is_really_copy_constructible<T, std::void_t<typename T::value_type>>
- : std::is_copy_constructible<typename T::value_type> {};
-template <typename T>
-constexpr bool is_really_copy_constructible_v = is_really_copy_constructible<T>::value;
-} // namespace
-
template <typename T>
class Promise;
@@ -102,6 +88,18 @@ inline constexpr bool isFutureLike<ExecutorFuture<T>> = true;
template <typename T>
inline constexpr bool isFutureLike<SharedSemiFuture<T>> = true;
+// std::is_copy_constructible incorrectly returns true for containers of move-only types, so we use
+// our own modified version instead. Note this version is brittle at the moment, since it determines
+// whether or not the type is a container by the presense of a value_type field. After we switch to
+// C++20 we can use the Container concept for this instread.
+template <typename T, typename = void>
+struct is_really_copy_constructible : std::is_copy_constructible<T> {};
+template <typename T>
+struct is_really_copy_constructible<T, std::void_t<typename T::value_type>>
+ : is_really_copy_constructible<typename T::value_type> {};
+template <typename T>
+constexpr bool is_really_copy_constructible_v = is_really_copy_constructible<T>::value;
+
template <typename T>
struct UnstatusTypeImpl {
using type = T;
diff --git a/src/mongo/util/future_test_future_move_only.cpp b/src/mongo/util/future_test_future_move_only.cpp
index 19d5a0c027d..64a4498436d 100644
--- a/src/mongo/util/future_test_future_move_only.cpp
+++ b/src/mongo/util/future_test_future_move_only.cpp
@@ -40,8 +40,7 @@
namespace mongo {
namespace {
-// A move-only type that isn't default constructible. It has binary ops with int to make it easier
-// to have a common format with the above tests.
+// A move-only type that isn't default constructible. It has binary ops with int.
struct Widget {
explicit Widget(int val) : val(val) {}
@@ -63,8 +62,16 @@ struct Widget {
return val == i;
}
- bool operator==(Widget w) const {
- return val == w.val;
+ friend bool operator==(const Widget& a, const Widget& b) {
+ return a.val == b.val;
+ }
+ friend bool operator<(const Widget& a, const Widget& b) {
+ return a.val < b.val;
+ }
+
+ template <typename H>
+ friend H AbslHashValue(H h, const Widget& w) {
+ return H::combine(std::move(h), w.val);
}
int val;
@@ -745,7 +752,7 @@ TEST(Future_MoveOnly, Success_vector) {
vec.emplace_back(1);
return vec;
},
- [](/*Future<vector<Widget>>*/ auto&& fut) { ASSERT_EQ(fut.get()[0], 1); });
+ [](auto&& fut) { ASSERT_EQ(fut.get()[0], 1); });
}
TEST(Future_MoveOnly, Success_list) {
@@ -755,8 +762,80 @@ TEST(Future_MoveOnly, Success_list) {
lst.emplace_back(1);
return lst;
},
- [](/*Future<list<Widget>>*/ auto&& fut) { ASSERT_EQ(fut.get().front(), 1); });
+ [](auto&& fut) { ASSERT_EQ(fut.get().front(), 1); });
+}
+
+TEST(Future_MoveOnly, Success_set) {
+ FUTURE_SUCCESS_TEST(
+ [] {
+ std::set<Widget> set;
+ set.emplace(1);
+ return set;
+ },
+ [](auto&& fut) { ASSERT_EQ(fut.get().count(Widget{1}), 1); });
+}
+
+TEST(Future_MoveOnly, Success_unordered_set) {
+ FUTURE_SUCCESS_TEST(
+ [] {
+ stdx::unordered_set<Widget> set;
+ set.emplace(1);
+ return set;
+ },
+ [](auto&& fut) { ASSERT_EQ(fut.get().count(Widget{1}), 1); });
+}
+
+TEST(Future_MoveOnly, Success_pair) {
+ FUTURE_SUCCESS_TEST(
+ [] {
+ return std::pair<Widget, Widget>{1, 1};
+ },
+ [](auto&& fut) {
+ auto&& pair = fut.get();
+ ASSERT_EQ(pair.first, 1);
+ ASSERT_EQ(pair.second, 1);
+ });
+}
+
+TEST(Future_MoveOnly, Success_map) {
+ FUTURE_SUCCESS_TEST(
+ [] {
+ std::map<Widget, Widget> map;
+ map.emplace(1, 1);
+ return map;
+ },
+ [](auto&& fut) { ASSERT_EQ(fut.get().at(Widget{1}).val, 1); });
+}
+
+TEST(Future_MoveOnly, Success_unordered_map) {
+ FUTURE_SUCCESS_TEST(
+ [] {
+ stdx::unordered_map<Widget, Widget> map;
+ map.emplace(1, 1);
+ return map;
+ },
+ [](auto&& fut) { ASSERT_EQ(fut.get().at(Widget{1}).val, 1); });
}
+TEST(Future_MoveOnly, Success_nested_container) {
+ FUTURE_SUCCESS_TEST(
+ [] {
+ std::vector<std::vector<std::map<Widget, Widget>>> outer;
+ std::vector<std::map<Widget, Widget>> mid;
+ std::map<Widget, Widget> inner;
+ inner.emplace(1, 1);
+ mid.push_back(std::move(inner));
+ outer.push_back(std::move(mid));
+
+ return outer;
+ },
+ [](auto&& fut) {
+ auto&& outer = fut.get();
+ const auto& inner = outer[0][0];
+ ASSERT_EQ(inner.at(Widget{1}).val, 1);
+ });
+}
+
+
} // namespace
} // namespace mongo