intial commit
This commit is contained in:
140
source/mijin/async/future.hpp
Normal file
140
source/mijin/async/future.hpp
Normal file
@@ -0,0 +1,140 @@
|
||||
|
||||
#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)
|
||||
Reference in New Issue
Block a user