mijin2/source/mijin/async/future.hpp

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
{
Optional<TValue> value;
void setValue(TValue value_) noexcept { value = std::move(value_); }
[[nodiscard]] TValue& getValue() noexcept { return value.get(); }
};
// template<typename TValue>
// struct FutureStorage<TValue&>
// {
// Optional<TValue*> value;
//
// void setValue(TValue& value_) noexcept { value = &value_; }
// [[nodiscard]] TValue& getValue() const noexcept { return *value.get(); }
// };
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)