#pragma once #if !defined(MIJIN_ASYNC_FUTURE_HPP_INCLUDED) #define MIJIN_ASYNC_FUTURE_HPP_INCLUDED 1 #include #include #include #include "./signal.hpp" #include "../container/optional.hpp" #include "../debug/assert.hpp" #include "../internal/common.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 { Optional value; void setValue(TValue value_) MIJIN_NOEXCEPT { value = std::move(value_); } [[nodiscard]] TValue& getValue() MIJIN_NOEXCEPT { return value.get(); } }; // template // struct FutureStorage // { // Optional value; // // void setValue(TValue& value_) MIJIN_NOEXCEPT { value = &value_; } // [[nodiscard]] TValue& getValue() const MIJIN_NOEXCEPT { return *value.get(); } // }; template<> struct FutureStorage { }; } // namespace impl template class Future { private: impl::FutureStorage value_; bool isSet_ = false; public: Future() = default; Future(const Future&) = delete; Future(Future&&) MIJIN_NOEXCEPT = default; public: Future& operator=(const Future&) = delete; Future& operator=(Future&&) MIJIN_NOEXCEPT = default; [[nodiscard]] constexpr explicit operator bool() const MIJIN_NOEXCEPT { return ready(); } [[nodiscard]] constexpr bool operator!() const MIJIN_NOEXCEPT { return !ready(); } public: // access [[nodiscard]] constexpr decltype(auto) get() MIJIN_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 MIJIN_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 MIJIN_NOEXCEPT { return isSet_; } public: // modification template requires (!std::is_same_v) constexpr void set(TArg&& value) MIJIN_NOEXCEPT { MIJIN_ASSERT(!isSet_, "Trying to set a future twice!"); value_.setValue(std::move(value)); isSet_ = true; sigSet.emit(); } constexpr void set() MIJIN_NOEXCEPT requires (std::is_same_v) { 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)