ORIGINAL
Loading...
Searching...
No Matches
async.h
1#ifndef ORIGINAL_ASYNC_H
2#define ORIGINAL_ASYNC_H
3
4#include "atomic.h"
5#include "condition.h"
6#include "optional.h"
7#include "refCntPtr.h"
8#include "thread.h"
9#include <exception>
10#include <functional>
11#include <utility>
12
13namespace original {
14
21 class async {
22 // ==================== Async Wrapper (Internal) ====================
23
30 template<typename TYPE>
31 class asyncWrapper {
32 atomic<bool> ready_{makeAtomic(false)};
33 alternative<TYPE> alter_;
34 pCondition cond_{};
35 mutable pMutex mutex_{};
36 std::exception_ptr e_{};
37
38 public:
39 asyncWrapper();
40
45 void setValue(TYPE&& v);
46
51 void setException(std::exception_ptr e);
52
57 [[nodiscard]] bool ready() const;
58
62 void wait();
63
69 TYPE get();
70
74 void rethrowIfException() const;
75
80 [[nodiscard]] std::exception_ptr exception() const;
81
86 [[nodiscard]] bool available() const;
87 };
88
89 public:
90 // ==================== Future Class ====================
91
99 template<typename TYPE>
100 class future {
102
103 friend class async;
104 explicit future(strongPtr<asyncWrapper<TYPE>> awr);
105
106 public:
107 future() = default;
108
109 // Disable copying
110 future(const future&) = delete;
111 future& operator=(const future&) = delete;
112
113 // Allow moving
114 future(future&&) = default;
115 future& operator=(future&&) = default;
116
122 TYPE result();
123
128 [[nodiscard]] bool ready() const;
129
134 [[nodiscard]] std::exception_ptr exception() const noexcept;
135
139 void wait();
140 };
141
142 // ==================== Promise Class ====================
143
151 template<typename TYPE, typename Callback>
152 class promise {
153 std::function<TYPE()> c_;
155
156 public:
157 promise() = default;
158
163 explicit promise(Callback&& c);
164
170
174 void run();
175 };
176
177 // ==================== Static Factory Methods ====================
178
187 template <typename Callback, typename... Args>
188 static auto makePromise(Callback&& c, Args&&... args);
189
199 template <typename Callback, typename... Args>
200 static auto get(Callback&& c, Args&&... args);
201 };
202
203 // ==================== Void Specializations ====================
204
208 template <>
209 class async::asyncWrapper<void> {
210 atomic<bool> ready_{makeAtomic(false)};
211 alternative<void> alter_;
212 pCondition cond_{};
213 mutable pMutex mutex_{};
214 std::exception_ptr e_{};
215
216 public:
217 asyncWrapper() = default;
218
222 void setValue();
223
228 void setException(std::exception_ptr e);
229
234 [[nodiscard]] bool ready() const;
235
239 void wait();
240
245 void get();
246
250 void rethrowIfException() const;
251
256 [[nodiscard]] std::exception_ptr exception() const noexcept;
257
262 [[nodiscard]] bool available() const;
263 };
264
268 template <>
269 class async::future<void> {
271
272 friend class async;
273 explicit future(const strongPtr<asyncWrapper<void>>& awr) : awr_(std::move(awr)) {}
274
275 public:
276 future() = default;
277
278 // Disable copying
279 future(const future&) = delete;
280 future& operator=(const future&) = delete;
281
282 // Allow moving
283 future(future&&) = default;
284 future& operator=(future&&) = default;
285
290 void result();
291
296 [[nodiscard]] bool ready() const;
297
302 [[nodiscard]] std::exception_ptr exception() const noexcept;
303
307 void wait();
308 };
309
314 template <typename Callback>
315 class async::promise<void, Callback> {
316 std::function<void()> c_;
318
319 public:
320 promise() = default;
321
326 explicit promise(Callback&& c);
327
332 [[nodiscard]] future<void> getFuture() const;
333
337 void run();
338 };
339} // namespace original
340
341template <typename TYPE>
342original::async::asyncWrapper<TYPE>::asyncWrapper() = default;
343
344template <typename TYPE>
345void original::async::asyncWrapper<TYPE>::setValue(TYPE&& v)
346{
347 {
348 uniqueLock lock{this->mutex_};
349 this->alter_.set(std::move(v));
350 this->ready_.store(true);
351 }
352 this->cond_.notify();
353}
354
355template <typename TYPE>
356void original::async::asyncWrapper<TYPE>::setException(std::exception_ptr e)
357{
358 {
359 uniqueLock lock{this->mutex_};
360 this->e_ = std::move(e);
361 this->ready_.store(true);
362 }
363 this->cond_.notify();
364}
365
366template <typename TYPE>
367bool original::async::asyncWrapper<TYPE>::ready() const
368{
369 return this->ready_.load();
370}
371
372template <typename TYPE>
373void original::async::asyncWrapper<TYPE>::wait()
374{
375 uniqueLock lock{this->mutex_};
376 this->cond_.wait(this->mutex_, [this]
377 {
378 return this->ready();
379 });
380}
381
382template <typename TYPE>
383TYPE original::async::asyncWrapper<TYPE>::get()
384{
385 uniqueLock lock{this->mutex_};
386 this->cond_.wait(this->mutex_, [this]{
387 return this->ready();
388 });
389
390 if (this->e_) std::rethrow_exception(this->e_);
391
392 TYPE result = *this->alter_;
393 this->alter_.reset();
394 return result;
395}
396
397template <typename TYPE>
398void original::async::asyncWrapper<TYPE>::rethrowIfException() const
399{
400 if (this->e_)
401 std::rethrow_exception(this->e_);
402}
403
404template <typename TYPE>
405std::exception_ptr
406original::async::asyncWrapper<TYPE>::exception() const
407{
408 uniqueLock lock{this->mutex_};
409 return this->e_;
410}
411
412template <typename TYPE>
413bool original::async::asyncWrapper<TYPE>::available() const
414{
415 uniqueLock lock{this->mutex_};
416 return this->ready() && this->alter_.hasValue();
417}
418
419template <typename TYPE>
420original::async::future<TYPE>::future(strongPtr<asyncWrapper<TYPE>> awr)
421 : awr_(awr) {}
422
423template <typename TYPE>
425{
426 return this->awr_->get();
427}
428
429template <typename TYPE>
431{
432 return this->awr_->ready();
433}
434
435template <typename TYPE>
436std::exception_ptr original::async::future<TYPE>::exception() const noexcept
437{
438 return this->awr_->exception();
439}
440
441template <typename TYPE>
443{
444 this->awr_->wait();
445}
446
447template <typename TYPE, typename Callback>
449 : c_(std::forward<Callback>(c)), awr_(makeStrongPtr<asyncWrapper<TYPE>>()) {}
450
451template <typename TYPE, typename Callback>
457
458template <typename TYPE, typename Callback>
460{
461 try {
462 if constexpr (!std::is_void_v<TYPE>) {
463 this->awr_->setValue(this->c_());
464 } else {
465 this->c_();
466 this->awr_->setValue({});
467 }
468 } catch (...) {
469 this->awr_->setException(std::current_exception());
470 }
471}
472
473template <typename Callback, typename... Args>
474auto original::async::makePromise(Callback&& c, Args&&... args) {
475 using Return = std::invoke_result_t<Callback, Args...>;
476 auto bound = [c = std::forward<Callback>(c),
477 ... args = std::forward<Args>(args)]() mutable -> Return {
478 return c(args...);
479 };
480
481 return promise<Return, decltype(bound)>{std::move(bound)};
482}
483
484template <typename Callback, typename ... Args>
485auto original::async::get(Callback&& c, Args&&... args)
486{
487 using ResultType = std::invoke_result_t<std::decay_t<Callback>, std::decay_t<Args>...>;
488 auto task = [c = std::forward<Callback>(c), ... args = std::forward<Args>(args)]() mutable -> ResultType {
489 return c(std::forward<Args>(args)...);
490 };
491
492 auto p = makePromise(std::move(task));
493 auto fut = p.getFuture();
494
495 thread t{
496 [p = std::move(p)]() mutable {
497 p.run();
498 },
499 };
500
501 return fut.result();
502}
503
504inline void original::async::asyncWrapper<void>::setValue()
505{
506 {
507 uniqueLock lock{this->mutex_};
508 this->alter_.set();
509 this->ready_.store(true);
510 }
511 this->cond_.notify();
512}
513
514inline void original::async::asyncWrapper<void>::setException(std::exception_ptr e)
515{
516 {
517 uniqueLock lock{this->mutex_};
518 this->e_ = std::move(e);
519 this->ready_.store(true);
520 }
521 this->cond_.notify();
522}
523
524inline bool original::async::asyncWrapper<void>::ready() const
525{
526 return this->ready_.load();
527}
528
529inline void original::async::asyncWrapper<void>::wait()
530{
531 uniqueLock lock{this->mutex_};
532 this->cond_.wait(this->mutex_, [this]
533 {
534 return this->ready();
535 });
536}
537
538inline void original::async::asyncWrapper<void>::get()
539{
540 uniqueLock lock{this->mutex_};
541 this->cond_.wait(this->mutex_, [this] {
542 return this->ready();
543 });
544
545 if (this->e_) std::rethrow_exception(this->e_);
546}
547
548inline void original::async::asyncWrapper<void>::rethrowIfException() const
549{
550 if (this->e_)
551 std::rethrow_exception(this->e_);
552}
553
554inline std::exception_ptr
555original::async::asyncWrapper<void>::exception() const noexcept
556{
557 uniqueLock lock{this->mutex_};
558 return this->e_;
559}
560
561inline bool original::async::asyncWrapper<void>::available() const
562{
563 uniqueLock lock{this->mutex_};
564 return this->ready() && this->alter_.hasValue();
565}
566
568{
569 this->awr_->get();
570}
571
573{
574 return this->awr_->ready();
575}
576
577inline std::exception_ptr original::async::future<void>::exception() const noexcept
578{
579 return this->awr_->exception();
580}
581
583{
584 this->awr_->wait();
585}
586
587template <typename Callback>
589 : c_(std::forward<Callback>(c)), awr_(makeStrongPtr<asyncWrapper<void>>()) {}
590
591template <typename Callback>
596
597template <typename Callback>
599{
600 try {
601 this->c_();
602 this->awr_->setValue();
603 } catch (...) {
604 this->awr_->setException(std::current_exception());
605 }
606}
607
608#endif // ORIGINAL_ASYNC_H
A type-safe container that may or may not contain a value.
Definition optional.h:45
Represents a future result of an asynchronous computation.
Definition async.h:100
bool ready() const
Checks if the result is ready.
Definition async.h:430
std::exception_ptr exception() const noexcept
Gets the exception if computation failed.
Definition async.h:436
TYPE result()
Gets the result (blocks until ready)
Definition async.h:424
void wait()
Waits until the result becomes ready.
Definition async.h:442
Represents a promise of a future result.
Definition async.h:152
promise(Callback &&c)
Constructs a promise with a computation callback.
Definition async.h:448
future< TYPE > getFuture()
Gets the future associated with this promise.
Definition async.h:453
void run()
Executes the computation and sets the result.
Definition async.h:459
Asynchronous programming utilities with future/promise pattern.
Definition async.h:21
static auto get(Callback &&c, Args &&... args)
Executes a callable asynchronously and gets the result.
Definition async.h:485
static auto makePromise(Callback &&c, Args &&... args)
Creates a promise from a callable and arguments.
Definition async.h:474
POSIX condition variable implementation.
Definition condition.h:114
POSIX thread mutex implementation.
Definition mutex.h:153
Shared ownership smart pointer with strong references.
Definition refCntPtr.h:108
Concrete task implementation with result type.
Definition tasks.h:43
High-level thread wrapper.
Definition thread.h:263
RAII wrapper for single mutex locking.
Definition mutex.h:216
Condition variable implementation for thread synchronization.
Main namespace for the project Original.
Definition algorithms.h:21
strongPtr< T, DEL > makeStrongPtr(Args &&... args)
Creates a new strongPtr managing a shared object.
Definition refCntPtr.h:633
Type-safe optional value container.
Reference-counted smart pointer hierarchy.
Thread management utilities.