#pragma once #include "fwd.h" #include #include #include #include #include #include #include #include #include namespace NThreading { //////////////////////////////////////////////////////////////////////////////// struct TFutureException: public yexception {}; // creates unset promise template TPromise NewPromise(); TPromise NewPromise(); // creates preset future template TFuture MakeFuture(const T& value); template TFuture> MakeFuture(T&& value); template TFuture MakeFuture(); template TFuture MakeErrorFuture(std::exception_ptr exception); TFuture MakeFuture(); //////////////////////////////////////////////////////////////////////////////// namespace NImpl { template class TFutureState; template struct TFutureType { using TType = T; }; template struct TFutureType> { using TType = typename TFutureType::TType; }; template struct TFutureCallResult { // NOTE: separate class for msvc compatibility using TType = decltype(std::declval()(std::declval&>())); }; } template using TFutureType = typename NImpl::TFutureType::TType; template using TFutureCallResult = typename NImpl::TFutureCallResult::TType; //! Type of the future/promise state identifier class TFutureStateId; //////////////////////////////////////////////////////////////////////////////// template class TFuture { using TFutureState = NImpl::TFutureState; private: TIntrusivePtr State; public: using value_type = T; TFuture() noexcept = default; TFuture(const TFuture& other) noexcept = default; TFuture(TFuture&& other) noexcept = default; TFuture(const TIntrusivePtr& state) noexcept; TFuture& operator=(const TFuture& other) noexcept = default; TFuture& operator=(TFuture&& other) noexcept = default; void Swap(TFuture& 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 const TFuture& Subscribe(F&& callback) const; // precondition: EnsureInitialized() passes // postcondition: std::terminate is highly unlikely template const TFuture& NoexceptSubscribe(F&& callback) const noexcept; template TFuture>> Apply(F&& func) const; TFuture 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 StateId() const noexcept; void EnsureInitialized() const; }; //////////////////////////////////////////////////////////////////////////////// template <> class TFuture { using TFutureState = NImpl::TFutureState; private: TIntrusivePtr State = nullptr; public: using value_type = void; TFuture() noexcept = default; TFuture(const TFuture& other) noexcept = default; TFuture(TFuture&& other) noexcept = default; TFuture(const TIntrusivePtr& state) noexcept; TFuture& operator=(const TFuture& other) noexcept = default; TFuture& operator=(TFuture&& other) noexcept = default; void Swap(TFuture& 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 const TFuture& Subscribe(F&& callback) const; // precondition: EnsureInitialized() passes // postcondition: std::terminate is highly unlikely template const TFuture& NoexceptSubscribe(F&& callback) const noexcept; template TFuture>> Apply(F&& func) const; template TFuture> Return(R&& value) const; TFuture 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 StateId() const noexcept; void EnsureInitialized() const; }; //////////////////////////////////////////////////////////////////////////////// template class TPromise { using TFutureState = NImpl::TFutureState; private: TIntrusivePtr State = nullptr; public: TPromise() noexcept = default; TPromise(const TPromise& other) noexcept = default; TPromise(TPromise&& other) noexcept = default; TPromise(const TIntrusivePtr& state) noexcept; TPromise& operator=(const TPromise& other) noexcept = default; TPromise& operator=(TPromise&& other) noexcept = default; void Swap(TPromise& 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 GetFuture() const; operator TFuture() const; private: void EnsureInitialized() const; }; //////////////////////////////////////////////////////////////////////////////// template <> class TPromise { using TFutureState = NImpl::TFutureState; private: TIntrusivePtr State; public: TPromise() noexcept = default; TPromise(const TPromise& other) noexcept = default; TPromise(TPromise&& other) noexcept = default; TPromise(const TIntrusivePtr& state) noexcept; TPromise& operator=(const TPromise& other) noexcept = default; TPromise& operator=(TPromise&& other) noexcept = default; void Swap(TPromise& 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 GetFuture() const; operator TFuture() const; private: void EnsureInitialized() const; }; } #define INCLUDE_FUTURE_INL_H #include "future-inl.h" #undef INCLUDE_FUTURE_INL_H