#pragma once #if !defined(MIJIN_ASYNC_FUTURE_HPP_INCLUDED) #define MIJIN_ASYNC_FUTURE_HPP_INCLUDED 1 #include #include #include #include "./signal.hpp" #include "../debug/assert.hpp" #include "../container/optional.hpp" namespace mijin { // // public defines // // // public constants // // // public types // template class Future; // TODO: add support for mutexes and waiting for futures namespace impl { template struct FutureStorage { std::optional value; void setValue(TValue value_) noexcept { value = std::move(value_); } [[nodiscard]] TValue& getValue() noexcept { return value.value(); } }; template struct FutureStorage { std::optional value; void setValue(TValue& value_) noexcept { value = &value_; } [[nodiscard]] TValue& getValue() const noexcept { return *value.value(); } }; template<> struct FutureStorage { }; } // namespace impl template class Future { private: impl::FutureStorage value_; bool isSet_ = false; public: Future() = default; Future(const Future&) = delete; Future(Future&&) noexcept = default; public: Future& operator=(const Future&) = delete; Future& operator=(Future&&) noexcept = default; [[nodiscard]] constexpr explicit operator bool() const noexcept { return ready(); } [[nodiscard]] constexpr bool operator!() const noexcept { return !ready(); } public: // access [[nodiscard]] constexpr decltype(auto) get() noexcept { MIJIN_ASSERT(isSet_, "Attempting to get from future that is not ready."); if constexpr(std::is_same_v) { return; } else { return value_.getValue(); } } [[nodiscard]] constexpr decltype(auto) get() const noexcept { MIJIN_ASSERT(isSet_, "Attempting to get from future that is not ready."); if constexpr(std::is_same_v) { return; } else { return value_.getValue(); } } [[nodiscard]] constexpr bool ready() const noexcept { return isSet_; } public: // modification template requires (!std::is_same_v) constexpr void set(TArg&& value) noexcept { MIJIN_ASSERT(!isSet_, "Trying to set a future twice!"); value_.setValue(std::move(value)); isSet_ = true; sigSet.emit(); } constexpr void set() noexcept { MIJIN_ASSERT(!isSet_, "Trying to set a future twice!"); isSet_ = true; if constexpr (std::is_same_v) { sigSet.emit(); } else { // would love to make this a compile-time error :/ MIJIN_ERROR("Attempting to call set(void) on future with value."); } } public: // signals Signal<> sigSet; }; template using FuturePtr = std::shared_ptr>; // // public functions // } // namespace mijin #endif // !defined(MIJIN_ASYNC_FUTURE_HPP_INCLUDED)