53 inline co_routine_error(jsonifier::string_view message,
const std::source_location& location = std::source_location::current()) :
dca_exception{ message, location } {};
56 template<
typename value_type>
class result_holder {
58 template<
typename value_type_new>
inline void setResult(value_type_new&& newResult) {
59 result = makeUnique<value_type>(std::forward<value_type_new>(newResult));
60 sentYet.store(
true, std::memory_order_release);
63 inline value_type getResult() {
64 if (sentYet.load(std::memory_order_acquire) && result) {
65 sentYet.store(
false, std::memory_order_release);
66 return std::move(*result);
72 inline bool checkForResult() {
73 return sentYet.load(std::memory_order_acquire);
77 unique_ptr<value_type> result{};
78 std::atomic_bool sentYet{};
83 template<
typename return_type_new,
bool timeOut>
class co_routine {
89 template<
typename return_type02,
bool timeOut02>
friend class co_routine;
91 inline void requestStop() {
92 areWeStoppedBool.store(
true, std::memory_order_release);
95 inline bool stopRequested() {
96 return areWeStoppedBool.load(std::memory_order_acquire);
99 template<
typename return_type_newer>
inline void return_value(return_type_newer&& returnValue) {
101 resultBuffer->setResult(std::forward<return_type_newer>(returnValue));
105 inline auto get_return_object() {
109 inline std::suspend_never initial_suspend() {
110 while (!resultBuffer) {
111 std::this_thread::sleep_for(1ms);
116 inline std::suspend_always final_suspend()
noexcept {
120 inline void unhandled_exception() {
121 if (exceptionBuffer) {
122 exceptionBuffer->setResult(std::current_exception());
126 inline ~promise_type() {
127 exceptionBuffer =
nullptr;
128 resultBuffer =
nullptr;
132 result_holder<std::exception_ptr>* exceptionBuffer{};
133 result_holder<return_type>* resultBuffer{};
134 std::atomic_bool areWeStoppedBool{};
140 if (
this != &other) {
141 coroutineHandle = other.coroutineHandle;
142 other.coroutineHandle =
nullptr;
143 coroutineHandle.promise().exceptionBuffer = &exceptionBuffer;
144 coroutineHandle.promise().resultBuffer = &resultBuffer;
145 currentStatus.store(other.currentStatus.load(std::memory_order_acquire), std::memory_order_release);
151 inline co_routine(co_routine<return_type, timeOut>&& other)
noexcept {
152 *
this = std::move(other);
155 inline co_routine& operator=(
const co_routine<return_type, timeOut>& other) =
delete;
156 inline co_routine(
const co_routine<return_type, timeOut>& other) =
delete;
158 inline co_routine& operator=(std::coroutine_handle<promise_type> coroutineHandleNew) {
159 coroutineHandle = coroutineHandleNew;
160 coroutineHandle.promise().exceptionBuffer = &exceptionBuffer;
161 coroutineHandle.promise().resultBuffer = &resultBuffer;
165 inline explicit co_routine(std::coroutine_handle<promise_type> coroutineHandleNew) {
166 *
this = coroutineHandleNew;
169 inline ~co_routine() {
170 if (coroutineHandle) {
171 coroutineHandle.promise().exceptionBuffer =
nullptr;
172 coroutineHandle.promise().resultBuffer =
nullptr;
179 if (!coroutineHandle) {
181 }
else if (coroutineHandle && !coroutineHandle.done()) {
183 }
else if (coroutineHandle && coroutineHandle.done()) {
186 return currentStatus.load(std::memory_order_acquire);
192 if (coroutineHandle) {
193 if (!coroutineHandle.done()) {
194 stop_watch<milliseconds> stopWatch{ 15000 };
196 while (!resultBuffer.checkForResult()) {
197 checkForExceptions();
198 if constexpr (timeOut) {
199 if (stopWatch.hasTimeElapsed()) {
200 return resultBuffer.getResult();
203 std::this_thread::sleep_for(1ms);
206 checkForExceptions();
208 return resultBuffer.getResult();
210 throw co_routine_error{
"co_routine::get(), you called get() on a co_routine that is "
211 "not in a valid state." };
218 if (coroutineHandle) {
219 if (!coroutineHandle.done()) {
220 coroutineHandle.promise().requestStop();
221 stop_watch<milliseconds> stopWatch{ 15000 };
223 while (!resultBuffer.checkForResult()) {
224 checkForExceptions();
225 if constexpr (timeOut) {
226 if (stopWatch.hasTimeElapsed()) {
227 return resultBuffer.getResult();
230 std::this_thread::sleep_for(1ms);
233 checkForExceptions();
235 return resultBuffer.getResult();
237 throw co_routine_error{
"co_routine::cancelAndWait(), you called get() on a co_routine that is "
238 "not in a valid state." };
245 if (coroutineHandle) {
246 if (!coroutineHandle.done()) {
247 coroutineHandle.promise().requestStop();
249 checkForExceptions();
251 return resultBuffer.getResult();
253 throw co_routine_error{
"co_routine::cancel(), you called cancel() on a co_routine that is "
254 "not in a valid state." };
260 std::coroutine_handle<promise_type> coroutineHandle{};
261 result_holder<std::exception_ptr> exceptionBuffer{};
262 result_holder<return_type> resultBuffer{};
264 inline void checkForExceptions() {
265 if (exceptionBuffer.checkForResult()) {
266 std::rethrow_exception(exceptionBuffer.getResult());
273 template<jsonifier::concepts::
void_t return_type_new,
bool timeOut>
class co_routine<return_type_new, timeOut> {
279 template<
typename return_type02,
bool timeOut02>
friend class co_routine;
281 inline void requestStop() {
282 areWeStoppedBool.store(
true, std::memory_order_release);
285 inline bool stopRequested() {
286 return areWeStoppedBool.load(std::memory_order_acquire);
289 inline void return_void() {
293 inline auto get_return_object() {
297 inline std::suspend_never initial_suspend() {
298 while (!resultBuffer) {
299 std::this_thread::sleep_for(1ms);
304 inline std::suspend_always final_suspend()
noexcept {
306 resultBuffer->store(
true);
311 inline void unhandled_exception() {
312 if (exceptionBuffer) {
313 exceptionBuffer->setResult(std::current_exception());
317 inline ~promise_type() {
318 exceptionBuffer =
nullptr;
319 resultBuffer =
nullptr;
323 result_holder<std::exception_ptr>* exceptionBuffer{};
324 std::atomic_bool areWeStoppedBool{};
325 std::atomic_bool* resultBuffer{};
331 if (
this != &other) {
332 coroutineHandle = other.coroutineHandle;
333 other.coroutineHandle =
nullptr;
334 coroutineHandle.promise().exceptionBuffer = &exceptionBuffer;
335 coroutineHandle.promise().resultBuffer = &resultBuffer;
336 currentStatus.store(other.currentStatus.load(std::memory_order_acquire), std::memory_order_release);
342 inline co_routine(co_routine<return_type, timeOut>&& other)
noexcept {
343 *
this = std::move(other);
346 inline co_routine& operator=(
const co_routine<return_type, timeOut>& other) =
delete;
347 inline co_routine(
const co_routine<return_type, timeOut>& other) =
delete;
349 inline co_routine& operator=(std::coroutine_handle<promise_type> coroutineHandleNew) {
350 coroutineHandle = coroutineHandleNew;
351 coroutineHandle.promise().exceptionBuffer = &exceptionBuffer;
352 coroutineHandle.promise().resultBuffer = &resultBuffer;
356 inline explicit co_routine(std::coroutine_handle<promise_type> coroutineHandleNew) {
357 *
this = coroutineHandleNew;
360 inline ~co_routine() {
361 if (coroutineHandle) {
362 coroutineHandle.promise().exceptionBuffer =
nullptr;
363 coroutineHandle.promise().resultBuffer =
nullptr;
370 if (!coroutineHandle) {
372 }
else if (coroutineHandle && !coroutineHandle.done()) {
374 }
else if (coroutineHandle && coroutineHandle.done()) {
377 return currentStatus.load(std::memory_order_acquire);
382 if (coroutineHandle) {
383 if (!coroutineHandle.done()) {
384 stop_watch<milliseconds> stopWatch{ 15000 };
386 while (!resultBuffer.load()) {
387 checkForExceptions();
388 if constexpr (timeOut) {
389 if (stopWatch.hasTimeElapsed()) {
393 std::this_thread::sleep_for(1ms);
396 checkForExceptions();
400 throw co_routine_error{
"co_routine::get(), you called get() on a co_routine that is "
401 "not in a valid state." };
407 if (coroutineHandle) {
408 if (!coroutineHandle.done()) {
409 coroutineHandle.promise().requestStop();
410 stop_watch<milliseconds> stopWatch{ 15000 };
412 while (!resultBuffer.load()) {
413 checkForExceptions();
414 if constexpr (timeOut) {
415 if (stopWatch.hasTimeElapsed()) {
419 std::this_thread::sleep_for(1ms);
422 checkForExceptions();
426 throw co_routine_error{
"co_routine::cancelAndWait(), you called get() on a co_routine that is "
427 "not in a valid state." };
433 if (coroutineHandle) {
434 if (!coroutineHandle.done()) {
435 coroutineHandle.promise().requestStop();
437 checkForExceptions();
441 throw co_routine_error{
"co_routine::cancel(), you called cancel() on a co_routine that is "
442 "not in a valid state." };
448 std::coroutine_handle<promise_type> coroutineHandle{};
449 result_holder<std::exception_ptr> exceptionBuffer{};
450 std::atomic_bool resultBuffer{};
452 inline void checkForExceptions() {
453 if (exceptionBuffer.checkForResult()) {
454 std::rethrow_exception(exceptionBuffer.getResult());
459 class new_thread_awaiter_base {
461 inline static discord_core_internal::co_routine_thread_pool threadPool{};
466 template<
typename return_type,
bool timeOut>
class new_thread_awaiter :
public new_thread_awaiter_base {
468 inline bool await_ready()
const {
473 new_thread_awaiter_base::threadPool.submitTask(coroHandleNew);
474 coroHandle = coroHandleNew;
477 inline auto await_resume() {
482 std::coroutine_handle<typename co_routine<return_type, timeOut>::promise_type> coroHandle{};
void cancel()
Cancels the currently executing co_routine and returns the current result.
co_routine_status getStatus()
Collects the status of the co_routine.
return_type_new return_type
The return type of this co_routine.
void cancelAndWait()
Cancels the currently running co_routine, while blocking to wait for it to complete.
void get()
Gets the resulting value of the co_routine.
A co_routine - representing a potentially asynchronous operation/function.
return_type cancel()
Cancels the currently executing co_routine and returns the current result.
co_routine_status getStatus()
Collects the status of the co_routine.
return_type cancelAndWait()
Cancels the currently running co_routine, while blocking to wait for it to complete.
return_type_new return_type
The return type of this co_routine.
return_type get()
Gets the resulting value of the co_routine.
An awaitable that can be used to launch the co_routine onto a new thread - as well as return the hand...
co_routine_status
The current status of the associated co_routine.
The main namespace for the forward-facing interfaces.
An error type for co_routines.
An exception class derived from std::runtime_error for dca-related exceptions.