AUI Framework  develop
Cross-platform base for C++ UI apps
Loading...
Searching...
No Matches
AFuture.h
    1/*
    2 * AUI Framework - Declarative UI toolkit for modern C++20
    3 * Copyright (C) 2020-2025 Alex2772 and Contributors
    4 *
    5 * SPDX-License-Identifier: MPL-2.0
    6 *
    7 * This Source Code Form is subject to the terms of the Mozilla Public
    8 * License, v. 2.0. If a copy of the MPL was not distributed with this
    9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
   10 */
   11
   12#pragma once
   13
   14#include <exception>
   15#include <thread>
   16#include <utility>
   17#include "AUI/Traits/concepts.h"
   18#include "AUI/Util/ABitField.h"
   19#if AUI_COROUTINES
   20#include <coroutine>
   21#endif
   22
   23#include <atomic>
   24#include <functional>
   25#include <optional>
   26#include "AConditionVariable.h"
   27#include "AMutex.h"
   28#include <AUI/Common/SharedPtrTypes.h>
   29#include <AUI/Common/AString.h>
   30#include <AUI/Common/AException.h>
   31#include <AUI/Logging/ALogger.h>
   32#include <AUI/Reflect/AReflect.h>
   33
   34class AThreadPool;
   35
   36
   37class AInvocationTargetException: public AException {
   38
   39public:
   40    AInvocationTargetException(const AString& message = {}, std::exception_ptr causedBy = std::current_exception()):
   41        AException(message, std::move(causedBy), AStacktrace::capture(3)) {}
   42
   43
   44    ~AInvocationTargetException() noexcept override = default;
   45};
   46
   47
   52AUI_ENUM_FLAG(AFutureWait) {
   53    JUST_WAIT = 0b00,
   54    ALLOW_STACKFUL_COROUTINES = 0b10,
   55
   59    ALLOW_TASK_EXECUTION_IF_NOT_PICKED_UP = 0b01,
   60    DEFAULT = ALLOW_STACKFUL_COROUTINES | ALLOW_TASK_EXECUTION_IF_NOT_PICKED_UP,
   61};
   62
   63
   64namespace aui::impl::future {
   69    template<typename Inner>
   70    struct CancellationWrapper {
   71
   72        explicit CancellationWrapper(_unique<Inner> wrapped) : wrapped(std::move(wrapped)) {}
   73
   74        ~CancellationWrapper() {
   75            wrapped->cancel();
   76            wrapped->waitForTask();
   77        }
   78
   79        [[nodiscard]]
   80        const _unique<Inner>& ptr() noexcept {
   81            return wrapped;
   82        }
   83
   84        Inner* operator->() const noexcept {
   85            return wrapped.get();
   86        }
   87
   88    private:
   89        _unique<Inner> wrapped;
   90    };
   91
   92    template<typename T>
   93    struct OnSuccessCallback {
   94        using type = std::function<void(const T& value)>;
   95    };
   96
   97    template<typename T>
   98    struct FutureReturnType {
   99        using type = T&;
  100    };
  101
  102    template<>
  103    struct FutureReturnType<void> {
  104        using type = void;
  105    };
  106
  107
  108    template<>
  109    struct OnSuccessCallback<void> {
  110        using type = std::function<void()>;
  111    };
  112    template<typename Value = void>
  113    class Future
  114    {
  115    public:
  116        static constexpr bool isVoid = std::is_same_v<void, Value>;
  117        using TaskCallback = std::function<Value()>;
  118
  119        using OnSuccessCallback = typename OnSuccessCallback<Value>::type;
  120
  121        struct Inner {
  122            bool interrupted = false;
  126            std::conditional_t<isVoid, bool, AOptional<Value>> value;
  127            AOptional<AInvocationTargetException> exception;
  132            ASpinlockMutex mutex;
  133            AConditionVariable cv;
  134            TaskCallback task;
  135            OnSuccessCallback onSuccess;
  136            std::function<void(const AException& exception)> onError;
  137            _<AAbstractThread> thread;
  138            bool cancelled = false;
  139
  140            explicit Inner(std::function<Value()> task) noexcept: task(std::move(task)) {
  141                if constexpr(isVoid) {
  142                    value = false;
  143                }
  144            }
  145
  146            void waitForTask() noexcept {
  147                std::unique_lock lock(mutex);
  148                bool rethrowInterrupted = false;
  149                while ((thread) && !hasResult() && !cancelled) {
  150                    try {
  151                        cv.wait(lock);
  152                    } catch (const AThread::Interrupted&) {
  153                        rethrowInterrupted = true;
  154                    }
  155                }
  156                if (rethrowInterrupted) {
  157                    AThread::current()->interrupt();
  158                }
  159            }
  160
  161            [[nodiscard]]
  162            bool isWaitNeeded() noexcept {
  163                return (thread || !cancelled) && !hasResult();
  164            }
  165
  166            [[nodiscard]]
  167            bool hasResult() const noexcept {
  168                return value || exception || interrupted;
  169            }
  170
  171            [[nodiscard]]
  172            bool hasValue() const noexcept {
  173                return bool(value);
  174            }
  175
  176            bool setThread(_<AAbstractThread> thr) noexcept {
  177                std::unique_lock lock(mutex);
  178                if (cancelled) return true;
  179                if (thread) return true;
  180                thread = std::move(thr);
  181                return false;
  182            }
  183
  184            void wait(const _weak<CancellationWrapper<Inner>>& innerWeak, ABitField<AFutureWait> flags = AFutureWait::DEFAULT) noexcept;
  185
  186            void cancel() noexcept {
  187                std::unique_lock lock(mutex);
  188                if (!cancelled) {
  189                    cancelled = true;
  190                    if (thread && !hasResult()) {
  191                        thread->interrupt();
  192                    }
  193                }
  194            }
  195
  202            bool tryExecute(const _weak<CancellationWrapper<Inner>>& innerWeak) {
  203                /*
  204                 * We should assume that this == nullptr or invalid.
  205                 * We can assert that this pointer is safe only if we hold at least one shared_ptr.
  206                 * It allows callers to pass a weak_ptr in any state.
  207                 */
  208                if (auto innerCancellation = innerWeak.lock()) {
  209                    if (value) return false;
  210                    auto& inner = innerCancellation->ptr();
  211                    if (inner->setThread(AThread::current())) return false;
  212                    try {
  213                        if (task == nullptr) { // task is executed in wait() function
  214                            return false;
  215                        }
  216                        std::unique_lock lock(mutex);
  217                        if (task == nullptr) { // task is executed in wait() function
  218                            return false;
  219                        }
  220                        auto func = std::move(task);
  221                        AUI_ASSERT(bool(func));
  222                        lock.unlock();
  223                        innerCancellation = nullptr;
  224                        if constexpr(isVoid) {
  225                            func();
  226                            if (auto sharedPtrLock = innerWeak.lock()) {
  227                                lock.lock();
  228                                value = true;
  229                                cv.notify_all();
  230                                notifyOnSuccessCallback(lock);
  231
  232                                (void)sharedPtrLock; // sharedPtrLock is *used*
  233                                if (lock.owns_lock()) lock.unlock(); // unlock earlier because destruction of shared_ptr may cause deadlock
  234                            }
  235                        } else {
  236                            auto result = func();
  237                            if (auto sharedPtrLock = innerWeak.lock()) {
  238                                lock.lock();
  239                                value = std::move(result);
  240                                cv.notify_all();
  241                                notifyOnSuccessCallback(lock);
  242
  243                                (void)sharedPtrLock; // sharedPtrLock is *used*
  244                                if (lock.owns_lock()) lock.unlock(); // unlock earlier because destruction of shared_ptr may cause deadlock
  245                            }
  246                        }
  247                    } catch (const AThread::Interrupted&) {
  248                        if (auto sharedPtrLock = innerWeak.lock()) {
  249                            inner->reportInterrupted();
  250                        }
  251                        throw;
  252                    } catch (...) {
  253                        if (auto sharedPtrLock = innerWeak.lock()) {
  254                            inner->reportException();
  255                        }
  256                        return false;
  257                    }
  258                }
  259                return true;
  260            }
  261
  262            void reportInterrupted() noexcept {
  263                std::unique_lock lock(mutex);
  264                interrupted = true;
  265                cv.notify_all();
  266            }
  267
  268            void reportException(std::exception_ptr causedBy = std::current_exception()) noexcept {
  269                if (cancelled) {
  270                    return;
  271                }
  272                std::unique_lock lock(mutex);
  273                exception.emplace("exception reported", std::move(causedBy));
  274                cv.notify_all();
  275                if (!onError) {
  276                    return;
  277                }
  278                auto localOnError = std::move(onError);
  279                lock.unlock();
  280                localOnError(*exception);
  281            }
  282
  283
  293            void notifyOnSuccessCallback(std::unique_lock<decltype(mutex)>& lock) noexcept {
  294                AUI_ASSERT(lock.owns_lock());
  295                if (cancelled) {
  296                    return;
  297                }
  298                if (value && onSuccess) {
  299                    auto localOnSuccess = std::move(onSuccess);
  300                    onSuccess = nullptr;
  301                    lock.unlock();
  302                    invokeOnSuccessCallback(localOnSuccess);
  303                }
  304            }
  305
  306            template<typename F>
  307            void invokeOnSuccessCallback(F&& f) {
  308                try {
  309                    if constexpr (isVoid) {
  310                        f();
  311                    } else {
  312                        f(*value);
  313                    }
  314                } catch (const AException& e) {
  315                    ALogger::err("AFuture") << "AFuture onSuccess thrown an exception: " << e;
  316                }
  317            }
  318
  319            template<typename Callback>
  320            void addOnSuccessCallback(Callback&& callback) {
  321                if constexpr (isVoid) {
  322                    if (onSuccess) {
  323                        onSuccess = [prev = std::move(onSuccess),
  324                                     callback = std::forward<Callback>(callback)]() mutable {
  325                            prev();
  326                            callback();
  327                        };
  328                    } else {
  329                        onSuccess = [callback = std::forward<Callback>(callback)]() mutable { callback(); };
  330                    }
  331                } else {
  332                    if (onSuccess) {
  333                        onSuccess = [prev = std::move(onSuccess),
  334                                     callback = std::forward<Callback>(callback)](const Value& v) mutable {
  335                            prev(v);
  336                            callback(v);
  337                        };
  338                    } else {
  339                        onSuccess = [callback = std::forward<Callback>(callback)](const Value& v) mutable {
  340                            callback(v);
  341                        };
  342                    }
  343                }
  344            }
  345
  346            template<typename Callback>
  347            void addOnErrorCallback(Callback&& callback) {
  348                if (onError) {
  349                    onError = [prev = std::move(onError),
  350                               callback = std::forward<Callback>(callback)](const AException& v) {
  351                        prev(v);
  352                        callback(v);
  353                    };
  354                } else {
  355                    onError = [callback = std::forward<Callback>(callback)](const AException& v) { callback(v); };
  356                }
  357            }
  358        };
  359
  360#if AUI_COROUTINES
  364        struct CoPromiseType;
  365#endif
  366
  367    protected:
  368        _<CancellationWrapper<Inner>> mInner;
  369
  370
  371    public:
  376        Future(TaskCallback task = nullptr): mInner(_new<CancellationWrapper<Inner>>((_unique<Inner>)(new Inner(std::move(task))))) {}
  377
  378        [[nodiscard]]
  379        const _<CancellationWrapper<Inner>>& inner() const noexcept {
  380            return mInner;
  381        }
  382
  386        [[nodiscard]]
  387        bool isWaitNeeded() const noexcept {
  388            return (*mInner)->isWaitNeeded();
  389        }
  390
  394        [[nodiscard]]
  395        bool hasResult() const noexcept {
  396            return (*mInner)->hasResult();
  397        }
  398
  403        [[nodiscard]]
  404        bool hasValue() const noexcept {
  405            return (*mInner)->hasValue();
  406        }
  407
  408        void reportException() const noexcept {
  409            (*mInner)->reportException();
  410        }
  411
  412        template<typename Callback>
  413        void onSuccess(Callback&& callback) const {
  414            if (hasValue()) { // cheap lookahead
  415                (*mInner)->invokeOnSuccessCallback(std::forward<Callback>(callback));
  416                return;
  417            }
  418            std::unique_lock lock((*mInner)->mutex);
  419            if (hasValue()) { // not so cheap, but cheapier than adding the callback to inner
  420                (*mInner)->invokeOnSuccessCallback(std::forward<Callback>(callback));
  421                return;
  422            }
  423            (*mInner)->addOnSuccessCallback(std::forward<Callback>(callback));
  424        }
  425
  426        template<aui::invocable<const AException&> Callback>
  427        void onError(Callback&& callback) const {
  428            std::unique_lock lock((*mInner)->mutex);
  429            (*mInner)->addOnErrorCallback(std::forward<Callback>(callback));
  430        }
  431
  435        template<aui::invocable Callback>
  436        void onFinally(Callback&& callback) const {
  437            std::unique_lock lock((*mInner)->mutex);
  438            (*mInner)->addOnSuccessCallback([callback](const auto&...) { callback(); });
  439            (*mInner)->addOnErrorCallback([callback = std::move(callback)](const auto&...) { callback(); });
  440            (*mInner)->notifyOnSuccessCallback(lock);
  441        }
  442
  452        void cancel() const noexcept {
  453            (*mInner)->cancel();
  454        }
  455
  456        void reportInterrupted() const {
  457            (*mInner)->reportInterrupted();
  458        }
  459
  465        void wait(AFutureWait flags = AFutureWait::DEFAULT) const {
  466            (*mInner)->wait(mInner, flags);
  467            checkForSelfWait();
  468        }
  469
  478        typename FutureReturnType<Value>::type get(AFutureWait flags = AFutureWait::DEFAULT) const {
  479            AThread::interruptionPoint();
  480
  481            (*mInner)->wait(mInner, flags);
  482
  483            AThread::interruptionPoint();
  484            if ((*mInner)->exception) {
  485                throw *(*mInner)->exception;
  486            }
  487            if ((*mInner)->interrupted) {
  488                throw AInvocationTargetException("Future execution interrupted");
  489            }
  490            checkForSelfWait();
  491            if constexpr(!isVoid) {
  492                return *(*mInner)->value;
  493            }
  494        }
  495
  496
  505        typename FutureReturnType<Value>::type operator*() const {
  506            return **const_cast<Future*>(this);
  507        }
  508
  517        typename FutureReturnType<Value>::type operator*() {
  518            return get();
  519        }
  520
  529        Value* operator->() const {
  530            return &operator*();
  531        }
  532
  533    private:
  534        void checkForSelfWait() const {
  535            if (!(*mInner)->hasResult() && AThread::current() == (*mInner)->thread) {
  536                throw AException("self wait?");
  537            }
  538        }
  539    };
  540
  541}
  542
  543
  620template<typename T = void>
  621class AFuture final: public aui::impl::future::Future<T> {
  622private:
  623    using super = typename aui::impl::future::Future<T>;
  624
  625public:
  626    using Task = typename super::TaskCallback;
  627#if AUI_COROUTINES
  628    using promise_type = typename super::CoPromiseType;
  629#endif
  631
  632    explicit AFuture(T immediateValue): super() {
  633        auto& inner = (*super::mInner);
  634        inner->value = std::move(immediateValue);
  635    }
  636    AFuture(Task task = nullptr) noexcept: super(std::move(task)) {}
  637    ~AFuture() = default;
  638
  639    AFuture(const AFuture&) = default;
  640    AFuture(AFuture&&) noexcept = default;
  641
  642    AFuture& operator=(const AFuture&) = default;
  643    AFuture& operator=(AFuture&&) noexcept = default;
  644
  651    void supplyValue(T v) const noexcept {
  652        auto& inner = (*super::mInner);
  653        AUI_ASSERTX(inner->task == nullptr, "task is already provided");
  654
  655        std::unique_lock lock(inner->mutex);
  656        inner->value = std::move(v);
  657        inner->cv.notify_all();
  658        inner->notifyOnSuccessCallback(lock);
  659    }
  660
  664    void supplyException(std::exception_ptr causedBy = std::current_exception()) const noexcept {
  665        auto& inner = (*super::mInner);
  666        inner->reportException(std::move(causedBy));
  667    }
  668
  669    AFuture& operator=(std::nullptr_t) noexcept {
  670        super::mInner = nullptr;
  671        return *this;
  672    }
  673
  674    [[nodiscard]]
  675    bool operator==(std::nullptr_t) const noexcept {
  676        return super::mInner == nullptr;
  677    }
  678
  679    [[nodiscard]]
  680    bool operator!=(std::nullptr_t) const noexcept {
  681        return super::mInner != nullptr;
  682    }
  683
  684    [[nodiscard]]
  685    bool operator==(const AFuture& r) const noexcept {
  686        return super::mInner == r.mInner;
  687    }
  688
  708    template<aui::invocable<const T&> Callback>
  709    const AFuture& onSuccess(Callback&& callback) const noexcept {
  710        super::onSuccess(std::forward<Callback>(callback));
  711        return *this;
  712    }
  713
  733    template<aui::invocable<const AException&> Callback>
  734    const AFuture& onError(Callback&& callback) const noexcept {
  735        super::onError(std::forward<Callback>(callback));
  736        return *this;
  737    }
  738
  742    template<aui::invocable Callback>
  743    const AFuture& onFinally(Callback&& callback) const noexcept {
  744        super::onFinally(std::forward<Callback>(callback));
  745        return *this;
  746    }
  747
  751    template<aui::invocable<const T&> Callback>
  752    auto map(Callback&& callback) -> AFuture<decltype(callback(std::declval<T>()))> const {
  753        AFuture<decltype(callback(std::declval<T>()))> result;
  754        onSuccess([result, callback = std::forward<Callback>(callback)](const T& v) {
  755            result.supplyValue(callback(v));
  756        });
  757        onError([result](const AException& v) {
  758            try {
  759                throw v;
  760            } catch (...) {
  761                result.reportException();
  762            }
  763        });
  764        return result;
  765    }
  766};
  767
  768template<>
  769class AFuture<void> final: public aui::impl::future::Future<void> {
  770private:
  771    using T = void;
  772    using super = typename aui::impl::future::Future<T>;
  773
  774public:
  775    using Task = typename super::TaskCallback;
  776#if AUI_COROUTINES
  777    using promise_type = typename super::CoPromiseType;
  778#endif
  779    using Inner = decltype(std::declval<super>().inner());
  780
  781    AFuture(Task task = nullptr) noexcept: super(std::move(task)) {}
  782    ~AFuture() = default;
  783
  784    AFuture(const AFuture&) = default;
  785    AFuture(AFuture&&) noexcept = default;
  786
  787    AFuture& operator=(const AFuture&) = default;
  788    AFuture& operator=(AFuture&&) noexcept = default;
  789
  793    void supplyException(std::exception_ptr causedBy = std::current_exception()) const noexcept {
  794        auto& inner = (*super::mInner);
  795        inner->reportException(std::move(causedBy));
  796    }
  797
  803    void supplyValue() const noexcept {
  804        auto& inner = (*super::mInner);
  805        AUI_ASSERTX(inner->task == nullptr, "task is already provided");
  806
  807        std::unique_lock lock(inner->mutex);
  808        inner->value = true;
  809        inner->cv.notify_all();
  810        inner->notifyOnSuccessCallback(lock);
  811    }
  812
  813    AFuture& operator=(std::nullptr_t) noexcept {
  814        super::mInner = nullptr;
  815        return *this;
  816    }
  817
  818    [[nodiscard]]
  819    bool operator==(std::nullptr_t) const noexcept {
  820        return super::mInner == nullptr;
  821    }
  822
  823    [[nodiscard]]
  824    bool operator!=(std::nullptr_t) const noexcept {
  825        return super::mInner != nullptr;
  826    }
  827
  828    [[nodiscard]]
  829    bool operator==(const AFuture& r) const noexcept {
  830        return super::mInner == r.mInner;
  831    }
  832
  852    template<aui::invocable Callback>
  853    const AFuture& onSuccess(Callback&& callback) const {
  854        super::onSuccess(std::forward<Callback>(callback));
  855        return *this;
  856    }
  857
  877    template<aui::invocable<const AException&> Callback>
  878    const AFuture& onError(Callback&& callback) const {
  879        super::onError(std::forward<Callback>(callback));
  880        return *this;
  881    }
  882
  886    template<aui::invocable Callback>
  887    const AFuture& onFinally(Callback&& callback) const {
  888        super::onFinally(std::forward<Callback>(callback));
  889        return *this;
  890    }
  891};
  892
  893
  894#include <AUI/Thread/AThreadPool.h>
  895#include <AUI/Common/AException.h>
  896
  897template <typename Value>
  898void aui::impl::future::Future<Value>::Inner::wait(const _weak<CancellationWrapper<Inner>>& innerWeak,
  899                                                   ABitField<AFutureWait> flags) noexcept {
  900    if (hasResult()) return; // cheap check
  901    std::unique_lock lock(mutex);
  902    try {
  903        if ((thread || !cancelled) && !hasResult() && flags & AFutureWait::ALLOW_TASK_EXECUTION_IF_NOT_PICKED_UP && task) {
  904            // task is not have picked up by the threadpool; execute it here
  905            lock.unlock();
  906            if (tryExecute(innerWeak)) {
  907                return;
  908            }
  909            lock.lock();
  910        }
  911
  912        if (flags & AFutureWait::ALLOW_STACKFUL_COROUTINES) {
  913            if (auto threadPoolWorker = _cast<AThreadPool::Worker>(AThread::current())) {
  914                if (hasResult()) return; // for sure
  915                AUI_ASSERT(lock.owns_lock());
  916                auto callback = [threadPoolWorker](auto&&...) {
  917                    threadPoolWorker->threadPool().wakeUpAll();
  918                };
  919                addOnSuccessCallback(callback);
  920                addOnErrorCallback(callback);
  921
  922                threadPoolWorker->loop([&] {
  923                  if (lock.owns_lock())
  924                    lock.unlock();
  925                  return !hasResult();
  926                });
  927
  928                return;
  929            }
  930        }
  931        while ((thread || !cancelled) && !hasResult()) {
  932            if (thread == AThread::current()) [[unlikely]] {
  933                // self wait?
  934                return;
  935            }
  936            cv.wait(lock);
  937        }
  938    } catch (const AThread::Interrupted& e) {
  939        e.needRethrow();
  940    }
  941}
  942
  943#if AUI_COROUTINES
  944template<typename Value>
  945struct aui::impl::future::Future<Value>::CoPromiseType {
  946    AFuture<Value> future;
  947    auto initial_suspend() const noexcept
  948    {
  949        return std::suspend_never{};
  950    }
  951
  952    auto final_suspend() const noexcept
  953    {
  954        return std::suspend_never{};
  955    }
  956    auto unhandled_exception() const noexcept {
  957        future.supplyException();
  958    }
  959
  960    const AFuture<Value>& get_return_object() const noexcept {
  961        return future;
  962    }
  963
  964    void return_value(Value v) const noexcept {
  965        future.supplyValue(std::move(v));
  966    }
  967};
  968
  969template<typename T>
  970auto operator co_await(AFuture<T> future) {
  971    struct Awaitable {
  972        AFuture<T> future;
  973
  974        bool await_ready() const noexcept {
  975            return future.hasResult();
  976        }
  977
  978        T await_resume() {
  979            return *future;
  980        }
  981
  982
  983        void await_suspend(std::coroutine_handle<> h)
  984        {
  985            future.onSuccess([h](const int&) {
  986                h.resume();
  987            });
  988            
  989            future.onError([h](const AException&) {
  990                h.resume();
  991            });
  992        }
  993    };
  994
  995    return Awaitable{ std::move(future) };
  996}
  997#endif
Bit field implementation.
Definition ABitField.h:20
Represents a condition variable.
Definition AConditionVariable.h:24
void notify_all() noexcept
Definition AConditionVariable.h:62
Abstract AUI exception.
Definition AException.h:28
Represents a value that will be available at some point in the future.
Definition AFuture.h:621
const AFuture & onError(Callback &&callback) const
Add onSuccess callback to the future.
Definition AFuture.h:878
const AFuture & onSuccess(Callback &&callback) const noexcept
Add onSuccess callback to the future.
Definition AFuture.h:709
const AFuture & onFinally(Callback &&callback) const
Adds the callback to both onSuccess and onResult.
Definition AFuture.h:887
const AFuture & onError(Callback &&callback) const noexcept
Add onError callback to the future.
Definition AFuture.h:734
void supplyException(std::exception_ptr causedBy=std::current_exception()) const noexcept
Stores an exception from std::current_exception to the future.
Definition AFuture.h:793
auto map(Callback &&callback) -> AFuture< decltype(callback(std::declval< T >()))> const
Maps this AFuture to another type of AFuture.
Definition AFuture.h:752
void supplyValue(T v) const noexcept
Pushes the result to AFuture.
Definition AFuture.h:651
const AFuture & onSuccess(Callback &&callback) const
Add onSuccess callback to the future.
Definition AFuture.h:853
void supplyException(std::exception_ptr causedBy=std::current_exception()) const noexcept
Stores an exception from std::current_exception to the future.
Definition AFuture.h:664
const AFuture & onFinally(Callback &&callback) const noexcept
Adds the callback to both onSuccess and onResult.
Definition AFuture.h:743
void supplyValue() const noexcept
Pushes "success" result.
Definition AFuture.h:803
Definition AFuture.h:37
Utility wrapper implementing the stack-allocated (fast) optional idiom.
Definition AOptional.h:33
Synchronization primitive that is implemented with atomic values instead of doing syscalls.
Definition AMutex.h:65
static AStacktrace capture(unsigned skipFrames=0, unsigned maxFrames=128) noexcept
Creates stacktrace of the current thread.
Represents a Unicode character string.
Definition AString.h:38
Thread pool implementation.
Definition AThreadPool.h:33
Exception that is thrown by AThread::interruptionPoint(), if interruption is requested for this threa...
Definition AThread.h:175
void needRethrow() const noexcept
Schedules AThread::Interrupted exception to the next interruption point. Sometimes you could not thro...
Definition AThread.h:182
static void interruptionPoint()
Interruption point.
static _< AAbstractThread > current()
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:179
Definition AFuture.h:114
bool isWaitNeeded() const noexcept
Definition AFuture.h:387
bool hasValue() const noexcept
Definition AFuture.h:404
FutureReturnType< Value >::type operator*()
Returns the supplyValue from the another thread. Sleeps if the supplyValue is not currently available...
Definition AFuture.h:517
void onFinally(Callback &&callback) const
Adds the callback to both onSuccess and onResult.
Definition AFuture.h:436
Value * operator->() const
Returns the supplyValue from the another thread. Sleeps if the supplyValue is not currently available...
Definition AFuture.h:529
void cancel() const noexcept
Cancels the AFuture's task.
Definition AFuture.h:452
void wait(AFutureWait flags=AFutureWait::DEFAULT) const
Sleeps if the supplyValue is not currently available.
Definition AFuture.h:465
bool hasResult() const noexcept
Definition AFuture.h:395
Future(TaskCallback task=nullptr)
Definition AFuture.h:376
FutureReturnType< Value >::type get(AFutureWait flags=AFutureWait::DEFAULT) const
Returns the supplyValue from the another thread. Sleeps if the supplyValue is not currently available...
Definition AFuture.h:478
FutureReturnType< Value >::type operator*() const
Returns the task result from the another thread. Sleeps if the task result is not currently available...
Definition AFuture.h:505
#define AUI_ENUM_FLAG(name)
Make a bitfield-style enum class.
Definition AEnumerate.h:227
#define AUI_ASSERT(condition)
Asserts that the passed condition evaluates to true.
Definition Assert.h:55
#define AUI_ASSERTX(condition, what)
Asserts that the passed condition evaluates to true. Adds extra message string.
Definition Assert.h:74
@ DEFAULT
There's no concrete input action. Let the OS decide which action is the most appropriate.
Definition ATextInputActionIcon.h:36
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:52
Definition AFuture.h:121
std::conditional_t< isVoid, bool, AOptional< Value > > value
Definition AFuture.h:126
void notifyOnSuccessCallback(std::unique_lock< decltype(mutex)> &lock) noexcept
Calls onSuccess callback.
Definition AFuture.h:293
bool tryExecute(const _weak< CancellationWrapper< Inner > > &innerWeak)
Executes the task stored in the future. Using weak_ptr to internal object in order to make possible F...
Definition AFuture.h:202
ASpinlockMutex mutex
Definition AFuture.h:132