// future standard header // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef _FUTURE_ #define _FUTURE_ #include #if _STL_COMPILER_PREPROCESSOR #ifdef _M_CEE_PURE #error is not supported when compiling with /clr:pure. #endif // defined(_M_CEE_PURE) #ifdef _RESUMABLE_FUNCTIONS_SUPPORTED #include #endif // _RESUMABLE_FUNCTIONS_SUPPORTED #include <__msvc_chrono.hpp> #include #include #include #include #include #include #include #include #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 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 using _Unique_ptr_alloc = unique_ptr>; template _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 : 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(_Ec), _STD future_category()); } _EXPORT_STD _NODISCARD inline error_condition make_error_condition(future_errc _Ec) noexcept { return error_condition(static_cast(_Ec), _STD future_category()); } _NODISCARD inline const char* _Future_error_map(int _Errcode) noexcept { // convert to name of future error switch (static_cast(_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 _Associated_state; template 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 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 union _Result_holder { _Result_holder() noexcept {} ~_Result_holder() noexcept {} _Ty _Held_value; }; template 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 _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 future_status _Wait_for(const chrono::duration<_Rep, _Per>& _Rel_time) { // wait for duration unique_lock _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 future_status _Wait_until(const chrono::time_point<_Clock, _Dur>& _Abs_time) { // wait until time point unique_lock _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 _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 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(_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 _Lock(_Mtx); _Set_value_raw(_Val, &_Lock, _At_thread_exit); } void _Set_value_raw(const _Ty& _Val, unique_lock* _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 _Lock(_Mtx); _Set_value_raw(_STD forward<_Ty>(_Val), &_Lock, _At_thread_exit); } void _Set_value_raw(_Ty&& _Val, unique_lock* _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 _Lock(_Mtx); _Set_exception_raw(_Exc, &_Lock, _At_thread_exit); } void _Set_exception_raw(exception_ptr _Exc, unique_lock* _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::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 _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& _Lock) { // run a deferred function if not already done if (!_Running) { // run the function _Running = true; _Run_deferred_function(_Lock); } } public: conditional_t, _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&) {} // do nothing virtual void _Do_notify(unique_lock* _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 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 struct _P_arg_type { // type for functions returning T using type = _Fret; }; template struct _P_arg_type<_Fret&> { // type for functions returning reference to T using type = _Fret*; }; template <> struct _P_arg_type { // type for functions returning void using type = int; }; template class _Packaged_state; // class for managing associated asynchronous state for packaged_task template class _Packaged_state<_Ret(_ArgTypes...)> : public _Associated_state::type> { public: using _Mybase = _Associated_state::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 , _Function_type>, int> = 0> explicit _Packaged_state(_Fty2&& _Fnarg) : _Fn(_Secret_copyability_ignoring_tag{}, _STD forward<_Fty2>(_Fnarg)) {} #if _HAS_FUNCTION_ALLOCATOR_SUPPORT template _Packaged_state(const _Function_type& _Fnarg, const _Alloc& _Al, _Mydel* _Dp) : _Mybase(_Dp), _Fn(allocator_arg, _Al, _Fnarg) {} template _Packaged_state(_Function_type&& _Fnarg, const _Alloc& _Al, _Mydel* _Dp) : _Mybase(_Dp), _Fn(allocator_arg, _Al, _STD move(_Fnarg)) {} template , _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 _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 _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; 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 _Deferred_async_state : public _Packaged_state<_Rx()> { // class for managing associated synchronous state for deferred execution from async public: template _Deferred_async_state(const _Fty2& _Fnarg) : _Packaged_state<_Rx()>(_Fnarg) {} template _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& _Lock) override { // run the deferred function _Lock.unlock(); _Packaged_state<_Rx()>::_Call_immediate(); _Lock.lock(); } }; template 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 _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 _Task; }; template 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 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 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 shared_future; _EXPORT_STD template 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 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 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 : public _State_manager { // class that defines a non-copyable asynchronous return object that does not hold a value private: using _Mybase = _State_manager; 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 share() noexcept; future(const future&) = delete; future& operator=(const future&) = delete; }; _EXPORT_STD template 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 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 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 : public _State_manager { // class that defines a copyable asynchronous return object that does not hold a value private: using _Mybase = _State_manager; 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&& _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 future::share() noexcept { return shared_future(_STD move(*this)); } template 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 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 must meet the Cpp17Destructible requirements (N4950 [futures.promise]/1)."); promise() : _MyPromise(new _Associated_state<_Ty>) {} template 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 promise<_Ty&> { // class that defines an asynchronous provider that holds a reference public: promise() : _MyPromise(new _Associated_state<_Ty*>) {} template 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 { // defines an asynchronous provider that does not hold a value public: promise() : _MyPromise(new _Associated_state) {} template promise(allocator_arg_t, const _Alloc& _Al) : _MyPromise(_Make_associated_state(_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 get_future() { return future(_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 _MyPromise; }; template struct uses_allocator, _Alloc> : true_type {}; _EXPORT_STD template void swap(promise<_Ty>& _Left, promise<_Ty>& _Right) noexcept { _Left.swap(_Right); } _EXPORT_STD template class packaged_task; // not defined template 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 , 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 , 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 \ 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 packaged_task(_Fx) -> packaged_task::type>; #endif // _HAS_CXX17 #if _HAS_FUNCTION_ALLOCATOR_SUPPORT template struct uses_allocator, _Alloc> : true_type {}; #endif // _HAS_FUNCTION_ALLOCATOR_SUPPORT _EXPORT_STD template void swap(packaged_task<_Ty>& _Left, packaged_task<_Ty>& _Right) noexcept { _Left.swap(_Right); } template 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 decltype(auto) _Invoke_stored(tuple<_Types...>&& _Tuple) { // invoke() a tuple return _Invoke_stored_explicit(_STD move(_Tuple), index_sequence_for<_Types...>{}); } template 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...>; 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 _Associated_state::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 _NODISCARD_ASYNC future<_Invoke_result_t, 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<_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 _NODISCARD_ASYNC future<_Invoke_result_t, 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 struct coroutine_traits, _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 void return_value(_Ut&& _Value) { _MyPromise.set_value(_STD forward<_Ut>(_Value)); } void unhandled_exception() { _MyPromise.set_exception(_STD current_exception()); } }; }; template struct coroutine_traits, _ArgTypes...> { // defines resumable traits for functions returning future struct promise_type { promise _MyPromise; future 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 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 auto operator co_await(future<_Ty>&& _Fut) { return experimental::_Future_awaiter<_Ty>{_Fut}; } template 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_