1 /* 2 * Copyright (c) 2021-2024 NVIDIA Corporation 3 * 4 * Licensed under the Apache License Version 2.0 with LLVM Exceptions 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * https://llvm.org/LICENSE.txt 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include "__as_awaitable.hpp" 19 #include "__concepts.hpp" 20 #include "__execution_fwd.hpp" 21 22 #include <exception> 23 24 namespace stdexec 25 { 26 #if !STDEXEC_STD_NO_COROUTINES() 27 namespace __was 28 { 29 template <class _Promise = void> 30 class __continuation_handle; 31 32 template <> 33 class __continuation_handle<void> 34 { 35 public: 36 __continuation_handle() = default; 37 38 template <class _Promise> __continuation_handle(__coro::coroutine_handle<_Promise> __coro)39 __continuation_handle(__coro::coroutine_handle<_Promise> __coro) noexcept : 40 __coro_(__coro) 41 { 42 if constexpr (requires(_Promise& __promise) { 43 __promise.unhandled_stopped(); 44 }) 45 { 46 __stopped_callback_ = 47 [](void* __address) noexcept -> __coro::coroutine_handle<> { 48 // This causes the rest of the coroutine (the part after the 49 // co_await of the sender) to be skipped and invokes the calling 50 // coroutine's stopped handler. 51 return __coro::coroutine_handle<_Promise>::from_address( 52 __address) 53 .promise() 54 .unhandled_stopped(); 55 }; 56 } 57 // If _Promise doesn't implement unhandled_stopped(), then if a 58 // "stopped" unwind reaches this point, it's considered an unhandled 59 // exception and terminate() is called. 60 } 61 handle() const62 [[nodiscard]] auto handle() const noexcept -> __coro::coroutine_handle<> 63 { 64 return __coro_; 65 } 66 unhandled_stopped() const67 [[nodiscard]] auto unhandled_stopped() const noexcept 68 -> __coro::coroutine_handle<> 69 { 70 return __stopped_callback_(__coro_.address()); 71 } 72 73 private: 74 using __stopped_callback_t = __coro::coroutine_handle<> (*)(void*) noexcept; 75 76 __coro::coroutine_handle<> __coro_{}; 77 __stopped_callback_t __stopped_callback_ = __anon7e953c250202(void*) 78 [](void*) noexcept -> __coro::coroutine_handle<> { std::terminate(); }; 79 }; 80 81 template <class _Promise> 82 class __continuation_handle 83 { 84 public: 85 __continuation_handle() = default; 86 __continuation_handle(__coro::coroutine_handle<_Promise> __coro)87 __continuation_handle(__coro::coroutine_handle<_Promise> __coro) noexcept : 88 __continuation_{__coro} 89 {} 90 handle() const91 auto handle() const noexcept -> __coro::coroutine_handle<_Promise> 92 { 93 return __coro::coroutine_handle<_Promise>::from_address( 94 __continuation_.handle().address()); 95 } 96 unhandled_stopped() const97 [[nodiscard]] auto unhandled_stopped() const noexcept 98 -> __coro::coroutine_handle<> 99 { 100 return __continuation_.unhandled_stopped(); 101 } 102 103 private: 104 __continuation_handle<> __continuation_{}; 105 }; 106 107 struct __with_awaitable_senders_base 108 { 109 template <class _OtherPromise> set_continuationstdexec::__was::__with_awaitable_senders_base110 void set_continuation( 111 __coro::coroutine_handle<_OtherPromise> __hcoro) noexcept 112 { 113 static_assert(!__same_as<_OtherPromise, void>); 114 __continuation_ = __hcoro; 115 } 116 set_continuationstdexec::__was::__with_awaitable_senders_base117 void set_continuation(__continuation_handle<> __continuation) noexcept 118 { 119 __continuation_ = __continuation; 120 } 121 continuationstdexec::__was::__with_awaitable_senders_base122 [[nodiscard]] auto continuation() const noexcept -> __continuation_handle<> 123 { 124 return __continuation_; 125 } 126 unhandled_stoppedstdexec::__was::__with_awaitable_senders_base127 auto unhandled_stopped() noexcept -> __coro::coroutine_handle<> 128 { 129 return __continuation_.unhandled_stopped(); 130 } 131 132 private: 133 __continuation_handle<> __continuation_{}; 134 }; 135 136 template <class _Promise> 137 struct with_awaitable_senders : __with_awaitable_senders_base 138 { 139 template <class _Value> await_transformstdexec::__was::with_awaitable_senders140 auto await_transform(_Value&& __val) 141 -> __call_result_t<as_awaitable_t, _Value, _Promise&> 142 { 143 static_assert(derived_from<_Promise, with_awaitable_senders>); 144 return as_awaitable(static_cast<_Value&&>(__val), 145 static_cast<_Promise&>(*this)); 146 } 147 }; 148 } // namespace __was 149 150 using __was::__continuation_handle; 151 using __was::with_awaitable_senders; 152 #endif 153 } // namespace stdexec 154