Index: source/ps/Future.h =================================================================== --- source/ps/Future.h +++ source/ps/Future.h @@ -22,7 +22,6 @@ #include #include -#include #include #include @@ -85,16 +84,16 @@ }; /** - * The shared state between futures and packaged state. - * Holds all relevant data. + * The Receiver is responsible for comunicating the result back to the thread + * which is waiting on it. */ template -class SharedState final : public SharedStateResult, public ErasedSharedState +class Receiver : public SharedStateResult { static constexpr bool VoidResult = std::is_same_v; public: - SharedState(std::function&& func) : m_Func(std::move(func)) {} - ~SharedState() + Receiver() = default; + ~Receiver() { // For safety, wait on started task completion, but not on pending ones (auto-cancelled). if (!Cancel()) @@ -106,21 +105,20 @@ SharedStateResult::ResetResult(); } - SharedState(const SharedState&) = delete; - SharedState(SharedState&&) = delete; - - void operator()() final + template + void Execute(Fun&& function) { Status expected = Status::PENDING; if (!m_Status.compare_exchange_strong(expected, Status::STARTED)) return; if constexpr (VoidResult) - m_Func(); + std::forward(function)(); else { // To avoid UB, explicitly placement-new the value. - new (&SharedStateResult::m_Result.m_Result) ResultType{m_Func()}; + new (&SharedStateResult::m_Result.m_Result) ResultType{ + std::forward(function)()}; SharedStateResult::m_HasResult = true; } @@ -188,8 +186,33 @@ std::atomic m_Status = Status::PENDING; std::mutex m_Mutex; std::condition_variable m_ConditionVariable; +}; + +/** + * The SharedState has to stay alive untill the task is finished. + */ +template +class SharedState final : public ErasedSharedState +{ +public: + SharedState(Fun&& fun) : + m_Fun{std::forward(fun)} + {} + ~SharedState() = default; - std::function m_Func; + void operator()() final + { + m_Recv.Execute(std::forward(m_Fun)); + } + + Receiver>& GetReceiver() noexcept + { + return m_Recv; + } + +private: + Fun m_Fun; + Receiver> m_Recv; }; } // namespace FutureSharedStateDetail @@ -213,7 +236,6 @@ static constexpr bool VoidResult = std::is_same_v; using Status = FutureSharedStateDetail::Status; - using SharedState = FutureSharedStateDetail::SharedState; public: Future() = default; Future(const Future& o) = delete; @@ -235,17 +257,17 @@ template std::enable_if_t, ResultType> Get() { - ENSURE(!!m_SharedState); + ENSURE(!!m_Receiver); Wait(); if constexpr (VoidResult) return; else { - ENSURE(m_SharedState->m_Status != Status::CANCELED); + ENSURE(m_Receiver->m_Status != Status::CANCELED); // This mark the state invalid - can't call Get again. - return m_SharedState->GetResult(); + return m_Receiver->GetResult(); } } @@ -254,7 +276,7 @@ */ bool IsReady() const { - return !!m_SharedState && m_SharedState->m_Status == Status::DONE; + return !!m_Receiver && m_Receiver->m_Status == Status::DONE; } /** @@ -262,13 +284,13 @@ */ bool Valid() const { - return !!m_SharedState && m_SharedState->m_Status != Status::CANCELED; + return !!m_Receiver && m_Receiver->m_Status != Status::CANCELED; } void Wait() { if (Valid()) - m_SharedState->Wait(); + m_Receiver->Wait(); } /** @@ -280,9 +302,9 @@ { if (!Valid()) return; - if (!m_SharedState->Cancel()) - m_SharedState->Wait(); - m_SharedState.reset(); + if (!m_Receiver->Cancel()) + m_Receiver->Wait(); + m_Receiver.reset(); } /** @@ -292,12 +314,13 @@ */ void Cancel() { - if (m_SharedState) - m_SharedState->Cancel(); - m_SharedState.reset(); + if (m_Receiver) + m_Receiver->Cancel(); + m_Receiver.reset(); } -protected: - std::shared_ptr m_SharedState; +private: + // Points to the Receiver but manages lifetime of the whole SharedState. + std::shared_ptr> m_Receiver; }; /** @@ -329,8 +352,10 @@ { static_assert(std::is_same_v, ResultType>, "The return type of the wrapped function is not the same as the type of the Future."); - m_SharedState = std::make_shared(std::move(func)); - return PackagedTask{m_SharedState}; + auto sharedState = std::make_shared>(std::forward(func)); + m_Receiver = std::shared_ptr>>{sharedState, + &sharedState->GetReceiver()}; + return PackagedTask{std::move(sharedState)}; } #endif // INCLUDED_FUTURE