summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGregory Wlodarek <gregory.wlodarek@mongodb.com>2019-06-06 12:55:23 -0400
committerGregory Wlodarek <gregory.wlodarek@mongodb.com>2019-06-06 12:55:23 -0400
commitd60d7d2985f8a75ed08a7836cb5e460415f2e26d (patch)
tree3378e8ba8bab71667688cf88da6bcc15d9948394 /src
parent0d8e5d0e79431df3f25cd49914a16e2dd61d064c (diff)
downloadmongo-d60d7d2985f8a75ed08a7836cb5e460415f2e26d.tar.gz
Revert "SERVER-41372 Constrain callback-taking methods on Futures"
This reverts commit e5115d5bf9761ba1bbaf058830bea713ef1cf9fc.
Diffstat (limited to 'src')
-rw-r--r--src/mongo/util/future.h112
-rw-r--r--src/mongo/util/future_impl.h38
2 files changed, 47 insertions, 103 deletions
diff --git a/src/mongo/util/future.h b/src/mongo/util/future.h
index f46f3c541e1..0dabd2c98ff 100644
--- a/src/mongo/util/future.h
+++ b/src/mongo/util/future.h
@@ -144,7 +144,7 @@ public:
return SemiFuture(Impl::makeReady(std::move(val)));
}
- REQUIRES_FOR_NON_TEMPLATE(std::is_void_v<T>)
+ template <typename U = T, typename = std::enable_if_t<std::is_void_v<U>>>
static SemiFuture<void> makeReady() {
return SemiFuture(Impl::makeReady());
}
@@ -281,8 +281,8 @@ private:
};
// Deduction Guides
-TEMPLATE(typename T)
-REQUIRES(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>)
+template <typename T,
+ typename = std::enable_if_t<!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>>>
SemiFuture(T)->SemiFuture<T>;
template <typename T>
SemiFuture(StatusWith<T>)->SemiFuture<T>;
@@ -327,7 +327,7 @@ public:
static Future<T> makeReady(StatusWith<T_unless_void> val) {
return Future(Impl::makeReady(std::move(val)));
}
- REQUIRES_FOR_NON_TEMPLATE(std::is_void_v<T>)
+ template <typename U = T, typename = std::enable_if_t<std::is_void_v<U>>>
static Future<void> makeReady() {
return Future(Impl::makeReady());
}
@@ -343,9 +343,8 @@ public:
* For now, the callback must not fail, since there is nowhere to propagate the error to.
* TODO decide how to handle func throwing.
*/
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallableExactR<void, Func, StatusOrStatusWith<T>>)
- void getAsync(Func&& func) && noexcept {
+ template <typename Func>
+ void getAsync(Func&& func) && noexcept {
std::move(this->_impl).getAsync(std::forward<Func>(func));
}
@@ -384,9 +383,8 @@ public:
* The callback takes a T and can return anything (see above for how Statusy and Futurey returns
* are handled.)
*/
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallable<Func, T>)
- /*see above*/ auto then(Func&& func) && noexcept {
+ template <typename Func>
+ /*see above*/ auto then(Func&& func) && noexcept {
return wrap<Func, T>(std::move(this->_impl).then(std::forward<Func>(func)));
}
@@ -397,9 +395,8 @@ public:
* The callback takes a StatusOrStatusWith<T> and can return anything (see above for how Statusy
* and Futurey returns are handled.)
*/
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallable<Func, StatusOrStatusWith<T>>)
- /*see above*/ auto onCompletion(Func&& func) && noexcept {
+ template <typename Func>
+ /*see above*/ auto onCompletion(Func&& func) && noexcept {
return wrap<Func, Status>(std::move(this->_impl).onCompletion(std::forward<Func>(func)));
}
@@ -416,9 +413,8 @@ public:
* The callback takes a non-OK Status and returns a possibly-wrapped T (see above for how
* Statusy and Futurey returns are handled.)
*/
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallableR<T, Func, Status>)
- /*see above*/ auto onError(Func&& func) && noexcept {
+ template <typename Func>
+ /*see above*/ auto onError(Func&& func) && noexcept {
return wrap<Func, Status>(std::move(this->_impl).onError(std::forward<Func>(func)));
}
@@ -429,9 +425,8 @@ public:
* The callback takes a non-OK Status and returns a possibly-wrapped T (see above for how
* Statusy and Futurey returns are handled.)
*/
- TEMPLATE(ErrorCodes::Error code, typename Func)
- REQUIRES(future_details::isCallableR<T, Func, Status>)
- /*see above*/ auto onError(Func&& func) && noexcept {
+ template <ErrorCodes::Error code, typename Func>
+ /*see above*/ auto onError(Func&& func) && noexcept {
return wrap<Func, Status>(
std::move(this->_impl).template onError<code>(std::forward<Func>(func)));
}
@@ -443,9 +438,8 @@ public:
* The callback takes a non-OK Status and returns a possibly-wrapped T (see above for how
* Statusy and Futurey returns are handled.)
*/
- TEMPLATE(ErrorCategory category, typename Func)
- REQUIRES(future_details::isCallableR<T, Func, Status>)
- /*see above*/ auto onErrorCategory(Func&& func) && noexcept {
+ template <ErrorCategory category, typename Func>
+ /*see above*/ auto onErrorCategory(Func&& func) && noexcept {
return wrap<Func, Status>(
std::move(this->_impl).template onErrorCategory<category>(std::forward<Func>(func)));
}
@@ -470,9 +464,8 @@ public:
*
* The callback takes a const T& and must return void.
*/
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallableExactR<void, Func, const T>)
- Future<T> tap(Func&& func) && noexcept {
+ template <typename Func>
+ Future<T> tap(Func&& func) && noexcept {
return Future<T>(std::move(this->_impl).tap(std::forward<Func>(func)));
}
@@ -483,9 +476,8 @@ public:
*
* The callback takes a non-OK Status and must return void.
*/
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallableExactR<void, Func, const Status>)
- Future<T> tapError(Func&& func) && noexcept {
+ template <typename Func>
+ Future<T> tapError(Func&& func) && noexcept {
return Future<T>(std::move(this->_impl).tapError(std::forward<Func>(func)));
}
@@ -497,9 +489,8 @@ public:
*
* The callback takes a StatusOrStatusWith<T> and must return void.
*/
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallableExactR<void, Func, const StatusOrStatusWith<T>>)
- Future<T> tapAll(Func&& func) && noexcept {
+ template <typename Func>
+ Future<T> tapAll(Func&& func) && noexcept {
return Future<T>(std::move(this->_impl).tapAll(std::forward<Func>(func)));
}
@@ -523,8 +514,8 @@ private:
};
// Deduction Guides
-TEMPLATE(typename T)
-REQUIRES(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>)
+template <typename T,
+ typename = std::enable_if_t<!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>>>
Future(T)->Future<T>;
template <typename T>
Future(StatusWith<T>)->Future<T>;
@@ -565,7 +556,7 @@ public:
static_assert(!std::is_void_v<T>);
}
- REQUIRES_FOR_NON_TEMPLATE(std::is_void_v<T>)
+ template <typename U = T, typename = std::enable_if_t<std::is_void_v<U>>>
explicit ExecutorFuture(ExecutorPtr exec) : SemiFuture<void>(), _exec(std::move(exec)) {}
/**
@@ -601,9 +592,8 @@ public:
// it should be doable, but will be fairly complicated.
//
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallableExactR<void, Func, StatusOrStatusWith<T>>)
- void getAsync(Func&& func) && noexcept {
+ template <typename Func>
+ void getAsync(Func&& func) && noexcept {
static_assert(std::is_void_v<decltype(func(std::declval<StatusOrStatusWith<T>>()))>,
"func passed to getAsync must return void");
@@ -621,42 +611,37 @@ public:
});
}
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallable<Func, T>)
- auto then(Func&& func) && noexcept {
+ template <typename Func>
+ auto then(Func&& func) && noexcept {
return mongo::ExecutorFuture(
std::move(_exec), std::move(this->_impl).then(wrapCB<T>(std::forward<Func>(func))));
}
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallable<Func, StatusOrStatusWith<T>>)
- auto onCompletion(Func&& func) && noexcept {
+ template <typename Func>
+ auto onCompletion(Func&& func) && noexcept {
return mongo::ExecutorFuture(
std::move(_exec),
std::move(this->_impl)
.onCompletion(wrapCB<StatusOrStatusWith<T>>(std::forward<Func>(func))));
}
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallableR<T, Func, Status>)
- ExecutorFuture<T> onError(Func&& func) && noexcept {
+ template <typename Func>
+ ExecutorFuture<T> onError(Func&& func) && noexcept {
return mongo::ExecutorFuture(
std::move(_exec),
std::move(this->_impl).onError(wrapCB<Status>(std::forward<Func>(func))));
}
- TEMPLATE(ErrorCodes::Error code, typename Func)
- REQUIRES(future_details::isCallableR<T, Func, Status>)
- ExecutorFuture<T> onError(Func&& func) && noexcept {
+ template <ErrorCodes::Error code, typename Func>
+ ExecutorFuture<T> onError(Func&& func) && noexcept {
return mongo::ExecutorFuture(
std::move(_exec),
std::move(this->_impl)
.template onError<code>(wrapCB<Status>(std::forward<Func>(func))));
}
- TEMPLATE(ErrorCategory category, typename Func)
- REQUIRES(future_details::isCallableR<T, Func, Status>)
- ExecutorFuture<T> onErrorCategory(Func&& func) && noexcept {
+ template <ErrorCategory category, typename Func>
+ ExecutorFuture<T> onErrorCategory(Func&& func) && noexcept {
return mongo::ExecutorFuture(
std::move(_exec),
std::move(this->_impl)
@@ -707,8 +692,8 @@ private:
};
// Deduction Guides
-TEMPLATE(typename T)
-REQUIRES(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>)
+template <typename T,
+ typename = std::enable_if_t<!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>>>
ExecutorFuture(ExecutorPtr, T)->ExecutorFuture<T>;
template <typename T>
ExecutorFuture(ExecutorPtr, future_details::FutureImpl<T>)->ExecutorFuture<T>;
@@ -781,8 +766,7 @@ public:
* because this method will correctly propagate errors thrown from makeResult(), rather than
* ErrorCodes::BrokenPromise.
*/
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallableR<T, Func, void>)
+ template <typename Func>
void setWith(Func&& func) noexcept {
setFrom(Future<void>::makeReady().then(std::forward<Func>(func)));
}
@@ -798,8 +782,7 @@ public:
});
}
- TEMPLATE(typename... Args)
- REQUIRES(std::is_constructible_v<T, Args...> || (std::is_void_v<T> && sizeof...(Args) == 0))
+ template <typename... Args>
void emplaceValue(Args&&... args) noexcept {
setImpl([&](boost::intrusive_ptr<SharedStateT>&& sharedState) {
sharedState->emplaceValue(std::forward<Args>(args)...);
@@ -980,8 +963,8 @@ private:
};
// Deduction Guides
-TEMPLATE(typename T)
-REQUIRES(!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>)
+template <typename T,
+ typename = std::enable_if_t<!isStatusOrStatusWith<T> && !future_details::isFutureLike<T>>>
SharedSemiFuture(T)->SharedSemiFuture<T>;
template <typename T>
SharedSemiFuture(StatusWith<T>)->SharedSemiFuture<T>;
@@ -1031,8 +1014,7 @@ public:
return SharedSemiFuture<T>(_sharedState);
}
- TEMPLATE(typename Func)
- REQUIRES(future_details::isCallableR<T, Func, void>)
+ template <typename Func>
void setWith(Func&& func) noexcept {
invariant(!std::exchange(_haveCompleted, true));
setFrom(Future<void>::makeReady().then(std::forward<Func>(func)));
@@ -1043,8 +1025,7 @@ public:
std::move(future).propagateResultTo(_sharedState.get());
}
- TEMPLATE(typename... Args)
- REQUIRES(std::is_constructible_v<T, Args...> || (std::is_void_v<T> && sizeof...(Args) == 0))
+ template <typename... Args>
void emplaceValue(Args&&... args) noexcept {
invariant(!std::exchange(_haveCompleted, true));
_sharedState->emplaceValue(std::forward<Args>(args)...);
@@ -1077,8 +1058,7 @@ private:
* Promise::setWith, and has the same reasons to prefer it over Future<T>::makeReady(). Also, it
* deduces the T, so it is easier to use.
*/
-TEMPLATE(typename Func)
-REQUIRES(future_details::isCallable<Func, void>)
+template <typename Func>
auto makeReadyFutureWith(Func&& func) {
return Future<void>::makeReady().then(std::forward<Func>(func));
}
diff --git a/src/mongo/util/future_impl.h b/src/mongo/util/future_impl.h
index 4d4aacf1194..1deacc38733 100644
--- a/src/mongo/util/future_impl.h
+++ b/src/mongo/util/future_impl.h
@@ -50,6 +50,7 @@
#include "mongo/util/scopeguard.h"
namespace mongo {
+
template <typename T>
class Promise;
@@ -69,7 +70,6 @@ template <typename T>
class SharedSemiFuture;
namespace future_details {
-
template <typename T>
class FutureImpl;
template <>
@@ -188,42 +188,6 @@ using VoidToFakeVoid = std::conditional_t<std::is_void_v<T>, FakeVoid, T>;
template <typename T>
using FakeVoidToVoid = std::conditional_t<std::is_same_v<T, FakeVoid>, void, T>;
-struct InvalidCallSentinal; // Nothing actually returns this.
-template <typename Func, typename Arg, typename = void>
-struct FriendlyInvokeResultImpl {
- using type = InvalidCallSentinal;
-};
-template <typename Func, typename Arg>
-struct FriendlyInvokeResultImpl<Func, Arg, std::enable_if_t<std::is_invocable_v<Func, Arg>>> {
- using type = std::invoke_result_t<Func, Arg>;
-};
-template <typename Func>
-struct FriendlyInvokeResultImpl<Func, void, std::enable_if_t<std::is_invocable_v<Func>>> {
- using type = std::invoke_result_t<Func>;
-};
-template <typename Func>
-struct FriendlyInvokeResultImpl<Func, const void, std::enable_if_t<std::is_invocable_v<Func>>> {
- using type = std::invoke_result_t<Func>;
-};
-
-template <typename Func, typename Arg>
-using FriendlyInvokeResult = typename FriendlyInvokeResultImpl<Func, Arg>::type;
-
-// Like is_invocable_v<Func, Args>, but handles Args == void correctly.
-template <typename Func, typename Arg>
-inline constexpr bool isCallable =
- !std::is_same_v<FriendlyInvokeResult<Func, Arg>, InvalidCallSentinal>;
-
-// Like is_invocable_r_v<Func, Args>, but handles Args == void correctly and unwraps the return.
-template <typename Ret, typename Func, typename Arg>
-inline constexpr bool isCallableR =
- (isCallable<Func, Arg> && std::is_same_v<UnwrappedType<FriendlyInvokeResult<Func, Arg>>, Ret>);
-
-// Like isCallableR, but doesn't unwrap the result type.
-template <typename Ret, typename Func, typename Arg>
-inline constexpr bool isCallableExactR = (isCallable<Func, Arg> &&
- std::is_same_v<FriendlyInvokeResult<Func, Arg>, Ret>);
-
/**
* call() normalizes arguments to hide the FakeVoid shenanigans from users of Futures.
* In the future it may also expand tuples to argument lists.