53 DCA_INLINE co_routine_error(
const jsonifier::string_view& message, 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> DCA_INLINE
void setResult(value_type_new&& newResult) {
60 sentYet.store(
true, std::memory_order_release);
63 DCA_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 DCA_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 DCA_INLINE
void requestStop() {
92 areWeStoppedBool.store(
true, std::memory_order_release);
95 DCA_INLINE
bool stopRequested() {
96 return areWeStoppedBool.load(std::memory_order_acquire);
99 template<
typename return_type_newer> DCA_INLINE
void return_value(return_type_newer&& returnValue) {
101 resultBuffer->setResult(std::forward<return_type_newer>(returnValue));
105 DCA_INLINE
auto get_return_object() {
106 return co_routine<return_type, timeOut>{ std::coroutine_handle<promise_type>::from_promise(*
this) };
109 DCA_INLINE std::suspend_never initial_suspend() {
110 while (!resultBuffer) {
111 std::this_thread::sleep_for(1ms);
116 DCA_INLINE std::suspend_always final_suspend()
noexcept {
120 DCA_INLINE
void unhandled_exception() {
121 if (exceptionBuffer) {
122 exceptionBuffer->setResult(std::current_exception());
126 DCA_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{};
137 DCA_INLINE co_routine() =
default;
139 DCA_INLINE co_routine& operator=(co_routine<return_type, timeOut>&& other)
noexcept {
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 DCA_INLINE co_routine(co_routine<return_type, timeOut>&& other)
noexcept {
152 *
this = std::move(other);
155 DCA_INLINE co_routine& operator=(
const co_routine<return_type, timeOut>& other) =
delete;
156 DCA_INLINE co_routine(
const co_routine<return_type, timeOut>& other) =
delete;
158 DCA_INLINE co_routine& operator=(std::coroutine_handle<promise_type> coroutineHandleNew) {
159 coroutineHandle = coroutineHandleNew;
160 coroutineHandle.promise().exceptionBuffer = &exceptionBuffer;
161 coroutineHandle.promise().resultBuffer = &resultBuffer;
165 DCA_INLINE
explicit co_routine(std::coroutine_handle<promise_type> coroutineHandleNew) {
166 *
this = coroutineHandleNew;
169 DCA_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 DCA_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 DCA_INLINE
void requestStop() {
282 areWeStoppedBool.store(
true, std::memory_order_release);
285 DCA_INLINE
bool stopRequested() {
286 return areWeStoppedBool.load(std::memory_order_acquire);
289 DCA_INLINE
void return_void() {
293 DCA_INLINE
auto get_return_object() {
294 return co_routine<return_type, timeOut>{ std::coroutine_handle<promise_type>::from_promise(*
this) };
297 DCA_INLINE std::suspend_never initial_suspend() {
298 while (!resultBuffer) {
299 std::this_thread::sleep_for(1ms);
304 DCA_INLINE std::suspend_always final_suspend()
noexcept {
306 resultBuffer->store(
true);
311 DCA_INLINE
void unhandled_exception() {
312 if (exceptionBuffer) {
313 exceptionBuffer->setResult(std::current_exception());
317 DCA_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{};
328 DCA_INLINE co_routine() =
default;
330 DCA_INLINE co_routine& operator=(co_routine<return_type, timeOut>&& other)
noexcept {
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 DCA_INLINE co_routine(co_routine<return_type, timeOut>&& other)
noexcept {
343 *
this = std::move(other);
346 DCA_INLINE co_routine& operator=(
const co_routine<return_type, timeOut>& other) =
delete;
347 DCA_INLINE co_routine(
const co_routine<return_type, timeOut>& other) =
delete;
349 DCA_INLINE co_routine& operator=(std::coroutine_handle<promise_type> coroutineHandleNew) {
350 coroutineHandle = coroutineHandleNew;
351 coroutineHandle.promise().exceptionBuffer = &exceptionBuffer;
352 coroutineHandle.promise().resultBuffer = &resultBuffer;
356 DCA_INLINE
explicit co_routine(std::coroutine_handle<promise_type> coroutineHandleNew) {
357 *
this = coroutineHandleNew;
360 DCA_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 DCA_INLINE
void checkForExceptions() {
453 if (exceptionBuffer.checkForResult()) {
454 std::rethrow_exception(exceptionBuffer.getResult());
459 class new_thread_awaiter_base {
461 DCA_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 DCA_INLINE
bool await_ready()
const {
472 DCA_INLINE
void await_suspend(std::coroutine_handle<
typename co_routine<return_type, timeOut>::promise_type> coroHandleNew) {
473 new_thread_awaiter_base::threadPool.submitTask(coroHandleNew);
474 coroHandle = coroHandleNew;
477 DCA_INLINE
auto await_resume() {
482 std::coroutine_handle<typename co_routine<return_type, timeOut>::promise_type> coroHandle{};
A co_routine - representing a potentially asynchronous operation/function.
DCA_INLINE void cancel()
Cancels the currently executing co_routine and returns the current result.
DCA_INLINE void get()
Gets the resulting value of the co_routine.
return_type_new return_type
The return type of this co_routine.
DCA_INLINE return_type cancelAndWait()
Cancels the currently running co_routine, while blocking to wait for it to complete.
DCA_INLINE return_type get()
Gets the resulting value of the co_routine.
DCA_INLINE void cancelAndWait()
Cancels the currently running co_routine, while blocking to wait for it to complete.
DCA_INLINE return_type cancel()
Cancels the currently executing co_routine and returns the current result.
DCA_INLINE co_routine_status getStatus()
Collects the status of the co_routine.
DCA_INLINE co_routine_status getStatus()
Collects the status 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...
DCA_INLINE unique_ptr< value_type, deleter > makeUnique(arg_types &&... args)
Helper function to create a unique_ptr for a non-array object.
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.
DCA_INLINE dca_exception(jsonifier::string_view error, std::source_location location=std::source_location::current())
Constructor to create a dca_exception with an error message and optional source location.