diff options
author | Spencer T Brody <spencer@mongodb.com> | 2020-04-29 01:04:04 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-04-30 22:58:41 +0000 |
commit | a6dbdff35b3367f110fca078980cc46c3752446e (patch) | |
tree | 0ab321b402c5e18a138f6779073c19904d2ac07f | |
parent | d43a9f044f9a25980c467f8b7922ad691f517803 (diff) | |
download | mongo-a6dbdff35b3367f110fca078980cc46c3752446e.tar.gz |
SERVER-45591 Fix is_really_copy_constructible and add more tests.
-rw-r--r-- | src/mongo/util/future_impl.h | 26 | ||||
-rw-r--r-- | src/mongo/util/future_test_future_move_only.cpp | 91 |
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 |