gcc/libstdc++-v3/include/std/future
Jonathan Wakely bf1fc37bb4 libstdc++: Define and use chrono::is_clock for C++20
For C++20 the wait_until members of mutexes and condition variables are
required to be ill-formed if given a clock that doesn't meet the
requirements for a clock type. To implement that requirement this patch
adds static assertions using the chrono::is_clock trait, and defines
that trait.

To avoid expensive checks for the common cases, the trait (and
associated variable template) are explicitly specialized for the
standard clock types.

This also moves the filesystem::__file_clock type from <filesystem> to
<chrono>, so that chrono::file_clock and chrono::file_time can be
defined in <chrono> as required.

	* include/bits/fs_fwd.h (filesystem::__file_clock): Move to ...
	* include/std/chrono (filesystem::__file_clock): Here.
	(filesystem::__file_clock::from_sys, filesystem::__file_clock::to_sys):
	Define public member functions for C++20.
	(is_clock, is_clock_v): Define traits for C++20.
	* include/std/condition_variable (condition_variable::wait_until): Add
	check for valid clock.
	* include/std/future (_State_baseV2::wait_until): Likewise.
	* include/std/mutex (__timed_mutex_impl::_M_try_lock_until): Likewise.
	* include/std/shared_mutex (shared_timed_mutex::try_lock_shared_until):
	Likewise.
	* include/std/thread (this_thread::sleep_until): Likewise.
	* testsuite/30_threads/condition_variable/members/2.cc: Qualify
	slow_clock with new namespace.
	* testsuite/30_threads/condition_variable/members/clock_neg.cc: New
	test.
	* testsuite/30_threads/condition_variable_any/members/clock_neg.cc:
	New test.
	* testsuite/30_threads/future/members/clock_neg.cc: New test.
	* testsuite/30_threads/recursive_timed_mutex/try_lock_until/3.cc:
	Qualify slow_clock with new namespace.
	* testsuite/30_threads/recursive_timed_mutex/try_lock_until/
	clock_neg.cc: New test.
	* testsuite/30_threads/shared_future/members/clock_neg.cc: New
	test.
	* testsuite/30_threads/shared_lock/locking/clock_neg.cc: New test.
	* testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc:
	New test.
	* testsuite/30_threads/timed_mutex/try_lock_until/3.cc: Qualify
	slow_clock with new namespace.
	* testsuite/30_threads/timed_mutex/try_lock_until/4.cc: Likewise.
	* testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc: New
	test.
	* testsuite/30_threads/unique_lock/locking/clock_neg.cc: New test.
	* testsuite/std/time/traits/is_clock.cc: New test.
	* testsuite/util/slow_clock.h (slow_clock): Move to __gnu_test
	namespace.
2020-03-25 22:07:02 +00:00

1769 lines
50 KiB
C++

// <future> -*- C++ -*-
// Copyright (C) 2009-2020 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
/** @file include/future
* This is a Standard C++ Library header.
*/
#ifndef _GLIBCXX_FUTURE
#define _GLIBCXX_FUTURE 1
#pragma GCC system_header
#if __cplusplus < 201103L
# include <bits/c++0x_warning.h>
#else
#include <mutex>
#include <thread>
#include <condition_variable>
#include <system_error>
#include <atomic>
#include <bits/atomic_futex.h>
#include <bits/functexcept.h>
#include <bits/invoke.h>
#include <bits/unique_ptr.h>
#include <bits/shared_ptr.h>
#include <bits/std_function.h>
#include <bits/uses_allocator.h>
#include <bits/allocated_ptr.h>
#include <ext/aligned_buffer.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
/**
* @defgroup futures Futures
* @ingroup concurrency
*
* Classes for futures support.
* @{
*/
/// Error code for futures
enum class future_errc
{
future_already_retrieved = 1,
promise_already_satisfied,
no_state,
broken_promise
};
/// Specialization.
template<>
struct is_error_code_enum<future_errc> : public true_type { };
/// Points to a statically-allocated object derived from error_category.
const error_category&
future_category() noexcept;
/// Overload for make_error_code.
inline error_code
make_error_code(future_errc __errc) noexcept
{ return error_code(static_cast<int>(__errc), future_category()); }
/// Overload for make_error_condition.
inline error_condition
make_error_condition(future_errc __errc) noexcept
{ return error_condition(static_cast<int>(__errc), future_category()); }
/**
* @brief Exception type thrown by futures.
* @ingroup exceptions
*/
class future_error : public logic_error
{
public:
explicit
future_error(future_errc __errc)
: future_error(std::make_error_code(__errc))
{ }
virtual ~future_error() noexcept;
virtual const char*
what() const noexcept;
const error_code&
code() const noexcept { return _M_code; }
private:
explicit
future_error(error_code __ec)
: logic_error("std::future_error: " + __ec.message()), _M_code(__ec)
{ }
friend void __throw_future_error(int);
error_code _M_code;
};
// Forward declarations.
template<typename _Res>
class future;
template<typename _Res>
class shared_future;
template<typename _Signature>
class packaged_task;
template<typename _Res>
class promise;
/// Launch code for futures
enum class launch
{
async = 1,
deferred = 2
};
constexpr launch operator&(launch __x, launch __y)
{
return static_cast<launch>(
static_cast<int>(__x) & static_cast<int>(__y));
}
constexpr launch operator|(launch __x, launch __y)
{
return static_cast<launch>(
static_cast<int>(__x) | static_cast<int>(__y));
}
constexpr launch operator^(launch __x, launch __y)
{
return static_cast<launch>(
static_cast<int>(__x) ^ static_cast<int>(__y));
}
constexpr launch operator~(launch __x)
{ return static_cast<launch>(~static_cast<int>(__x)); }
inline launch& operator&=(launch& __x, launch __y)
{ return __x = __x & __y; }
inline launch& operator|=(launch& __x, launch __y)
{ return __x = __x | __y; }
inline launch& operator^=(launch& __x, launch __y)
{ return __x = __x ^ __y; }
/// Status code for futures
enum class future_status
{
ready,
timeout,
deferred
};
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2021. Further incorrect usages of result_of
template<typename _Fn, typename... _Args>
using __async_result_of = typename __invoke_result<
typename decay<_Fn>::type, typename decay<_Args>::type...>::type;
template<typename _Fn, typename... _Args>
future<__async_result_of<_Fn, _Args...>>
async(launch __policy, _Fn&& __fn, _Args&&... __args);
template<typename _Fn, typename... _Args>
future<__async_result_of<_Fn, _Args...>>
async(_Fn&& __fn, _Args&&... __args);
#if defined(_GLIBCXX_HAS_GTHREADS)
/// Base class and enclosing scope.
struct __future_base
{
/// Base class for results.
struct _Result_base
{
exception_ptr _M_error;
_Result_base(const _Result_base&) = delete;
_Result_base& operator=(const _Result_base&) = delete;
// _M_destroy() allows derived classes to control deallocation
virtual void _M_destroy() = 0;
struct _Deleter
{
void operator()(_Result_base* __fr) const { __fr->_M_destroy(); }
};
protected:
_Result_base();
virtual ~_Result_base();
};
/// A unique_ptr for result objects.
template<typename _Res>
using _Ptr = unique_ptr<_Res, _Result_base::_Deleter>;
/// A result object that has storage for an object of type _Res.
template<typename _Res>
struct _Result : _Result_base
{
private:
__gnu_cxx::__aligned_buffer<_Res> _M_storage;
bool _M_initialized;
public:
typedef _Res result_type;
_Result() noexcept : _M_initialized() { }
~_Result()
{
if (_M_initialized)
_M_value().~_Res();
}
// Return lvalue, future will add const or rvalue-reference
_Res&
_M_value() noexcept { return *_M_storage._M_ptr(); }
void
_M_set(const _Res& __res)
{
::new (_M_storage._M_addr()) _Res(__res);
_M_initialized = true;
}
void
_M_set(_Res&& __res)
{
::new (_M_storage._M_addr()) _Res(std::move(__res));
_M_initialized = true;
}
private:
void _M_destroy() { delete this; }
};
/// A result object that uses an allocator.
template<typename _Res, typename _Alloc>
struct _Result_alloc final : _Result<_Res>, _Alloc
{
using __allocator_type = __alloc_rebind<_Alloc, _Result_alloc>;
explicit
_Result_alloc(const _Alloc& __a) : _Result<_Res>(), _Alloc(__a)
{ }
private:
void _M_destroy()
{
__allocator_type __a(*this);
__allocated_ptr<__allocator_type> __guard_ptr{ __a, this };
this->~_Result_alloc();
}
};
// Create a result object that uses an allocator.
template<typename _Res, typename _Allocator>
static _Ptr<_Result_alloc<_Res, _Allocator>>
_S_allocate_result(const _Allocator& __a)
{
using __result_type = _Result_alloc<_Res, _Allocator>;
typename __result_type::__allocator_type __a2(__a);
auto __guard = std::__allocate_guarded(__a2);
__result_type* __p = ::new((void*)__guard.get()) __result_type{__a};
__guard = nullptr;
return _Ptr<__result_type>(__p);
}
// Keep it simple for std::allocator.
template<typename _Res, typename _Tp>
static _Ptr<_Result<_Res>>
_S_allocate_result(const std::allocator<_Tp>& __a)
{
return _Ptr<_Result<_Res>>(new _Result<_Res>);
}
// Base class for various types of shared state created by an
// asynchronous provider (such as a std::promise) and shared with one
// or more associated futures.
class _State_baseV2
{
typedef _Ptr<_Result_base> _Ptr_type;
enum _Status : unsigned {
__not_ready,
__ready
};
_Ptr_type _M_result;
__atomic_futex_unsigned<> _M_status;
atomic_flag _M_retrieved = ATOMIC_FLAG_INIT;
once_flag _M_once;
public:
_State_baseV2() noexcept : _M_result(), _M_status(_Status::__not_ready)
{ }
_State_baseV2(const _State_baseV2&) = delete;
_State_baseV2& operator=(const _State_baseV2&) = delete;
virtual ~_State_baseV2() = default;
_Result_base&
wait()
{
// Run any deferred function or join any asynchronous thread:
_M_complete_async();
// Acquire MO makes sure this synchronizes with the thread that made
// the future ready.
_M_status._M_load_when_equal(_Status::__ready, memory_order_acquire);
return *_M_result;
}
template<typename _Rep, typename _Period>
future_status
wait_for(const chrono::duration<_Rep, _Period>& __rel)
{
// First, check if the future has been made ready. Use acquire MO
// to synchronize with the thread that made it ready.
if (_M_status._M_load(memory_order_acquire) == _Status::__ready)
return future_status::ready;
if (_M_is_deferred_future())
return future_status::deferred;
if (_M_status._M_load_when_equal_for(_Status::__ready,
memory_order_acquire, __rel))
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2100. timed waiting functions must also join
// This call is a no-op by default except on an async future,
// in which case the async thread is joined. It's also not a
// no-op for a deferred future, but such a future will never
// reach this point because it returns future_status::deferred
// instead of waiting for the future to become ready (see
// above). Async futures synchronize in this call, so we need
// no further synchronization here.
_M_complete_async();
return future_status::ready;
}
return future_status::timeout;
}
template<typename _Clock, typename _Duration>
future_status
wait_until(const chrono::time_point<_Clock, _Duration>& __abs)
{
#if __cplusplus > 201703L
static_assert(chrono::is_clock_v<_Clock>);
#endif
// First, check if the future has been made ready. Use acquire MO
// to synchronize with the thread that made it ready.
if (_M_status._M_load(memory_order_acquire) == _Status::__ready)
return future_status::ready;
if (_M_is_deferred_future())
return future_status::deferred;
if (_M_status._M_load_when_equal_until(_Status::__ready,
memory_order_acquire, __abs))
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2100. timed waiting functions must also join
// See wait_for(...) above.
_M_complete_async();
return future_status::ready;
}
return future_status::timeout;
}
// Provide a result to the shared state and make it ready.
// Calls at most once: _M_result = __res();
void
_M_set_result(function<_Ptr_type()> __res, bool __ignore_failure = false)
{
bool __did_set = false;
// all calls to this function are serialized,
// side-effects of invoking __res only happen once
call_once(_M_once, &_State_baseV2::_M_do_set, this,
std::__addressof(__res), std::__addressof(__did_set));
if (__did_set)
// Use release MO to synchronize with observers of the ready state.
_M_status._M_store_notify_all(_Status::__ready,
memory_order_release);
else if (!__ignore_failure)
__throw_future_error(int(future_errc::promise_already_satisfied));
}
// Provide a result to the shared state but delay making it ready
// until the calling thread exits.
// Calls at most once: _M_result = __res();
void
_M_set_delayed_result(function<_Ptr_type()> __res,
weak_ptr<_State_baseV2> __self)
{
bool __did_set = false;
unique_ptr<_Make_ready> __mr{new _Make_ready};
// all calls to this function are serialized,
// side-effects of invoking __res only happen once
call_once(_M_once, &_State_baseV2::_M_do_set, this,
std::__addressof(__res), std::__addressof(__did_set));
if (!__did_set)
__throw_future_error(int(future_errc::promise_already_satisfied));
__mr->_M_shared_state = std::move(__self);
__mr->_M_set();
__mr.release();
}
// Abandon this shared state.
void
_M_break_promise(_Ptr_type __res)
{
if (static_cast<bool>(__res))
{
__res->_M_error =
make_exception_ptr(future_error(future_errc::broken_promise));
// This function is only called when the last asynchronous result
// provider is abandoning this shared state, so noone can be
// trying to make the shared state ready at the same time, and
// we can access _M_result directly instead of through call_once.
_M_result.swap(__res);
// Use release MO to synchronize with observers of the ready state.
_M_status._M_store_notify_all(_Status::__ready,
memory_order_release);
}
}
// Called when this object is first passed to a future.
void
_M_set_retrieved_flag()
{
if (_M_retrieved.test_and_set())
__throw_future_error(int(future_errc::future_already_retrieved));
}
template<typename _Res, typename _Arg>
struct _Setter;
// set lvalues
template<typename _Res, typename _Arg>
struct _Setter<_Res, _Arg&>
{
// check this is only used by promise<R>::set_value(const R&)
// or promise<R&>::set_value(R&)
static_assert(is_same<_Res, _Arg&>::value // promise<R&>
|| is_same<const _Res, _Arg>::value, // promise<R>
"Invalid specialisation");
// Used by std::promise to copy construct the result.
typename promise<_Res>::_Ptr_type operator()() const
{
_M_promise->_M_storage->_M_set(*_M_arg);
return std::move(_M_promise->_M_storage);
}
promise<_Res>* _M_promise;
_Arg* _M_arg;
};
// set rvalues
template<typename _Res>
struct _Setter<_Res, _Res&&>
{
// Used by std::promise to move construct the result.
typename promise<_Res>::_Ptr_type operator()() const
{
_M_promise->_M_storage->_M_set(std::move(*_M_arg));
return std::move(_M_promise->_M_storage);
}
promise<_Res>* _M_promise;
_Res* _M_arg;
};
// set void
template<typename _Res>
struct _Setter<_Res, void>
{
static_assert(is_void<_Res>::value, "Only used for promise<void>");
typename promise<_Res>::_Ptr_type operator()() const
{ return std::move(_M_promise->_M_storage); }
promise<_Res>* _M_promise;
};
struct __exception_ptr_tag { };
// set exceptions
template<typename _Res>
struct _Setter<_Res, __exception_ptr_tag>
{
// Used by std::promise to store an exception as the result.
typename promise<_Res>::_Ptr_type operator()() const
{
_M_promise->_M_storage->_M_error = *_M_ex;
return std::move(_M_promise->_M_storage);
}
promise<_Res>* _M_promise;
exception_ptr* _M_ex;
};
template<typename _Res, typename _Arg>
static _Setter<_Res, _Arg&&>
__setter(promise<_Res>* __prom, _Arg&& __arg)
{
_S_check(__prom->_M_future);
return _Setter<_Res, _Arg&&>{ __prom, std::__addressof(__arg) };
}
template<typename _Res>
static _Setter<_Res, __exception_ptr_tag>
__setter(exception_ptr& __ex, promise<_Res>* __prom)
{
_S_check(__prom->_M_future);
return _Setter<_Res, __exception_ptr_tag>{ __prom, &__ex };
}
template<typename _Res>
static _Setter<_Res, void>
__setter(promise<_Res>* __prom)
{
_S_check(__prom->_M_future);
return _Setter<_Res, void>{ __prom };
}
template<typename _Tp>
static void
_S_check(const shared_ptr<_Tp>& __p)
{
if (!static_cast<bool>(__p))
__throw_future_error((int)future_errc::no_state);
}
private:
// The function invoked with std::call_once(_M_once, ...).
void
_M_do_set(function<_Ptr_type()>* __f, bool* __did_set)
{
_Ptr_type __res = (*__f)();
// Notify the caller that we did try to set; if we do not throw an
// exception, the caller will be aware that it did set (e.g., see
// _M_set_result).
*__did_set = true;
_M_result.swap(__res); // nothrow
}
// Wait for completion of async function.
virtual void _M_complete_async() { }
// Return true if state corresponds to a deferred function.
virtual bool _M_is_deferred_future() const { return false; }
struct _Make_ready final : __at_thread_exit_elt
{
weak_ptr<_State_baseV2> _M_shared_state;
static void _S_run(void*);
void _M_set();
};
};
#ifdef _GLIBCXX_ASYNC_ABI_COMPAT
class _State_base;
class _Async_state_common;
#else
using _State_base = _State_baseV2;
class _Async_state_commonV2;
#endif
template<typename _BoundFn,
typename _Res = decltype(std::declval<_BoundFn&>()())>
class _Deferred_state;
template<typename _BoundFn,
typename _Res = decltype(std::declval<_BoundFn&>()())>
class _Async_state_impl;
template<typename _Signature>
class _Task_state_base;
template<typename _Fn, typename _Alloc, typename _Signature>
class _Task_state;
template<typename _BoundFn>
static std::shared_ptr<_State_base>
_S_make_deferred_state(_BoundFn&& __fn);
template<typename _BoundFn>
static std::shared_ptr<_State_base>
_S_make_async_state(_BoundFn&& __fn);
template<typename _Res_ptr, typename _Fn,
typename _Res = typename _Res_ptr::element_type::result_type>
struct _Task_setter;
template<typename _Res_ptr, typename _BoundFn>
static _Task_setter<_Res_ptr, _BoundFn>
_S_task_setter(_Res_ptr& __ptr, _BoundFn& __call)
{
return { std::__addressof(__ptr), std::__addressof(__call) };
}
};
/// Partial specialization for reference types.
template<typename _Res>
struct __future_base::_Result<_Res&> : __future_base::_Result_base
{
typedef _Res& result_type;
_Result() noexcept : _M_value_ptr() { }
void
_M_set(_Res& __res) noexcept
{ _M_value_ptr = std::addressof(__res); }
_Res& _M_get() noexcept { return *_M_value_ptr; }
private:
_Res* _M_value_ptr;
void _M_destroy() { delete this; }
};
/// Explicit specialization for void.
template<>
struct __future_base::_Result<void> : __future_base::_Result_base
{
typedef void result_type;
private:
void _M_destroy() { delete this; }
};
#ifndef _GLIBCXX_ASYNC_ABI_COMPAT
// Allow _Setter objects to be stored locally in std::function
template<typename _Res, typename _Arg>
struct __is_location_invariant
<__future_base::_State_base::_Setter<_Res, _Arg>>
: true_type { };
// Allow _Task_setter objects to be stored locally in std::function
template<typename _Res_ptr, typename _Fn, typename _Res>
struct __is_location_invariant
<__future_base::_Task_setter<_Res_ptr, _Fn, _Res>>
: true_type { };
/// Common implementation for future and shared_future.
template<typename _Res>
class __basic_future : public __future_base
{
protected:
typedef shared_ptr<_State_base> __state_type;
typedef __future_base::_Result<_Res>& __result_type;
private:
__state_type _M_state;
public:
// Disable copying.
__basic_future(const __basic_future&) = delete;
__basic_future& operator=(const __basic_future&) = delete;
bool
valid() const noexcept { return static_cast<bool>(_M_state); }
void
wait() const
{
_State_base::_S_check(_M_state);
_M_state->wait();
}
template<typename _Rep, typename _Period>
future_status
wait_for(const chrono::duration<_Rep, _Period>& __rel) const
{
_State_base::_S_check(_M_state);
return _M_state->wait_for(__rel);
}
template<typename _Clock, typename _Duration>
future_status
wait_until(const chrono::time_point<_Clock, _Duration>& __abs) const
{
_State_base::_S_check(_M_state);
return _M_state->wait_until(__abs);
}
protected:
/// Wait for the state to be ready and rethrow any stored exception
__result_type
_M_get_result() const
{
_State_base::_S_check(_M_state);
_Result_base& __res = _M_state->wait();
if (!(__res._M_error == 0))
rethrow_exception(__res._M_error);
return static_cast<__result_type>(__res);
}
void _M_swap(__basic_future& __that) noexcept
{
_M_state.swap(__that._M_state);
}
// Construction of a future by promise::get_future()
explicit
__basic_future(const __state_type& __state) : _M_state(__state)
{
_State_base::_S_check(_M_state);
_M_state->_M_set_retrieved_flag();
}
// Copy construction from a shared_future
explicit
__basic_future(const shared_future<_Res>&) noexcept;
// Move construction from a shared_future
explicit
__basic_future(shared_future<_Res>&&) noexcept;
// Move construction from a future
explicit
__basic_future(future<_Res>&&) noexcept;
constexpr __basic_future() noexcept : _M_state() { }
struct _Reset
{
explicit _Reset(__basic_future& __fut) noexcept : _M_fut(__fut) { }
~_Reset() { _M_fut._M_state.reset(); }
__basic_future& _M_fut;
};
};
/// Primary template for future.
template<typename _Res>
class future : public __basic_future<_Res>
{
friend class promise<_Res>;
template<typename> friend class packaged_task;
template<typename _Fn, typename... _Args>
friend future<__async_result_of<_Fn, _Args...>>
async(launch, _Fn&&, _Args&&...);
typedef __basic_future<_Res> _Base_type;
typedef typename _Base_type::__state_type __state_type;
explicit
future(const __state_type& __state) : _Base_type(__state) { }
public:
constexpr future() noexcept : _Base_type() { }
/// Move constructor
future(future&& __uf) noexcept : _Base_type(std::move(__uf)) { }
// Disable copying
future(const future&) = delete;
future& operator=(const future&) = delete;
future& operator=(future&& __fut) noexcept
{
future(std::move(__fut))._M_swap(*this);
return *this;
}
/// Retrieving the value
_Res
get()
{
typename _Base_type::_Reset __reset(*this);
return std::move(this->_M_get_result()._M_value());
}
shared_future<_Res> share() noexcept;
};
/// Partial specialization for future<R&>
template<typename _Res>
class future<_Res&> : public __basic_future<_Res&>
{
friend class promise<_Res&>;
template<typename> friend class packaged_task;
template<typename _Fn, typename... _Args>
friend future<__async_result_of<_Fn, _Args...>>
async(launch, _Fn&&, _Args&&...);
typedef __basic_future<_Res&> _Base_type;
typedef typename _Base_type::__state_type __state_type;
explicit
future(const __state_type& __state) : _Base_type(__state) { }
public:
constexpr future() noexcept : _Base_type() { }
/// Move constructor
future(future&& __uf) noexcept : _Base_type(std::move(__uf)) { }
// Disable copying
future(const future&) = delete;
future& operator=(const future&) = delete;
future& operator=(future&& __fut) noexcept
{
future(std::move(__fut))._M_swap(*this);
return *this;
}
/// Retrieving the value
_Res&
get()
{
typename _Base_type::_Reset __reset(*this);
return this->_M_get_result()._M_get();
}
shared_future<_Res&> share() noexcept;
};
/// Explicit specialization for future<void>
template<>
class future<void> : public __basic_future<void>
{
friend class promise<void>;
template<typename> friend class packaged_task;
template<typename _Fn, typename... _Args>
friend future<__async_result_of<_Fn, _Args...>>
async(launch, _Fn&&, _Args&&...);
typedef __basic_future<void> _Base_type;
typedef typename _Base_type::__state_type __state_type;
explicit
future(const __state_type& __state) : _Base_type(__state) { }
public:
constexpr future() noexcept : _Base_type() { }
/// Move constructor
future(future&& __uf) noexcept : _Base_type(std::move(__uf)) { }
// Disable copying
future(const future&) = delete;
future& operator=(const future&) = delete;
future& operator=(future&& __fut) noexcept
{
future(std::move(__fut))._M_swap(*this);
return *this;
}
/// Retrieving the value
void
get()
{
typename _Base_type::_Reset __reset(*this);
this->_M_get_result();
}
shared_future<void> share() noexcept;
};
/// Primary template for shared_future.
template<typename _Res>
class shared_future : public __basic_future<_Res>
{
typedef __basic_future<_Res> _Base_type;
public:
constexpr shared_future() noexcept : _Base_type() { }
/// Copy constructor
shared_future(const shared_future& __sf) noexcept : _Base_type(__sf) { }
/// Construct from a future rvalue
shared_future(future<_Res>&& __uf) noexcept
: _Base_type(std::move(__uf))
{ }
/// Construct from a shared_future rvalue
shared_future(shared_future&& __sf) noexcept
: _Base_type(std::move(__sf))
{ }
shared_future& operator=(const shared_future& __sf) noexcept
{
shared_future(__sf)._M_swap(*this);
return *this;
}
shared_future& operator=(shared_future&& __sf) noexcept
{
shared_future(std::move(__sf))._M_swap(*this);
return *this;
}
/// Retrieving the value
const _Res&
get() const { return this->_M_get_result()._M_value(); }
};
/// Partial specialization for shared_future<R&>
template<typename _Res>
class shared_future<_Res&> : public __basic_future<_Res&>
{
typedef __basic_future<_Res&> _Base_type;
public:
constexpr shared_future() noexcept : _Base_type() { }
/// Copy constructor
shared_future(const shared_future& __sf) : _Base_type(__sf) { }
/// Construct from a future rvalue
shared_future(future<_Res&>&& __uf) noexcept
: _Base_type(std::move(__uf))
{ }
/// Construct from a shared_future rvalue
shared_future(shared_future&& __sf) noexcept
: _Base_type(std::move(__sf))
{ }
shared_future& operator=(const shared_future& __sf)
{
shared_future(__sf)._M_swap(*this);
return *this;
}
shared_future& operator=(shared_future&& __sf) noexcept
{
shared_future(std::move(__sf))._M_swap(*this);
return *this;
}
/// Retrieving the value
_Res&
get() const { return this->_M_get_result()._M_get(); }
};
/// Explicit specialization for shared_future<void>
template<>
class shared_future<void> : public __basic_future<void>
{
typedef __basic_future<void> _Base_type;
public:
constexpr shared_future() noexcept : _Base_type() { }
/// Copy constructor
shared_future(const shared_future& __sf) : _Base_type(__sf) { }
/// Construct from a future rvalue
shared_future(future<void>&& __uf) noexcept
: _Base_type(std::move(__uf))
{ }
/// Construct from a shared_future rvalue
shared_future(shared_future&& __sf) noexcept
: _Base_type(std::move(__sf))
{ }
shared_future& operator=(const shared_future& __sf)
{
shared_future(__sf)._M_swap(*this);
return *this;
}
shared_future& operator=(shared_future&& __sf) noexcept
{
shared_future(std::move(__sf))._M_swap(*this);
return *this;
}
// Retrieving the value
void
get() const { this->_M_get_result(); }
};
// Now we can define the protected __basic_future constructors.
template<typename _Res>
inline __basic_future<_Res>::
__basic_future(const shared_future<_Res>& __sf) noexcept
: _M_state(__sf._M_state)
{ }
template<typename _Res>
inline __basic_future<_Res>::
__basic_future(shared_future<_Res>&& __sf) noexcept
: _M_state(std::move(__sf._M_state))
{ }
template<typename _Res>
inline __basic_future<_Res>::
__basic_future(future<_Res>&& __uf) noexcept
: _M_state(std::move(__uf._M_state))
{ }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2556. Wide contract for future::share()
template<typename _Res>
inline shared_future<_Res>
future<_Res>::share() noexcept
{ return shared_future<_Res>(std::move(*this)); }
template<typename _Res>
inline shared_future<_Res&>
future<_Res&>::share() noexcept
{ return shared_future<_Res&>(std::move(*this)); }
inline shared_future<void>
future<void>::share() noexcept
{ return shared_future<void>(std::move(*this)); }
/// Primary template for promise
template<typename _Res>
class promise
{
typedef __future_base::_State_base _State;
typedef __future_base::_Result<_Res> _Res_type;
typedef __future_base::_Ptr<_Res_type> _Ptr_type;
template<typename, typename> friend class _State::_Setter;
friend _State;
shared_ptr<_State> _M_future;
_Ptr_type _M_storage;
public:
promise()
: _M_future(std::make_shared<_State>()),
_M_storage(new _Res_type())
{ }
promise(promise&& __rhs) noexcept
: _M_future(std::move(__rhs._M_future)),
_M_storage(std::move(__rhs._M_storage))
{ }
template<typename _Allocator>
promise(allocator_arg_t, const _Allocator& __a)
: _M_future(std::allocate_shared<_State>(__a)),
_M_storage(__future_base::_S_allocate_result<_Res>(__a))
{ }
template<typename _Allocator>
promise(allocator_arg_t, const _Allocator&, promise&& __rhs)
: _M_future(std::move(__rhs._M_future)),
_M_storage(std::move(__rhs._M_storage))
{ }
promise(const promise&) = delete;
~promise()
{
if (static_cast<bool>(_M_future) && !_M_future.unique())
_M_future->_M_break_promise(std::move(_M_storage));
}
// Assignment
promise&
operator=(promise&& __rhs) noexcept
{
promise(std::move(__rhs)).swap(*this);
return *this;
}
promise& operator=(const promise&) = delete;
void
swap(promise& __rhs) noexcept
{
_M_future.swap(__rhs._M_future);
_M_storage.swap(__rhs._M_storage);
}
// Retrieving the result
future<_Res>
get_future()
{ return future<_Res>(_M_future); }
// Setting the result
void
set_value(const _Res& __r)
{ _M_future->_M_set_result(_State::__setter(this, __r)); }
void
set_value(_Res&& __r)
{ _M_future->_M_set_result(_State::__setter(this, std::move(__r))); }
void
set_exception(exception_ptr __p)
{ _M_future->_M_set_result(_State::__setter(__p, this)); }
void
set_value_at_thread_exit(const _Res& __r)
{
_M_future->_M_set_delayed_result(_State::__setter(this, __r),
_M_future);
}
void
set_value_at_thread_exit(_Res&& __r)
{
_M_future->_M_set_delayed_result(
_State::__setter(this, std::move(__r)), _M_future);
}
void
set_exception_at_thread_exit(exception_ptr __p)
{
_M_future->_M_set_delayed_result(_State::__setter(__p, this),
_M_future);
}
};
template<typename _Res>
inline void
swap(promise<_Res>& __x, promise<_Res>& __y) noexcept
{ __x.swap(__y); }
template<typename _Res, typename _Alloc>
struct uses_allocator<promise<_Res>, _Alloc>
: public true_type { };
/// Partial specialization for promise<R&>
template<typename _Res>
class promise<_Res&>
{
typedef __future_base::_State_base _State;
typedef __future_base::_Result<_Res&> _Res_type;
typedef __future_base::_Ptr<_Res_type> _Ptr_type;
template<typename, typename> friend class _State::_Setter;
friend _State;
shared_ptr<_State> _M_future;
_Ptr_type _M_storage;
public:
promise()
: _M_future(std::make_shared<_State>()),
_M_storage(new _Res_type())
{ }
promise(promise&& __rhs) noexcept
: _M_future(std::move(__rhs._M_future)),
_M_storage(std::move(__rhs._M_storage))
{ }
template<typename _Allocator>
promise(allocator_arg_t, const _Allocator& __a)
: _M_future(std::allocate_shared<_State>(__a)),
_M_storage(__future_base::_S_allocate_result<_Res&>(__a))
{ }
template<typename _Allocator>
promise(allocator_arg_t, const _Allocator&, promise&& __rhs)
: _M_future(std::move(__rhs._M_future)),
_M_storage(std::move(__rhs._M_storage))
{ }
promise(const promise&) = delete;
~promise()
{
if (static_cast<bool>(_M_future) && !_M_future.unique())
_M_future->_M_break_promise(std::move(_M_storage));
}
// Assignment
promise&
operator=(promise&& __rhs) noexcept
{
promise(std::move(__rhs)).swap(*this);
return *this;
}
promise& operator=(const promise&) = delete;
void
swap(promise& __rhs) noexcept
{
_M_future.swap(__rhs._M_future);
_M_storage.swap(__rhs._M_storage);
}
// Retrieving the result
future<_Res&>
get_future()
{ return future<_Res&>(_M_future); }
// Setting the result
void
set_value(_Res& __r)
{ _M_future->_M_set_result(_State::__setter(this, __r)); }
void
set_exception(exception_ptr __p)
{ _M_future->_M_set_result(_State::__setter(__p, this)); }
void
set_value_at_thread_exit(_Res& __r)
{
_M_future->_M_set_delayed_result(_State::__setter(this, __r),
_M_future);
}
void
set_exception_at_thread_exit(exception_ptr __p)
{
_M_future->_M_set_delayed_result(_State::__setter(__p, this),
_M_future);
}
};
/// Explicit specialization for promise<void>
template<>
class promise<void>
{
typedef __future_base::_State_base _State;
typedef __future_base::_Result<void> _Res_type;
typedef __future_base::_Ptr<_Res_type> _Ptr_type;
template<typename, typename> friend class _State::_Setter;
friend _State;
shared_ptr<_State> _M_future;
_Ptr_type _M_storage;
public:
promise()
: _M_future(std::make_shared<_State>()),
_M_storage(new _Res_type())
{ }
promise(promise&& __rhs) noexcept
: _M_future(std::move(__rhs._M_future)),
_M_storage(std::move(__rhs._M_storage))
{ }
template<typename _Allocator>
promise(allocator_arg_t, const _Allocator& __a)
: _M_future(std::allocate_shared<_State>(__a)),
_M_storage(__future_base::_S_allocate_result<void>(__a))
{ }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2095. missing constructors needed for uses-allocator construction
template<typename _Allocator>
promise(allocator_arg_t, const _Allocator&, promise&& __rhs)
: _M_future(std::move(__rhs._M_future)),
_M_storage(std::move(__rhs._M_storage))
{ }
promise(const promise&) = delete;
~promise()
{
if (static_cast<bool>(_M_future) && !_M_future.unique())
_M_future->_M_break_promise(std::move(_M_storage));
}
// Assignment
promise&
operator=(promise&& __rhs) noexcept
{
promise(std::move(__rhs)).swap(*this);
return *this;
}
promise& operator=(const promise&) = delete;
void
swap(promise& __rhs) noexcept
{
_M_future.swap(__rhs._M_future);
_M_storage.swap(__rhs._M_storage);
}
// Retrieving the result
future<void>
get_future()
{ return future<void>(_M_future); }
// Setting the result
void
set_value()
{ _M_future->_M_set_result(_State::__setter(this)); }
void
set_exception(exception_ptr __p)
{ _M_future->_M_set_result(_State::__setter(__p, this)); }
void
set_value_at_thread_exit()
{ _M_future->_M_set_delayed_result(_State::__setter(this), _M_future); }
void
set_exception_at_thread_exit(exception_ptr __p)
{
_M_future->_M_set_delayed_result(_State::__setter(__p, this),
_M_future);
}
};
template<typename _Ptr_type, typename _Fn, typename _Res>
struct __future_base::_Task_setter
{
// Invoke the function and provide the result to the caller.
_Ptr_type operator()() const
{
__try
{
(*_M_result)->_M_set((*_M_fn)());
}
__catch(const __cxxabiv1::__forced_unwind&)
{
__throw_exception_again; // will cause broken_promise
}
__catch(...)
{
(*_M_result)->_M_error = current_exception();
}
return std::move(*_M_result);
}
_Ptr_type* _M_result;
_Fn* _M_fn;
};
template<typename _Ptr_type, typename _Fn>
struct __future_base::_Task_setter<_Ptr_type, _Fn, void>
{
_Ptr_type operator()() const
{
__try
{
(*_M_fn)();
}
__catch(const __cxxabiv1::__forced_unwind&)
{
__throw_exception_again; // will cause broken_promise
}
__catch(...)
{
(*_M_result)->_M_error = current_exception();
}
return std::move(*_M_result);
}
_Ptr_type* _M_result;
_Fn* _M_fn;
};
// Holds storage for a packaged_task's result.
template<typename _Res, typename... _Args>
struct __future_base::_Task_state_base<_Res(_Args...)>
: __future_base::_State_base
{
typedef _Res _Res_type;
template<typename _Alloc>
_Task_state_base(const _Alloc& __a)
: _M_result(_S_allocate_result<_Res>(__a))
{ }
// Invoke the stored task and make the state ready.
virtual void
_M_run(_Args&&... __args) = 0;
// Invoke the stored task and make the state ready at thread exit.
virtual void
_M_run_delayed(_Args&&... __args, weak_ptr<_State_base>) = 0;
virtual shared_ptr<_Task_state_base>
_M_reset() = 0;
typedef __future_base::_Ptr<_Result<_Res>> _Ptr_type;
_Ptr_type _M_result;
};
// Holds a packaged_task's stored task.
template<typename _Fn, typename _Alloc, typename _Res, typename... _Args>
struct __future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)> final
: __future_base::_Task_state_base<_Res(_Args...)>
{
template<typename _Fn2>
_Task_state(_Fn2&& __fn, const _Alloc& __a)
: _Task_state_base<_Res(_Args...)>(__a),
_M_impl(std::forward<_Fn2>(__fn), __a)
{ }
private:
virtual void
_M_run(_Args&&... __args)
{
auto __boundfn = [&] () -> _Res {
return std::__invoke_r<_Res>(_M_impl._M_fn,
std::forward<_Args>(__args)...);
};
this->_M_set_result(_S_task_setter(this->_M_result, __boundfn));
}
virtual void
_M_run_delayed(_Args&&... __args, weak_ptr<_State_base> __self)
{
auto __boundfn = [&] () -> _Res {
return std::__invoke_r<_Res>(_M_impl._M_fn,
std::forward<_Args>(__args)...);
};
this->_M_set_delayed_result(_S_task_setter(this->_M_result, __boundfn),
std::move(__self));
}
virtual shared_ptr<_Task_state_base<_Res(_Args...)>>
_M_reset();
struct _Impl : _Alloc
{
template<typename _Fn2>
_Impl(_Fn2&& __fn, const _Alloc& __a)
: _Alloc(__a), _M_fn(std::forward<_Fn2>(__fn)) { }
_Fn _M_fn;
} _M_impl;
};
template<typename _Signature, typename _Fn,
typename _Alloc = std::allocator<int>>
static shared_ptr<__future_base::_Task_state_base<_Signature>>
__create_task_state(_Fn&& __fn, const _Alloc& __a = _Alloc())
{
typedef typename decay<_Fn>::type _Fn2;
typedef __future_base::_Task_state<_Fn2, _Alloc, _Signature> _State;
return std::allocate_shared<_State>(__a, std::forward<_Fn>(__fn), __a);
}
template<typename _Fn, typename _Alloc, typename _Res, typename... _Args>
shared_ptr<__future_base::_Task_state_base<_Res(_Args...)>>
__future_base::_Task_state<_Fn, _Alloc, _Res(_Args...)>::_M_reset()
{
return __create_task_state<_Res(_Args...)>(std::move(_M_impl._M_fn),
static_cast<_Alloc&>(_M_impl));
}
/// packaged_task
template<typename _Res, typename... _ArgTypes>
class packaged_task<_Res(_ArgTypes...)>
{
typedef __future_base::_Task_state_base<_Res(_ArgTypes...)> _State_type;
shared_ptr<_State_type> _M_state;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3039. Unnecessary decay in thread and packaged_task
template<typename _Fn, typename _Fn2 = __remove_cvref_t<_Fn>>
using __not_same
= typename enable_if<!is_same<packaged_task, _Fn2>::value>::type;
public:
// Construction and destruction
packaged_task() noexcept { }
template<typename _Fn, typename = __not_same<_Fn>>
explicit
packaged_task(_Fn&& __fn)
: _M_state(
__create_task_state<_Res(_ArgTypes...)>(std::forward<_Fn>(__fn)))
{ }
#if __cplusplus < 201703L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2097. packaged_task constructors should be constrained
// 2407. [this constructor should not be] explicit
// 2921. packaged_task and type-erased allocators
template<typename _Fn, typename _Alloc, typename = __not_same<_Fn>>
packaged_task(allocator_arg_t, const _Alloc& __a, _Fn&& __fn)
: _M_state(__create_task_state<_Res(_ArgTypes...)>(
std::forward<_Fn>(__fn), __a))
{ }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2095. missing constructors needed for uses-allocator construction
template<typename _Allocator>
packaged_task(allocator_arg_t, const _Allocator& __a) noexcept
{ }
template<typename _Allocator>
packaged_task(allocator_arg_t, const _Allocator&,
const packaged_task&) = delete;
template<typename _Allocator>
packaged_task(allocator_arg_t, const _Allocator&,
packaged_task&& __other) noexcept
{ this->swap(__other); }
#endif
~packaged_task()
{
if (static_cast<bool>(_M_state) && !_M_state.unique())
_M_state->_M_break_promise(std::move(_M_state->_M_result));
}
// No copy
packaged_task(const packaged_task&) = delete;
packaged_task& operator=(const packaged_task&) = delete;
// Move support
packaged_task(packaged_task&& __other) noexcept
{ this->swap(__other); }
packaged_task& operator=(packaged_task&& __other) noexcept
{
packaged_task(std::move(__other)).swap(*this);
return *this;
}
void
swap(packaged_task& __other) noexcept
{ _M_state.swap(__other._M_state); }
bool
valid() const noexcept
{ return static_cast<bool>(_M_state); }
// Result retrieval
future<_Res>
get_future()
{ return future<_Res>(_M_state); }
// Execution
void
operator()(_ArgTypes... __args)
{
__future_base::_State_base::_S_check(_M_state);
_M_state->_M_run(std::forward<_ArgTypes>(__args)...);
}
void
make_ready_at_thread_exit(_ArgTypes... __args)
{
__future_base::_State_base::_S_check(_M_state);
_M_state->_M_run_delayed(std::forward<_ArgTypes>(__args)..., _M_state);
}
void
reset()
{
__future_base::_State_base::_S_check(_M_state);
packaged_task __tmp;
__tmp._M_state = _M_state;
_M_state = _M_state->_M_reset();
}
};
/// swap
template<typename _Res, typename... _ArgTypes>
inline void
swap(packaged_task<_Res(_ArgTypes...)>& __x,
packaged_task<_Res(_ArgTypes...)>& __y) noexcept
{ __x.swap(__y); }
#if __cplusplus < 201703L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2976. Dangling uses_allocator specialization for packaged_task
template<typename _Res, typename _Alloc>
struct uses_allocator<packaged_task<_Res>, _Alloc>
: public true_type { };
#endif
// Shared state created by std::async().
// Holds a deferred function and storage for its result.
template<typename _BoundFn, typename _Res>
class __future_base::_Deferred_state final
: public __future_base::_State_base
{
public:
explicit
_Deferred_state(_BoundFn&& __fn)
: _M_result(new _Result<_Res>()), _M_fn(std::move(__fn))
{ }
private:
typedef __future_base::_Ptr<_Result<_Res>> _Ptr_type;
_Ptr_type _M_result;
_BoundFn _M_fn;
// Run the deferred function.
virtual void
_M_complete_async()
{
// Multiple threads can call a waiting function on the future and
// reach this point at the same time. The call_once in _M_set_result
// ensures only the first one run the deferred function, stores the
// result in _M_result, swaps that with the base _M_result and makes
// the state ready. Tell _M_set_result to ignore failure so all later
// calls do nothing.
_M_set_result(_S_task_setter(_M_result, _M_fn), true);
}
// Caller should check whether the state is ready first, because this
// function will return true even after the deferred function has run.
virtual bool _M_is_deferred_future() const { return true; }
};
// Common functionality hoisted out of the _Async_state_impl template.
class __future_base::_Async_state_commonV2
: public __future_base::_State_base
{
protected:
~_Async_state_commonV2() = default;
// Make waiting functions block until the thread completes, as if joined.
//
// This function is used by wait() to satisfy the first requirement below
// and by wait_for() / wait_until() to satisfy the second.
//
// [futures.async]:
//
// - a call to a waiting function on an asynchronous return object that
// shares the shared state created by this async call shall block until
// the associated thread has completed, as if joined, or else time out.
//
// - the associated thread completion synchronizes with the return from
// the first function that successfully detects the ready status of the
// shared state or with the return from the last function that releases
// the shared state, whichever happens first.
virtual void _M_complete_async() { _M_join(); }
void _M_join() { std::call_once(_M_once, &thread::join, &_M_thread); }
thread _M_thread;
once_flag _M_once;
};
// Shared state created by std::async().
// Starts a new thread that runs a function and makes the shared state ready.
template<typename _BoundFn, typename _Res>
class __future_base::_Async_state_impl final
: public __future_base::_Async_state_commonV2
{
public:
explicit
_Async_state_impl(_BoundFn&& __fn)
: _M_result(new _Result<_Res>()), _M_fn(std::move(__fn))
{
_M_thread = std::thread{ [this] {
__try
{
_M_set_result(_S_task_setter(_M_result, _M_fn));
}
__catch (const __cxxabiv1::__forced_unwind&)
{
// make the shared state ready on thread cancellation
if (static_cast<bool>(_M_result))
this->_M_break_promise(std::move(_M_result));
__throw_exception_again;
}
} };
}
// Must not destroy _M_result and _M_fn until the thread finishes.
// Call join() directly rather than through _M_join() because no other
// thread can be referring to this state if it is being destroyed.
~_Async_state_impl() { if (_M_thread.joinable()) _M_thread.join(); }
private:
typedef __future_base::_Ptr<_Result<_Res>> _Ptr_type;
_Ptr_type _M_result;
_BoundFn _M_fn;
};
template<typename _BoundFn>
inline std::shared_ptr<__future_base::_State_base>
__future_base::_S_make_deferred_state(_BoundFn&& __fn)
{
typedef typename remove_reference<_BoundFn>::type __fn_type;
typedef _Deferred_state<__fn_type> __state_type;
return std::make_shared<__state_type>(std::move(__fn));
}
template<typename _BoundFn>
inline std::shared_ptr<__future_base::_State_base>
__future_base::_S_make_async_state(_BoundFn&& __fn)
{
typedef typename remove_reference<_BoundFn>::type __fn_type;
typedef _Async_state_impl<__fn_type> __state_type;
return std::make_shared<__state_type>(std::move(__fn));
}
/// async
template<typename _Fn, typename... _Args>
_GLIBCXX_NODISCARD future<__async_result_of<_Fn, _Args...>>
async(launch __policy, _Fn&& __fn, _Args&&... __args)
{
std::shared_ptr<__future_base::_State_base> __state;
if ((__policy & launch::async) == launch::async)
{
__try
{
__state = __future_base::_S_make_async_state(
std::thread::__make_invoker(std::forward<_Fn>(__fn),
std::forward<_Args>(__args)...)
);
}
#if __cpp_exceptions
catch(const system_error& __e)
{
if (__e.code() != errc::resource_unavailable_try_again
|| (__policy & launch::deferred) != launch::deferred)
throw;
}
#endif
}
if (!__state)
{
__state = __future_base::_S_make_deferred_state(
std::thread::__make_invoker(std::forward<_Fn>(__fn),
std::forward<_Args>(__args)...));
}
return future<__async_result_of<_Fn, _Args...>>(__state);
}
/// async, potential overload
template<typename _Fn, typename... _Args>
_GLIBCXX_NODISCARD inline future<__async_result_of<_Fn, _Args...>>
async(_Fn&& __fn, _Args&&... __args)
{
return std::async(launch::async|launch::deferred,
std::forward<_Fn>(__fn),
std::forward<_Args>(__args)...);
}
#endif // _GLIBCXX_ASYNC_ABI_COMPAT
#endif // _GLIBCXX_HAS_GTHREADS
// @} group futures
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
#endif // C++11
#endif // _GLIBCXX_FUTURE