blob: c803b28b756b753b9bf04ab1edbd1328a38fb5bb (
plain) (
tree)
|
|
#pragma once
#include "fwd.h"
#include <library/cpp/deprecated/atomic/atomic.h>
#include <util/datetime/base.h>
#include <util/generic/function.h>
#include <util/generic/maybe.h>
#include <util/generic/ptr.h>
#include <util/generic/vector.h>
#include <util/generic/yexception.h>
#include <util/system/event.h>
#include <util/system/spinlock.h>
namespace NThreading {
////////////////////////////////////////////////////////////////////////////////
struct TFutureException: public yexception {};
// creates unset promise
template <typename T>
TPromise<T> NewPromise();
TPromise<void> NewPromise();
// creates preset future
template <typename T>
TFuture<T> MakeFuture(const T& value);
template <typename T>
TFuture<std::remove_reference_t<T>> MakeFuture(T&& value);
template <typename T>
TFuture<T> MakeFuture();
template <typename T>
TFuture<T> MakeErrorFuture(std::exception_ptr exception);
TFuture<void> MakeFuture();
////////////////////////////////////////////////////////////////////////////////
namespace NImpl {
template <typename T>
class TFutureState;
template <typename T>
struct TFutureType {
using TType = T;
};
template <typename T>
struct TFutureType<TFuture<T>> {
using TType = typename TFutureType<T>::TType;
};
template <typename F, typename T>
struct TFutureCallResult {
// NOTE: separate class for msvc compatibility
using TType = decltype(std::declval<F&>()(std::declval<const TFuture<T>&>()));
};
}
template <typename F>
using TFutureType = typename NImpl::TFutureType<F>::TType;
template <typename F, typename T>
using TFutureCallResult = typename NImpl::TFutureCallResult<F, T>::TType;
//! Type of the future/promise state identifier
class TFutureStateId;
////////////////////////////////////////////////////////////////////////////////
template <typename T>
class TFuture {
using TFutureState = NImpl::TFutureState<T>;
private:
TIntrusivePtr<TFutureState> State;
public:
using value_type = T;
TFuture() noexcept = default;
TFuture(const TFuture<T>& other) noexcept = default;
TFuture(TFuture<T>&& other) noexcept = default;
TFuture(const TIntrusivePtr<TFutureState>& state) noexcept;
TFuture<T>& operator=(const TFuture<T>& other) noexcept = default;
TFuture<T>& operator=(TFuture<T>&& other) noexcept = default;
void Swap(TFuture<T>& other);
bool Initialized() const;
bool HasValue() const;
const T& GetValue(TDuration timeout = TDuration::Zero()) const;
const T& GetValueSync() const;
T ExtractValue(TDuration timeout = TDuration::Zero());
T ExtractValueSync();
void TryRethrow() const;
bool HasException() const;
void Wait() const;
bool Wait(TDuration timeout) const;
bool Wait(TInstant deadline) const;
template <typename F>
const TFuture<T>& Subscribe(F&& callback) const;
// precondition: EnsureInitialized() passes
// postcondition: std::terminate is highly unlikely
template <typename F>
const TFuture<T>& NoexceptSubscribe(F&& callback) const noexcept;
template <typename F>
TFuture<TFutureType<TFutureCallResult<F, T>>> Apply(F&& func) const;
TFuture<void> IgnoreResult() const;
//! If the future is initialized returns the future state identifier. Otherwise returns an empty optional
/** The state identifier is guaranteed to be unique during the future state lifetime and could be reused after its death
**/
TMaybe<TFutureStateId> StateId() const noexcept;
void EnsureInitialized() const;
};
////////////////////////////////////////////////////////////////////////////////
template <>
class TFuture<void> {
using TFutureState = NImpl::TFutureState<void>;
private:
TIntrusivePtr<TFutureState> State = nullptr;
public:
using value_type = void;
TFuture() noexcept = default;
TFuture(const TFuture<void>& other) noexcept = default;
TFuture(TFuture<void>&& other) noexcept = default;
TFuture(const TIntrusivePtr<TFutureState>& state) noexcept;
TFuture<void>& operator=(const TFuture<void>& other) noexcept = default;
TFuture<void>& operator=(TFuture<void>&& other) noexcept = default;
void Swap(TFuture<void>& other);
bool Initialized() const;
bool HasValue() const;
void GetValue(TDuration timeout = TDuration::Zero()) const;
void GetValueSync() const;
void TryRethrow() const;
bool HasException() const;
void Wait() const;
bool Wait(TDuration timeout) const;
bool Wait(TInstant deadline) const;
template <typename F>
const TFuture<void>& Subscribe(F&& callback) const;
// precondition: EnsureInitialized() passes
// postcondition: std::terminate is highly unlikely
template <typename F>
const TFuture<void>& NoexceptSubscribe(F&& callback) const noexcept;
template <typename F>
TFuture<TFutureType<TFutureCallResult<F, void>>> Apply(F&& func) const;
template <typename R>
TFuture<R> Return(const R& value) const;
TFuture<void> IgnoreResult() const {
return *this;
}
//! If the future is initialized returns the future state identifier. Otherwise returns an empty optional
/** The state identifier is guaranteed to be unique during the future state lifetime and could be reused after its death
**/
TMaybe<TFutureStateId> StateId() const noexcept;
void EnsureInitialized() const;
};
////////////////////////////////////////////////////////////////////////////////
template <typename T>
class TPromise {
using TFutureState = NImpl::TFutureState<T>;
private:
TIntrusivePtr<TFutureState> State = nullptr;
public:
TPromise() noexcept = default;
TPromise(const TPromise<T>& other) noexcept = default;
TPromise(TPromise<T>&& other) noexcept = default;
TPromise(const TIntrusivePtr<TFutureState>& state) noexcept;
TPromise<T>& operator=(const TPromise<T>& other) noexcept = default;
TPromise<T>& operator=(TPromise<T>&& other) noexcept = default;
void Swap(TPromise<T>& other);
bool Initialized() const;
bool HasValue() const;
const T& GetValue() const;
T ExtractValue();
void SetValue(const T& value);
void SetValue(T&& value);
bool TrySetValue(const T& value);
bool TrySetValue(T&& value);
void TryRethrow() const;
bool HasException() const;
void SetException(const TString& e);
void SetException(std::exception_ptr e);
bool TrySetException(std::exception_ptr e);
TFuture<T> GetFuture() const;
operator TFuture<T>() const;
private:
void EnsureInitialized() const;
};
////////////////////////////////////////////////////////////////////////////////
template <>
class TPromise<void> {
using TFutureState = NImpl::TFutureState<void>;
private:
TIntrusivePtr<TFutureState> State;
public:
TPromise() noexcept = default;
TPromise(const TPromise<void>& other) noexcept = default;
TPromise(TPromise<void>&& other) noexcept = default;
TPromise(const TIntrusivePtr<TFutureState>& state) noexcept;
TPromise<void>& operator=(const TPromise<void>& other) noexcept = default;
TPromise<void>& operator=(TPromise<void>&& other) noexcept = default;
void Swap(TPromise<void>& other);
bool Initialized() const;
bool HasValue() const;
void GetValue() const;
void SetValue();
bool TrySetValue();
void TryRethrow() const;
bool HasException() const;
void SetException(const TString& e);
void SetException(std::exception_ptr e);
bool TrySetException(std::exception_ptr e);
TFuture<void> GetFuture() const;
operator TFuture<void>() const;
private:
void EnsureInitialized() const;
};
}
#define INCLUDE_FUTURE_INL_H
#include "future-inl.h"
#undef INCLUDE_FUTURE_INL_H
|