blob: 3d4ba16979a1dc559045868b59f5c319ca8d63f3 [file] [log] [blame]
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_TEST_EXPERIMENTAL_TASK_AWAITABLE_TRAITS
#define _LIBCPP_TEST_EXPERIMENTAL_TASK_AWAITABLE_TRAITS
#include <type_traits>
#include <experimental/coroutine>
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES
template<typename _Tp>
struct __is_coroutine_handle : std::false_type {};
template<typename _Tp>
struct __is_coroutine_handle<std::experimental::coroutine_handle<_Tp>> :
std::true_type
{};
template<typename _Tp>
struct __is_valid_await_suspend_result :
std::disjunction<
std::is_void<_Tp>,
std::is_same<_Tp, bool>,
__is_coroutine_handle<_Tp>>
{};
template<typename _Tp, typename = void>
struct is_awaiter : std::false_type {};
template<typename _Tp>
struct is_awaiter<_Tp, std::void_t<
decltype(std::declval<_Tp&>().await_ready()),
decltype(std::declval<_Tp&>().await_resume()),
decltype(std::declval<_Tp&>().await_suspend(
std::declval<std::experimental::coroutine_handle<void>>()))>> :
std::conjunction<
std::is_same<decltype(std::declval<_Tp&>().await_ready()), bool>,
__is_valid_await_suspend_result<decltype(
std::declval<_Tp&>().await_suspend(
std::declval<std::experimental::coroutine_handle<void>>()))>>
{};
template<typename _Tp>
constexpr bool is_awaiter_v = is_awaiter<_Tp>::value;
template<typename _Tp, typename = void>
struct __has_member_operator_co_await : std::false_type {};
template<typename _Tp>
struct __has_member_operator_co_await<_Tp, std::void_t<decltype(std::declval<_Tp>().operator co_await())>>
: is_awaiter<decltype(std::declval<_Tp>().operator co_await())>
{};
template<typename _Tp, typename = void>
struct __has_non_member_operator_co_await : std::false_type {};
template<typename _Tp>
struct __has_non_member_operator_co_await<_Tp, std::void_t<decltype(operator co_await(std::declval<_Tp>()))>>
: is_awaiter<decltype(operator co_await(std::declval<_Tp>()))>
{};
template<typename _Tp>
struct is_awaitable : std::disjunction<
is_awaiter<_Tp>,
__has_member_operator_co_await<_Tp>,
__has_non_member_operator_co_await<_Tp>>
{};
template<typename _Tp>
constexpr bool is_awaitable_v = is_awaitable<_Tp>::value;
template<
typename _Tp,
std::enable_if_t<is_awaitable_v<_Tp>, int> = 0>
decltype(auto) get_awaiter(_Tp&& __awaitable)
{
if constexpr (__has_member_operator_co_await<_Tp>::value)
{
return static_cast<_Tp&&>(__awaitable).operator co_await();
}
else if constexpr (__has_non_member_operator_co_await<_Tp>::value)
{
return operator co_await(static_cast<_Tp&&>(__awaitable));
}
else
{
return static_cast<_Tp&&>(__awaitable);
}
}
template<typename _Tp, typename = void>
struct await_result
{};
template<typename _Tp>
struct await_result<_Tp, std::enable_if_t<is_awaitable_v<_Tp>>>
{
private:
using __awaiter = decltype(get_awaiter(std::declval<_Tp>()));
public:
using type = decltype(std::declval<__awaiter&>().await_resume());
};
template<typename _Tp>
using await_result_t = typename await_result<_Tp>::type;
_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES
#endif