summaryrefslogtreecommitdiff
path: root/src/mongo/stdx
diff options
context:
space:
mode:
authorADAM David Alan Martin <adam.martin@10gen.com>2018-09-06 14:28:18 -0400
committerADAM David Alan Martin <adam.martin@10gen.com>2018-09-06 14:28:18 -0400
commit0bb846536e3dda6905bd211db4e4a137705eeb51 (patch)
treef551ed75078517cc03042a6afc16ae8644422e6b /src/mongo/stdx
parent87235ccf747184cd32d5d3abc86fa4606c377f3b (diff)
downloadmongo-0bb846536e3dda6905bd211db4e4a137705eeb51.tar.gz
SERVER-36900 Add a `unique_function` utility.
The `mongo::unique_function` object is a move-only function object which is useful for capturing move-only lambdas (such as those with `std::unique_ptr` objects) into type-erased function objects that resemble `std::function`.
Diffstat (limited to 'src/mongo/stdx')
-rw-r--r--src/mongo/stdx/type_traits.h72
1 files changed, 66 insertions, 6 deletions
diff --git a/src/mongo/stdx/type_traits.h b/src/mongo/stdx/type_traits.h
index a746ef47096..5f0be745450 100644
--- a/src/mongo/stdx/type_traits.h
+++ b/src/mongo/stdx/type_traits.h
@@ -54,29 +54,89 @@ using enable_if_t = typename std::enable_if<B, T>::type;
} // namespace mongo
#endif
-#if __cplusplus >= 201703
-
+// TODO: Deal with importing this from C++20, when the time comes.
namespace mongo {
namespace stdx {
-using std::void_t;
+template <typename T>
+struct type_identity {
+ using type = T;
+};
+
+template <typename T>
+using type_identity_t = stdx::type_identity<T>;
} // namespace stdx
} // namespace mongo
-#else
+
+// TODO: Re-evaluate which of these we need when making the cutover to C++17.
namespace mongo {
namespace stdx {
+namespace detail {
template <typename...>
struct make_void {
using type = void;
};
+} // namespace detail
template <typename... Args>
-using void_t = typename make_void<Args...>::type;
+using void_t = typename detail::make_void<Args...>::type;
+
+template <bool b>
+using bool_constant = std::integral_constant<bool, b>;
+
+template <typename T>
+struct negation : stdx::bool_constant<!bool(T::value)> {};
+
+template <typename... B>
+struct disjunction : std::false_type {};
+template <typename B>
+struct disjunction<B> : B {};
+template <typename B1, typename... B>
+struct disjunction<B1, B...> : std::conditional_t<bool(B1::value), B1, stdx::disjunction<B...>> {};
+
+template <typename...>
+struct conjunction : std::true_type {};
+template <typename B>
+struct conjunction<B> : B {};
+template <typename B1, typename... B>
+struct conjunction<B1, B...> : std::conditional_t<bool(B1::value), stdx::conjunction<B...>, B1> {};
+
+namespace detail {
+template <typename Func,
+ typename... Args,
+ typename = typename std::result_of<Func && (Args && ...)>::type>
+auto is_invocable_impl(Func&& func, Args&&... args) -> std::true_type;
+auto is_invocable_impl(...) -> std::false_type;
+} // namespace detail
+
+template <typename Func, typename... Args>
+struct is_invocable
+ : decltype(detail::is_invocable_impl(std::declval<Func>(), std::declval<Args>()...)) {};
+
+namespace detail {
+
+// This helps solve the lack of regular void problem, when passing a 'conversion target' as a
+// parameter.
+
+template <typename R,
+ typename Func,
+ typename... Args,
+ typename ComputedResult = typename std::result_of<Func && (Args && ...)>::type>
+auto is_invocable_r_impl(stdx::type_identity<R>, Func&& func, Args&&... args) ->
+ typename stdx::disjunction<std::is_void<R>,
+ std::is_same<ComputedResult, R>,
+ std::is_convertible<ComputedResult, R>>::type;
+auto is_invocable_r_impl(...) -> std::false_type;
+} // namespace detail
+
+template <typename R, typename Func, typename... Args>
+struct is_invocable_r
+ : decltype(detail::is_invocable_r_impl(
+ stdx::type_identity<R>(), std::declval<Func>(), std::declval<Args>()...)) {};
} // namespace stdx
} // namespace mongo
-#endif