AUI Framework  develop
Cross-platform base for C++ UI apps
Loading...
Searching...
No Matches
AAsyncHolder.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 "AFuture.h"
   15#include <any>
   16#include <list>
   17
   18
   31class AAsyncHolder {
   32public:
   33    AAsyncHolder() = default;
   34    ~AAsyncHolder() {
   35        std::unique_lock lock(mSync);
   36
   37        while (!mFutureSet.empty()) {
   38            auto l = std::move(mFutureSet.last());
   39            mFutureSet.pop_back();
   40            lock.unlock();
   41            l.cancel();
   42            l.wait();
   43            l = nullptr;
   44            lock.lock();
   45        }
   46
   47        while (!mCustomTypeFutures.empty()) {
   48            auto l = std::move(mCustomTypeFutures.back());
   49            mCustomTypeFutures.pop_back();
   50            lock.unlock();
   51            l->cancelAndWait();
   52            l = nullptr;
   53            lock.lock();
   54        }
   55        mDead = true;
   56    }
   57
   58    template<typename T>
   59    AAsyncHolder& operator<<(AFuture<T> future) {
   60        std::unique_lock lock(mSync);
   61        if constexpr (std::is_same_v<void, T>) {
   62            auto impl = future.inner().get();
   63            mFutureSet << future;
   64            lock.unlock();
   65            future.onSuccess([this, impl]() {
   66                std::unique_lock lock(mSync);
   67                mFutureSet.removeIf([&](const AFuture<>& f) {
   68                    return f.inner().get() == impl;
   69                });
   70            });
   71        } else {
   72            auto uniquePtr = std::make_unique<Future<T>>(future);
   73            auto it = mCustomTypeFutures.insert(mCustomTypeFutures.end(), std::move(uniquePtr));
   74
   75            lock.unlock();
   76
   77            future.onSuccess([this, it](const T& result) {
   78                AUI_ASSERTX(!mDead, "you have concurrency issues");
   79                std::unique_lock lock(mSync);
   80                AUI_ASSERT(!mCustomTypeFutures.empty());
   81                mCustomTypeFutures.erase(it);
   82            });
   83        }
   84        return *this;
   85    }
   86
   87    [[nodiscard]]
   88    std::size_t size() const {
   89        std::unique_lock lock(mSync);
   90        return mFutureSet.size();
   91    }
   92
   93    void waitForAll() {
   94        std::unique_lock lock(mSync);
   95        if (!mFutureSet.empty()) {
   96            waitAgain:
   97            auto futureSet = std::move(mFutureSet);
   98            lock.unlock();
   99            futureSet.waitForAll();
  100            lock.lock();
  101            if (mFutureSet.empty()) {
  102                mFutureSet = std::move(futureSet);
  103            } else {
  104                mFutureSet.insertAll(futureSet);
  105                goto waitAgain;
  106            }
  107        }
  108
  109        while (!mCustomTypeFutures.empty()) {
  110            mCustomTypeFutures.front()->wait(lock);
  111        }
  112    }
  113
  114private:
  115    struct IFuture {
  116        virtual ~IFuture() = default;
  117        virtual void get() = 0;
  118        virtual void wait(std::unique_lock<AMutex>& lock) = 0;
  119        virtual void cancelAndWait() = 0;
  120    };
  121    bool mDead = false;
  122
  123    template<typename T>
  124    struct Future: IFuture {
  125        void get() override {
  126            mFuture.cancel();
  127            *mFuture;
  128        }
  129        void wait(std::unique_lock<AMutex>& lock) override {
  130            auto copy = mFuture;
  131            lock.unlock();
  132            copy.wait();
  133            lock.lock();
  134        }
  135
  136        void cancelAndWait() override {
  137            mFuture.cancel();
  138            mFuture.wait();
  139        }
  140
  141        ~Future() override = default;
  142
  143        Future(AFuture<T> future) : mFuture(std::move(future)) {}
  144
  145    private:
  146        AFuture<T> mFuture;
  147    };
  148
  149
  150    mutable AMutex mSync;
  151    AFutureSet<> mFutureSet;
  152    std::list<_unique<IFuture>> mCustomTypeFutures;
  153};
Manages multiple futures.
Definition AThreadPool.h:185
Represents a value that will be available at some point in the future.
Definition AFuture.h:621
const AFuture & onSuccess(Callback &&callback) const noexcept
Add onSuccess callback to the future.
Definition AFuture.h:709
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
#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
Basic syscall-based synchronization primitive.
Definition AMutex.h:33