STL/stl/inc/future

1482 строки
49 KiB
C++

// future standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef _FUTURE_
#define _FUTURE_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#ifdef _M_CEE_PURE
#error <future> is not supported when compiling with /clr:pure.
#endif // defined(_M_CEE_PURE)
#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED
#include <experimental/resumable>
#endif // _RESUMABLE_FUNCTIONS_SUPPORTED
#include <__msvc_chrono.hpp>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <ppltasks.h>
#include <system_error>
#include <thread>
#include <utility>
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
_STD_BEGIN
template <class _Alloc>
struct _Allocator_deleter {
_Alloc _Al;
using pointer = typename allocator_traits<_Alloc>::pointer;
void operator()(pointer _Ptr) noexcept { // delete the pointer
_STD _Destroy_in_place(*_Ptr);
_Al.deallocate(_Ptr, 1);
}
};
template <class _Alloc>
using _Unique_ptr_alloc = unique_ptr<typename _Alloc::value_type, _Allocator_deleter<_Alloc>>;
template <class _Alloc, class... _Args>
_NODISCARD _Unique_ptr_alloc<_Alloc> _Make_unique_alloc(_Alloc& _Al, _Args&&... _Vals) {
// construct an object with an allocator and return it owned by a unique_ptr
_Alloc_construct_ptr<_Alloc> _Constructor{_Al};
_Constructor._Allocate();
_STD _Construct_in_place(*_Constructor._Ptr, _STD forward<_Args>(_Vals)...);
return _Unique_ptr_alloc<_Alloc>(_Constructor._Release(), _Allocator_deleter<_Alloc>{_Al});
}
struct _From_raw_state_tag { // internal tag type for constructing a future from a raw state
explicit _From_raw_state_tag() = default;
};
_EXPORT_STD enum class future_errc { // names for futures errors
broken_promise = 1,
future_already_retrieved,
promise_already_satisfied,
no_state
};
_EXPORT_STD enum class launch { // names for launch options passed to async
async = 0x1,
deferred = 0x2
};
_BITMASK_OPS(_EXPORT_STD, launch)
_EXPORT_STD enum class future_status { // names for timed wait function returns
ready,
timeout,
deferred
};
template <>
struct is_error_code_enum<future_errc> : true_type {};
_EXPORT_STD _NODISCARD const error_category& future_category() noexcept;
_EXPORT_STD _NODISCARD inline error_code make_error_code(future_errc _Ec) noexcept {
return error_code(static_cast<int>(_Ec), _STD future_category());
}
_EXPORT_STD _NODISCARD inline error_condition make_error_condition(future_errc _Ec) noexcept {
return error_condition(static_cast<int>(_Ec), _STD future_category());
}
_NODISCARD inline const char* _Future_error_map(int _Errcode) noexcept { // convert to name of future error
switch (static_cast<future_errc>(_Errcode)) { // switch on error code value
case future_errc::broken_promise:
return "broken promise";
case future_errc::future_already_retrieved:
return "future already retrieved";
case future_errc::promise_already_satisfied:
return "promise already satisfied";
case future_errc::no_state:
return "no state";
default:
return nullptr;
}
}
_EXPORT_STD class future_error : public logic_error { // future exception
public:
explicit future_error(error_code _Errcode) // internal, TRANSITION, will be removed
: logic_error(""), _Mycode(_Errcode) {}
explicit future_error(future_errc _Ec) : logic_error(""), _Mycode(_STD make_error_code(_Ec)) {}
_NODISCARD const error_code& code() const noexcept {
return _Mycode;
}
_NODISCARD const char* __CLR_OR_THIS_CALL what() const noexcept override { // get message string
return _Future_error_map(_Mycode.value());
}
#if !_HAS_EXCEPTIONS
protected:
void _Doraise() const override { // perform class-specific exception handling
_RAISE(*this);
}
#endif // !_HAS_EXCEPTIONS
private:
error_code _Mycode; // the stored error code
};
// TRANSITION, ABI: remove `2` suffix
[[noreturn]] inline void _Throw_future_error2(const future_errc _Ec) {
_THROW(future_error{_Ec});
}
class _Future_error_category2 : public error_category { // categorize a future error
public:
constexpr _Future_error_category2() noexcept : error_category(_Future_addr) {}
const char* name() const noexcept override {
return "future";
}
string message(int _Errcode) const override {
const char* _Name = _Future_error_map(_Errcode);
if (_Name) {
return _Name;
}
return _Syserror_map(_Errcode);
}
};
_EXPORT_STD _NODISCARD inline const error_category& future_category() noexcept {
return _Immortalize_memcpy_image<_Future_error_category2>();
}
template <class _Ty>
class _Associated_state;
template <class _Ty>
struct __declspec(novtable) _Deleter_base { // abstract base class for managing deletion of state objects
virtual void _Delete(_Associated_state<_Ty>*) noexcept = 0;
virtual ~_Deleter_base() = default; // TRANSITION, vNext (make non-virtual, never called polymorphically)
};
template <class _Ty, class _Derived, class _Alloc>
struct _State_deleter : _Deleter_base<_Ty> { // manage allocator and deletion state objects
_State_deleter(const _Alloc& _Al) : _My_alloc(_Al) {}
_State_deleter(const _State_deleter&) = delete;
_State_deleter& operator=(const _State_deleter&) = delete;
void _Delete(_Associated_state<_Ty>* _State) noexcept override;
_Alloc _My_alloc;
};
template <class _Ty>
union _Result_holder {
_Result_holder() noexcept {}
~_Result_holder() noexcept {}
_Ty _Held_value;
};
template <class _Ty>
class _Associated_state { // class for managing associated synchronous state
public:
using _State_type = _Ty;
using _Mydel = _Deleter_base<_Ty>;
// TRANSITION, incorrectly default constructs _Result when _Ty is default constructible
_Associated_state(_Mydel* _Dp = nullptr)
: _Refs(1), // non-atomic initialization
_Result(), _Exception(), _Retrieved(false), _Ready(false), _Ready_at_thread_exit(false),
_Has_stored_result(false), _Running(false), _Deleter(_Dp) {}
virtual ~_Associated_state() noexcept {
if (_Already_has_stored_result() && !_Ready) { // registered for release at thread exit
_Cond._Unregister(_Mtx);
}
if constexpr (!is_default_constructible_v<_Ty>) {
if (_Has_stored_result) {
_Result._Held_value.~_Ty();
}
}
}
void _Retain() noexcept { // increment reference count
_MT_INCR(_Refs);
}
void _Release() noexcept { // decrement reference count and destroy when zero
if (_MT_DECR(_Refs) == 0) {
_Delete_this();
}
}
private:
_Atomic_counter_t _Refs;
public:
virtual void _Wait() { // wait for signal
unique_lock<mutex> _Lock(_Mtx);
_Maybe_run_deferred_function(_Lock);
while (!_Ready) {
_Cond.wait(_Lock);
}
}
struct _Test_ready { // wraps _Associated_state
_Test_ready(const _Associated_state* _St) : _State(_St) {}
bool operator()() const { // test state
return _State->_Ready != 0;
}
const _Associated_state* _State;
};
template <class _Rep, class _Per>
future_status _Wait_for(const chrono::duration<_Rep, _Per>& _Rel_time) { // wait for duration
unique_lock<mutex> _Lock(_Mtx);
if (_Has_deferred_function()) {
return future_status::deferred;
}
if (_Cond.wait_for(_Lock, _Rel_time, _Test_ready(this))) {
return future_status::ready;
}
return future_status::timeout;
}
template <class _Clock, class _Dur>
future_status _Wait_until(const chrono::time_point<_Clock, _Dur>& _Abs_time) { // wait until time point
unique_lock<mutex> _Lock(_Mtx);
if (_Has_deferred_function()) {
return future_status::deferred;
}
if (_Cond.wait_until(_Lock, _Abs_time, _Test_ready(this))) {
return future_status::ready;
}
return future_status::timeout;
}
virtual _Ty& _Get_value(bool _Get_only_once) {
unique_lock<mutex> _Lock(_Mtx);
if (_Get_only_once && _Retrieved) {
_Throw_future_error2(future_errc::future_already_retrieved);
}
if (_Exception) {
_STD rethrow_exception(_Exception);
}
// TRANSITION: `_Retrieved` should be assigned before `_Exception` is thrown so that a `future::get`
// that throws a stored exception invalidates the future (N4950 [futures.unique.future]/17)
_Retrieved = true;
_Maybe_run_deferred_function(_Lock);
while (!_Ready) {
_Cond.wait(_Lock);
}
if (_Exception) {
_STD rethrow_exception(_Exception);
}
if constexpr (is_default_constructible_v<_Ty>) {
return _Result;
} else {
return _Result._Held_value;
}
}
template <class _Ty2>
void _Emplace_result(_Ty2&& _Val) {
// TRANSITION, incorrectly assigns _Result when _Ty is default constructible
if constexpr (is_default_constructible_v<_Ty>) {
_Result = _STD forward<_Ty2>(_Val);
} else {
::new (static_cast<void*>(_STD addressof(_Result._Held_value))) _Ty(_STD forward<_Ty2>(_Val));
_Has_stored_result = true;
}
}
void _Set_value(const _Ty& _Val, bool _At_thread_exit) { // store a result
unique_lock<mutex> _Lock(_Mtx);
_Set_value_raw(_Val, &_Lock, _At_thread_exit);
}
void _Set_value_raw(const _Ty& _Val, unique_lock<mutex>* _Lock, bool _At_thread_exit) {
// store a result while inside a locked block
if (_Already_has_stored_result()) {
_Throw_future_error2(future_errc::promise_already_satisfied);
}
_Emplace_result(_Val);
_Do_notify(_Lock, _At_thread_exit);
}
void _Set_value(_Ty&& _Val, bool _At_thread_exit) { // store a result
unique_lock<mutex> _Lock(_Mtx);
_Set_value_raw(_STD forward<_Ty>(_Val), &_Lock, _At_thread_exit);
}
void _Set_value_raw(_Ty&& _Val, unique_lock<mutex>* _Lock, bool _At_thread_exit) {
// store a result while inside a locked block
if (_Already_has_stored_result()) {
_Throw_future_error2(future_errc::promise_already_satisfied);
}
_Emplace_result(_STD forward<_Ty>(_Val));
_Do_notify(_Lock, _At_thread_exit);
}
void _Set_exception(exception_ptr _Exc, bool _At_thread_exit) { // store a result
unique_lock<mutex> _Lock(_Mtx);
_Set_exception_raw(_Exc, &_Lock, _At_thread_exit);
}
void _Set_exception_raw(exception_ptr _Exc, unique_lock<mutex>* _Lock, bool _At_thread_exit) {
// store a result while inside a locked block
if (_Already_has_stored_result()) {
_Throw_future_error2(future_errc::promise_already_satisfied);
}
_STL_ASSERT(_Exc != nullptr, "promise<T>::set_exception/set_exception_at_thread_exit called with a null "
"std::exception_ptr, which is invalid per N4950 [futures.promise]/20");
_Exception = _Exc;
_Do_notify(_Lock, _At_thread_exit);
}
bool _Is_ready() const noexcept {
return _Ready != 0;
}
bool _Already_has_stored_result() const noexcept { // Has a result or an exception
if constexpr (is_default_constructible_v<_Ty>) {
return _Has_stored_result;
} else {
return _Has_stored_result || _Exception;
}
}
bool _Already_retrieved() const noexcept {
return _Retrieved;
}
void _Abandon() { // abandon shared state
unique_lock<mutex> _Lock(_Mtx);
if (!_Already_has_stored_result()) { // queue exception
future_error _Fut(_STD make_error_code(future_errc::broken_promise));
_Set_exception_raw(_STD make_exception_ptr(_Fut), &_Lock, false);
}
}
protected:
void _Maybe_run_deferred_function(unique_lock<mutex>& _Lock) { // run a deferred function if not already done
if (!_Running) { // run the function
_Running = true;
_Run_deferred_function(_Lock);
}
}
public:
conditional_t<is_default_constructible_v<_Ty>, _Ty, _Result_holder<_Ty>> _Result;
exception_ptr _Exception;
mutex _Mtx;
condition_variable _Cond;
bool _Retrieved;
int _Ready;
bool _Ready_at_thread_exit; // TRANSITION, ABI
bool _Has_stored_result;
bool _Running;
private:
virtual bool _Has_deferred_function() const noexcept { // overridden by _Deferred_async_state
return false;
}
virtual void _Run_deferred_function(unique_lock<mutex>&) {} // do nothing
virtual void _Do_notify(unique_lock<mutex>* _Lock, bool _At_thread_exit) { // notify waiting threads
// TRANSITION, ABI: This is virtual, but never overridden.
if constexpr (is_default_constructible_v<_Ty>) {
_Has_stored_result = true;
}
if (_At_thread_exit) { // notify at thread exit
_Cond._Register(*_Lock, &_Ready);
} else { // notify immediately
_Ready = true;
_Cond.notify_all();
}
}
void _Delete_this() noexcept { // delete this object
if (_Deleter) {
_Deleter->_Delete(this);
} else {
delete this;
}
}
_Mydel* _Deleter;
public:
_Associated_state(const _Associated_state&) = delete;
_Associated_state& operator=(const _Associated_state&) = delete;
};
template <class _Ty, class _Derived, class _Alloc>
void _State_deleter<_Ty, _Derived, _Alloc>::_Delete(_Associated_state<_Ty>* _State) noexcept {
// delete _State and this using stored allocator
using _State_allocator = _Rebind_alloc_t<_Alloc, _Derived>;
_State_allocator _St_alloc(_My_alloc);
using _Deleter_allocator = _Rebind_alloc_t<_Alloc, _State_deleter>;
_Deleter_allocator _Del_alloc(_My_alloc);
_Derived* _Ptr = static_cast<_Derived*>(_State);
_STD _Delete_plain_internal(_St_alloc, _Ptr);
_STD _Delete_plain_internal(_Del_alloc, this);
}
template <class _Fret>
struct _P_arg_type { // type for functions returning T
using type = _Fret;
};
template <class _Fret>
struct _P_arg_type<_Fret&> { // type for functions returning reference to T
using type = _Fret*;
};
template <>
struct _P_arg_type<void> { // type for functions returning void
using type = int;
};
template <class>
class _Packaged_state;
// class for managing associated asynchronous state for packaged_task
template <class _Ret, class... _ArgTypes>
class _Packaged_state<_Ret(_ArgTypes...)> : public _Associated_state<typename _P_arg_type<_Ret>::type> {
public:
using _Mybase = _Associated_state<typename _P_arg_type<_Ret>::type>;
using _Mydel = typename _Mybase::_Mydel;
using _Function_type = function<_Ret(_ArgTypes...)>; // TRANSITION, ABI, should not use std::function
explicit _Packaged_state(const _Function_type& _Fnarg) : _Fn(_Fnarg) {}
explicit _Packaged_state(_Function_type&& _Fnarg) noexcept : _Fn(_STD move(_Fnarg)) {}
template <class _Fty2, enable_if_t<!is_same_v<_Remove_cvref_t<_Fty2>, _Function_type>, int> = 0>
explicit _Packaged_state(_Fty2&& _Fnarg) : _Fn(_Secret_copyability_ignoring_tag{}, _STD forward<_Fty2>(_Fnarg)) {}
#if _HAS_FUNCTION_ALLOCATOR_SUPPORT
template <class _Alloc>
_Packaged_state(const _Function_type& _Fnarg, const _Alloc& _Al, _Mydel* _Dp)
: _Mybase(_Dp), _Fn(allocator_arg, _Al, _Fnarg) {}
template <class _Alloc>
_Packaged_state(_Function_type&& _Fnarg, const _Alloc& _Al, _Mydel* _Dp)
: _Mybase(_Dp), _Fn(allocator_arg, _Al, _STD move(_Fnarg)) {}
template <class _Fty2, class _Alloc, enable_if_t<!is_same_v<_Remove_cvref_t<_Fty2>, _Function_type>, int> = 0>
_Packaged_state(_Fty2&& _Fnarg, const _Alloc& _Al, _Mydel* _Dp)
: _Mybase(_Dp), _Fn(_Secret_copyability_ignoring_tag{}, allocator_arg, _Al, _STD forward<_Fty2>(_Fnarg)) {}
#endif // _HAS_FUNCTION_ALLOCATOR_SUPPORT
void _Call_deferred(_ArgTypes... _Args) { // set deferred call
_TRY_BEGIN
// call function object and catch exceptions
if constexpr (is_same_v<_Ret, void>) {
_Fn(_STD forward<_ArgTypes>(_Args)...);
this->_Set_value(1, true);
} else if constexpr (is_lvalue_reference_v<_Ret>) {
this->_Set_value(_STD addressof(_Fn(_STD forward<_ArgTypes>(_Args)...)), true);
} else {
this->_Set_value(_Fn(_STD forward<_ArgTypes>(_Args)...), true);
}
_CATCH_ALL
// function object threw exception; record result
this->_Set_exception(_STD current_exception(), true);
_CATCH_END
}
void _Call_immediate(_ArgTypes... _Args) { // call function object
_TRY_BEGIN
// call function object and catch exceptions
if constexpr (is_same_v<_Ret, void>) {
_Fn(_STD forward<_ArgTypes>(_Args)...);
this->_Set_value(1, false);
} else if constexpr (is_lvalue_reference_v<_Ret>) {
this->_Set_value(_STD addressof(_Fn(_STD forward<_ArgTypes>(_Args)...)), false);
} else {
this->_Set_value(_Fn(_STD forward<_ArgTypes>(_Args)...), false);
}
_CATCH_ALL
// function object threw exception; record result
this->_Set_exception(_STD current_exception(), false);
_CATCH_END
}
const auto& _Get_fn() const& {
return _Fn;
}
auto&& _Get_fn() && noexcept {
return _STD move(_Fn);
}
private:
_Function_type _Fn;
};
template <class _Ty, class _Alloc>
_Associated_state<_Ty>* _Make_associated_state(const _Alloc& _Al) {
// construct an _Associated_state object with an allocator
using _Delty = _State_deleter<_Ty, _Associated_state<_Ty>, _Alloc>;
using _Aldelty = _Rebind_alloc_t<_Alloc, _Delty>;
using _Alstate = _Rebind_alloc_t<_Alloc, _Associated_state<_Ty>>;
_Aldelty _Del_alloc(_Al);
_Alstate _State_alloc(_Al);
auto _Del = _STD _Make_unique_alloc(_Del_alloc, _Al);
auto _Res = _STD _Make_unique_alloc(_State_alloc, _STD _Unfancy(_Del.get()));
(void) _Del.release(); // ownership of _Del.get() now transferred to _Res
return _STD _Unfancy(_Res.release()); // ownership transferred to caller
}
#if _HAS_FUNCTION_ALLOCATOR_SUPPORT
template <class _Pack_state, class _Fty2, class _Alloc>
_Pack_state* _Make_packaged_state(_Fty2&& _Fnarg, const _Alloc& _Al) {
// construct a _Packaged_state object with an allocator from an rvalue function object
using _Delty = _State_deleter<typename _Pack_state::_Mybase::_State_type, _Pack_state, _Alloc>;
using _Aldelty = _Rebind_alloc_t<_Alloc, _Delty>;
using _Alstate = _Rebind_alloc_t<_Alloc, _Pack_state>;
_Aldelty _Del_alloc(_Al);
_Alstate _State_alloc(_Al);
auto _Del = _STD _Make_unique_alloc(_Del_alloc, _Al);
auto _Res = _STD _Make_unique_alloc(_State_alloc, _STD forward<_Fty2>(_Fnarg), _Al, _STD _Unfancy(_Del.get()));
(void) _Del.release(); // ownership of _Del.get() now transferred to _Res
return _STD _Unfancy(_Res.release()); // ownership transferred to caller
}
#endif // _HAS_FUNCTION_ALLOCATOR_SUPPORT
template <class _Rx>
class _Deferred_async_state : public _Packaged_state<_Rx()> {
// class for managing associated synchronous state for deferred execution from async
public:
template <class _Fty2>
_Deferred_async_state(const _Fty2& _Fnarg) : _Packaged_state<_Rx()>(_Fnarg) {}
template <class _Fty2>
_Deferred_async_state(_Fty2&& _Fnarg) : _Packaged_state<_Rx()>(_STD forward<_Fty2>(_Fnarg)) {}
private:
bool _Has_deferred_function() const noexcept override {
// this function is considered to be deferred until it's invoked
return !this->_Running;
}
void _Run_deferred_function(unique_lock<mutex>& _Lock) override { // run the deferred function
_Lock.unlock();
_Packaged_state<_Rx()>::_Call_immediate();
_Lock.lock();
}
};
template <class _Rx>
class _Task_async_state : public _Packaged_state<_Rx()> {
// class for managing associated synchronous state for asynchronous execution from async
public:
using _Mybase = _Packaged_state<_Rx()>;
using _State_type = typename _Mybase::_State_type;
template <class _Fty2>
_Task_async_state(_Fty2&& _Fnarg) : _Mybase(_STD forward<_Fty2>(_Fnarg)) {
_Task = ::Concurrency::create_task([this]() { // do it now
this->_Call_immediate();
});
this->_Running = true;
}
~_Task_async_state() noexcept override {
_Wait();
}
void _Wait() override { // wait for completion
_Task.wait();
}
_State_type& _Get_value(bool _Get_only_once) override {
// return the stored result or throw stored exception
_Task.wait();
return _Mybase::_Get_value(_Get_only_once);
}
private:
::Concurrency::task<void> _Task;
};
template <class _Ty>
class _State_manager {
// class for managing possibly non-existent associated asynchronous state object
public:
_State_manager() = default; // construct with no associated asynchronous state object
_State_manager(_Associated_state<_Ty>* _New_state, bool _Get_once) noexcept
: _Assoc_state(_New_state), _Get_only_once(_Get_once) {} // construct with _New_state
_State_manager(const _State_manager& _Other, bool _Get_once = false) noexcept
: _Assoc_state(_Other._Assoc_state), _Get_only_once(_Get_once) {
if (_Assoc_state) { // do the copy
_Assoc_state->_Retain();
}
}
_State_manager(_State_manager&& _Other, bool _Get_once = false) noexcept
: _Assoc_state(_STD exchange(_Other._Assoc_state, nullptr)), _Get_only_once(_Get_once) {}
~_State_manager() noexcept {
if (_Assoc_state) {
_Assoc_state->_Release();
}
}
_State_manager& operator=(const _State_manager& _Other) noexcept {
// copy stored associated asynchronous state object from _Other
if (_Other._Assoc_state) {
_Other._Assoc_state->_Retain();
}
if (_Assoc_state) {
_Assoc_state->_Release();
}
_Assoc_state = _Other._Assoc_state;
_Get_only_once = _Other._Get_only_once;
return *this;
}
_State_manager& operator=(_State_manager&& _Other) noexcept {
// move stored associated asynchronous state object from _Other
if (this != _STD addressof(_Other)) {
if (_Assoc_state) {
_Assoc_state->_Release();
}
_Assoc_state = _STD exchange(_Other._Assoc_state, nullptr);
_Get_only_once = _Other._Get_only_once;
}
return *this;
}
_NODISCARD bool valid() const noexcept {
return _Assoc_state && !(_Get_only_once && _Assoc_state->_Already_retrieved());
}
void wait() const { // wait for signal
if (!valid()) {
_Throw_future_error2(future_errc::no_state);
}
_Assoc_state->_Wait();
}
template <class _Rep, class _Per>
future_status wait_for(const chrono::duration<_Rep, _Per>& _Rel_time) const { // wait for duration
if (!valid()) {
_Throw_future_error2(future_errc::no_state);
}
return _Assoc_state->_Wait_for(_Rel_time);
}
template <class _Clock, class _Dur>
future_status wait_until(const chrono::time_point<_Clock, _Dur>& _Abs_time) const { // wait until time point
static_assert(chrono::_Is_clock_v<_Clock>, "Clock type required");
if (!valid()) {
_Throw_future_error2(future_errc::no_state);
}
return _Assoc_state->_Wait_until(_Abs_time);
}
_Ty& _Get_value() const {
if (!valid()) {
_Throw_future_error2(future_errc::no_state);
}
return _Assoc_state->_Get_value(_Get_only_once);
}
void _Set_value(const _Ty& _Val, bool _Defer) { // store a result
if (!valid()) {
_Throw_future_error2(future_errc::no_state);
}
_Assoc_state->_Set_value(_Val, _Defer);
}
void _Set_value(_Ty&& _Val, bool _Defer) { // store a result
if (!valid()) {
_Throw_future_error2(future_errc::no_state);
}
_Assoc_state->_Set_value(_STD forward<_Ty>(_Val), _Defer);
}
void _Abandon() { // abandon shared state
if (_Assoc_state) {
_Assoc_state->_Abandon();
}
}
void _Set_exception(exception_ptr _Exc, bool _Defer) { // store a result
if (!valid()) {
_Throw_future_error2(future_errc::no_state);
}
_Assoc_state->_Set_exception(_Exc, _Defer);
}
void _Swap(_State_manager& _Other) noexcept { // exchange with _Other
_STD swap(_Assoc_state, _Other._Assoc_state);
}
_Associated_state<_Ty>* _Ptr() const noexcept {
return _Assoc_state;
}
bool _Is_ready() const noexcept {
return _Assoc_state && _Assoc_state->_Is_ready();
}
private:
_Associated_state<_Ty>* _Assoc_state = nullptr;
bool _Get_only_once = false;
};
_EXPORT_STD template <class _Ty>
class shared_future;
_EXPORT_STD template <class _Ty>
class future : public _State_manager<_Ty> {
// class that defines a non-copyable asynchronous return object that holds a value
private:
using _Mybase = _State_manager<_Ty>;
public:
static_assert(!is_array_v<_Ty> && is_object_v<_Ty> && is_destructible_v<_Ty>,
"T in future<T> must meet the Cpp17Destructible requirements (N4950 [futures.unique.future]/4).");
future() = default;
future(future&& _Other) noexcept : _Mybase(_STD move(_Other), true) {}
future& operator=(future&&) = default;
future(_From_raw_state_tag, const _Mybase& _State) noexcept : _Mybase(_State, true) {}
_Ty get() {
// block until ready then return the stored result or throw the stored exception
future _Local{_STD move(*this)};
return _STD move(_Local._Get_value());
}
_NODISCARD shared_future<_Ty> share() noexcept {
return shared_future<_Ty>(_STD move(*this));
}
future(const future&) = delete;
future& operator=(const future&) = delete;
};
template <class _Ty>
class future<_Ty&> : public _State_manager<_Ty*> {
// class that defines a non-copyable asynchronous return object that holds a reference
private:
using _Mybase = _State_manager<_Ty*>;
public:
future() = default;
future(future&& _Other) noexcept : _Mybase(_STD move(_Other), true) {}
future& operator=(future&&) = default;
future(_From_raw_state_tag, const _Mybase& _State) noexcept : _Mybase(_State, true) {}
_Ty& get() {
// block until ready then return the stored result or throw the stored exception
future _Local{_STD move(*this)};
return *_Local._Get_value();
}
_NODISCARD shared_future<_Ty&> share() noexcept {
return shared_future<_Ty&>(_STD move(*this));
}
future(const future&) = delete;
future& operator=(const future&) = delete;
};
template <>
class future<void> : public _State_manager<int> {
// class that defines a non-copyable asynchronous return object that does not hold a value
private:
using _Mybase = _State_manager<int>;
public:
future() = default;
future(future&& _Other) noexcept : _Mybase(_STD move(_Other), true) {}
future& operator=(future&&) = default;
future(_From_raw_state_tag, const _Mybase& _State) noexcept : _Mybase(_State, true) {}
void get() {
// block until ready then return or throw the stored exception
future _Local{_STD move(*this)};
_Local._Get_value();
}
_NODISCARD shared_future<void> share() noexcept;
future(const future&) = delete;
future& operator=(const future&) = delete;
};
_EXPORT_STD template <class _Ty>
class shared_future : public _State_manager<_Ty> {
// class that defines a copyable asynchronous return object that holds a value
private:
using _Mybase = _State_manager<_Ty>;
public:
static_assert(!is_array_v<_Ty> && is_object_v<_Ty> && is_destructible_v<_Ty>,
"T in shared_future<T> must meet the Cpp17Destructible requirements (N4950 [futures.shared.future]/4).");
shared_future() = default;
shared_future(const shared_future& _Other) noexcept : _Mybase(_Other) {}
shared_future& operator=(const shared_future&) = default;
shared_future(future<_Ty>&& _Other) noexcept : _Mybase(static_cast<_Mybase&&>(_Other)) {}
shared_future(shared_future&& _Other) noexcept : _Mybase(_STD move(_Other)) {}
shared_future& operator=(shared_future&&) = default;
const _Ty& get() const {
// block until ready then return the stored result or throw the stored exception
return this->_Get_value();
}
};
template <class _Ty>
class shared_future<_Ty&> : public _State_manager<_Ty*> {
// class that defines a copyable asynchronous return object that holds a reference
private:
using _Mybase = _State_manager<_Ty*>;
public:
shared_future() = default;
shared_future(const shared_future& _Other) noexcept : _Mybase(_Other) {}
shared_future& operator=(const shared_future&) = default;
shared_future(future<_Ty&>&& _Other) noexcept : _Mybase(static_cast<_Mybase&&>(_Other)) {}
shared_future(shared_future&& _Other) noexcept : _Mybase(_STD move(_Other)) {}
shared_future& operator=(shared_future&&) = default;
_Ty& get() const {
// block until ready then return the stored result or throw the stored exception
return *this->_Get_value();
}
};
template <>
class shared_future<void> : public _State_manager<int> {
// class that defines a copyable asynchronous return object that does not hold a value
private:
using _Mybase = _State_manager<int>;
public:
shared_future() noexcept {}
shared_future(const shared_future& _Other) noexcept : _Mybase(_Other) {}
shared_future& operator=(const shared_future&) = default;
shared_future(shared_future&& _Other) noexcept : _Mybase(_STD move(_Other)) {}
shared_future(future<void>&& _Other) noexcept : _Mybase(static_cast<_Mybase&&>(_Other)) {}
shared_future& operator=(shared_future&&) = default;
void get() const { // block until ready then return or throw the stored exception
this->_Get_value();
}
};
_NODISCARD inline shared_future<void> future<void>::share() noexcept {
return shared_future<void>(_STD move(*this));
}
template <class _Ty>
class _Promise {
public:
_Promise(_Associated_state<_Ty>* _State_ptr) noexcept : _State(_State_ptr, false), _Future_retrieved(false) {}
_Promise(_Promise&&) = default;
_Promise& operator=(_Promise&&) = default;
void _Swap(_Promise& _Other) noexcept {
_State._Swap(_Other._State);
_STD swap(_Future_retrieved, _Other._Future_retrieved);
}
const _State_manager<_Ty>& _Get_state() const noexcept {
return _State;
}
_State_manager<_Ty>& _Get_state() noexcept {
return _State;
}
_State_manager<_Ty>& _Get_state_for_set() {
if (!_State.valid()) {
_Throw_future_error2(future_errc::no_state);
}
return _State;
}
_State_manager<_Ty>& _Get_state_for_future() {
if (!_State.valid()) {
_Throw_future_error2(future_errc::no_state);
}
if (_Future_retrieved) {
_Throw_future_error2(future_errc::future_already_retrieved);
}
_Future_retrieved = true;
return _State;
}
bool _Is_valid() const noexcept {
return _State.valid();
}
bool _Is_ready() const noexcept {
return _State._Is_ready();
}
_Promise(const _Promise&) = delete;
_Promise& operator=(const _Promise&) = delete;
private:
_State_manager<_Ty> _State;
bool _Future_retrieved;
};
_EXPORT_STD template <class _Ty>
class promise { // class that defines an asynchronous provider that holds a value
public:
static_assert(!is_array_v<_Ty> && is_object_v<_Ty> && is_destructible_v<_Ty>,
"T in promise<T> must meet the Cpp17Destructible requirements (N4950 [futures.promise]/1).");
promise() : _MyPromise(new _Associated_state<_Ty>) {}
template <class _Alloc>
promise(allocator_arg_t, const _Alloc& _Al) : _MyPromise(_Make_associated_state<_Ty>(_Al)) {}
promise(promise&&) = default;
promise& operator=(promise&& _Other) noexcept {
promise(_STD move(_Other)).swap(*this);
return *this;
}
~promise() noexcept {
if (_MyPromise._Is_valid() && !_MyPromise._Is_ready()) {
// exception if destroyed before function object returns
future_error _Fut(_STD make_error_code(future_errc::broken_promise));
_MyPromise._Get_state()._Set_exception(_STD make_exception_ptr(_Fut), false);
}
}
void swap(promise& _Other) noexcept {
_MyPromise._Swap(_Other._MyPromise);
}
_NODISCARD_GET_FUTURE future<_Ty> get_future() {
return future<_Ty>(_From_raw_state_tag{}, _MyPromise._Get_state_for_future());
}
void set_value(const _Ty& _Val) {
_MyPromise._Get_state_for_set()._Set_value(_Val, false);
}
void set_value_at_thread_exit(const _Ty& _Val) {
_MyPromise._Get_state_for_set()._Set_value(_Val, true);
}
void set_value(_Ty&& _Val) {
_MyPromise._Get_state_for_set()._Set_value(_STD forward<_Ty>(_Val), false);
}
void set_value_at_thread_exit(_Ty&& _Val) {
_MyPromise._Get_state_for_set()._Set_value(_STD forward<_Ty>(_Val), true);
}
void set_exception(exception_ptr _Exc) {
_MyPromise._Get_state_for_set()._Set_exception(_Exc, false);
}
void set_exception_at_thread_exit(exception_ptr _Exc) {
_MyPromise._Get_state_for_set()._Set_exception(_Exc, true);
}
promise(const promise&) = delete;
promise& operator=(const promise&) = delete;
private:
_Promise<_Ty> _MyPromise;
};
template <class _Ty>
class promise<_Ty&> { // class that defines an asynchronous provider that holds a reference
public:
promise() : _MyPromise(new _Associated_state<_Ty*>) {}
template <class _Alloc>
promise(allocator_arg_t, const _Alloc& _Al) : _MyPromise(_Make_associated_state<_Ty*>(_Al)) {}
promise(promise&&) = default;
promise& operator=(promise&& _Other) noexcept {
promise(_STD move(_Other)).swap(*this);
return *this;
}
~promise() noexcept {
if (_MyPromise._Is_valid() && !_MyPromise._Is_ready()) {
// exception if destroyed before function object returns
future_error _Fut(_STD make_error_code(future_errc::broken_promise));
_MyPromise._Get_state()._Set_exception(_STD make_exception_ptr(_Fut), false);
}
}
void swap(promise& _Other) noexcept {
_MyPromise._Swap(_Other._MyPromise);
}
_NODISCARD_GET_FUTURE future<_Ty&> get_future() {
return future<_Ty&>(_From_raw_state_tag{}, _MyPromise._Get_state_for_future());
}
void set_value(_Ty& _Val) {
_MyPromise._Get_state_for_set()._Set_value(_STD addressof(_Val), false);
}
void set_value_at_thread_exit(_Ty& _Val) {
_MyPromise._Get_state_for_set()._Set_value(_STD addressof(_Val), true);
}
void set_exception(exception_ptr _Exc) {
_MyPromise._Get_state_for_set()._Set_exception(_Exc, false);
}
void set_exception_at_thread_exit(exception_ptr _Exc) {
_MyPromise._Get_state_for_set()._Set_exception(_Exc, true);
}
promise(const promise&) = delete;
promise& operator=(const promise&) = delete;
private:
_Promise<_Ty*> _MyPromise;
};
template <>
class promise<void> { // defines an asynchronous provider that does not hold a value
public:
promise() : _MyPromise(new _Associated_state<int>) {}
template <class _Alloc>
promise(allocator_arg_t, const _Alloc& _Al) : _MyPromise(_Make_associated_state<int>(_Al)) {}
promise(promise&&) = default;
promise& operator=(promise&& _Other) noexcept {
promise(_STD move(_Other)).swap(*this);
return *this;
}
~promise() noexcept {
if (_MyPromise._Is_valid() && !_MyPromise._Is_ready()) {
// exception if destroyed before function object returns
future_error _Fut(_STD make_error_code(future_errc::broken_promise));
_MyPromise._Get_state()._Set_exception(_STD make_exception_ptr(_Fut), false);
}
}
void swap(promise& _Other) noexcept {
_MyPromise._Swap(_Other._MyPromise);
}
_NODISCARD_GET_FUTURE future<void> get_future() {
return future<void>(_From_raw_state_tag{}, _MyPromise._Get_state_for_future());
}
void set_value() {
_MyPromise._Get_state_for_set()._Set_value(1, false);
}
void set_value_at_thread_exit() {
_MyPromise._Get_state_for_set()._Set_value(1, true);
}
void set_exception(exception_ptr _Exc) {
_MyPromise._Get_state_for_set()._Set_exception(_Exc, false);
}
void set_exception_at_thread_exit(exception_ptr _Exc) {
_MyPromise._Get_state_for_set()._Set_exception(_Exc, true);
}
promise(const promise&) = delete;
promise& operator=(const promise&) = delete;
private:
_Promise<int> _MyPromise;
};
template <class _Ty, class _Alloc>
struct uses_allocator<promise<_Ty>, _Alloc> : true_type {};
_EXPORT_STD template <class _Ty>
void swap(promise<_Ty>& _Left, promise<_Ty>& _Right) noexcept {
_Left.swap(_Right);
}
_EXPORT_STD template <class>
class packaged_task; // not defined
template <class _Ret, class... _ArgTypes>
class packaged_task<_Ret(_ArgTypes...)> {
// class that defines an asynchronous provider that returns the result of a call to a function object
private:
using _Ptype = typename _P_arg_type<_Ret>::type;
using _MyPromiseType = _Promise<_Ptype>;
using _MyStateManagerType = _State_manager<_Ptype>;
using _MyStateType = _Packaged_state<_Ret(_ArgTypes...)>;
public:
packaged_task() = default;
template <class _Fty2, enable_if_t<!is_same_v<_Remove_cvref_t<_Fty2>, packaged_task>, int> = 0>
explicit packaged_task(_Fty2&& _Fnarg) : _MyPromise(new _MyStateType(_STD forward<_Fty2>(_Fnarg))) {
static_assert(_Is_invocable_r<_Ret, decay_t<_Fty2>&, _ArgTypes...>::value, // per LWG-4154
"The function object must be callable with _ArgTypes... and return _Ret (N4988 [futures.task.members]/3).");
}
packaged_task(packaged_task&&) noexcept = default;
packaged_task& operator=(packaged_task&&) noexcept = default;
#if _HAS_FUNCTION_ALLOCATOR_SUPPORT
template <class _Fty2, class _Alloc, enable_if_t<!is_same_v<_Remove_cvref_t<_Fty2>, packaged_task>, int> = 0>
packaged_task(allocator_arg_t, const _Alloc& _Al, _Fty2&& _Fnarg)
: _MyPromise(_STD _Make_packaged_state<_MyStateType>(_STD forward<_Fty2>(_Fnarg), _Al)) {
static_assert(_Is_invocable_r<_Ret, decay_t<_Fty2>&, _ArgTypes...>::value, // per LWG-4154
"The function object must be callable with _ArgTypes... and return _Ret (N4140 [futures.task.members]/2).");
}
#endif // _HAS_FUNCTION_ALLOCATOR_SUPPORT
~packaged_task() noexcept {
_MyPromise._Get_state()._Abandon();
}
void swap(packaged_task& _Other) noexcept {
_STD swap(_MyPromise, _Other._MyPromise);
}
_NODISCARD bool valid() const noexcept {
return _MyPromise._Is_valid();
}
_NODISCARD_GET_FUTURE future<_Ret> get_future() {
return future<_Ret>(_From_raw_state_tag{}, _MyPromise._Get_state_for_future());
}
void operator()(_ArgTypes... _Args) {
if (_MyPromise._Is_ready()) {
_Throw_future_error2(future_errc::promise_already_satisfied);
}
_MyStateManagerType& _State = _MyPromise._Get_state_for_set();
_MyStateType* _Ptr = static_cast<_MyStateType*>(_State._Ptr());
_Ptr->_Call_immediate(_STD forward<_ArgTypes>(_Args)...);
}
void make_ready_at_thread_exit(_ArgTypes... _Args) {
if (_MyPromise._Is_ready()) {
_Throw_future_error2(future_errc::promise_already_satisfied);
}
_MyStateManagerType& _State = _MyPromise._Get_state_for_set();
if (_State._Ptr()->_Already_has_stored_result()) {
_Throw_future_error2(future_errc::promise_already_satisfied);
}
_MyStateType* _Ptr = static_cast<_MyStateType*>(_State._Ptr());
_Ptr->_Call_deferred(_STD forward<_ArgTypes>(_Args)...);
}
void reset() { // reset to newly constructed state
_MyStateManagerType& _State_mgr = _MyPromise._Get_state_for_set();
_MyStateType& _MyState = *static_cast<_MyStateType*>(_State_mgr._Ptr());
_MyPromiseType _New_promise(new _MyStateType(_STD move(_MyState)._Get_fn()));
_MyPromise._Get_state()._Abandon();
_MyPromise._Swap(_New_promise);
}
packaged_task(const packaged_task&) = delete;
packaged_task& operator=(const packaged_task&) = delete;
private:
_MyPromiseType _MyPromise{nullptr};
};
#if _HAS_CXX17
#define _PACKAGED_TASK_DEDUCTION_GUIDE(CALL_OPT, X1, X2, X3) \
template <class _Ret, class... _Types> \
packaged_task(_Ret(CALL_OPT*)(_Types...)) -> packaged_task<_Ret(_Types...)>; // intentionally discards CALL_OPT
_NON_MEMBER_CALL(_PACKAGED_TASK_DEDUCTION_GUIDE, X1, X2, X3)
#undef _PACKAGED_TASK_DEDUCTION_GUIDE
template <class _Fx>
packaged_task(_Fx) -> packaged_task<typename _Deduce_signature<_Fx>::type>;
#endif // _HAS_CXX17
#if _HAS_FUNCTION_ALLOCATOR_SUPPORT
template <class _Ty, class _Alloc>
struct uses_allocator<packaged_task<_Ty>, _Alloc> : true_type {};
#endif // _HAS_FUNCTION_ALLOCATOR_SUPPORT
_EXPORT_STD template <class _Ty>
void swap(packaged_task<_Ty>& _Left, packaged_task<_Ty>& _Right) noexcept {
_Left.swap(_Right);
}
template <class... _Types, size_t... _Indices>
decltype(auto) _Invoke_stored_explicit(
tuple<_Types...>&& _Tuple, index_sequence<_Indices...>) { // invoke() a tuple with explicit parameter ordering
return _STD invoke(_STD get<_Indices>(_STD move(_Tuple))...);
}
template <class... _Types>
decltype(auto) _Invoke_stored(tuple<_Types...>&& _Tuple) { // invoke() a tuple
return _Invoke_stored_explicit(_STD move(_Tuple), index_sequence_for<_Types...>{});
}
template <class... _Types>
class _Fake_no_copy_callable_adapter {
// async() is built on packaged_task internals which incorrectly use
// std::function, which requires that things be copyable. We can't fix this in an
// update, so this adapter turns copies into abort(). When VSO-153581 is
// fixed, remove this adapter.
private:
using _Storaget = tuple<decay_t<_Types>...>;
public:
explicit _Fake_no_copy_callable_adapter(_Types&&... _Vals) : _Storage(_STD forward<_Types>(_Vals)...) {
// Initializes _Fake_no_copy_callable_adapter with a decayed callable object and arguments
}
[[noreturn]] _Fake_no_copy_callable_adapter(const _Fake_no_copy_callable_adapter& _Other)
: _Storage(_STD move(_Other._Storage)) {
_CSTD abort(); // shouldn't be called
}
_Fake_no_copy_callable_adapter(_Fake_no_copy_callable_adapter&& _Other) = default;
_Fake_no_copy_callable_adapter& operator=(const _Fake_no_copy_callable_adapter&) = delete;
_Fake_no_copy_callable_adapter& operator=(_Fake_no_copy_callable_adapter&&) = delete;
decltype(auto) operator()() {
return _Invoke_stored(_STD move(_Storage));
}
private:
mutable _Storaget _Storage;
};
template <class _Ret, class _Fty>
_Associated_state<typename _P_arg_type<_Ret>::type>* _Get_associated_state(launch _Psync, _Fty&& _Fnarg) {
// construct associated asynchronous state object for the launch type
switch (_Psync) { // select launch type
case launch::deferred:
return new _Deferred_async_state<_Ret>(_STD forward<_Fty>(_Fnarg));
case launch::async: // TRANSITION, fixed in vMajorNext, should create a new thread here
default:
return new _Task_async_state<_Ret>(_STD forward<_Fty>(_Fnarg));
}
}
_EXPORT_STD template <class _Fty, class... _ArgTypes>
_NODISCARD_ASYNC future<_Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>> async(
launch _Policy, _Fty&& _Fnarg, _ArgTypes&&... _Args) {
// manages a callable object launched with supplied policy
using _Ret = _Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>;
using _Ptype = typename _P_arg_type<_Ret>::type;
_Promise<_Ptype> _Pr(
_Get_associated_state<_Ret>(_Policy, _Fake_no_copy_callable_adapter<_Fty, _ArgTypes...>(
_STD forward<_Fty>(_Fnarg), _STD forward<_ArgTypes>(_Args)...)));
return future<_Ret>(_From_raw_state_tag{}, _Pr._Get_state_for_future());
}
_EXPORT_STD template <class _Fty, class... _ArgTypes>
_NODISCARD_ASYNC future<_Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>> async(
_Fty&& _Fnarg, _ArgTypes&&... _Args) {
// manages a callable object launched with default policy
return _STD async(launch::async | launch::deferred, _STD forward<_Fty>(_Fnarg), _STD forward<_ArgTypes>(_Args)...);
}
#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED
// Experimental coroutine support for std::future. Subject to change/removal!
namespace experimental {
template <class _Ty, class... _ArgTypes>
struct coroutine_traits<future<_Ty>, _ArgTypes...> {
// defines resumable traits for functions returning future<_Ty>
struct promise_type {
promise<_Ty> _MyPromise;
future<_Ty> get_return_object() {
return _MyPromise.get_future();
}
suspend_never initial_suspend() const noexcept {
return {};
}
suspend_never final_suspend() const noexcept {
return {};
}
template <class _Ut>
void return_value(_Ut&& _Value) {
_MyPromise.set_value(_STD forward<_Ut>(_Value));
}
void unhandled_exception() {
_MyPromise.set_exception(_STD current_exception());
}
};
};
template <class... _ArgTypes>
struct coroutine_traits<future<void>, _ArgTypes...> {
// defines resumable traits for functions returning future<void>
struct promise_type {
promise<void> _MyPromise;
future<void> get_return_object() {
return _MyPromise.get_future();
}
suspend_never initial_suspend() const noexcept {
return {};
}
suspend_never final_suspend() const noexcept {
return {};
}
void return_void() {
_MyPromise.set_value();
}
void unhandled_exception() {
_MyPromise.set_exception(_STD current_exception());
}
};
};
template <class _Ty>
struct _Future_awaiter {
future<_Ty>& _Fut;
bool await_ready() const {
return _Fut._Is_ready();
}
void await_suspend(experimental::coroutine_handle<> _ResumeCb) {
// TRANSITION, change to .then if and when future gets .then
thread _WaitingThread([&_Fut = _Fut, _ResumeCb]() mutable {
_Fut.wait();
_ResumeCb();
});
_WaitingThread.detach();
}
decltype(auto) await_resume() {
return _Fut.get();
}
};
} // namespace experimental
// Coroutines TS and C++20 coroutine adapter.
template <class _Ty>
auto operator co_await(future<_Ty>&& _Fut) {
return experimental::_Future_awaiter<_Ty>{_Fut};
}
template <class _Ty>
auto operator co_await(future<_Ty>& _Fut) {
return experimental::_Future_awaiter<_Ty>{_Fut};
}
#endif // _RESUMABLE_FUNCTIONS_SUPPORTED
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _FUTURE_