forked from NVIDIA/stdexec
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy path__awaitable.hpp
More file actions
104 lines (89 loc) · 3.86 KB
/
__awaitable.hpp
File metadata and controls
104 lines (89 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
* Copyright (c) 2021-2024 NVIDIA Corporation
*
* Licensed under the Apache License Version 2.0 with LLVM Exceptions
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://llvm.org/LICENSE.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "../functional.hpp"
#include "__concepts.hpp"
#include "__config.hpp"
#include "__meta.hpp"
namespace STDEXEC
{
#if !STDEXEC_NO_STDCPP_COROUTINES()
// Define some concepts and utilities for working with awaitables
template <class _Tp>
concept __await_suspend_result = __one_of<_Tp, void, bool>
|| __is_instance_of<_Tp, __std::coroutine_handle>;
template <class _Awaiter, class... _Promise>
concept __awaiter = requires(_Awaiter &__awaiter, __std::coroutine_handle<_Promise...> __h) {
__awaiter.await_ready() ? 1 : 0;
{ __awaiter.await_suspend(__h) } -> __await_suspend_result;
__awaiter.await_resume();
};
template <class _Awaitable, class _Promise>
concept __has_await_transform = requires(_Awaitable &&__awaitable, _Promise &__promise) {
__promise.await_transform(static_cast<_Awaitable &&>(__awaitable));
};
inline constexpr auto __get_awaitable = __first_callable{
[]<class _Promise, __has_await_transform<_Promise> _Awaitable>(_Awaitable &&__awaitable,
_Promise &__promise)
-> decltype(auto)
{ return __promise.await_transform(static_cast<_Awaitable &&>(__awaitable)); },
[]<class _Awaitable>(_Awaitable &&__awaitable, __ignore = {}) -> decltype(auto)
{ return static_cast<_Awaitable &&>(__awaitable); }};
template <class _Awaitable, class _Promise>
using __awaitable_of_t = decltype(STDEXEC::__get_awaitable(__declval<_Awaitable>(),
__declval<_Promise &>()));
inline constexpr auto __get_awaiter =
[]<class _Awaitable>(_Awaitable &&__awaitable) -> decltype(auto)
{
if constexpr (requires { __declval<_Awaitable>().operator co_await(); })
{
return static_cast<_Awaitable &&>(__awaitable).operator co_await();
}
else if constexpr (requires { operator co_await(__declval<_Awaitable>()); })
{
return operator co_await(static_cast<_Awaitable &&>(__awaitable));
}
else
{
return static_cast<_Awaitable &&>(__awaitable);
}
};
template <class _Awaitable>
using __awaiter_of_t = decltype(STDEXEC::__get_awaiter(__declval<_Awaitable>()));
template <class _Awaitable, class... _Promise>
concept __awaitable = requires(_Awaitable &&__awaitable, _Promise &...__promise) {
{
STDEXEC::__get_awaiter(
STDEXEC::__get_awaitable(static_cast<_Awaitable &&>(__awaitable), __promise...))
} -> __awaiter<_Promise...>;
};
template <class _Tp>
constexpr auto __as_lvalue(_Tp &&) -> _Tp &;
template <class _Awaitable, class... _Promise>
requires __awaitable<_Awaitable, _Promise...>
using __await_result_t = decltype(STDEXEC::__as_lvalue(
STDEXEC::__get_awaiter(
STDEXEC::__get_awaitable(__declval<_Awaitable>(),
__declval<_Promise &>()...)))
.await_resume());
#else
template <class _Awaitable, class... _Promise>
concept __awaitable = false;
template <class _Awaitable, class... _Promise>
requires __awaitable<_Awaitable, _Promise...>
using __await_result_t = void;
#endif
} // namespace STDEXEC