141 lines
3.1 KiB
C++
141 lines
3.1 KiB
C++
|
|
#pragma once
|
|
|
|
#if !defined(MIJIN_ASYNC_FUTURE_HPP_INCLUDED)
|
|
#define MIJIN_ASYNC_FUTURE_HPP_INCLUDED 1
|
|
|
|
#include <optional>
|
|
#include <memory>
|
|
#include <type_traits>
|
|
#include "./signal.hpp"
|
|
#include "../debug/assert.hpp"
|
|
#include "../container/optional.hpp"
|
|
|
|
namespace mijin
|
|
{
|
|
|
|
//
|
|
// public defines
|
|
//
|
|
|
|
//
|
|
// public constants
|
|
//
|
|
|
|
//
|
|
// public types
|
|
//
|
|
template<typename TValue>
|
|
class Future;
|
|
|
|
// TODO: add support for mutexes and waiting for futures
|
|
namespace impl
|
|
{
|
|
template<typename TValue>
|
|
struct FutureStorage
|
|
{
|
|
std::optional<TValue> value;
|
|
|
|
void setValue(TValue value_) noexcept { value = std::move(value_); }
|
|
[[nodiscard]] TValue& getValue() noexcept { return value.value(); }
|
|
|
|
};
|
|
|
|
template<typename TValue>
|
|
struct FutureStorage<TValue&>
|
|
{
|
|
std::optional<TValue*> value;
|
|
|
|
void setValue(TValue& value_) noexcept { value = &value_; }
|
|
[[nodiscard]] TValue& getValue() const noexcept { return *value.value(); }
|
|
};
|
|
|
|
template<>
|
|
struct FutureStorage<void>
|
|
{
|
|
};
|
|
} // namespace impl
|
|
|
|
template<typename TValue>
|
|
class Future
|
|
{
|
|
private:
|
|
impl::FutureStorage<TValue> 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<TValue, void>) {
|
|
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<TValue, void>) {
|
|
return;
|
|
}
|
|
else {
|
|
return value_.getValue();
|
|
}
|
|
}
|
|
[[nodiscard]]
|
|
constexpr bool ready() const noexcept
|
|
{
|
|
return isSet_;
|
|
}
|
|
public: // modification
|
|
template<typename TArg> requires (!std::is_same_v<TValue, void>)
|
|
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<TValue, void>) {
|
|
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<typename TValue>
|
|
using FuturePtr = std::shared_ptr<Future<TValue>>;
|
|
|
|
//
|
|
// public functions
|
|
//
|
|
|
|
} // namespace mijin
|
|
|
|
#endif // !defined(MIJIN_ASYNC_FUTURE_HPP_INCLUDED)
|