2015-05-15 21:28:25 +08:00
/***
* = = + + = =
*
* Copyright ( c ) Microsoft Corporation . All rights reserved .
*
* Modified for native C + + WRL support by Gregory Morse
*
* = = - - = =
* = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = + = +
*
* ppltasks_winrt . h
*
* Parallel Patterns Library - PPL Tasks
*
* = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = -
* * * */
# pragma once
# ifndef _PPLTASKS_WINRT_H
# define _PPLTASKS_WINRT_H
# include <concrt.h>
# include <ppltasks.h>
# if _MSC_VER >= 1800
# include <pplconcrt.h>
// Cannot build using a compiler that is older than dev10 SP1
# ifdef _MSC_VER
# if _MSC_FULL_VER < 160040219 /*IFSTRIP=IGN*/
# error ERROR: Visual Studio 2010 SP1 or later is required to build ppltasks
# endif /*IFSTRIP=IGN*/
# endif
# else
# include <ppl.h>
# endif
# include <functional>
# include <vector>
# include <utility>
# include <exception>
# if _MSC_VER >= 1800
# include <algorithm>
# endif
# ifndef __cplusplus_winrt
# include <wrl\implements.h>
# include <wrl\async.h>
# if _MSC_VER >= 1800
# include "agile_wrl.hpp"
# endif
# include <windows.foundation.h>
# include <ctxtcall.h>
# ifndef _UITHREADCTXT_SUPPORT
# ifdef WINAPI_FAMILY /*IFSTRIP=IGN*/
// It is safe to include winapifamily as WINAPI_FAMILY was defined by the user
# include <winapifamily.h>
# if WINAPI_FAMILY == WINAPI_FAMILY_APP /*IFSTRIP=IGN*/
// UI thread context support is not required for desktop and Windows Store apps
# define _UITHREADCTXT_SUPPORT 0
# elif WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP /*IFSTRIP=IGN*/
// UI thread context support is not required for desktop and Windows Store apps
# define _UITHREADCTXT_SUPPORT 0
# else /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */
# define _UITHREADCTXT_SUPPORT 1
# endif /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */
# else /* WINAPI_FAMILY */
// Not supported without a WINAPI_FAMILY setting.
# define _UITHREADCTXT_SUPPORT 0
# endif /* WINAPI_FAMILY */
# endif /* _UITHREADCTXT_SUPPORT */
# if _UITHREADCTXT_SUPPORT
# include <uithreadctxt.h>
# endif /* _UITHREADCTXT_SUPPORT */
# pragma detect_mismatch("_PPLTASKS_WITH_WINRT", "0")
# ifdef _DEBUG
# define _DBG_ONLY(X) X
# else
# define _DBG_ONLY(X)
# endif // #ifdef _DEBUG
// std::copy_exception changed to std::make_exception_ptr from VS 2010 to VS 11.
# ifdef _MSC_VER
# if _MSC_VER < 1700 /*IFSTRIP=IGN*/
namespace std
{
template < class _E > exception_ptr make_exception_ptr ( _E _Except )
{
return copy_exception ( _Except ) ;
}
}
# endif
# ifndef _PPLTASK_ASYNC_LOGGING
# if _MSC_VER >= 1800 && defined(__cplusplus_winrt)
# define _PPLTASK_ASYNC_LOGGING 1 // Only enable async logging under dev12 winrt
# else
# define _PPLTASK_ASYNC_LOGGING 0
# endif
# endif
# endif
# pragma pack(push,_CRT_PACKING)
# pragma warning(push)
# pragma warning(disable: 28197)
# pragma warning(disable: 4100) // Unreferenced formal parameter - needed for document generation
# if _MSC_VER >= 1800
# pragma warning(disable: 4127) // constant express in if condition - we use it for meta programming
# else
# pragma warning(disable: 4702) // Unreachable code - it is caused by user lambda throw exceptions
# endif
// All CRT public header files are required to be protected from the macro new
# pragma push_macro("new")
# undef new
// stuff ported from Dev11 CRT
// NOTE: this doesn't actually match std::declval. it behaves differently for void!
// so don't blindly change it to std::declval.
namespace stdx
{
template < class _T >
_T & & declval ( ) ;
}
/// <summary>
/// The <c>Concurrency_winrt</c> namespace provides classes and functions that give you access to the Concurrency Runtime,
/// a concurrent programming framework for C++. For more information, see <see cref="Concurrency Runtime"/>.
/// </summary>
/**/
namespace Concurrency_winrt
{
// In debug builds, default to 10 frames, unless this is overridden prior to #includ'ing ppltasks.h. In retail builds, default to only one frame.
# ifndef PPL_TASK_SAVE_FRAME_COUNT
# ifdef _DEBUG
# define PPL_TASK_SAVE_FRAME_COUNT 10
# else
# define PPL_TASK_SAVE_FRAME_COUNT 1
# endif
# endif
/// <summary>
/// Helper macro to determine how many stack frames need to be saved. When any number less or equal to 1 is specified,
/// only one frame is captured and no stackwalk will be involved. Otherwise, the number of callstack frames will be captured.
/// </summary>
/// <ramarks>
/// This needs to be defined as a macro rather than a function so that if we're only gathering one frame, _ReturnAddress()
/// will evaluate to client code, rather than a helper function inside of _TaskCreationCallstack, itself.
/// </remarks>
# ifdef _CAPTURE_CALLSTACK
# undef _CAPTURE_CALLSTACK
# endif
# if PPL_TASK_SAVE_FRAME_COUNT > 1
# if !defined(_DEBUG)
# pragma message ("WARNING: Redefinning PPL_TASK_SAVE_FRAME_COUNT under Release build for non-desktop applications is not supported; only one frame will be captured!")
# define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())
# else
# define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureMultiFramesCallstack(PPL_TASK_SAVE_FRAME_COUNT)
# endif
# else
# define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())
# endif
/// <summary>
/// A type that represents the terminal state of a task. Valid values are <c>completed</c> and <c>canceled</c>.
/// </summary>
/// <seealso cref="task Class"/>
/**/
typedef Concurrency : : task_group_status task_status ;
template < typename _Type > class task ;
template < > class task < void > ;
/// <summary>
/// Returns an indication of whether the task that is currently executing has received a request to cancel its
/// execution. Cancellation is requested on a task if the task was created with a cancellation token, and
/// the token source associated with that token is canceled.
/// </summary>
/// <returns>
/// <c>true</c> if the currently executing task has received a request for cancellation, <c>false</c> otherwise.
/// </returns>
/// <remarks>
/// If you call this method in the body of a task and it returns <c>true</c>, you must respond with a call to
/// <see cref="cancel_current_task Function">cancel_current_task</see> to acknowledge the cancellation request,
/// after performing any cleanup you need. This will abort the execution of the task and cause it to enter into
/// the <c>canceled</c> state. If you do not respond and continue execution, or return instead of calling
/// <c>cancel_current_task</c>, the task will enter the <c>completed</c> state when it is done.
/// state.
/// <para>A task is not cancellable if it was created without a cancellation token.</para>
/// </remarks>
/// <seealso cref="task Class"/>
/// <seealso cref="cancellation_token_source Class"/>
/// <seealso cref="cancellation_token Class"/>
/// <seealso cref="cancel_current_task Function"/>
/**/
# if _MSC_VER >= 1800
inline bool __cdecl is_task_cancellation_requested ( )
{
return : : Concurrency : : details : : _TaskCollection_t : : _Is_cancellation_requested ( ) ;
}
# else
inline bool __cdecl is_task_cancellation_requested ( )
{
// ConcRT scheduler under the hood is using TaskCollection, which is same as task_group
return : : Concurrency : : is_current_task_group_canceling ( ) ;
}
# endif
/// <summary>
/// Cancels the currently executing task. This function can be called from within the body of a task to abort the
/// task's execution and cause it to enter the <c>canceled</c> state. While it may be used in response to
/// the <see cref="is_task_cancellation_requested Function">is_task_cancellation_requested</see> function, you may
/// also use it by itself, to initiate cancellation of the task that is currently executing.
/// <para>It is not a supported scenario to call this function if you are not within the body of a <c>task</c>.
/// Doing so will result in undefined behavior such as a crash or a hang in your application.</para>
/// </summary>
/// <seealso cref="task Class"/>
/// <seealso cref="is_task_cancellation_requested"/>
/**/
//#if _MSC_VER >= 1800
inline __declspec ( noreturn ) void __cdecl cancel_current_task ( )
{
throw Concurrency : : task_canceled ( ) ;
}
//#else
//_CRTIMP2 __declspec(noreturn) void __cdecl cancel_current_task();
//#endif
namespace details
{
# if _MSC_VER >= 1800
/// <summary>
/// Callstack container, which is used to capture and preserve callstacks in ppltasks.
/// Members of this class is examined by vc debugger, thus there will be no public access methods.
/// Please note that names of this class should be kept stable for debugger examining.
/// </summary>
class _TaskCreationCallstack
{
private :
// If _M_SingleFrame != nullptr, there will be only one frame of callstacks, which is stored in _M_SingleFrame;
// otherwise, _M_Frame will store all the callstack frames.
void * _M_SingleFrame ;
std : : vector < void * > _M_frames ;
public :
_TaskCreationCallstack ( )
{
_M_SingleFrame = nullptr ;
}
// Store one frame of callstack. This function works for both Debug / Release CRT.
static _TaskCreationCallstack _CaptureSingleFrameCallstack ( void * _SingleFrame )
{
_TaskCreationCallstack _csc ;
_csc . _M_SingleFrame = _SingleFrame ;
return _csc ;
}
// Capture _CaptureFrames number of callstack frames. This function only work properly for Desktop or Debug CRT.
__declspec ( noinline )
static _TaskCreationCallstack _CaptureMultiFramesCallstack ( size_t _CaptureFrames )
{
_TaskCreationCallstack _csc ;
_csc . _M_frames . resize ( _CaptureFrames ) ;
// skip 2 frames to make sure callstack starts from user code
_csc . _M_frames . resize ( : : Concurrency : : details : : platform : : CaptureCallstack ( & _csc . _M_frames [ 0 ] , 2 , _CaptureFrames ) ) ;
return _csc ;
}
} ;
# endif
typedef UINT32 _Unit_type ;
struct _TypeSelectorNoAsync { } ;
struct _TypeSelectorAsyncOperationOrTask { } ;
struct _TypeSelectorAsyncOperation : public _TypeSelectorAsyncOperationOrTask { } ;
struct _TypeSelectorAsyncTask : public _TypeSelectorAsyncOperationOrTask { } ;
struct _TypeSelectorAsyncAction { } ;
struct _TypeSelectorAsyncActionWithProgress { } ;
struct _TypeSelectorAsyncOperationWithProgress { } ;
template < typename _Ty >
struct _NormalizeVoidToUnitType
{
typedef _Ty _Type ;
} ;
template < >
struct _NormalizeVoidToUnitType < void >
{
typedef _Unit_type _Type ;
} ;
template < typename _T >
struct _IsUnwrappedAsyncSelector
{
static const bool _Value = true ;
} ;
template < >
struct _IsUnwrappedAsyncSelector < _TypeSelectorNoAsync >
{
static const bool _Value = false ;
} ;
template < typename _Ty >
struct _UnwrapTaskType
{
typedef _Ty _Type ;
} ;
template < typename _Ty >
struct _UnwrapTaskType < task < _Ty > >
{
typedef _Ty _Type ;
} ;
template < typename _T >
_TypeSelectorAsyncTask _AsyncOperationKindSelector ( task < _T > ) ;
_TypeSelectorNoAsync _AsyncOperationKindSelector ( . . . ) ;
template < typename _Type >
struct _Unhat
{
typedef _Type _Value ;
} ;
template < typename _Type >
struct _Unhat < _Type * >
{
typedef _Type _Value ;
} ;
//struct _NonUserType { public: int _Dummy; };
template < typename _Type , bool _IsValueTypeOrRefType = __is_valid_winrt_type ( _Type ) >
struct _ValueTypeOrRefType
{
typedef _Unit_type _Value ;
} ;
template < typename _Type >
struct _ValueTypeOrRefType < _Type , true >
{
typedef _Type _Value ;
} ;
template < typename _Ty >
_Ty _UnwrapAsyncActionWithProgressSelector ( ABI : : Windows : : Foundation : : IAsyncActionWithProgress_impl < _Ty > * ) ;
template < typename _Ty >
_Ty _UnwrapAsyncActionWithProgressSelector ( . . . ) ;
template < typename _Ty , typename _Progress >
_Progress _UnwrapAsyncOperationWithProgressProgressSelector ( ABI : : Windows : : Foundation : : IAsyncOperationWithProgress_impl < _Ty , _Progress > * ) ;
template < typename _Ty , typename _Progress >
_Progress _UnwrapAsyncOperationWithProgressProgressSelector ( . . . ) ;
template < typename _T1 , typename _T2 >
_T2 _ProgressTypeSelector ( ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _T1 , _T2 > * ) ;
template < typename _T1 >
_T1 _ProgressTypeSelector ( ABI : : Windows : : Foundation : : IAsyncActionWithProgress < _T1 > * ) ;
template < typename _Type >
struct _GetProgressType
{
typedef decltype ( _ProgressTypeSelector ( stdx : : declval < _Type > ( ) ) ) _Value ;
} ;
template < typename _T >
_TypeSelectorAsyncOperation _AsyncOperationKindSelector ( ABI : : Windows : : Foundation : : IAsyncOperation < _T > * ) ;
_TypeSelectorAsyncAction _AsyncOperationKindSelector ( ABI : : Windows : : Foundation : : IAsyncAction * ) ;
template < typename _T1 , typename _T2 >
_TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector ( ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _T1 , _T2 > * ) ;
template < typename _T >
_TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector ( ABI : : Windows : : Foundation : : IAsyncActionWithProgress < _T > * ) ;
template < typename _Type >
struct _IsIAsyncInfo
{
static const bool _Value = std : : is_base_of < ABI : : Windows : : Foundation : : IAsyncInfo , typename _Unhat < _Type > : : _Value > : : value | |
std : : is_same < _TypeSelectorAsyncAction , decltype ( details : : _AsyncOperationKindSelector ( stdx : : declval < _Type > ( ) ) ) > : : value | |
std : : is_same < _TypeSelectorAsyncOperation , decltype ( details : : _AsyncOperationKindSelector ( stdx : : declval < _Type > ( ) ) ) > : : value | |
std : : is_same < _TypeSelectorAsyncOperationWithProgress , decltype ( details : : _AsyncOperationKindSelector ( stdx : : declval < _Type > ( ) ) ) > : : value | |
std : : is_same < _TypeSelectorAsyncActionWithProgress , decltype ( details : : _AsyncOperationKindSelector ( stdx : : declval < _Type > ( ) ) ) > : : value ;
} ;
template < >
struct _IsIAsyncInfo < void >
{
static const bool _Value = false ;
} ;
template < typename _Ty >
_Ty _UnwrapAsyncOperationSelector ( ABI : : Windows : : Foundation : : IAsyncOperation_impl < _Ty > * ) ;
template < typename _Ty >
_Ty _UnwrapAsyncOperationSelector ( . . . ) ;
template < typename _Ty , typename _Progress >
_Ty _UnwrapAsyncOperationWithProgressSelector ( ABI : : Windows : : Foundation : : IAsyncOperationWithProgress_impl < _Ty , _Progress > * ) ;
template < typename _Ty , typename _Progress >
_Ty _UnwrapAsyncOperationWithProgressSelector ( . . . ) ;
// Unwrap functions for asyncOperations
template < typename _Ty >
auto _GetUnwrappedType ( ABI : : Windows : : Foundation : : IAsyncOperation < _Ty > * ) - > typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncOperationSelector ( stdx : : declval < ABI : : Windows : : Foundation : : IAsyncOperation < _Ty > * > ( ) ) ) > : : type ;
void _GetUnwrappedType ( ABI : : Windows : : Foundation : : IAsyncAction * ) ;
template < typename _Ty , typename _Progress >
auto _GetUnwrappedType ( ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _Ty , _Progress > * ) - > typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncOperationWithProgressSelector ( stdx : : declval < ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _Ty , _Progress > * > ( ) ) ) > : : type ;
template < typename _Progress >
void _GetUnwrappedType ( ABI : : Windows : : Foundation : : IAsyncActionWithProgress < _Progress > * ) ;
template < typename _T >
_T _ReturnAsyncOperationKindSelector ( ABI : : Windows : : Foundation : : IAsyncOperation < _T > * ) ;
void _ReturnAsyncOperationKindSelector ( ABI : : Windows : : Foundation : : IAsyncAction * ) ;
template < typename _T1 , typename _T2 >
_T1 _ReturnAsyncOperationKindSelector ( ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _T1 , _T2 > * ) ;
template < typename _T >
void _ReturnAsyncOperationKindSelector ( ABI : : Windows : : Foundation : : IAsyncActionWithProgress < _T > * ) ;
class _ProgressReporterCtorArgType { } ;
template < typename _Type , bool _IsAsync = _IsIAsyncInfo < _Type > : : _Value >
struct _TaskTypeTraits
{
typedef typename details : : _UnwrapTaskType < _Type > : : _Type _TaskRetType ;
typedef _TaskRetType _TaskRetType_abi ;
typedef decltype ( _AsyncOperationKindSelector ( stdx : : declval < _Type > ( ) ) ) _AsyncKind ;
typedef typename details : : _NormalizeVoidToUnitType < _TaskRetType > : : _Type _NormalizedTaskRetType ;
static const bool _IsAsyncTask = _IsAsync ;
static const bool _IsUnwrappedTaskOrAsync = details : : _IsUnwrappedAsyncSelector < _AsyncKind > : : _Value ;
} ;
template < typename _Type >
struct _TaskTypeTraits < _Type , true >
{
typedef decltype ( _ReturnAsyncOperationKindSelector ( stdx : : declval < _Type > ( ) ) ) _TaskRetType ;
typedef decltype ( _GetUnwrappedType ( stdx : : declval < _Type > ( ) ) ) _TaskRetType_abi ;
typedef _TaskRetType _NormalizedTaskRetType ;
typedef decltype ( _AsyncOperationKindSelector ( stdx : : declval < _Type > ( ) ) ) _AsyncKind ;
static const bool _IsAsyncTask = true ;
static const bool _IsUnwrappedTaskOrAsync = details : : _IsUnwrappedAsyncSelector < _AsyncKind > : : _Value ;
} ;
template < typename _ReturnType , typename _Function > auto _IsCallable ( _Function _Func , int , int , int ) - > decltype ( _Func ( stdx : : declval < task < _ReturnType > * > ( ) ) , std : : true_type ( ) ) { ( void ) _Func ; return std : : true_type ( ) ; }
template < typename _ReturnType , typename _Function > auto _IsCallable ( _Function _Func , int , int , . . . ) - > decltype ( _Func ( stdx : : declval < _ReturnType * > ( ) ) , std : : true_type ( ) ) { ( void ) _Func ; return std : : true_type ( ) ; }
template < typename _ReturnType , typename _Function > auto _IsCallable ( _Function _Func , int , . . . ) - > decltype ( _Func ( ) , std : : true_type ( ) ) { ( void ) _Func ; return std : : true_type ( ) ; }
template < typename _ReturnType , typename _Function > std : : false_type _IsCallable ( _Function , . . . ) { return std : : false_type ( ) ; }
template < >
struct _TaskTypeTraits < void >
{
typedef void _TaskRetType ;
typedef void _TaskRetType_abi ;
typedef _TypeSelectorNoAsync _AsyncKind ;
typedef _Unit_type _NormalizedTaskRetType ;
static const bool _IsAsyncTask = false ;
static const bool _IsUnwrappedTaskOrAsync = false ;
} ;
// ***************************************************************************
// Template type traits and helpers for async production APIs:
//
struct _ZeroArgumentFunctor { } ;
struct _OneArgumentFunctor { } ;
struct _TwoArgumentFunctor { } ;
struct _ThreeArgumentFunctor { } ;
// ****************************************
// CLASS TYPES:
// mutable functions
// ********************
// THREE ARGUMENTS:
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg1 _Arg1ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg2 _Arg2ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg3 _Arg3ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_ReturnType _ReturnTypeClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_ThreeArgumentFunctor _ArgumentCountHelper ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
// ********************
// TWO ARGUMENTS:
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 >
_Arg1 _Arg1ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 ) ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 >
_Arg2 _Arg2ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 ) ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 >
void _Arg3ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 >
_ReturnType _ReturnTypeClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 >
_TwoArgumentFunctor _ArgumentCountHelper ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 ) ) ;
// ********************
// ONE ARGUMENT:
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 >
_Arg1 _Arg1ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 ) ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 >
void _Arg2ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 ) ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 >
void _Arg3ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 ) ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 >
_ReturnType _ReturnTypeClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 ) ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 >
_OneArgumentFunctor _ArgumentCountHelper ( _ReturnType ( _Class : : * ) ( _Arg1 ) ) ;
// ********************
// ZERO ARGUMENT:
// void arg:
template < typename _Class , typename _ReturnType >
void _Arg1ClassHelperThunk ( _ReturnType ( _Class : : * ) ( ) ) ;
// void arg:
template < typename _Class , typename _ReturnType >
void _Arg2ClassHelperThunk ( _ReturnType ( _Class : : * ) ( ) ) ;
// void arg:
template < typename _Class , typename _ReturnType >
void _Arg3ClassHelperThunk ( _ReturnType ( _Class : : * ) ( ) ) ;
// void arg:
template < typename _Class , typename _ReturnType >
_ReturnType _ReturnTypeClassHelperThunk ( _ReturnType ( _Class : : * ) ( ) ) ;
template < typename _Class , typename _ReturnType >
_ZeroArgumentFunctor _ArgumentCountHelper ( _ReturnType ( _Class : : * ) ( ) ) ;
// ********************
// THREE ARGUMENTS:
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg1 _Arg1ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 , _Arg3 ) const ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg2 _Arg2ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 , _Arg3 ) const ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg3 _Arg3ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 , _Arg3 ) const ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_ReturnType _ReturnTypeClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 , _Arg3 ) const ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_ThreeArgumentFunctor _ArgumentCountHelper ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 , _Arg3 ) const ) ;
// ********************
// TWO ARGUMENTS:
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 >
_Arg1 _Arg1ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 ) const ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 >
_Arg2 _Arg2ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 ) const ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 >
void _Arg3ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 ) const ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 >
_ReturnType _ReturnTypeClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 ) const ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 , typename _Arg2 >
_TwoArgumentFunctor _ArgumentCountHelper ( _ReturnType ( _Class : : * ) ( _Arg1 , _Arg2 ) const ) ;
// ********************
// ONE ARGUMENT:
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 >
_Arg1 _Arg1ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 ) const ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 >
void _Arg2ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 ) const ) ;
// non-void arg:
template < typename _Class , typename _ReturnType , typename _Arg1 >
void _Arg3ClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 ) const ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 >
_ReturnType _ReturnTypeClassHelperThunk ( _ReturnType ( _Class : : * ) ( _Arg1 ) const ) ;
template < typename _Class , typename _ReturnType , typename _Arg1 >
_OneArgumentFunctor _ArgumentCountHelper ( _ReturnType ( _Class : : * ) ( _Arg1 ) const ) ;
// ********************
// ZERO ARGUMENT:
// void arg:
template < typename _Class , typename _ReturnType >
void _Arg1ClassHelperThunk ( _ReturnType ( _Class : : * ) ( ) const ) ;
// void arg:
template < typename _Class , typename _ReturnType >
void _Arg2ClassHelperThunk ( _ReturnType ( _Class : : * ) ( ) const ) ;
// void arg:
template < typename _Class , typename _ReturnType >
void _Arg3ClassHelperThunk ( _ReturnType ( _Class : : * ) ( ) const ) ;
// void arg:
template < typename _Class , typename _ReturnType >
_ReturnType _ReturnTypeClassHelperThunk ( _ReturnType ( _Class : : * ) ( ) const ) ;
template < typename _Class , typename _ReturnType >
_ZeroArgumentFunctor _ArgumentCountHelper ( _ReturnType ( _Class : : * ) ( ) const ) ;
// ****************************************
// POINTER TYPES:
// ********************
// THREE ARGUMENTS:
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg1 _Arg1PFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg2 _Arg2PFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg3 _Arg3PFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_ThreeArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __cdecl * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg1 _Arg1PFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg2 _Arg2PFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg3 _Arg3PFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_ThreeArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __stdcall * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg1 _Arg1PFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg2 _Arg2PFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_Arg3 _Arg3PFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 , typename _Arg3 >
_ThreeArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __fastcall * ) ( _Arg1 , _Arg2 , _Arg3 ) ) ;
// ********************
// TWO ARGUMENTS:
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_Arg1 _Arg1PFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_Arg2 _Arg2PFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
void _Arg3PFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_TwoArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __cdecl * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_Arg1 _Arg1PFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_Arg2 _Arg2PFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
void _Arg3PFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_TwoArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __stdcall * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_Arg1 _Arg1PFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_Arg2 _Arg2PFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
void _Arg3PFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 , _Arg2 ) ) ;
template < typename _ReturnType , typename _Arg1 , typename _Arg2 >
_TwoArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __fastcall * ) ( _Arg1 , _Arg2 ) ) ;
// ********************
// ONE ARGUMENT:
template < typename _ReturnType , typename _Arg1 >
_Arg1 _Arg1PFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
void _Arg2PFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
void _Arg3PFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __cdecl * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
_OneArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __cdecl * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
_Arg1 _Arg1PFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
void _Arg2PFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
void _Arg3PFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __stdcall * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
_OneArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __stdcall * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
_Arg1 _Arg1PFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
void _Arg2PFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
void _Arg3PFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __fastcall * ) ( _Arg1 ) ) ;
template < typename _ReturnType , typename _Arg1 >
_OneArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __fastcall * ) ( _Arg1 ) ) ;
// ********************
// ZERO ARGUMENT:
template < typename _ReturnType >
void _Arg1PFNHelperThunk ( _ReturnType ( __cdecl * ) ( ) ) ;
template < typename _ReturnType >
void _Arg2PFNHelperThunk ( _ReturnType ( __cdecl * ) ( ) ) ;
template < typename _ReturnType >
void _Arg3PFNHelperThunk ( _ReturnType ( __cdecl * ) ( ) ) ;
template < typename _ReturnType >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __cdecl * ) ( ) ) ;
template < typename _ReturnType >
_ZeroArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __cdecl * ) ( ) ) ;
template < typename _ReturnType >
void _Arg1PFNHelperThunk ( _ReturnType ( __stdcall * ) ( ) ) ;
template < typename _ReturnType >
void _Arg2PFNHelperThunk ( _ReturnType ( __stdcall * ) ( ) ) ;
template < typename _ReturnType >
void _Arg3PFNHelperThunk ( _ReturnType ( __stdcall * ) ( ) ) ;
template < typename _ReturnType >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __stdcall * ) ( ) ) ;
template < typename _ReturnType >
_ZeroArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __stdcall * ) ( ) ) ;
template < typename _ReturnType >
void _Arg1PFNHelperThunk ( _ReturnType ( __fastcall * ) ( ) ) ;
template < typename _ReturnType >
void _Arg2PFNHelperThunk ( _ReturnType ( __fastcall * ) ( ) ) ;
template < typename _ReturnType >
void _Arg3PFNHelperThunk ( _ReturnType ( __fastcall * ) ( ) ) ;
template < typename _ReturnType >
_ReturnType _ReturnTypePFNHelperThunk ( _ReturnType ( __fastcall * ) ( ) ) ;
template < typename _ReturnType >
_ZeroArgumentFunctor _ArgumentCountHelper ( _ReturnType ( __fastcall * ) ( ) ) ;
template < typename _T >
struct _FunctorArguments
{
static const size_t _Count = 0 ;
} ;
template < >
struct _FunctorArguments < _OneArgumentFunctor >
{
static const size_t _Count = 1 ;
} ;
template < >
struct _FunctorArguments < _TwoArgumentFunctor >
{
static const size_t _Count = 2 ;
} ;
template < >
struct _FunctorArguments < _ThreeArgumentFunctor >
{
static const size_t _Count = 3 ;
} ;
template < typename _T >
struct _FunctorTypeTraits
{
typedef decltype ( _ArgumentCountHelper ( & ( _T : : operator ( ) ) ) ) _ArgumentCountType ;
static const size_t _ArgumentCount = _FunctorArguments < _ArgumentCountType > : : _Count ;
typedef decltype ( _ReturnTypeClassHelperThunk ( & ( _T : : operator ( ) ) ) ) _ReturnType ;
typedef decltype ( _Arg1ClassHelperThunk ( & ( _T : : operator ( ) ) ) ) _Argument1Type ;
typedef decltype ( _Arg2ClassHelperThunk ( & ( _T : : operator ( ) ) ) ) _Argument2Type ;
typedef decltype ( _Arg3ClassHelperThunk ( & ( _T : : operator ( ) ) ) ) _Argument3Type ;
} ;
template < typename _T >
struct _FunctorTypeTraits < _T * >
{
typedef decltype ( _ArgumentCountHelper ( stdx : : declval < _T * > ( ) ) ) _ArgumentCountType ;
static const size_t _ArgumentCount = _FunctorArguments < _ArgumentCountType > : : _Count ;
typedef decltype ( _ReturnTypePFNHelperThunk ( stdx : : declval < _T * > ( ) ) ) _ReturnType ;
typedef decltype ( _Arg1PFNHelperThunk ( stdx : : declval < _T * > ( ) ) ) _Argument1Type ;
typedef decltype ( _Arg2PFNHelperThunk ( stdx : : declval < _T * > ( ) ) ) _Argument2Type ;
typedef decltype ( _Arg3PFNHelperThunk ( stdx : : declval < _T * > ( ) ) ) _Argument3Type ;
} ;
task < void > _To_task ( ) ;
template < typename _Function > auto _IsVoidConversionHelper ( _Function _Func , int ) - > typename decltype ( _Func ( _To_task ( ) ) , std : : true_type ( ) ) ;
template < typename _Function > std : : false_type _IsVoidConversionHelper ( _Function _Func , . . . ) ;
template < typename T > std : : true_type _VoidIsTaskHelper ( task < T > _Arg , int ) ;
template < typename T > std : : false_type _VoidIsTaskHelper ( T _Arg , . . . ) ;
template < typename _Function , typename _ExpectedParameterType , const bool _IsVoidConversion = std : : is_same < decltype ( _IsVoidConversionHelper ( stdx : : declval < _Function > ( ) , 0 ) ) , std : : true_type > : : value , const size_t _Count = _FunctorTypeTraits < _Function > : : _ArgumentCount >
struct _FunctionTypeTraits
{
typedef typename _Unhat < typename _FunctorTypeTraits < _Function > : : _Argument2Type > : : _Value _FuncRetType ;
static_assert ( std : : is_same < typename _FunctorTypeTraits < _Function > : : _Argument1Type , _ExpectedParameterType > : : value | |
std : : is_same < typename _FunctorTypeTraits < _Function > : : _Argument1Type , task < _ExpectedParameterType > > : : value , " incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below) " ) ;
typedef decltype ( _VoidIsTaskHelper ( stdx : : declval < _FunctorTypeTraits < _Function > : : _Argument1Type > ( ) , 0 ) ) _Takes_task ;
} ;
//if there is a continuation parameter, then must use void/no return value
template < typename _Function , typename _ExpectedParameterType , const bool _IsVoidConversion >
struct _FunctionTypeTraits < _Function , _ExpectedParameterType , _IsVoidConversion , 1 >
{
typedef void _FuncRetType ;
static_assert ( std : : is_same < typename _FunctorTypeTraits < _Function > : : _Argument1Type , _ExpectedParameterType > : : value | |
std : : is_same < typename _FunctorTypeTraits < _Function > : : _Argument1Type , task < _ExpectedParameterType > > : : value , " incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below) " ) ;
typedef decltype ( _VoidIsTaskHelper ( stdx : : declval < _FunctorTypeTraits < _Function > : : _Argument1Type > ( ) , 0 ) ) _Takes_task ;
} ;
template < typename _Function >
struct _FunctionTypeTraits < _Function , void , true , 1 >
{
typedef void _FuncRetType ;
static_assert ( std : : is_same < typename _FunctorTypeTraits < _Function > : : _Argument1Type , decltype ( _To_task ( ) ) > : : value , " incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below) " ) ;
typedef decltype ( _VoidIsTaskHelper ( stdx : : declval < _FunctorTypeTraits < _Function > : : _Argument1Type > ( ) , 0 ) ) _Takes_task ;
} ;
template < typename _Function >
struct _FunctionTypeTraits < _Function , void , false , 1 >
{
typedef typename _Unhat < typename _FunctorTypeTraits < _Function > : : _Argument1Type > : : _Value _FuncRetType ;
typedef std : : false_type _Takes_task ;
} ;
template < typename _Function , typename _ExpectedParameterType , const bool _IsVoidConversion >
struct _FunctionTypeTraits < _Function , _ExpectedParameterType , _IsVoidConversion , 0 >
{
typedef void _FuncRetType ;
typedef std : : false_type _Takes_task ;
} ;
template < typename _Function , typename _ReturnType >
struct _ContinuationTypeTraits
{
typedef typename task < typename _TaskTypeTraits < typename _FunctionTypeTraits < _Function , _ReturnType > : : _FuncRetType > : : _TaskRetType_abi > _TaskOfType ;
} ;
// _InitFunctorTypeTraits is used to decide whether a task constructed with a lambda should be unwrapped. Depending on how the variable is
// declared, the constructor may or may not perform unwrapping. For eg.
//
// This declaration SHOULD NOT cause unwrapping
// task<task<void>> t1([]() -> task<void> {
// task<void> t2([]() {});
// return t2;
// });
//
// This declaration SHOULD cause unwrapping
// task<void>> t1([]() -> task<void> {
// task<void> t2([]() {});
// return t2;
// });
// If the type of the task is the same as the return type of the function, no unwrapping should take place. Else normal rules apply.
template < typename _TaskType , typename _FuncRetType >
struct _InitFunctorTypeTraits
{
typedef typename _TaskTypeTraits < _FuncRetType > : : _AsyncKind _AsyncKind ;
static const bool _IsAsyncTask = _TaskTypeTraits < _FuncRetType > : : _IsAsyncTask ;
static const bool _IsUnwrappedTaskOrAsync = _TaskTypeTraits < _FuncRetType > : : _IsUnwrappedTaskOrAsync ;
} ;
template < typename T >
struct _InitFunctorTypeTraits < T , T >
{
typedef _TypeSelectorNoAsync _AsyncKind ;
static const bool _IsAsyncTask = false ;
static const bool _IsUnwrappedTaskOrAsync = false ;
} ;
/// <summary>
/// Helper object used for LWT invocation.
/// </summary>
struct _TaskProcThunk
{
_TaskProcThunk ( const std : : function < HRESULT ( void ) > & _Callback ) :
_M_func ( _Callback )
{
}
static void __cdecl _Bridge ( void * _PData )
{
_TaskProcThunk * _PThunk = reinterpret_cast < _TaskProcThunk * > ( _PData ) ;
# if _MSC_VER >= 1800
_Holder _ThunkHolder ( _PThunk ) ;
# endif
_PThunk - > _M_func ( ) ;
# if _MSC_VER < 1800
delete _PThunk ;
# endif
}
private :
# if _MSC_VER >= 1800
// RAII holder
struct _Holder
{
_Holder ( _TaskProcThunk * _PThunk ) : _M_pThunk ( _PThunk )
{
}
~ _Holder ( )
{
delete _M_pThunk ;
}
_TaskProcThunk * _M_pThunk ;
private :
_Holder & operator = ( const _Holder & ) ;
} ;
# endif
std : : function < HRESULT ( void ) > _M_func ;
_TaskProcThunk & operator = ( const _TaskProcThunk & ) ;
} ;
/// <summary>
/// Schedule a functor with automatic inlining. Note that this is "fire and forget" scheduling, which cannot be
/// waited on or canceled after scheduling.
/// This schedule method will perform automatic inlining base on <paramref value="_InliningMode"/>.
/// </summary>
/// <param name="_Func">
/// The user functor need to be scheduled.
/// </param>
/// <param name="_InliningMode">
/// The inlining scheduling policy for current functor.
/// </param>
# if _MSC_VER >= 1800
typedef Concurrency : : details : : _TaskInliningMode_t _TaskInliningMode ;
# else
typedef Concurrency : : details : : _TaskInliningMode _TaskInliningMode ;
# endif
static void _ScheduleFuncWithAutoInline ( const std : : function < HRESULT ( void ) > & _Func , _TaskInliningMode _InliningMode )
{
# if _MSC_VER >= 1800
Concurrency : : details : : _TaskCollection_t : : _RunTask ( & _TaskProcThunk : : _Bridge , new _TaskProcThunk ( _Func ) , _InliningMode ) ;
# else
Concurrency : : details : : _StackGuard _Guard ;
if ( _Guard . _ShouldInline ( _InliningMode ) )
{
_Func ( ) ;
}
else
{
Concurrency : : details : : _CurrentScheduler : : _ScheduleTask ( reinterpret_cast < Concurrency : : TaskProc > ( & _TaskProcThunk : : _Bridge ) , new _TaskProcThunk ( _Func ) ) ;
}
# endif
}
class _ContextCallback
{
typedef std : : function < HRESULT ( void ) > _CallbackFunction ;
public :
static _ContextCallback _CaptureCurrent ( )
{
_ContextCallback _Context ;
_Context . _Capture ( ) ;
return _Context ;
}
~ _ContextCallback ( )
{
_Reset ( ) ;
}
_ContextCallback ( bool _DeferCapture = false )
{
if ( _DeferCapture )
{
_M_context . _M_captureMethod = _S_captureDeferred ;
}
else
{
_M_context . _M_pContextCallback = nullptr ;
}
}
// Resolves a context that was created as _S_captureDeferred based on the environment (ancestor, current context).
void _Resolve ( bool _CaptureCurrent )
{
if ( _M_context . _M_captureMethod = = _S_captureDeferred )
{
_M_context . _M_pContextCallback = nullptr ;
if ( _CaptureCurrent )
{
if ( _IsCurrentOriginSTA ( ) )
{
_Capture ( ) ;
}
# if _UITHREADCTXT_SUPPORT
else
{
// This method will fail if not called from the UI thread.
HRESULT _Hr = CaptureUiThreadContext ( & _M_context . _M_pContextCallback ) ;
if ( FAILED ( _Hr ) )
{
_M_context . _M_pContextCallback = nullptr ;
}
}
# endif // _UITHREADCTXT_SUPPORT
}
}
}
void _Capture ( )
{
HRESULT _Hr = CoGetObjectContext ( IID_IContextCallback , reinterpret_cast < void * * > ( & _M_context . _M_pContextCallback ) ) ;
if ( FAILED ( _Hr ) )
{
_M_context . _M_pContextCallback = nullptr ;
}
}
_ContextCallback ( const _ContextCallback & _Src )
{
_Assign ( _Src . _M_context . _M_pContextCallback ) ;
}
_ContextCallback ( _ContextCallback & & _Src )
{
_M_context . _M_pContextCallback = _Src . _M_context . _M_pContextCallback ;
_Src . _M_context . _M_pContextCallback = nullptr ;
}
_ContextCallback & operator = ( const _ContextCallback & _Src )
{
if ( this ! = & _Src )
{
_Reset ( ) ;
_Assign ( _Src . _M_context . _M_pContextCallback ) ;
}
return * this ;
}
_ContextCallback & operator = ( _ContextCallback & & _Src )
{
if ( this ! = & _Src )
{
_M_context . _M_pContextCallback = _Src . _M_context . _M_pContextCallback ;
_Src . _M_context . _M_pContextCallback = nullptr ;
}
return * this ;
}
bool _HasCapturedContext ( ) const
{
_CONCRT_ASSERT ( _M_context . _M_captureMethod ! = _S_captureDeferred ) ;
return ( _M_context . _M_pContextCallback ! = nullptr ) ;
}
HRESULT _CallInContext ( _CallbackFunction _Func ) const
{
if ( ! _HasCapturedContext ( ) )
{
_Func ( ) ;
}
else
{
ComCallData callData ;
ZeroMemory ( & callData , sizeof ( callData ) ) ;
callData . pUserDefined = reinterpret_cast < void * > ( & _Func ) ;
HRESULT _Hr = _M_context . _M_pContextCallback - > ContextCallback ( & _Bridge , & callData , IID_ICallbackWithNoReentrancyToApplicationSTA , 5 , nullptr ) ;
if ( FAILED ( _Hr ) )
{
return _Hr ;
}
}
return S_OK ;
}
bool operator = = ( const _ContextCallback & _Rhs ) const
{
return ( _M_context . _M_pContextCallback = = _Rhs . _M_context . _M_pContextCallback ) ;
}
bool operator ! = ( const _ContextCallback & _Rhs ) const
{
return ! ( operator = = ( _Rhs ) ) ;
}
private :
void _Reset ( )
{
if ( _M_context . _M_captureMethod ! = _S_captureDeferred & & _M_context . _M_pContextCallback ! = nullptr )
{
_M_context . _M_pContextCallback - > Release ( ) ;
}
}
void _Assign ( IContextCallback * _PContextCallback )
{
_M_context . _M_pContextCallback = _PContextCallback ;
if ( _M_context . _M_captureMethod ! = _S_captureDeferred & & _M_context . _M_pContextCallback ! = nullptr )
{
_M_context . _M_pContextCallback - > AddRef ( ) ;
}
}
static HRESULT __stdcall _Bridge ( ComCallData * _PParam )
{
_CallbackFunction * pFunc = reinterpret_cast < _CallbackFunction * > ( _PParam - > pUserDefined ) ;
return ( * pFunc ) ( ) ;
}
// Returns the origin information for the caller (runtime / Windows Runtime apartment as far as task continuations need know)
static bool _IsCurrentOriginSTA ( )
{
APTTYPE _AptType ;
APTTYPEQUALIFIER _AptTypeQualifier ;
HRESULT hr = CoGetApartmentType ( & _AptType , & _AptTypeQualifier ) ;
if ( SUCCEEDED ( hr ) )
{
// We determine the origin of a task continuation by looking at where .then is called, so we can tell whether
// to need to marshal the continuation back to the originating apartment. If an STA thread is in executing in
// a neutral aparment when it schedules a continuation, we will not marshal continuations back to the STA,
// since variables used within a neutral apartment are expected to be apartment neutral.
switch ( _AptType )
{
case APTTYPE_MAINSTA :
case APTTYPE_STA :
return true ;
default :
break ;
}
}
return false ;
}
union
{
IContextCallback * _M_pContextCallback ;
size_t _M_captureMethod ;
} _M_context ;
static const size_t _S_captureDeferred = 1 ;
} ;
# if _MSC_VER >= 1800
template < typename _Type >
struct _ResultHolder
{
void Set ( const _Type & _type )
{
_Result = _type ;
}
_Type Get ( )
{
return _Result ;
}
_Type _Result ;
} ;
template < typename _Type >
struct _ResultHolder < _Type * >
{
void Set ( _Type * const & _type )
{
_M_Result = _type ;
}
_Type * Get ( )
{
return _M_Result . Get ( ) ;
}
private :
// ::Platform::Agile handle specialization of all hats
// including ::Platform::String and ::Platform::Array
Agile < _Type * > _M_Result ;
} ;
//
// The below are for composability with tasks auto-created from when_any / when_all / && / || constructs.
//
template < typename _Type >
struct _ResultHolder < std : : vector < _Type * > >
{
void Set ( const std : : vector < _Type * > & _type )
{
_Result . reserve ( _type . size ( ) ) ;
for ( auto _PTask = _type . begin ( ) ; _PTask ! = _type . end ( ) ; + + _PTask )
{
_Result . emplace_back ( * _PTask ) ;
}
}
std : : vector < _Type * > Get ( )
{
// Return vectory<T^> with the objects that are marshaled in the proper appartment
std : : vector < _Type * > _Return ;
_Return . reserve ( _Result . size ( ) ) ;
for ( auto _PTask = _Result . begin ( ) ; _PTask ! = _Result . end ( ) ; + + _PTask )
{
_Return . push_back ( _PTask - > Get ( ) ) ; // Agile will marshal the object to appropriate appartment if neccessary
}
return _Return ;
}
std : : vector < Agile < _Type * > > _Result ;
} ;
template < typename _Type >
struct _ResultHolder < std : : pair < _Type * , void * > >
{
void Set ( const std : : pair < _Type * , size_t > & _type )
{
_M_Result = _type ;
}
std : : pair < _Type * , size_t > Get ( )
{
return std : : make_pair ( _M_Result . first , _M_Result . second ) ;
}
private :
std : : pair < Agile < _Type * > , size_t > _M_Result ;
} ;
# else
template < typename _Type >
struct _ResultContext
{
static _ContextCallback _GetContext ( bool /* _RuntimeAggregate */ )
{
return _ContextCallback ( ) ;
}
static _Type _GetValue ( _Type _ObjInCtx , const _ContextCallback & /* _Ctx */ , bool /* _RuntimeAggregate */ )
{
return _ObjInCtx ;
}
} ;
template < typename _Type , size_t N = 0 , bool bIsArray = std : : is_array < _Type > : : value >
struct _MarshalHelper
{
} ;
template < typename _Type , size_t N >
struct _MarshalHelper < _Type , N , true >
{
static _Type * _Perform ( _Type ( & _ObjInCtx ) [ N ] , const _ContextCallback & _Ctx )
{
static_assert ( __is_valid_winrt_type ( _Type * ) , " must be a WinRT array compatible type " ) ;
if ( _ObjInCtx = = nullptr )
{
return nullptr ;
}
HRESULT _Hr ;
IStream * _PStream ;
_Ctx . _CallInContext ( [ & ] ( ) - > HRESULT {
// It isn't safe to simply reinterpret_cast a hat type to IUnknown* because some types do not have a real vtable ptr.
// Instead, we could to create a property value to make it "grow" the vtable ptr but instead primitives are not marshalled.
IUnknown * _PUnk = winrt_array_type : : create ( _ObjInCtx , N ) ;
_Hr = CoMarshalInterThreadInterfaceInStream ( winrt_type < _Type > : : getuuid ( ) , _PUnk , & _PStream ) ;
return S_OK ;
} ) ;
// With an APPX manifest, this call should never fail.
_CONCRT_ASSERT ( SUCCEEDED ( _Hr ) ) ;
_Type * _Proxy ;
//
// Cannot use IID_PPV_ARGS with ^ types.
//
_Hr = CoGetInterfaceAndReleaseStream ( _PStream , winrt_type < _Type > : : getuuid ( ) , reinterpret_cast < void * * > ( & _Proxy ) ) ;
if ( FAILED ( _Hr ) )
{
throw std : : make_exception_ptr ( _Hr ) ;
}
return _Proxy ;
}
} ;
template < typename _Type >
struct _MarshalHelper < _Type , 0 , false >
{
static _Type * _Perform ( _Type * _ObjInCtx , const _ContextCallback & _Ctx )
{
static_assert ( std : : is_base_of < IUnknown , _Type > : : value | | __is_valid_winrt_type ( _Type ) , " must be a COM or WinRT type " ) ;
if ( _ObjInCtx = = nullptr )
{
return nullptr ;
}
HRESULT _Hr ;
IStream * _PStream ;
_Ctx . _CallInContext ( [ & ] ( ) - > HRESULT {
// It isn't safe to simply reinterpret_cast a hat type to IUnknown* because some types do not have a real vtable ptr.
// Instead, we could to create a property value to make it "grow" the vtable ptr but instead primitives are not marshalled.
IUnknown * _PUnk = winrt_type < _Type > : : create ( _ObjInCtx ) ;
_Hr = CoMarshalInterThreadInterfaceInStream ( winrt_type < _Type > : : getuuid ( ) , _PUnk , & _PStream ) ;
return S_OK ;
} ) ;
// With an APPX manifest, this call should never fail.
_CONCRT_ASSERT ( SUCCEEDED ( _Hr ) ) ;
_Type * _Proxy ;
//
// Cannot use IID_PPV_ARGS with ^ types.
//
_Hr = CoGetInterfaceAndReleaseStream ( _PStream , winrt_type < _Type > : : getuuid ( ) , reinterpret_cast < void * * > ( & _Proxy ) ) ;
if ( FAILED ( _Hr ) )
{
throw std : : make_exception_ptr ( _Hr ) ;
}
return _Proxy ;
}
} ;
// Arrays must be converted to IPropertyValue objects.
template < >
struct _MarshalHelper < HSTRING__ >
{
static HSTRING _Perform ( HSTRING _ObjInCtx , const _ContextCallback & _Ctx )
{
return _ObjInCtx ;
}
} ;
template < typename _Type >
_Type * _Marshal ( _Type * _ObjInCtx , const _ContextCallback & _Ctx )
{
return _MarshalHelper < _Type > : : _Perform ( _ObjInCtx , _Ctx ) ;
}
template < typename _Type >
struct _InContext
{
static _Type _Get ( _Type _ObjInCtx , const _ContextCallback & _Ctx )
{
return _ObjInCtx ;
}
} ;
template < typename _Type >
struct _InContext < _Type * >
{
static _Type * _Get ( _Type * _ObjInCtx , const _ContextCallback & _Ctx )
{
_ContextCallback _CurrentContext = _ContextCallback : : _CaptureCurrent ( ) ;
if ( ! _Ctx . _HasCapturedContext ( ) | | _Ctx = = _CurrentContext )
{
return _ObjInCtx ;
}
//
// The object is from another apartment. If it's marshalable, do so.
//
return _Marshal < _Type > ( _ObjInCtx , _Ctx ) ;
}
} ;
template < typename _Type >
struct _ResultContext < _Type * >
{
static _Type * _GetValue ( _Type * _ObjInCtx , const _ContextCallback & _Ctx , bool /* _RuntimeAggregate */ )
{
return _InContext < _Type * > : : _Get ( _ObjInCtx , _Ctx ) ;
}
static _ContextCallback _GetContext ( bool /* _RuntimeAggregate */ )
{
return _ContextCallback : : _CaptureCurrent ( ) ;
}
} ;
//
// The below are for composability with tasks auto-created from when_any / when_all / && / || constructs.
//
template < typename _Type >
struct _ResultContext < std : : vector < _Type * > >
{
static std : : vector < _Type * > _GetValue ( std : : vector < _Type * > _ObjInCtx , const _ContextCallback & _Ctx , bool _RuntimeAggregate )
{
if ( ! _RuntimeAggregate )
{
return _ObjInCtx ;
}
_ContextCallback _CurrentContext = _ContextCallback : : _CaptureCurrent ( ) ;
if ( ! _Ctx . _HasCapturedContext ( ) | | _Ctx = = _CurrentContext )
{
return _ObjInCtx ;
}
for ( auto _It = _ObjInCtx . begin ( ) ; _It ! = _ObjInCtx . end ( ) ; + + _It )
{
* _It = _Marshal < _Type > ( * _It , _Ctx ) ;
}
return _ObjInCtx ;
}
static _ContextCallback _GetContext ( bool _RuntimeAggregate )
{
if ( ! _RuntimeAggregate )
{
return _ContextCallback ( ) ;
}
else
{
return _ContextCallback : : _CaptureCurrent ( ) ;
}
}
} ;
template < typename _Type >
struct _ResultContext < std : : pair < _Type * , size_t > >
{
static std : : pair < _Type * , size_t > _GetValue ( std : : pair < _Type * , size_t > _ObjInCtx , const _ContextCallback & _Ctx , bool _RuntimeAggregate )
{
if ( ! _RuntimeAggregate )
{
return _ObjInCtx ;
}
_ContextCallback _CurrentContext = _ContextCallback : : _CaptureCurrent ( ) ;
if ( ! _Ctx . _HasCapturedContext ( ) | | _Ctx = = _CurrentContext )
{
return _ObjInCtx ;
}
return std : : pair < _Type * , size_t > ( _Marshal < _Type > ( _ObjInCtx . first , _Ctx ) , _ObjInCtx . second ) ;
}
static _ContextCallback _GetContext ( bool _RuntimeAggregate )
{
if ( ! _RuntimeAggregate )
{
return _ContextCallback ( ) ;
}
else
{
return _ContextCallback : : _CaptureCurrent ( ) ;
}
}
} ;
# endif
// An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task.
// The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception
// is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.
struct _ExceptionHolder
{
# if _MSC_VER >= 1800
private :
void ReportUnhandledError ( )
{
if ( _M_winRTException ! = nullptr )
{
throw _M_winRTException . Get ( ) ;
}
}
public :
explicit _ExceptionHolder ( const std : : exception_ptr & _E , const _TaskCreationCallstack & _stackTrace ) :
_M_exceptionObserved ( 0 ) , _M_stdException ( _E ) , _M_stackTrace ( _stackTrace )
{
}
explicit _ExceptionHolder ( IRestrictedErrorInfo * & _E , const _TaskCreationCallstack & _stackTrace ) :
_M_exceptionObserved ( 0 ) , _M_winRTException ( _E ) , _M_stackTrace ( _stackTrace )
{
}
# else
explicit _ExceptionHolder ( const std : : exception_ptr & _E , void * _SourceAddressHint ) :
_M_exceptionObserved ( 0 ) , _M_stdException ( _E ) , _M_disassembleMe ( _SourceAddressHint )
{
}
explicit _ExceptionHolder ( IRestrictedErrorInfo * & _E , void * _SourceAddressHint ) :
_M_exceptionObserved ( 0 ) , _M_disassembleMe ( _SourceAddressHint ) , _M_winRTException ( _E )
{
}
# endif
__declspec ( noinline )
~ _ExceptionHolder ( )
{
if ( _M_exceptionObserved = = 0 )
{
# if _MSC_VER >= 1800
// If you are trapped here, it means an exception thrown in task chain didn't get handled.
// Please add task-based continuation to handle all exceptions coming from tasks.
// this->_M_stackTrace keeps the creation callstack of the task generates this exception.
_REPORT_PPLTASK_UNOBSERVED_EXCEPTION ( ) ;
# else
// Disassemble at this->_M_disassembleMe to get to the source location right after either the creation of the task (constructor
// or then method) that encountered this exception, or the set_exception call for a task_completion_event.
Concurrency : : details : : _ReportUnobservedException ( ) ;
# endif
}
}
void _RethrowUserException ( )
{
if ( _M_exceptionObserved = = 0 )
{
# if _MSC_VER >= 1800
Concurrency : : details : : atomic_exchange ( _M_exceptionObserved , 1l ) ;
# else
_InterlockedExchange ( & _M_exceptionObserved , 1 ) ;
# endif
}
if ( _M_winRTException ! = nullptr )
{
throw _M_winRTException . Get ( ) ;
}
std : : rethrow_exception ( _M_stdException ) ;
}
// A variable that remembers if this exception was every rethrown into user code (and hence handled by the user). Exceptions that
// are unobserved when the exception holder is destructed will terminate the process.
# if _MSC_VER >= 1800
Concurrency : : details : : atomic_long _M_exceptionObserved ;
# else
long volatile _M_exceptionObserved ;
# endif
// Either _M_stdException or _M_winRTException is populated based on the type of exception encountered.
std : : exception_ptr _M_stdException ;
Microsoft : : WRL : : ComPtr < IRestrictedErrorInfo > _M_winRTException ;
// Disassembling this value will point to a source instruction right after a call instruction. If the call is to create_task,
// a task constructor or the then method, the task created by that method is the one that encountered this exception. If the call
// is to task_completion_event::set_exception, the set_exception method was the source of the exception.
// DO NOT REMOVE THIS VARIABLE. It is extremely helpful for debugging.
# if _MSC_VER >= 1800
_TaskCreationCallstack _M_stackTrace ;
# else
void * _M_disassembleMe ;
# endif
} ;
# ifndef RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoImpl_DEFINED
# define RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoImpl_DEFINED
extern const __declspec ( selectany ) WCHAR RuntimeClass_Concurrency_winrt_details__AsyncInfoImpl [ ] = L " Concurrency_winrt.details._AsyncInfoImpl " ;
# endif
/// <summary>
/// Base converter class for converting asynchronous interfaces to IAsyncOperation
/// </summary>
template < typename _AsyncOperationType , typename _CompletionHandlerType , typename _Result_abi >
struct _AsyncInfoImpl abstract : public Microsoft : : WRL : : RuntimeClass <
Microsoft : : WRL : : RuntimeClassFlags < Microsoft : : WRL : : RuntimeClassType : : WinRt > ,
Microsoft : : WRL : : Implements < Microsoft : : WRL : : AsyncBase < _CompletionHandlerType > > >
{
InspectableClass ( RuntimeClass_Concurrency_winrt_details__AsyncInfoImpl , BaseTrust )
public :
// The async action, action with progress or operation with progress that this stub forwards to.
# if _MSC_VER >= 1800
Agile < _AsyncOperationType > _M_asyncInfo ;
# else
Microsoft : : WRL : : ComPtr < _AsyncOperationType > _M_asyncInfo ;
// The context in which this async info is valid - may be different from the context where the completion handler runs,
// and may require marshalling before it is used.
_ContextCallback _M_asyncInfoContext ;
# endif
Microsoft : : WRL : : ComPtr < _CompletionHandlerType > _M_CompletedHandler ;
_AsyncInfoImpl ( _AsyncOperationType * _AsyncInfo ) : _M_asyncInfo ( _AsyncInfo )
# if _MSC_VER < 1800
, _M_asyncInfoContext ( _ContextCallback : : _CaptureCurrent ( ) )
# endif
{ }
public :
virtual HRESULT OnStart ( ) { return S_OK ; }
virtual void OnCancel ( ) {
Microsoft : : WRL : : ComPtr < ABI : : Windows : : Foundation : : IAsyncInfo > pAsyncInfo ;
HRESULT hr ;
# if _MSC_VER >= 1800
if ( SUCCEEDED ( hr = _M_asyncInfo . Get ( ) - > QueryInterface < ABI : : Windows : : Foundation : : IAsyncInfo > ( pAsyncInfo . GetAddressOf ( ) ) ) )
# else
if ( SUCCEEDED ( hr = _M_asyncInfo . As ( & pAsyncInfo ) ) )
# endif
pAsyncInfo - > Cancel ( ) ;
else
throw std : : make_exception_ptr ( hr ) ;
}
virtual void OnClose ( ) {
Microsoft : : WRL : : ComPtr < ABI : : Windows : : Foundation : : IAsyncInfo > pAsyncInfo ;
HRESULT hr ;
# if _MSC_VER >= 1800
if ( SUCCEEDED ( hr = _M_asyncInfo . Get ( ) - > QueryInterface < ABI : : Windows : : Foundation : : IAsyncInfo > ( pAsyncInfo . GetAddressOf ( ) ) ) )
# else
if ( SUCCEEDED ( hr = _M_asyncInfo . As ( & pAsyncInfo ) ) )
# endif
pAsyncInfo - > Close ( ) ;
else
throw std : : make_exception_ptr ( hr ) ;
}
virtual STDMETHODIMP get_ErrorCode ( HRESULT * errorCode )
{
Microsoft : : WRL : : ComPtr < ABI : : Windows : : Foundation : : IAsyncInfo > pAsyncInfo ;
HRESULT hr ;
# if _MSC_VER >= 1800
if ( SUCCEEDED ( hr = _M_asyncInfo . Get ( ) - > QueryInterface < ABI : : Windows : : Foundation : : IAsyncInfo > ( pAsyncInfo . GetAddressOf ( ) ) ) )
# else
if ( SUCCEEDED ( hr = _M_asyncInfo . As ( & pAsyncInfo ) ) )
# endif
return pAsyncInfo - > get_ErrorCode ( errorCode ) ;
return hr ;
}
virtual STDMETHODIMP get_Id ( UINT * id )
{
Microsoft : : WRL : : ComPtr < ABI : : Windows : : Foundation : : IAsyncInfo > pAsyncInfo ;
HRESULT hr ;
# if _MSC_VER >= 1800
if ( SUCCEEDED ( hr = _M_asyncInfo . Get ( ) - > QueryInterface < ABI : : Windows : : Foundation : : IAsyncInfo > ( pAsyncInfo . GetAddressOf ( ) ) ) )
# else
if ( SUCCEEDED ( hr = _M_asyncInfo . As ( & pAsyncInfo ) ) )
# endif
return pAsyncInfo - > get_Id ( id ) ;
return hr ;
}
virtual STDMETHODIMP get_Status ( ABI : : Windows : : Foundation : : AsyncStatus * status )
{
Microsoft : : WRL : : ComPtr < ABI : : Windows : : Foundation : : IAsyncInfo > pAsyncInfo ;
HRESULT hr ;
# if _MSC_VER >= 1800
if ( SUCCEEDED ( hr = _M_asyncInfo . Get ( ) - > QueryInterface < ABI : : Windows : : Foundation : : IAsyncInfo > ( pAsyncInfo . GetAddressOf ( ) ) ) )
# else
if ( SUCCEEDED ( hr = _M_asyncInfo . As ( & pAsyncInfo ) ) )
# endif
return pAsyncInfo - > get_Status ( status ) ;
return hr ;
}
virtual STDMETHODIMP GetResults ( _Result_abi * ) { throw std : : runtime_error ( " derived class must implement " ) ; }
virtual STDMETHODIMP get_Completed ( _CompletionHandlerType * * handler )
{
if ( ! handler ) return E_POINTER ;
_M_CompletedHandler . CopyTo ( handler ) ;
return S_OK ;
}
virtual STDMETHODIMP put_Completed ( _CompletionHandlerType * value )
{
_M_CompletedHandler = value ;
Microsoft : : WRL : : ComPtr < _CompletionHandlerType > handler = Microsoft : : WRL : : Callback < _CompletionHandlerType > ( [ & ] ( _AsyncOperationType * , ABI : : Windows : : Foundation : : AsyncStatus status ) - > HRESULT {
# if _MSC_VER < 1800
// Update the saved _M_asyncInfo with a proxy valid in the current context if required. Some Windows APIs return an IAsyncInfo
// that is only valid for the thread that called the API to retrieve. Since this completion handler can run on any thread, we
// need to ensure that the async info is valid in the current apartment. _M_asyncInfo will be accessed via calls to 'this' inside
// _AsyncInit.
_M_asyncInfo = _ResultContext < _AsyncOperationType * > : : _GetValue ( _M_asyncInfo . Get ( ) , _M_asyncInfoContext , false ) ;
# endif
return _M_CompletedHandler - > Invoke ( _M_asyncInfo . Get ( ) , status ) ;
} ) ;
# if _MSC_VER >= 1800
return _M_asyncInfo . Get ( ) - > put_Completed ( handler . Get ( ) ) ;
# else
return _M_asyncInfo - > put_Completed ( handler . Get ( ) ) ;
# endif
}
} ;
extern const __declspec ( selectany ) WCHAR RuntimeClass_IAsyncOperationToAsyncOperationConverter [ ] = L " _IAsyncOperationToAsyncOperationConverter " ;
/// <summary>
/// Class _IAsyncOperationToAsyncOperationConverter is used to convert an instance of IAsyncOperationWithProgress<T> into IAsyncOperation<T>
/// </summary>
template < typename _Result >
struct _IAsyncOperationToAsyncOperationConverter :
_AsyncInfoImpl < ABI : : Windows : : Foundation : : IAsyncOperation < _Result > ,
ABI : : Windows : : Foundation : : IAsyncOperationCompletedHandler < _Result > ,
typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncOperationSelector ( stdx : : declval < ABI : : Windows : : Foundation : : IAsyncOperation < _Result > * > ( ) ) ) > : : type >
{
typedef typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncOperationSelector ( stdx : : declval < ABI : : Windows : : Foundation : : IAsyncOperation < _Result > * > ( ) ) ) > : : type _Result_abi ;
InspectableClass ( RuntimeClass_IAsyncOperationToAsyncOperationConverter , BaseTrust )
public :
_IAsyncOperationToAsyncOperationConverter ( ABI : : Windows : : Foundation : : IAsyncOperation < _Result > * _Operation ) :
_AsyncInfoImpl < ABI : : Windows : : Foundation : : IAsyncOperation < _Result > ,
ABI : : Windows : : Foundation : : IAsyncOperationCompletedHandler < _Result > ,
_Result_abi > ( _Operation ) { }
public :
virtual STDMETHODIMP GetResults ( _Result_abi * results ) override {
if ( ! results ) return E_POINTER ;
# if _MSC_VER >= 1800
return _M_asyncInfo . Get ( ) - > GetResults ( results ) ;
# else
return _M_asyncInfo - > GetResults ( results ) ;
# endif
}
} ;
extern const __declspec ( selectany ) WCHAR RuntimeClass_IAsyncOperationWithProgressToAsyncOperationConverter [ ] = L " _IAsyncOperationWithProgressToAsyncOperationConverter " ;
/// <summary>
/// Class _IAsyncOperationWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncOperationWithProgress<T> into IAsyncOperation<T>
/// </summary>
template < typename _Result , typename _Progress >
struct _IAsyncOperationWithProgressToAsyncOperationConverter :
_AsyncInfoImpl < ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _Result , _Progress > ,
ABI : : Windows : : Foundation : : IAsyncOperationWithProgressCompletedHandler < _Result , _Progress > ,
typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncOperationWithProgressSelector ( stdx : : declval < ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _Result , _Progress > * > ( ) ) ) > : : type >
{
typedef typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncOperationWithProgressSelector ( stdx : : declval < ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _Result , _Progress > * > ( ) ) ) > : : type _Result_abi ;
InspectableClass ( RuntimeClass_IAsyncOperationWithProgressToAsyncOperationConverter , BaseTrust )
public :
_IAsyncOperationWithProgressToAsyncOperationConverter ( ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _Result , _Progress > * _Operation ) :
_AsyncInfoImpl < ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _Result , _Progress > ,
ABI : : Windows : : Foundation : : IAsyncOperationWithProgressCompletedHandler < _Result , _Progress > ,
_Result_abi > ( _Operation ) { }
public :
virtual STDMETHODIMP GetResults ( _Result_abi * results ) override {
if ( ! results ) return E_POINTER ;
# if _MSC_VER >= 1800
return _M_asyncInfo . Get ( ) - > GetResults ( results ) ;
# else
return _M_asyncInfo - > GetResults ( results ) ;
# endif
}
} ;
extern const __declspec ( selectany ) WCHAR RuntimeClass_IAsyncActionToAsyncOperationConverter [ ] = L " _IAsyncActionToAsyncOperationConverter " ;
/// <summary>
/// Class _IAsyncActionToAsyncOperationConverter is used to convert an instance of IAsyncAction into IAsyncOperation<_Unit_type>
/// </summary>
struct _IAsyncActionToAsyncOperationConverter :
_AsyncInfoImpl < ABI : : Windows : : Foundation : : IAsyncAction ,
ABI : : Windows : : Foundation : : IAsyncActionCompletedHandler ,
_Unit_type >
{
InspectableClass ( RuntimeClass_IAsyncActionToAsyncOperationConverter , BaseTrust )
public :
_IAsyncActionToAsyncOperationConverter ( ABI : : Windows : : Foundation : : IAsyncAction * _Operation ) :
_AsyncInfoImpl < ABI : : Windows : : Foundation : : IAsyncAction ,
ABI : : Windows : : Foundation : : IAsyncActionCompletedHandler ,
_Unit_type > ( _Operation ) { }
public :
virtual STDMETHODIMP GetResults ( details : : _Unit_type * results )
{
if ( ! results ) return E_POINTER ;
// Invoke GetResults on the IAsyncAction to allow exceptions to be thrown to higher layers before returning a dummy value.
# if _MSC_VER >= 1800
HRESULT hr = _M_asyncInfo . Get ( ) - > GetResults ( ) ;
# else
HRESULT hr = _M_asyncInfo - > GetResults ( ) ;
# endif
if ( SUCCEEDED ( hr ) ) * results = _Unit_type ( ) ;
return hr ;
}
} ;
extern const __declspec ( selectany ) WCHAR RuntimeClass_IAsyncActionWithProgressToAsyncOperationConverter [ ] = L " _IAsyncActionWithProgressToAsyncOperationConverter " ;
/// <summary>
/// Class _IAsyncActionWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncActionWithProgress into IAsyncOperation<_Unit_type>
/// </summary>
template < typename _Progress >
struct _IAsyncActionWithProgressToAsyncOperationConverter :
_AsyncInfoImpl < ABI : : Windows : : Foundation : : IAsyncActionWithProgress < _Progress > ,
ABI : : Windows : : Foundation : : IAsyncActionWithProgressCompletedHandler < _Progress > ,
_Unit_type >
{
InspectableClass ( RuntimeClass_IAsyncActionWithProgressToAsyncOperationConverter , BaseTrust )
public :
_IAsyncActionWithProgressToAsyncOperationConverter ( ABI : : Windows : : Foundation : : IAsyncActionWithProgress < _Progress > * _Action ) :
_AsyncInfoImpl < ABI : : Windows : : Foundation : : IAsyncActionWithProgress < _Progress > ,
ABI : : Windows : : Foundation : : IAsyncActionWithProgressCompletedHandler < _Progress > ,
_Unit_type > ( _Action ) { }
public :
virtual STDMETHODIMP GetResults ( _Unit_type * results ) override
{
if ( ! results ) return E_POINTER ;
// Invoke GetResults on the IAsyncActionWithProgress to allow exceptions to be thrown before returning a dummy value.
# if _MSC_VER >= 1800
HRESULT hr = _M_asyncInfo . Get ( ) - > GetResults ( ) ;
# else
HRESULT hr = _M_asyncInfo - > GetResults ( ) ;
# endif
if ( SUCCEEDED ( hr ) ) * results = _Unit_type ( ) ;
return hr ;
}
} ;
}
/// <summary>
/// The <c>task_continuation_context</c> class allows you to specify where you would like a continuation to be executed.
/// It is only useful to use this class from a Windows Store app. For non-Windows Store apps, the task continuation's
/// execution context is determined by the runtime, and not configurable.
/// </summary>
/// <seealso cref="task Class"/>
/**/
class task_continuation_context : public details : : _ContextCallback
{
public :
/// <summary>
/// Creates the default task continuation context.
/// </summary>
/// <returns>
/// The default continuation context.
/// </returns>
/// <remarks>
/// The default context is used if you don't specifiy a continuation context when you call the <c>then</c> method. In Windows
/// applications for Windows 7 and below, as well as desktop applications on Windows 8 and higher, the runtime determines where
/// task continuations will execute. However, in a Windows Store app, the default continuation context for a continuation on an
/// apartment aware task is the apartment where <c>then</c> is invoked.
/// <para>An apartment aware task is a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such
/// a task. Therefore, if you schedule a continuation on an apartment aware task in a Windows Runtime STA, the continuation will execute in
/// that STA.</para>
/// <para>A continuation on a non-apartment aware task will execute in a context the Runtime chooses.</para>
/// </remarks>
/**/
static task_continuation_context use_default ( )
{
// The callback context is created with the context set to CaptureDeferred and resolved when it is used in .then()
return task_continuation_context ( true ) ; // sets it to deferred, is resolved in the constructor of _ContinuationTaskHandle
}
/// <summary>
/// Creates a task continuation context which allows the Runtime to choose the execution context for a continuation.
/// </summary>
/// <returns>
/// A task continuation context that represents an arbitrary location.
/// </returns>
/// <remarks>
/// When this continuation context is used the continuation will execute in a context the runtime chooses even if the antecedent task
/// is apartment aware.
/// <para><c>use_arbitrary</c> can be used to turn off the default behavior for a continuation on an apartment
/// aware task created in an STA. </para>
/// <para>This method is only available to Windows Store apps.</para>
/// </remarks>
/**/
static task_continuation_context use_arbitrary ( )
{
task_continuation_context _Arbitrary ( true ) ;
_Arbitrary . _Resolve ( false ) ;
return _Arbitrary ;
}
/// <summary>
/// Returns a task continuation context object that represents the current execution context.
/// </summary>
/// <returns>
/// The current execution context.
/// </returns>
/// <remarks>
/// This method captures the caller's Windows Runtime context so that continuations can be executed in the right apartment.
/// <para>The value returned by <c>use_current</c> can be used to indicate to the Runtime that the continuation should execute in
/// the captured context (STA vs MTA) regardless of whether or not the antecedent task is apartment aware. An apartment aware task is
/// a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such a task. </para>
/// <para>This method is only available to Windows Store apps.</para>
/// </remarks>
/**/
static task_continuation_context use_current ( )
{
task_continuation_context _Current ( true ) ;
_Current . _Resolve ( true ) ;
return _Current ;
}
private :
task_continuation_context ( bool _DeferCapture = false ) : details : : _ContextCallback ( _DeferCapture )
{
}
} ;
# if _MSC_VER >= 1800
class task_options ;
namespace details
{
struct _Internal_task_options
{
bool _M_hasPresetCreationCallstack ;
_TaskCreationCallstack _M_presetCreationCallstack ;
void _set_creation_callstack ( const _TaskCreationCallstack & _callstack )
{
_M_hasPresetCreationCallstack = true ;
_M_presetCreationCallstack = _callstack ;
}
_Internal_task_options ( )
{
_M_hasPresetCreationCallstack = false ;
}
} ;
inline _Internal_task_options & _get_internal_task_options ( task_options & options ) ;
inline const _Internal_task_options & _get_internal_task_options ( const task_options & options ) ;
}
/// <summary>
/// Represents the allowed options for creating a task
/// </summary>
class task_options
{
public :
/// <summary>
/// Default list of task creation options
/// </summary>
task_options ( )
: _M_Scheduler ( Concurrency : : get_ambient_scheduler ( ) ) ,
_M_CancellationToken ( Concurrency : : cancellation_token : : none ( ) ) ,
_M_ContinuationContext ( task_continuation_context : : use_default ( ) ) ,
_M_HasCancellationToken ( false ) ,
_M_HasScheduler ( false )
{
}
/// <summary>
/// Task option that specify a cancellation token
/// </summary>
task_options ( Concurrency : : cancellation_token _Token )
: _M_Scheduler ( Concurrency : : get_ambient_scheduler ( ) ) ,
_M_CancellationToken ( _Token ) ,
_M_ContinuationContext ( task_continuation_context : : use_default ( ) ) ,
_M_HasCancellationToken ( true ) ,
_M_HasScheduler ( false )
{
}
/// <summary>
/// Task option that specify a continuation context. This is valid only for continuations (then)
/// </summary>
task_options ( task_continuation_context _ContinuationContext )
: _M_Scheduler ( Concurrency : : get_ambient_scheduler ( ) ) ,
_M_CancellationToken ( Concurrency : : cancellation_token : : none ( ) ) ,
_M_ContinuationContext ( _ContinuationContext ) ,
_M_HasCancellationToken ( false ) ,
_M_HasScheduler ( false )
{
}
/// <summary>
/// Task option that specify a cancellation token and a continuation context. This is valid only for continuations (then)
/// </summary>
task_options ( Concurrency : : cancellation_token _Token , task_continuation_context _ContinuationContext )
: _M_Scheduler ( Concurrency : : get_ambient_scheduler ( ) ) ,
_M_CancellationToken ( _Token ) ,
_M_ContinuationContext ( _ContinuationContext ) ,
_M_HasCancellationToken ( false ) ,
_M_HasScheduler ( false )
{
}
/// <summary>
/// Task option that specify a scheduler with shared lifetime
/// </summary>
template < typename _SchedType >
task_options ( std : : shared_ptr < _SchedType > _Scheduler )
: _M_Scheduler ( std : : move ( _Scheduler ) ) ,
_M_CancellationToken ( cancellation_token : : none ( ) ) ,
_M_ContinuationContext ( task_continuation_context : : use_default ( ) ) ,
_M_HasCancellationToken ( false ) ,
_M_HasScheduler ( true )
{
}
/// <summary>
/// Task option that specify a scheduler reference
/// </summary>
task_options ( Concurrency : : scheduler_interface & _Scheduler )
: _M_Scheduler ( & _Scheduler ) ,
_M_CancellationToken ( Concurrency : : cancellation_token : : none ( ) ) ,
_M_ContinuationContext ( task_continuation_context : : use_default ( ) ) ,
_M_HasCancellationToken ( false ) ,
_M_HasScheduler ( true )
{
}
/// <summary>
/// Task option that specify a scheduler
/// </summary>
task_options ( Concurrency : : scheduler_ptr _Scheduler )
: _M_Scheduler ( std : : move ( _Scheduler ) ) ,
_M_CancellationToken ( Concurrency : : cancellation_token : : none ( ) ) ,
_M_ContinuationContext ( task_continuation_context : : use_default ( ) ) ,
_M_HasCancellationToken ( false ) ,
_M_HasScheduler ( true )
{
}
/// <summary>
/// Task option copy constructor
/// </summary>
task_options ( const task_options & _TaskOptions )
: _M_Scheduler ( _TaskOptions . get_scheduler ( ) ) ,
_M_CancellationToken ( _TaskOptions . get_cancellation_token ( ) ) ,
_M_ContinuationContext ( _TaskOptions . get_continuation_context ( ) ) ,
_M_HasCancellationToken ( _TaskOptions . has_cancellation_token ( ) ) ,
_M_HasScheduler ( _TaskOptions . has_scheduler ( ) )
{
}
/// <summary>
/// Sets the given token in the options
/// </summary>
void set_cancellation_token ( Concurrency : : cancellation_token _Token )
{
_M_CancellationToken = _Token ;
_M_HasCancellationToken = true ;
}
/// <summary>
/// Sets the given continuation context in the options
/// </summary>
void set_continuation_context ( task_continuation_context _ContinuationContext )
{
_M_ContinuationContext = _ContinuationContext ;
}
/// <summary>
/// Indicates whether a cancellation token was specified by the user
/// </summary>
bool has_cancellation_token ( ) const
{
return _M_HasCancellationToken ;
}
/// <summary>
/// Returns the cancellation token
/// </summary>
Concurrency : : cancellation_token get_cancellation_token ( ) const
{
return _M_CancellationToken ;
}
/// <summary>
/// Returns the continuation context
/// </summary>
task_continuation_context get_continuation_context ( ) const
{
return _M_ContinuationContext ;
}
/// <summary>
/// Indicates whether a scheduler n was specified by the user
/// </summary>
bool has_scheduler ( ) const
{
return _M_HasScheduler ;
}
/// <summary>
/// Returns the scheduler
/// </summary>
Concurrency : : scheduler_ptr get_scheduler ( ) const
{
return _M_Scheduler ;
}
private :
task_options const & operator = ( task_options const & _Right ) ;
friend details : : _Internal_task_options & details : : _get_internal_task_options ( task_options & ) ;
friend const details : : _Internal_task_options & details : : _get_internal_task_options ( const task_options & ) ;
Concurrency : : scheduler_ptr _M_Scheduler ;
Concurrency : : cancellation_token _M_CancellationToken ;
task_continuation_context _M_ContinuationContext ;
details : : _Internal_task_options _M_InternalTaskOptions ;
bool _M_HasCancellationToken ;
bool _M_HasScheduler ;
} ;
# endif
namespace details
{
# if _MSC_VER >= 1800
inline _Internal_task_options & _get_internal_task_options ( task_options & options )
{
return options . _M_InternalTaskOptions ;
}
inline const _Internal_task_options & _get_internal_task_options ( const task_options & options )
{
return options . _M_InternalTaskOptions ;
}
# endif
struct _Task_impl_base ;
template < typename _ReturnType > struct _Task_impl ;
template < typename _ReturnType >
struct _Task_ptr
{
typedef std : : shared_ptr < _Task_impl < _ReturnType > > _Type ;
# if _MSC_VER >= 1800
static _Type _Make ( Concurrency : : details : : _CancellationTokenState * _Ct , Concurrency : : scheduler_ptr _Scheduler_arg ) { return std : : make_shared < _Task_impl < _ReturnType > > ( _Ct , _Scheduler_arg ) ; }
# else
static _Type _Make ( Concurrency : : details : : _CancellationTokenState * _Ct ) { return std : : make_shared < _Task_impl < _ReturnType > > ( _Ct ) ; }
# endif
} ;
# if _MSC_VER >= 1800
typedef Concurrency : : details : : _TaskCollection_t : : _TaskProcHandle_t _UnrealizedChore_t ;
typedef _UnrealizedChore_t _UnrealizedChore ;
typedef Concurrency : : extensibility : : scoped_critical_section_t scoped_lock ;
typedef Concurrency : : extensibility : : critical_section_t critical_section ;
typedef Concurrency : : details : : atomic_size_t atomic_size_t ;
# else
typedef Concurrency : : details : : _UnrealizedChore _UnrealizedChore ;
typedef Concurrency : : critical_section : : scoped_lock scoped_lock ;
typedef Concurrency : : critical_section critical_section ;
typedef volatile size_t atomic_size_t ;
# endif
typedef std : : shared_ptr < _Task_impl_base > _Task_ptr_base ;
// The weak-typed base task handler for continuation tasks.
struct _ContinuationTaskHandleBase : _UnrealizedChore
{
_ContinuationTaskHandleBase * _M_next ;
task_continuation_context _M_continuationContext ;
bool _M_isTaskBasedContinuation ;
// This field gives inlining scheduling policy for current chore.
_TaskInliningMode _M_inliningMode ;
virtual _Task_ptr_base _GetTaskImplBase ( ) const = 0 ;
_ContinuationTaskHandleBase ( ) :
_M_next ( nullptr ) , _M_isTaskBasedContinuation ( false ) , _M_continuationContext ( task_continuation_context : : use_default ( ) ) , _M_inliningMode ( Concurrency : : details : : _NoInline )
{
}
virtual ~ _ContinuationTaskHandleBase ( ) { }
} ;
# if _MSC_VER >= 1800
# if _PPLTASK_ASYNC_LOGGING
// GUID used for identifying causality logs from PPLTask
const : : Platform : : Guid _PPLTaskCausalityPlatformID ( 0x7A76B220 , 0xA758 , 0x4E6E , 0xB0 , 0xE0 , 0xD7 , 0xC6 , 0xD7 , 0x4A , 0x88 , 0xFE ) ;
__declspec ( selectany ) volatile long _isCausalitySupported = 0 ;
inline bool _IsCausalitySupported ( )
{
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
if ( _isCausalitySupported = = 0 )
{
long _causality = 1 ;
OSVERSIONINFOEX _osvi = { } ;
_osvi . dwOSVersionInfoSize = sizeof ( OSVERSIONINFOEX ) ;
// The Causality is supported on Windows version higher than Windows 8
_osvi . dwMajorVersion = 6 ;
_osvi . dwMinorVersion = 3 ;
DWORDLONG _conditionMask = 0 ;
VER_SET_CONDITION ( _conditionMask , VER_MAJORVERSION , VER_GREATER_EQUAL ) ;
VER_SET_CONDITION ( _conditionMask , VER_MINORVERSION , VER_GREATER_EQUAL ) ;
if ( : : VerifyVersionInfo ( & _osvi , VER_MAJORVERSION | VER_MINORVERSION , _conditionMask ) )
{
_causality = 2 ;
}
_isCausalitySupported = _causality ;
return _causality = = 2 ;
}
return _isCausalitySupported = = 2 ? true : false ;
# else
return true ;
# endif
}
// Stateful logger rests inside task_impl_base.
struct _TaskEventLogger
{
_Task_impl_base * _M_task ;
bool _M_scheduled ;
bool _M_taskPostEventStarted ;
// Log before scheduling task
void _LogScheduleTask ( bool _isContinuation )
{
if ( details : : _IsCausalitySupported ( ) )
{
: : Windows : : Foundation : : Diagnostics : : AsyncCausalityTracer : : TraceOperationCreation ( : : Windows : : Foundation : : Diagnostics : : CausalityTraceLevel : : Required , : : Windows : : Foundation : : Diagnostics : : CausalitySource : : Library ,
_PPLTaskCausalityPlatformID , reinterpret_cast < unsigned long long > ( _M_task ) ,
_isContinuation ? " Concurrency::PPLTask::ScheduleContinuationTask " : " Concurrency::PPLTask::ScheduleTask " , 0 ) ;
_M_scheduled = true ;
}
}
// It will log the cancel event but not canceled state. _LogTaskCompleted will log the terminal state, which includes cancel state.
void _LogCancelTask ( )
{
if ( details : : _IsCausalitySupported ( ) )
{
: : Windows : : Foundation : : Diagnostics : : AsyncCausalityTracer : : TraceOperationRelation ( : : Windows : : Foundation : : Diagnostics : : CausalityTraceLevel : : Important , : : Windows : : Foundation : : Diagnostics : : CausalitySource : : Library ,
_PPLTaskCausalityPlatformID , reinterpret_cast < unsigned long long > ( _M_task ) , : : Windows : : Foundation : : Diagnostics : : CausalityRelation : : Cancel ) ;
}
}
// Log when task reaches terminal state. Note: the task can reach a terminal state (by cancellation or exception) without having run
void _LogTaskCompleted ( ) ;
// Log when task body (which includes user lambda and other scheduling code) begin to run
void _LogTaskExecutionStarted ( ) { }
// Log when task body finish executing
void _LogTaskExecutionCompleted ( )
{
if ( _M_taskPostEventStarted & & details : : _IsCausalitySupported ( ) )
{
: : Windows : : Foundation : : Diagnostics : : AsyncCausalityTracer : : TraceSynchronousWorkCompletion ( : : Windows : : Foundation : : Diagnostics : : CausalityTraceLevel : : Required , : : Windows : : Foundation : : Diagnostics : : CausalitySource : : Library ,
: : Windows : : Foundation : : Diagnostics : : CausalitySynchronousWork : : CompletionNotification ) ;
}
}
// Log right before user lambda being invoked
void _LogWorkItemStarted ( )
{
if ( details : : _IsCausalitySupported ( ) )
{
: : Windows : : Foundation : : Diagnostics : : AsyncCausalityTracer : : TraceSynchronousWorkStart ( : : Windows : : Foundation : : Diagnostics : : CausalityTraceLevel : : Required , : : Windows : : Foundation : : Diagnostics : : CausalitySource : : Library ,
_PPLTaskCausalityPlatformID , reinterpret_cast < unsigned long long > ( _M_task ) , : : Windows : : Foundation : : Diagnostics : : CausalitySynchronousWork : : Execution ) ;
}
}
// Log right after user lambda being invoked
void _LogWorkItemCompleted ( )
{
if ( details : : _IsCausalitySupported ( ) )
{
: : Windows : : Foundation : : Diagnostics : : AsyncCausalityTracer : : TraceSynchronousWorkCompletion ( : : Windows : : Foundation : : Diagnostics : : CausalityTraceLevel : : Required , : : Windows : : Foundation : : Diagnostics : : CausalitySource : : Library ,
: : Windows : : Foundation : : Diagnostics : : CausalitySynchronousWork : : Execution ) ;
: : Windows : : Foundation : : Diagnostics : : AsyncCausalityTracer : : TraceSynchronousWorkStart ( : : Windows : : Foundation : : Diagnostics : : CausalityTraceLevel : : Required , : : Windows : : Foundation : : Diagnostics : : CausalitySource : : Library ,
_PPLTaskCausalityPlatformID , reinterpret_cast < unsigned long long > ( _M_task ) , : : Windows : : Foundation : : Diagnostics : : CausalitySynchronousWork : : CompletionNotification ) ;
_M_taskPostEventStarted = true ;
}
}
_TaskEventLogger ( _Task_impl_base * _task ) : _M_task ( _task )
{
_M_scheduled = false ;
_M_taskPostEventStarted = false ;
}
} ;
// Exception safe logger for user lambda
struct _TaskWorkItemRAIILogger
{
_TaskEventLogger & _M_logger ;
_TaskWorkItemRAIILogger ( _TaskEventLogger & _taskHandleLogger ) : _M_logger ( _taskHandleLogger )
{
_M_logger . _LogWorkItemStarted ( ) ;
}
~ _TaskWorkItemRAIILogger ( )
{
_M_logger . _LogWorkItemCompleted ( ) ;
}
_TaskWorkItemRAIILogger & operator = ( const _TaskWorkItemRAIILogger & ) ; // cannot be assigned
} ;
# else
inline void _LogCancelTask ( _Task_impl_base * ) { }
struct _TaskEventLogger
{
void _LogScheduleTask ( bool ) { }
void _LogCancelTask ( ) { }
void _LogWorkItemStarted ( ) { }
void _LogWorkItemCompleted ( ) { }
void _LogTaskExecutionStarted ( ) { }
void _LogTaskExecutionCompleted ( ) { }
void _LogTaskCompleted ( ) { }
_TaskEventLogger ( _Task_impl_base * ) { }
} ;
struct _TaskWorkItemRAIILogger
{
_TaskWorkItemRAIILogger ( _TaskEventLogger & ) { }
} ;
# endif
# endif
/// <summary>
/// The _PPLTaskHandle is the strong-typed task handle base. All user task functions need to be wrapped in this task handler
/// to be executable by PPL. By deriving from a different _BaseTaskHandle, it can be used for both initial tasks and continuation tasks.
/// For initial tasks, _PPLTaskHandle will be derived from _UnrealizedChore, and for continuation tasks, it will be derived from
/// _ContinuationTaskHandleBase. The life time of the _PPLTaskHandle object is be managed by runtime if task handle is scheduled.
/// </summary>
/// <typeparam name="_ReturnType">
/// The result type of the _Task_impl.
/// </typeparam>
/// <typeparam name="_DerivedTaskHandle">
/// The derived task handle class. The <c>operator ()</c> needs to be implemented.
/// </typeparam>
/// <typeparam name="_BaseTaskHandle">
/// The base class from which _PPLTaskHandle should be derived. This is either _UnrealizedChore or _ContinuationTaskHandleBase.
/// </typeparam>
template < typename _ReturnType , typename _DerivedTaskHandle , typename _BaseTaskHandle >
struct _PPLTaskHandle : _BaseTaskHandle
{
_PPLTaskHandle ( const typename _Task_ptr < _ReturnType > : : _Type & _PTask ) : _M_pTask ( _PTask )
{
# if _MSC_VER < 1800
m_pFunction = reinterpret_cast < Concurrency : : TaskProc > ( & _UnrealizedChore : : _InvokeBridge < _PPLTaskHandle > ) ;
_SetRuntimeOwnsLifetime ( true ) ;
# endif
}
virtual ~ _PPLTaskHandle ( ) {
# if _MSC_VER >= 1800
// Here is the sink of all task completion code paths
_M_pTask - > _M_taskEventLogger . _LogTaskCompleted ( ) ;
# endif
}
# if _MSC_VER >= 1800
virtual void invoke ( ) const
# else
void operator ( ) ( ) const
# endif
{
// All exceptions should be rethrown to finish cleanup of the task collection. They will be caught and handled
// by the runtime.
_CONCRT_ASSERT ( _M_pTask ! = nullptr ) ;
if ( ! _M_pTask - > _TransitionedToStarted ( ) ) {
# if _MSC_VER >= 1800
static_cast < const _DerivedTaskHandle * > ( this ) - > _SyncCancelAndPropagateException ( ) ;
# endif
return ;
}
# if _MSC_VER >= 1800
_M_pTask - > _M_taskEventLogger . _LogTaskExecutionStarted ( ) ;
# endif
try
{
// All derived task handle must implement this contract function.
static_cast < const _DerivedTaskHandle * > ( this ) - > _Perform ( ) ;
}
catch ( const Concurrency : : task_canceled & )
{
_M_pTask - > _Cancel ( true ) ;
# if _MSC_VER < 1800
throw ;
# endif
}
catch ( const Concurrency : : details : : _Interruption_exception & )
{
_M_pTask - > _Cancel ( true ) ;
# if _MSC_VER < 1800
throw ;
# endif
}
catch ( IRestrictedErrorInfo * & _E )
{
_M_pTask - > _CancelWithException ( _E ) ;
# if _MSC_VER < 1800
throw ;
# endif
}
catch ( . . . )
{
_M_pTask - > _CancelWithException ( std : : current_exception ( ) ) ;
# if _MSC_VER < 1800
throw ;
# endif
}
# if _MSC_VER >= 1800
_M_pTask - > _M_taskEventLogger . _LogTaskExecutionCompleted ( ) ;
# endif
}
// Cast _M_pTask pointer to "type-less" _Task_impl_base pointer, which can be used in _ContinuationTaskHandleBase.
// The return value should be automatically optimized by R-value ref.
_Task_ptr_base _GetTaskImplBase ( ) const
{
return _M_pTask ;
}
typename _Task_ptr < _ReturnType > : : _Type _M_pTask ;
private :
_PPLTaskHandle const & operator = ( _PPLTaskHandle const & ) ; // no assignment operator
} ;
/// <summary>
/// The base implementation of a first-class task. This class contains all the non-type specific
/// implementation details of the task.
/// </summary>
/**/
struct _Task_impl_base
{
enum _TaskInternalState
{
// Tracks the state of the task, rather than the task collection on which the task is scheduled
_Created ,
_Started ,
_PendingCancel ,
_Completed ,
_Canceled
} ;
# if _MSC_VER >= 1800
_Task_impl_base ( Concurrency : : details : : _CancellationTokenState * _PTokenState , Concurrency : : scheduler_ptr _Scheduler_arg )
: _M_TaskState ( _Created ) ,
_M_fFromAsync ( false ) , _M_fUnwrappedTask ( false ) ,
_M_pRegistration ( nullptr ) , _M_Continuations ( nullptr ) , _M_TaskCollection ( _Scheduler_arg ) ,
_M_taskEventLogger ( this )
# else
_Task_impl_base ( Concurrency : : details : : _CancellationTokenState * _PTokenState ) : _M_TaskState ( _Created ) ,
_M_fFromAsync ( false ) , _M_fRuntimeAggregate ( false ) , _M_fUnwrappedTask ( false ) ,
_M_pRegistration ( nullptr ) , _M_Continuations ( nullptr ) , _M_pTaskCollection ( nullptr ) ,
_M_pTaskCreationAddressHint ( nullptr )
# endif
{
// Set cancelation token
_M_pTokenState = _PTokenState ;
_CONCRT_ASSERT ( _M_pTokenState ! = nullptr ) ;
if ( _M_pTokenState ! = Concurrency : : details : : _CancellationTokenState : : _None ( ) )
_M_pTokenState - > _Reference ( ) ;
}
virtual ~ _Task_impl_base ( )
{
_CONCRT_ASSERT ( _M_pTokenState ! = nullptr ) ;
if ( _M_pTokenState ! = Concurrency : : details : : _CancellationTokenState : : _None ( ) )
{
_M_pTokenState - > _Release ( ) ;
}
# if _MSC_VER < 1800
if ( _M_pTaskCollection ! = nullptr )
{
_M_pTaskCollection - > _Release ( ) ;
_M_pTaskCollection = nullptr ;
}
# endif
}
task_status _Wait ( )
{
bool _DoWait = true ;
if ( _IsNonBlockingThread ( ) )
{
// In order to prevent Windows Runtime STA threads from blocking the UI, calling task.wait() task.get() is illegal
// if task has not been completed.
if ( ! _IsCompleted ( ) & & ! _IsCanceled ( ) )
{
throw Concurrency : : invalid_operation ( " Illegal to wait on a task in a Windows Runtime STA " ) ;
}
else
{
// Task Continuations are 'scheduled' *inside* the chore that is executing on the ancestors's task group. If a continuation
// needs to be marshalled to a different apartment, instead of scheduling, we make a synchronous cross apartment COM
// call to execute the continuation. If it then happens to do something which waits on the ancestor (say it calls .get(), which
// task based continuations are wont to do), waiting on the task group results in on the chore that is making this
// synchronous callback, which causes a deadlock. To avoid this, we test the state ancestor's event , and we will NOT wait on
// if it has finished execution (which means now we are on the inline synchronous callback).
_DoWait = false ;
}
}
if ( _DoWait )
{
# if _MSC_VER < 1800
// Wait for the task to be actually scheduled, otherwise the underlying task collection
// might not be created yet. If we don't wait, we will miss the chance to inline this task.
_M_Scheduled . wait ( ) ;
// A PPL task created by a task_completion_event does not have an underlying TaskCollection. For
// These tasks, a call to wait should wait for the event to be set. The TaskCollection must either
// be nullptr or allocated (the setting of _M_Scheduled) ensures that.
# endif
// If this task was created from a Windows Runtime async operation, do not attempt to inline it. The
// async operation will take place on a thread in the appropriate apartment Simply wait for the completed
// event to be set.
# if _MSC_VER >= 1800
if ( _M_fFromAsync )
# else
if ( ( _M_pTaskCollection = = nullptr ) | | _M_fFromAsync )
# endif
{
# if _MSC_VER >= 1800
_M_TaskCollection . _Wait ( ) ;
# else
_M_Completed . wait ( ) ;
# endif
}
else
{
// Wait on the task collection to complete. The task collection is guaranteed to still be
// valid since the task must be still within scope so that the _Task_impl_base destructor
// has not yet been called. This call to _Wait potentially inlines execution of work.
try
{
// Invoking wait on a task collection resets the state of the task collection. This means that
// if the task collection itself were canceled, or had encountered an exception, only the first
// call to wait will receive this status. However, both cancellation and exceptions flowing through
// tasks set state in the task impl itself.
// When it returns cancelled, either work chore or the cancel thread should already have set task's state
// properly -- cancelled state or completed state (because there was no interruption point).
// For tasks with unwrapped tasks, we should not change the state of current task, since the unwrapped task are still running.
# if _MSC_VER >= 1800
_M_TaskCollection . _RunAndWait ( ) ;
# else
_M_pTaskCollection - > _RunAndWait ( ) ;
# endif
}
catch ( Concurrency : : details : : _Interruption_exception & )
{
// The _TaskCollection will never be an interruption point since it has a none token.
_CONCRT_ASSERT ( false ) ;
}
catch ( Concurrency : : task_canceled & )
{
// task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task
// must be called from code that is executed within the task (throwing it from parallel work created by and waited
// upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen
// the exception and canceled the task. Swallow the exception here.
_CONCRT_ASSERT ( _IsCanceled ( ) ) ;
}
catch ( IRestrictedErrorInfo * & _E )
{
// Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.
if ( ! _HasUserException ( ) )
{
_CancelWithException ( _E ) ;
}
// Rethrow will mark the exception as observed.
_M_exceptionHolder - > _RethrowUserException ( ) ;
}
catch ( . . . )
{
// Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.
if ( ! _HasUserException ( ) )
{
_CancelWithException ( std : : current_exception ( ) ) ;
}
// Rethrow will mark the exception as observed.
_M_exceptionHolder - > _RethrowUserException ( ) ;
}
// If the lambda body for this task (executed or waited upon in _RunAndWait above) happened to return a task
// which is to be unwrapped and plumbed to the output of this task, we must not only wait on the lambda body, we must
// wait on the **INNER** body. It is in theory possible that we could inline such if we plumb a series of things through;
// however, this takes the tact of simply waiting upon the completion signal.
if ( _M_fUnwrappedTask )
{
# if _MSC_VER >= 1800
_M_TaskCollection . _Wait ( ) ;
# else
_M_Completed . wait ( ) ;
# endif
}
}
}
if ( _HasUserException ( ) )
{
_M_exceptionHolder - > _RethrowUserException ( ) ;
}
else if ( _IsCanceled ( ) )
{
return Concurrency : : canceled ;
}
_CONCRT_ASSERT ( _IsCompleted ( ) ) ;
return Concurrency : : completed ;
}
/// <summary>
/// Requests cancellation on the task and schedules continuations if the task can be transitioned to a terminal state.
/// </summary>
/// <param name="_SynchronousCancel">
/// Set to true if the cancel takes place as a result of the task body encountering an exception, or because an ancestor or task_completion_event the task
/// was registered with were canceled with an exception. A synchronous cancel is one that assures the task could not be running on a different thread at
/// the time the cancellation is in progress. An asynchronous cancel is one where the thread performing the cancel has no control over the thread that could
/// be executing the task, that is the task could execute concurrently while the cancellation is in progress.
/// </param>
/// <param name="_UserException">
/// Whether an exception other than the internal runtime cancellation exceptions caused this cancellation.
/// </param>
/// <param name="_PropagatedFromAncestor">
/// Whether this exception came from an ancestor task or a task_completion_event as opposed to an exception that was encountered by the task itself. Only valid when
/// _UserException is set to true.
/// </param>
/// <param name="_ExHolder">
/// The exception holder that represents the exception. Only valid when _UserException is set to true.
/// </param>
virtual bool _CancelAndRunContinuations ( bool _SynchronousCancel , bool _UserException , bool _PropagatedFromAncestor , const std : : shared_ptr < _ExceptionHolder > & _ExHolder ) = 0 ;
bool _Cancel ( bool _SynchronousCancel )
{
// Send in a dummy value for exception. It is not used when the first parameter is false.
return _CancelAndRunContinuations ( _SynchronousCancel , false , false , _M_exceptionHolder ) ;
}
bool _CancelWithExceptionHolder ( const std : : shared_ptr < _ExceptionHolder > & _ExHolder , bool _PropagatedFromAncestor )
{
// This task was canceled because an ancestor task encountered an exception.
return _CancelAndRunContinuations ( true , true , _PropagatedFromAncestor , _ExHolder ) ;
}
bool _CancelWithException ( IRestrictedErrorInfo * & _Exception )
{
// This task was canceled because the task body encountered an exception.
_CONCRT_ASSERT ( ! _HasUserException ( ) ) ;
# if _MSC_VER >= 1800
return _CancelAndRunContinuations ( true , true , false , std : : make_shared < _ExceptionHolder > ( _Exception , _GetTaskCreationCallstack ( ) ) ) ;
# else
return _CancelAndRunContinuations ( true , true , false , std : : make_shared < _ExceptionHolder > ( _Exception , _GetTaskCreationAddressHint ( ) ) ) ;
# endif
}
bool _CancelWithException ( const std : : exception_ptr & _Exception )
{
// This task was canceled because the task body encountered an exception.
_CONCRT_ASSERT ( ! _HasUserException ( ) ) ;
# if _MSC_VER >= 1800
return _CancelAndRunContinuations ( true , true , false , std : : make_shared < _ExceptionHolder > ( _Exception , _GetTaskCreationCallstack ( ) ) ) ;
# else
return _CancelAndRunContinuations ( true , true , false , std : : make_shared < _ExceptionHolder > ( _Exception , _GetTaskCreationAddressHint ( ) ) ) ;
# endif
}
# if _MSC_VER >= 1800
void _RegisterCancellation ( std : : weak_ptr < _Task_impl_base > _WeakPtr )
# else
void _RegisterCancellation ( )
# endif
{
_CONCRT_ASSERT ( Concurrency : : details : : _CancellationTokenState : : _IsValid ( _M_pTokenState ) ) ;
# if _MSC_VER >= 1800
auto _CancellationCallback = [ _WeakPtr ] ( ) {
// Taking ownership of the task prevents dead lock during destruction
// if the destructor waits for the cancellations to be finished
auto _task = _WeakPtr . lock ( ) ;
if ( _task ! = nullptr )
_task - > _Cancel ( false ) ;
} ;
_M_pRegistration = new Concurrency : : details : : _CancellationTokenCallback < decltype ( _CancellationCallback ) > ( _CancellationCallback ) ;
_M_pTokenState - > _RegisterCallback ( _M_pRegistration ) ;
# else
_M_pRegistration = _M_pTokenState - > _RegisterCallback ( reinterpret_cast < Concurrency : : TaskProc > ( & _CancelViaToken ) , ( _Task_impl_base * ) this ) ;
# endif
}
void _DeregisterCancellation ( )
{
if ( _M_pRegistration ! = nullptr )
{
_M_pTokenState - > _DeregisterCallback ( _M_pRegistration ) ;
_M_pRegistration - > _Release ( ) ;
_M_pRegistration = nullptr ;
}
}
# if _MSC_VER < 1800
static void _CancelViaToken ( _Task_impl_base * _PImpl )
{
_PImpl - > _Cancel ( false ) ;
}
# endif
bool _IsCreated ( )
{
return ( _M_TaskState = = _Created ) ;
}
bool _IsStarted ( )
{
return ( _M_TaskState = = _Started ) ;
}
bool _IsPendingCancel ( )
{
return ( _M_TaskState = = _PendingCancel ) ;
}
bool _IsCompleted ( )
{
return ( _M_TaskState = = _Completed ) ;
}
bool _IsCanceled ( )
{
return ( _M_TaskState = = _Canceled ) ;
}
bool _HasUserException ( )
{
return static_cast < bool > ( _M_exceptionHolder ) ;
}
# if _MSC_VER < 1800
void _SetScheduledEvent ( )
{
_M_Scheduled . set ( ) ;
}
# endif
const std : : shared_ptr < _ExceptionHolder > & _GetExceptionHolder ( )
{
_CONCRT_ASSERT ( _HasUserException ( ) ) ;
return _M_exceptionHolder ;
}
bool _IsApartmentAware ( )
{
return _M_fFromAsync ;
}
void _SetAsync ( bool _Async = true )
{
_M_fFromAsync = _Async ;
}
# if _MSC_VER >= 1800
_TaskCreationCallstack _GetTaskCreationCallstack ( )
{
return _M_pTaskCreationCallstack ;
}
void _SetTaskCreationCallstack ( const _TaskCreationCallstack & _Callstack )
{
_M_pTaskCreationCallstack = _Callstack ;
}
# else
void * _GetTaskCreationAddressHint ( )
{
return _M_pTaskCreationAddressHint ;
}
void _SetTaskCreationAddressHint ( void * _AddressHint )
{
_M_pTaskCreationAddressHint = _AddressHint ;
}
# endif
/// <summary>
/// Helper function to schedule the task on the Task Collection.
/// </summary>
/// <param name="_PTaskHandle">
/// The task chore handle that need to be executed.
/// </param>
/// <param name="_InliningMode">
/// The inlining scheduling policy for current _PTaskHandle.
/// </param>
void _ScheduleTask ( _UnrealizedChore * _PTaskHandle , _TaskInliningMode _InliningMode )
{
# if _MSC_VER < 1800
// Construct the task collection; We use none token to provent it becoming interruption point.
_M_pTaskCollection = Concurrency : : details : : _AsyncTaskCollection : : _NewCollection ( Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
// _M_pTaskCollection->_ScheduleWithAutoInline will schedule the chore onto AsyncTaskCollection with automatic inlining, in a way that honors cancellation etc.
# endif
try
{
# if _MSC_VER >= 1800
_M_TaskCollection . _ScheduleTask ( _PTaskHandle , _InliningMode ) ;
# else
// Do not need to check its returning state, more details please refer to _Wait method.
_M_pTaskCollection - > _ScheduleWithAutoInline ( _PTaskHandle , _InliningMode ) ;
# endif
}
catch ( const Concurrency : : task_canceled & )
{
// task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task
// must be called from code that is executed within the task (throwing it from parallel work created by and waited
// upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen
// the exception and canceled the task. Swallow the exception here.
_CONCRT_ASSERT ( _IsCanceled ( ) ) ;
}
catch ( const Concurrency : : details : : _Interruption_exception & )
{
// The _TaskCollection will never be an interruption point since it has a none token.
_CONCRT_ASSERT ( false ) ;
}
catch ( . . . )
{
// This exception could only have come from within the chore body. It should've been caught
// and the task should be canceled with exception. Swallow the exception here.
_CONCRT_ASSERT ( _HasUserException ( ) ) ;
}
# if _MSC_VER < 1800
// Set the event in case anyone is waiting to notify that this task has been scheduled. In the case where we
// execute the chore inline, the event should be set after the chore has executed, to prevent a different thread
// performing a wait on the task from waiting on the task collection before the chore is actually added to it,
// and thereby returning from the wait() before the chore has executed.
_SetScheduledEvent ( ) ;
# endif
}
/// <summary>
/// Function executes a continuation. This function is recorded by a parent task implementation
/// when a continuation is created in order to execute later.
/// </summary>
/// <param name="_PTaskHandle">
/// The continuation task chore handle that need to be executed.
/// </param>
/**/
void _RunContinuation ( _ContinuationTaskHandleBase * _PTaskHandle )
{
_Task_ptr_base _ImplBase = _PTaskHandle - > _GetTaskImplBase ( ) ;
if ( _IsCanceled ( ) & & ! _PTaskHandle - > _M_isTaskBasedContinuation )
{
if ( _HasUserException ( ) )
{
// If the ancestor encountered an exception, transfer the exception to the continuation
// This traverses down the tree to propagate the exception.
_ImplBase - > _CancelWithExceptionHolder ( _GetExceptionHolder ( ) , true ) ;
}
else
{
// If the ancestor was canceled, then your own execution should be canceled.
// This traverses down the tree to cancel it.
_ImplBase - > _Cancel ( true ) ;
}
}
else
{
// This can only run when the ancestor has completed or it's a task based continuation that fires when a task is canceled
// (with or without a user exception).
_CONCRT_ASSERT ( _IsCompleted ( ) | | _PTaskHandle - > _M_isTaskBasedContinuation ) ;
# if _MSC_VER >= 1800
_CONCRT_ASSERT ( ! _ImplBase - > _IsCanceled ( ) ) ;
return _ImplBase - > _ScheduleContinuationTask ( _PTaskHandle ) ;
# else
// If it has been canceled here (before starting), do nothing. The guy firing cancel will do the clean up.
if ( ! _ImplBase - > _IsCanceled ( ) )
{
return _ImplBase - > _ScheduleContinuationTask ( _PTaskHandle ) ;
}
# endif
}
// If the handle is not scheduled, we need to manually delete it.
delete _PTaskHandle ;
}
// Schedule a continuation to run
void _ScheduleContinuationTask ( _ContinuationTaskHandleBase * _PTaskHandle )
{
# if _MSC_VER >= 1800
_M_taskEventLogger . _LogScheduleTask ( true ) ;
# endif
// Ensure that the continuation runs in proper context (this might be on a Concurrency Runtime thread or in a different Windows Runtime apartment)
if ( _PTaskHandle - > _M_continuationContext . _HasCapturedContext ( ) )
{
// For those continuations need to be scheduled inside captured context, we will try to apply automatic inlining to their inline modes,
// if they haven't been specified as _ForceInline yet. This change will encourage those continuations to be executed inline so that reduce
// the cost of marshaling.
// For normal continuations we won't do any change here, and their inline policies are completely decided by ._ThenImpl method.
if ( _PTaskHandle - > _M_inliningMode ! = Concurrency : : details : : _ForceInline )
{
_PTaskHandle - > _M_inliningMode = Concurrency : : details : : _DefaultAutoInline ;
}
details : : _ScheduleFuncWithAutoInline ( [ _PTaskHandle ] ( ) - > HRESULT {
// Note that we cannot directly capture "this" pointer, instead, we should use _TaskImplPtr, a shared_ptr to the _Task_impl_base.
// Because "this" pointer will be invalid as soon as _PTaskHandle get deleted. _PTaskHandle will be deleted after being scheduled.
auto _TaskImplPtr = _PTaskHandle - > _GetTaskImplBase ( ) ;
if ( details : : _ContextCallback : : _CaptureCurrent ( ) = = _PTaskHandle - > _M_continuationContext )
{
_TaskImplPtr - > _ScheduleTask ( _PTaskHandle , Concurrency : : details : : _ForceInline ) ;
}
else
{
//
// It's entirely possible that the attempt to marshal the call into a differing context will fail. In this case, we need to handle
// the exception and mark the continuation as canceled with the appropriate exception. There is one slight hitch to this:
//
// NOTE: COM's legacy behavior is to swallow SEH exceptions and marshal them back as HRESULTS. This will in effect turn an SEH into
// a C++ exception that gets tagged on the task. One unfortunate result of this is that various pieces of the task infrastructure will
// not be in a valid state after this in /EHsc (due to the lack of destructors running, etc...).
//
try
{
// Dev10 compiler needs this!
auto _PTaskHandle1 = _PTaskHandle ;
_PTaskHandle - > _M_continuationContext . _CallInContext ( [ _PTaskHandle1 , _TaskImplPtr ] ( ) - > HRESULT {
_TaskImplPtr - > _ScheduleTask ( _PTaskHandle1 , Concurrency : : details : : _ForceInline ) ;
return S_OK ;
} ) ;
}
catch ( IRestrictedErrorInfo * & _E )
{
_TaskImplPtr - > _CancelWithException ( _E ) ;
}
catch ( . . . )
{
_TaskImplPtr - > _CancelWithException ( std : : current_exception ( ) ) ;
}
}
return S_OK ;
} , _PTaskHandle - > _M_inliningMode ) ;
}
else
{
_ScheduleTask ( _PTaskHandle , _PTaskHandle - > _M_inliningMode ) ;
}
}
/// <summary>
/// Schedule the actual continuation. This will either schedule the function on the continuation task's implementation
/// if the task has completed or append it to a list of functions to execute when the task actually does complete.
/// </summary>
/// <typeparam name="_FuncInputType">
/// The input type of the task.
/// </typeparam>
/// <typeparam name="_FuncOutputType">
/// The output type of the task.
/// </typeparam>
/**/
void _ScheduleContinuation ( _ContinuationTaskHandleBase * _PTaskHandle )
{
enum { _Nothing , _Schedule , _Cancel , _CancelWithException } _Do = _Nothing ;
// If the task has canceled, cancel the continuation. If the task has completed, execute the continuation right away.
// Otherwise, add it to the list of pending continuations
{
scoped_lock _LockHolder ( _M_ContinuationsCritSec ) ;
if ( _IsCompleted ( ) | | ( _IsCanceled ( ) & & _PTaskHandle - > _M_isTaskBasedContinuation ) )
{
_Do = _Schedule ;
}
else if ( _IsCanceled ( ) )
{
if ( _HasUserException ( ) )
{
_Do = _CancelWithException ;
}
else
{
_Do = _Cancel ;
}
}
else
{
// chain itself on the continuation chain.
_PTaskHandle - > _M_next = _M_Continuations ;
_M_Continuations = _PTaskHandle ;
}
}
// Cancellation and execution of continuations should be performed after releasing the lock. Continuations off of
// async tasks may execute inline.
switch ( _Do )
{
case _Schedule :
{
_PTaskHandle - > _GetTaskImplBase ( ) - > _ScheduleContinuationTask ( _PTaskHandle ) ;
break ;
}
case _Cancel :
{
// If the ancestor was canceled, then your own execution should be canceled.
// This traverses down the tree to cancel it.
_PTaskHandle - > _GetTaskImplBase ( ) - > _Cancel ( true ) ;
delete _PTaskHandle ;
break ;
}
case _CancelWithException :
{
// If the ancestor encountered an exception, transfer the exception to the continuation
// This traverses down the tree to propagate the exception.
_PTaskHandle - > _GetTaskImplBase ( ) - > _CancelWithExceptionHolder ( _GetExceptionHolder ( ) , true ) ;
delete _PTaskHandle ;
break ;
}
case _Nothing :
default :
// In this case, we have inserted continuation to continuation chain,
// nothing more need to be done, just leave.
break ;
}
}
void _RunTaskContinuations ( )
{
// The link list can no longer be modified at this point,
// since all following up continuations will be scheduled by themselves.
_ContinuationList _Cur = _M_Continuations , _Next ;
_M_Continuations = nullptr ;
while ( _Cur )
{
// Current node might be deleted after running,
// so we must fetch the next first.
_Next = _Cur - > _M_next ;
_RunContinuation ( _Cur ) ;
_Cur = _Next ;
}
}
static bool _IsNonBlockingThread ( )
{
APTTYPE _AptType ;
APTTYPEQUALIFIER _AptTypeQualifier ;
HRESULT hr = CoGetApartmentType ( & _AptType , & _AptTypeQualifier ) ;
//
// If it failed, it's not a Windows Runtime/COM initialized thread. This is not a failure.
//
if ( SUCCEEDED ( hr ) )
{
switch ( _AptType )
{
case APTTYPE_STA :
case APTTYPE_MAINSTA :
return true ;
break ;
case APTTYPE_NA :
switch ( _AptTypeQualifier )
{
// A thread executing in a neutral apartment is either STA or MTA. To find out if this thread is allowed
// to wait, we check the app qualifier. If it is an STA thread executing in a neutral apartment, waiting
// is illegal, because the thread is responsible for pumping messages and waiting on a task could take the
// thread out of circulation for a while.
case APTTYPEQUALIFIER_NA_ON_STA :
case APTTYPEQUALIFIER_NA_ON_MAINSTA :
return true ;
break ;
}
break ;
}
}
# if _UITHREADCTXT_SUPPORT
// This method is used to throw an exepection in _Wait() if called within STA. We
// want the same behavior if _Wait is called on the UI thread.
if ( SUCCEEDED ( CaptureUiThreadContext ( nullptr ) ) )
{
return true ;
}
# endif // _UITHREADCTXT_SUPPORT
return false ;
}
template < typename _ReturnType , typename _Result , typename _OpType , typename _CompHandlerType , typename _ResultType >
static void _AsyncInit ( const typename _Task_ptr < _ReturnType > : : _Type & _OuterTask ,
_AsyncInfoImpl < _OpType , _CompHandlerType , _ResultType > * _AsyncOp )
{
typedef typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _GetUnwrappedType ( stdx : : declval < _OpType * > ( ) ) ) > : : type _Result_abi ;
// This method is invoked either when a task is created from an existing async operation or
// when a lambda that creates an async operation executes.
// If the outer task is pending cancel, cancel the async operation before setting the completed handler. The COM reference on
// the IAsyncInfo object will be released when all *references to the operation go out of scope.
// This assertion uses the existence of taskcollection to determine if the task was created from an event.
// That is no longer valid as even tasks created from a user lambda could have no underlying taskcollection
// when a custom scheduler is used.
# if _MSC_VER < 1800
_CONCRT_ASSERT ( ( ( _OuterTask - > _M_pTaskCollection = = nullptr ) | | _OuterTask - > _M_fUnwrappedTask ) & & ! _OuterTask - > _IsCanceled ( ) ) ;
# endif
// Pass the shared_ptr by value into the lambda instead of using 'this'.
_AsyncOp - > put_Completed ( Microsoft : : WRL : : Callback < _CompHandlerType > (
[ _OuterTask , _AsyncOp ] ( _OpType * _Operation , ABI : : Windows : : Foundation : : AsyncStatus _Status ) mutable - > HRESULT
{
HRESULT hr = S_OK ;
if ( _Status = = ABI : : Windows : : Foundation : : AsyncStatus : : Canceled )
{
_OuterTask - > _Cancel ( true ) ;
}
else if ( _Status = = ABI : : Windows : : Foundation : : AsyncStatus : : Error )
{
HRESULT _hr ;
Microsoft : : WRL : : ComPtr < ABI : : Windows : : Foundation : : IAsyncInfo > pAsyncInfo ;
if ( SUCCEEDED ( hr = _Operation - > QueryInterface < ABI : : Windows : : Foundation : : IAsyncInfo > ( pAsyncInfo . GetAddressOf ( ) ) ) & & SUCCEEDED ( hr = pAsyncInfo - > get_ErrorCode ( & _hr ) ) )
_OuterTask - > _CancelWithException ( std : : make_exception_ptr ( _hr ) ) ;
}
else
{
_CONCRT_ASSERT ( _Status = = ABI : : Windows : : Foundation : : AsyncStatus : : Completed ) ;
_NormalizeVoidToUnitType < _Result_abi > : : _Type results ;
if ( SUCCEEDED ( hr = _AsyncOp - > GetResults ( & results ) ) )
_OuterTask - > _FinalizeAndRunContinuations ( results ) ;
}
// Take away this shared pointers reference on the task instead of waiting for the delegate to be released. It could
// be released on a different thread after a delay, and not releasing the reference here could cause the tasks to hold
// on to resources longer than they should. As an example, without this reset, writing to a file followed by reading from
// it using the Windows Runtime Async APIs causes a sharing violation.
// Using const_cast is the workaround for failed mutable keywords
const_cast < _Task_ptr < _ReturnType > : : _Type & > ( _OuterTask ) . reset ( ) ;
return hr ;
} ) . Get ( ) ) ;
_OuterTask - > _SetUnwrappedAsyncOp ( _AsyncOp ) ;
}
template < typename _ReturnType , typename _InternalReturnType >
static void _AsyncInit ( const typename _Task_ptr < _ReturnType > : : _Type & _OuterTask , const task < _InternalReturnType > & _UnwrappedTask )
{
_CONCRT_ASSERT ( _OuterTask - > _M_fUnwrappedTask & & ! _OuterTask - > _IsCanceled ( ) ) ;
//
// We must ensure that continuations off _OuterTask (especially exception handling ones) continue to function in the
// presence of an exception flowing out of the inner task _UnwrappedTask. This requires an exception handling continuation
// off the inner task which does the appropriate funnelling to the outer one. We use _Then instead of then to prevent
// the exception from being marked as observed by our internal continuation. This continuation must be scheduled regardless
// of whether or not the _OuterTask task is canceled.
//
_UnwrappedTask . _Then ( [ _OuterTask ] ( task < _InternalReturnType > _AncestorTask ) - > HRESULT {
if ( _AncestorTask . _GetImpl ( ) - > _IsCompleted ( ) )
{
_OuterTask - > _FinalizeAndRunContinuations ( _AncestorTask . _GetImpl ( ) - > _GetResult ( ) ) ;
}
else
{
_CONCRT_ASSERT ( _AncestorTask . _GetImpl ( ) - > _IsCanceled ( ) ) ;
if ( _AncestorTask . _GetImpl ( ) - > _HasUserException ( ) )
{
// Set _PropagatedFromAncestor to false, since _AncestorTask is not an ancestor of _UnwrappedTask.
// Instead, it is the enclosing task.
_OuterTask - > _CancelWithExceptionHolder ( _AncestorTask . _GetImpl ( ) - > _GetExceptionHolder ( ) , false ) ;
}
else
{
_OuterTask - > _Cancel ( true ) ;
}
}
return S_OK ;
# if _MSC_VER >= 1800
} , nullptr , Concurrency : : details : : _DefaultAutoInline ) ;
# else
} , nullptr , false , Concurrency : : details : : _DefaultAutoInline ) ;
# endif
}
# if _MSC_VER >= 1800
Concurrency : : scheduler_ptr _GetScheduler ( ) const
{
return _M_TaskCollection . _GetScheduler ( ) ;
}
# else
Concurrency : : event _M_Completed ;
Concurrency : : event _M_Scheduled ;
# endif
// Tracks the internal state of the task
volatile _TaskInternalState _M_TaskState ;
// Set to true either if the ancestor task had the flag set to true, or if the lambda that does the work of this task returns an
// async operation or async action that is unwrapped by the runtime.
bool _M_fFromAsync ;
# if _MSC_VER < 1800
// Set to true if we need to marshal the inner parts of an aggregate type like std::vector<T^> or std::pair<T^, size_t>. We only marshal
// the contained T^s if we create the vector or pair, such as on a when_any or a when_all operation.
bool _M_fRuntimeAggregate ;
# endif
// Set to true when a continuation unwraps a task or async operation.
bool _M_fUnwrappedTask ;
// An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task.
// The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception
// is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.
std : : shared_ptr < _ExceptionHolder > _M_exceptionHolder ;
typedef _ContinuationTaskHandleBase * _ContinuationList ;
critical_section _M_ContinuationsCritSec ;
_ContinuationList _M_Continuations ;
// The cancellation token state.
Concurrency : : details : : _CancellationTokenState * _M_pTokenState ;
// The registration on the token.
Concurrency : : details : : _CancellationTokenRegistration * _M_pRegistration ;
// The async task collection wrapper
# if _MSC_VER >= 1800
Concurrency : : details : : _TaskCollection_t _M_TaskCollection ;
// Callstack for function call (constructor or .then) that created this task impl.
_TaskCreationCallstack _M_pTaskCreationCallstack ;
_TaskEventLogger _M_taskEventLogger ;
# else
Concurrency : : details : : _AsyncTaskCollection * _M_pTaskCollection ;
// Points to the source code instruction right after the function call (constructor or .then) that created this task impl.
void * _M_pTaskCreationAddressHint ;
# endif
private :
// Must not be copied by value:
_Task_impl_base ( const _Task_impl_base & ) ;
_Task_impl_base const & operator = ( _Task_impl_base const & ) ;
} ;
# if _MSC_VER >= 1800
# if _PPLTASK_ASYNC_LOGGING
inline void _TaskEventLogger : : _LogTaskCompleted ( )
{
if ( _M_scheduled )
{
: : Windows : : Foundation : : AsyncStatus _State ;
if ( _M_task - > _IsCompleted ( ) )
_State = : : Windows : : Foundation : : AsyncStatus : : Completed ;
else if ( _M_task - > _HasUserException ( ) )
_State = : : Windows : : Foundation : : AsyncStatus : : Error ;
else
_State = : : Windows : : Foundation : : AsyncStatus : : Canceled ;
if ( details : : _IsCausalitySupported ( ) )
{
: : Windows : : Foundation : : Diagnostics : : AsyncCausalityTracer : : TraceOperationCompletion ( : : Windows : : Foundation : : Diagnostics : : CausalityTraceLevel : : Required , : : Windows : : Foundation : : Diagnostics : : CausalitySource : : Library ,
_PPLTaskCausalityPlatformID , reinterpret_cast < unsigned long long > ( _M_task ) , _State ) ;
}
}
}
# endif
# endif
template < typename _ReturnType >
struct _Task_impl : public _Task_impl_base
{
typedef ABI : : Windows : : Foundation : : IAsyncInfo _AsyncOperationType ;
# if _MSC_VER >= 1800
_Task_impl ( Concurrency : : details : : _CancellationTokenState * _Ct , Concurrency : : scheduler_ptr _Scheduler_arg )
: _Task_impl_base ( _Ct , _Scheduler_arg )
# else
_Task_impl ( Concurrency : : details : : _CancellationTokenState * _Ct ) : _Task_impl_base ( _Ct )
# endif
{
_M_unwrapped_async_op = nullptr ;
}
virtual ~ _Task_impl ( )
{
// We must invoke _DeregisterCancellation in the derived class destructor. Calling it in the base class destructor could cause
// a partially initialized _Task_impl to be in the list of registrations for a cancellation token.
_DeregisterCancellation ( ) ;
}
virtual bool _CancelAndRunContinuations ( bool _SynchronousCancel , bool _UserException , bool _PropagatedFromAncestor , const std : : shared_ptr < _ExceptionHolder > & _ExceptionHolder )
{
enum { _Nothing , _RunContinuations , _Cancel } _Do = _Nothing ;
{
scoped_lock _LockHolder ( _M_ContinuationsCritSec ) ;
if ( _UserException )
{
_CONCRT_ASSERT ( _SynchronousCancel & & ! _IsCompleted ( ) ) ;
// If the state is _Canceled, the exception has to be coming from an ancestor.
_CONCRT_ASSERT ( ! _IsCanceled ( ) | | _PropagatedFromAncestor ) ;
# if _MSC_VER < 1800
// If the state is _Started or _PendingCancel, the exception cannot be coming from an ancestor.
_CONCRT_ASSERT ( ( ! _IsStarted ( ) & & ! _IsPendingCancel ( ) ) | | ! _PropagatedFromAncestor ) ;
# endif
// We should not be canceled with an exception more than once.
_CONCRT_ASSERT ( ! _HasUserException ( ) ) ;
if ( _M_TaskState = = _Canceled )
{
// If the task has finished cancelling there should not be any continuation records in the array.
return false ;
}
else
{
_CONCRT_ASSERT ( _M_TaskState ! = _Completed ) ;
_M_exceptionHolder = _ExceptionHolder ;
}
}
else
{
// Completed is a non-cancellable state, and if this is an asynchronous cancel, we're unable to do better than the last async cancel
// which is to say, cancellation is already initiated, so return early.
if ( _IsCompleted ( ) | | _IsCanceled ( ) | | ( _IsPendingCancel ( ) & & ! _SynchronousCancel ) )
{
_CONCRT_ASSERT ( ! _IsCompleted ( ) | | ! _HasUserException ( ) ) ;
return false ;
}
_CONCRT_ASSERT ( ! _SynchronousCancel | | ! _HasUserException ( ) ) ;
}
# if _MSC_VER >= 1800
if ( _SynchronousCancel )
# else
if ( _SynchronousCancel | | _IsCreated ( ) )
# endif
{
// Be aware that this set must be done BEFORE _M_Scheduled being set, or race will happen between this and wait()
_M_TaskState = _Canceled ;
# if _MSC_VER < 1800
_M_Scheduled . set ( ) ;
# endif
// Cancellation completes the task, so all dependent tasks must be run to cancel them
// They are canceled when they begin running (see _RunContinuation) and see that their
// ancestor has been canceled.
_Do = _RunContinuations ;
}
else
{
# if _MSC_VER >= 1800
_CONCRT_ASSERT ( ! _UserException ) ;
if ( _IsStarted ( ) )
{
// should not initiate cancellation under a lock
_Do = _Cancel ;
}
// The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore).
// In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from
// _Started to _PendingCancel before it can move to _Canceled when it is finished executing.
_M_TaskState = _PendingCancel ;
_M_taskEventLogger . _LogCancelTask ( ) ;
}
}
switch ( _Do )
{
case _Cancel :
{
# else
_CONCRT_ASSERT ( _IsStarted ( ) & & ! _UserException ) ;
# endif
// The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore).
// In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from
// _Started to _PendingCancel before it can move to _Canceled when it is finished executing.
_M_TaskState = _PendingCancel ;
if ( _M_unwrapped_async_op ! = nullptr )
{
// We will only try to cancel async operation but not unwrapped tasks, since unwrapped tasks cannot be canceled without its token.
if ( _M_unwrapped_async_op ) _M_unwrapped_async_op - > Cancel ( ) ;
}
# if _MSC_VER >= 1800
_M_TaskCollection . _Cancel ( ) ;
break ;
# else
// Optimistic trying for cancelation
if ( _M_pTaskCollection ! = nullptr )
{
_M_pTaskCollection - > _Cancel ( ) ;
}
# endif
}
# if _MSC_VER < 1800
}
# endif
// Only execute continuations and mark the task as completed if we were able to move the task to the _Canceled state.
# if _MSC_VER >= 1800
case _RunContinuations :
{
_M_TaskCollection . _Complete ( ) ;
# else
if ( _RunContinuations )
{
_M_Completed . set ( ) ;
# endif
if ( _M_Continuations )
{
// Scheduling cancellation with automatic inlining.
details : : _ScheduleFuncWithAutoInline ( [ = ] ( ) - > HRESULT { _RunTaskContinuations ( ) ; return S_OK ; } , Concurrency : : details : : _DefaultAutoInline ) ;
}
# if _MSC_VER >= 1800
break ;
}
# endif
}
return true ;
}
void _FinalizeAndRunContinuations ( _ReturnType _Result )
{
# if _MSC_VER >= 1800
_M_Result . Set ( _Result ) ;
# else
_M_Result = _Result ;
_M_ResultContext = _ResultContext < _ReturnType > : : _GetContext ( _M_fRuntimeAggregate ) ;
# endif
{
//
// Hold this lock to ensure continuations being concurrently either get added
// to the _M_Continuations vector or wait for the result
//
scoped_lock _LockHolder ( _M_ContinuationsCritSec ) ;
// A task could still be in the _Created state if it was created with a task_completion_event.
// It could also be in the _Canceled state for the same reason.
_CONCRT_ASSERT ( ! _HasUserException ( ) & & ! _IsCompleted ( ) ) ;
if ( _IsCanceled ( ) )
{
return ;
}
// Always transition to "completed" state, even in the face of unacknowledged pending cancellation
_M_TaskState = _Completed ;
}
# if _MSC_VER >= 1800
_M_TaskCollection . _Complete ( ) ;
# else
_M_Completed . set ( ) ;
# endif
_RunTaskContinuations ( ) ;
}
//
// This method is invoked when the starts executing. The task returns early if this method returns true.
//
bool _TransitionedToStarted ( )
{
scoped_lock _LockHolder ( _M_ContinuationsCritSec ) ;
# if _MSC_VER >= 1800
// Canceled state could only result from antecedent task's canceled state, but that code path will not reach here.
_ASSERT ( ! _IsCanceled ( ) ) ;
if ( _IsPendingCancel ( ) )
# else
if ( _IsCanceled ( ) )
# endif
{
return false ;
}
_CONCRT_ASSERT ( _IsCreated ( ) ) ;
_M_TaskState = _Started ;
return true ;
}
void _SetUnwrappedAsyncOp ( _AsyncOperationType * _AsyncOp )
{
scoped_lock _LockHolder ( _M_ContinuationsCritSec ) ;
// Cancel the async operation if the task itself is canceled, since the thread that canceled the task missed it.
if ( _IsPendingCancel ( ) )
{
_CONCRT_ASSERT ( ! _IsCanceled ( ) ) ;
if ( _AsyncOp ) _AsyncOp - > Cancel ( ) ;
}
else
{
_M_unwrapped_async_op = _AsyncOp ;
}
}
# if _MSC_VER >= 1800
// Return true if the task has reached a terminal state
bool _IsDone ( )
{
return _IsCompleted ( ) | | _IsCanceled ( ) ;
}
# endif
_ReturnType _GetResult ( )
{
# if _MSC_VER >= 1800
return _M_Result . Get ( ) ;
# else
return _ResultContext < _ReturnType > : : _GetValue ( _M_Result , _M_ResultContext , _M_fRuntimeAggregate ) ;
# endif
}
# if _MSC_VER >= 1800
_ResultHolder < _ReturnType > _M_Result ; // this means that the result type must have a public default ctor.
# else
_ReturnType _M_Result ; // this means that the result type must have a public default ctor.
# endif
Microsoft : : WRL : : ComPtr < _AsyncOperationType > _M_unwrapped_async_op ;
# if _MSC_VER < 1800
_ContextCallback _M_ResultContext ;
# endif
} ;
template < typename _ResultType >
struct _Task_completion_event_impl
{
# if _MSC_VER >= 1800
private :
_Task_completion_event_impl ( const _Task_completion_event_impl & ) ;
_Task_completion_event_impl & operator = ( const _Task_completion_event_impl & ) ;
public :
# endif
typedef std : : vector < typename _Task_ptr < _ResultType > : : _Type > _TaskList ;
_Task_completion_event_impl ( ) : _M_fHasValue ( false ) , _M_fIsCanceled ( false )
{
}
bool _HasUserException ( )
{
return _M_exceptionHolder ! = nullptr ;
}
~ _Task_completion_event_impl ( )
{
for ( auto _TaskIt = _M_tasks . begin ( ) ; _TaskIt ! = _M_tasks . end ( ) ; + + _TaskIt )
{
_CONCRT_ASSERT ( ! _M_fHasValue & & ! _M_fIsCanceled ) ;
// Cancel the tasks since the event was never signaled or canceled.
( * _TaskIt ) - > _Cancel ( true ) ;
}
}
// We need to protect the loop over the array, so concurrent_vector would not have helped
_TaskList _M_tasks ;
critical_section _M_taskListCritSec ;
# if _MSC_VER >= 1800
_ResultHolder < _ResultType > _M_value ;
# else
_ResultType _M_value ;
# endif
std : : shared_ptr < _ExceptionHolder > _M_exceptionHolder ;
bool _M_fHasValue ;
bool _M_fIsCanceled ;
} ;
// Utility method for dealing with void functions
inline std : : function < HRESULT ( _Unit_type * ) > _MakeVoidToUnitFunc ( const std : : function < HRESULT ( void ) > & _Func )
{
return [ = ] ( _Unit_type * retVal ) - > HRESULT { HRESULT hr = _Func ( ) ; * retVal = _Unit_type ( ) ; return hr ; } ;
}
template < typename _Type >
std : : function < HRESULT ( _Unit_type , _Type * ) > _MakeUnitToTFunc ( const std : : function < HRESULT ( _Type * ) > & _Func )
{
return [ = ] ( _Unit_type , _Type * retVal ) - > HRESULT { HRESULT hr = _Func ( retVal ) ; return hr ; } ;
}
template < typename _Type >
std : : function < HRESULT ( _Type , _Unit_type * ) > _MakeTToUnitFunc ( const std : : function < HRESULT ( _Type ) > & _Func )
{
return [ = ] ( _Type t , _Unit_type * retVal ) - > HRESULT { HRESULT hr = _Func ( t ) ; * retVal = _Unit_type ( ) ; return hr ; } ;
}
inline std : : function < HRESULT ( _Unit_type , _Unit_type * ) > _MakeUnitToUnitFunc ( const std : : function < HRESULT ( void ) > & _Func )
{
return [ = ] ( _Unit_type , _Unit_type * retVal ) - > HRESULT { HRESULT hr = _Func ( ) ; * retVal = _Unit_type ( ) ; return hr ; } ;
}
}
/// <summary>
/// The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied,
/// or start a task in response to an external event.
/// </summary>
/// <typeparam name="_ResultType">
/// The result type of this <c>task_completion_event</c> class.
/// </typeparam>
/// <remarks>
/// Use a task created from a task completion event when your scenario requires you to create a task that will complete, and
/// thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must
/// have the same type as the task you create, and calling the set method on the task completion event with a value of that type
/// will cause the associated task to complete, and provide that value as a result to its continuations.
/// <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para>
/// <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para>
/// </remarks>
/// <seealso cref="task Class"/>
/**/
template < typename _ResultType >
class task_completion_event
{
public :
/// <summary>
/// Constructs a <c>task_completion_event</c> object.
/// </summary>
/**/
task_completion_event ( ) : _M_Impl ( std : : make_shared < details : : _Task_completion_event_impl < _ResultType > > ( ) )
{
}
/// <summary>
/// Sets the task completion event.
/// </summary>
/// <param name="_Result">
/// The result to set this event with.
/// </param>
/// <returns>
/// The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set.
/// </returns>
/// <remarks>
/// In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the
/// task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the
/// tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have
/// a <typeparamref name="_ResultType"/> other than <c>void</c> will pass the value <paramref value="_Result"/> to their continuations.
/// </remarks>
/**/
bool set ( _ResultType _Result ) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
{
// Subsequent sets are ignored. This makes races to set benign: the first setter wins and all others are ignored.
if ( _IsTriggered ( ) )
{
return false ;
}
_TaskList _Tasks ;
bool _RunContinuations = false ;
{
details : : scoped_lock _LockHolder ( _M_Impl - > _M_taskListCritSec ) ;
if ( ! _IsTriggered ( ) )
{
# if _MSC_VER >= 1800
_M_Impl - > _M_value . Set ( _Result ) ;
# else
_M_Impl - > _M_value = _Result ;
# endif
_M_Impl - > _M_fHasValue = true ;
_Tasks . swap ( _M_Impl - > _M_tasks ) ;
_RunContinuations = true ;
}
}
if ( _RunContinuations )
{
for ( auto _TaskIt = _Tasks . begin ( ) ; _TaskIt ! = _Tasks . end ( ) ; + + _TaskIt )
{
# if _MSC_VER >= 1800
// If current task was cancelled by a cancellation_token, it would be in cancel pending state.
if ( ( * _TaskIt ) - > _IsPendingCancel ( ) )
( * _TaskIt ) - > _Cancel ( true ) ;
else
{
// Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all
// if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we
// need to run continuations after the lock is released.
( * _TaskIt ) - > _FinalizeAndRunContinuations ( _M_Impl - > _M_value . Get ( ) ) ;
}
# else
// Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all
// if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we
// need to run continuations after the lock is released.
( * _TaskIt ) - > _FinalizeAndRunContinuations ( _M_Impl - > _M_value ) ;
# endif
}
if ( _M_Impl - > _HasUserException ( ) )
{
_M_Impl - > _M_exceptionHolder . reset ( ) ;
}
return true ;
}
return false ;
}
# if _MSC_VER >= 1800
template < typename _E >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
bool set_exception ( _E _Except ) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
{
// It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.
return _Cancel ( std : : make_exception_ptr ( _Except ) , _CAPTURE_CALLSTACK ( ) ) ;
}
# endif
/// <summary>
/// Propagates an exception to all tasks associated with this event.
/// </summary>
/// <param>
/// The exception_ptr that indicates the exception to set this event with.
/// </param>
/**/
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
bool set_exception ( std : : exception_ptr _ExceptionPtr ) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
{
// It is important that _ReturnAddress() evaluate to the instruction after the call instruction for set_exception.
# if _MSC_VER >= 1800
return _Cancel ( _ExceptionPtr , _CAPTURE_CALLSTACK ( ) ) ;
# else
return _Cancel ( _ExceptionPtr , _ReturnAddress ( ) ) ;
# endif
}
/// <summary>
/// Internal method to cancel the task_completion_event. Any task created using this event will be marked as canceled if it has
/// not already been set.
/// </summary>
bool _Cancel ( ) const
{
// Cancel with the stored exception if one exists.
return _CancelInternal ( ) ;
}
/// <summary>
/// Internal method to cancel the task_completion_event with the exception provided. Any task created using this event will be canceled
/// with the same exception.
/// </summary>
template < typename _ExHolderType >
# if _MSC_VER >= 1800
bool _Cancel ( _ExHolderType _ExHolder , const details : : _TaskCreationCallstack & _SetExceptionAddressHint = details : : _TaskCreationCallstack ( ) ) const
# else
bool _Cancel ( _ExHolderType _ExHolder , void * _SetExceptionAddressHint = nullptr ) const
# endif
{
( void ) _SetExceptionAddressHint ;
bool _Canceled ;
# if _MSC_VER >= 1800
if ( _StoreException ( _ExHolder , _SetExceptionAddressHint ) )
# else
if ( _StoreException ( _ExHolder ) )
# endif
{
_Canceled = _CancelInternal ( ) ;
_CONCRT_ASSERT ( _Canceled ) ;
}
else
{
_Canceled = false ;
}
return _Canceled ;
}
/// <summary>
/// Internal method that stores an exception in the task completion event. This is used internally by when_any.
/// Note, this does not cancel the task completion event. A task completion event with a stored exception
/// can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present.
/// </summary>
template < typename _ExHolderType >
# if _MSC_VER >= 1800
bool _StoreException ( _ExHolderType _ExHolder , const details : : _TaskCreationCallstack & _SetExceptionAddressHint = details : : _TaskCreationCallstack ( ) ) const
# else
bool _StoreException ( _ExHolderType _ExHolder , void * _SetExceptionAddressHint = nullptr ) const
# endif
{
details : : scoped_lock _LockHolder ( _M_Impl - > _M_taskListCritSec ) ;
if ( ! _IsTriggered ( ) & & ! _M_Impl - > _HasUserException ( ) )
{
// Create the exception holder only if we have ensured there we will be successful in setting it onto the
// task completion event. Failing to do so will result in an unobserved task exception.
_M_Impl - > _M_exceptionHolder = _ToExceptionHolder ( _ExHolder , _SetExceptionAddressHint ) ;
return true ;
}
return false ;
}
/// <summary>
/// Tests whether current event has been either Set, or Canceled.
/// </summary>
bool _IsTriggered ( ) const
{
return _M_Impl - > _M_fHasValue | | _M_Impl - > _M_fIsCanceled ;
}
private :
# if _MSC_VER >= 1800
static std : : shared_ptr < details : : _ExceptionHolder > _ToExceptionHolder ( const std : : shared_ptr < details : : _ExceptionHolder > & _ExHolder , const details : : _TaskCreationCallstack & )
# else
static std : : shared_ptr < details : : _ExceptionHolder > _ToExceptionHolder ( const std : : shared_ptr < details : : _ExceptionHolder > & _ExHolder , void * )
# endif
{
return _ExHolder ;
}
# if _MSC_VER >= 1800
static std : : shared_ptr < details : : _ExceptionHolder > _ToExceptionHolder ( std : : exception_ptr _ExceptionPtr , const details : : _TaskCreationCallstack & _SetExceptionAddressHint )
# else
static std : : shared_ptr < details : : _ExceptionHolder > _ToExceptionHolder ( std : : exception_ptr _ExceptionPtr , void * _SetExceptionAddressHint )
# endif
{
return std : : make_shared < details : : _ExceptionHolder > ( _ExceptionPtr , _SetExceptionAddressHint ) ;
}
template < typename T > friend class task ; // task can register itself with the event by calling the private _RegisterTask
template < typename T > friend class task_completion_event ;
typedef typename details : : _Task_completion_event_impl < _ResultType > : : _TaskList _TaskList ;
/// <summary>
/// Cancels the task_completion_event.
/// </summary>
bool _CancelInternal ( ) const
{
// Cancellation of task completion events is an internal only utility. Our usage is such that _CancelInternal
// will never be invoked if the task completion event has been set.
_CONCRT_ASSERT ( ! _M_Impl - > _M_fHasValue ) ;
if ( _M_Impl - > _M_fIsCanceled )
{
return false ;
}
_TaskList _Tasks ;
bool _Cancel = false ;
{
details : : scoped_lock _LockHolder ( _M_Impl - > _M_taskListCritSec ) ;
_CONCRT_ASSERT ( ! _M_Impl - > _M_fHasValue ) ;
if ( ! _M_Impl - > _M_fIsCanceled )
{
_M_Impl - > _M_fIsCanceled = true ;
_Tasks . swap ( _M_Impl - > _M_tasks ) ;
_Cancel = true ;
}
}
bool _UserException = _M_Impl - > _HasUserException ( ) ;
if ( _Cancel )
{
for ( auto _TaskIt = _Tasks . begin ( ) ; _TaskIt ! = _Tasks . end ( ) ; + + _TaskIt )
{
// Need to call this after the lock is released. See comments in set().
if ( _UserException )
{
( * _TaskIt ) - > _CancelWithExceptionHolder ( _M_Impl - > _M_exceptionHolder , true ) ;
}
else
{
( * _TaskIt ) - > _Cancel ( true ) ;
}
}
}
return _Cancel ;
}
/// <summary>
/// Register a task with this event. This function is called when a task is constructed using
/// a task_completion_event.
/// </summary>
void _RegisterTask ( const typename details : : _Task_ptr < _ResultType > : : _Type & _TaskParam )
{
details : : scoped_lock _LockHolder ( _M_Impl - > _M_taskListCritSec ) ;
# if _MSC_VER < 1800
_TaskParam - > _SetScheduledEvent ( ) ;
# endif
//If an exception was already set on this event, then cancel the task with the stored exception.
if ( _M_Impl - > _HasUserException ( ) )
{
_TaskParam - > _CancelWithExceptionHolder ( _M_Impl - > _M_exceptionHolder , true ) ;
}
else if ( _M_Impl - > _M_fHasValue )
{
# if _MSC_VER >= 1800
_TaskParam - > _FinalizeAndRunContinuations ( _M_Impl - > _M_value . Get ( ) ) ;
# else
_TaskParam - > _FinalizeAndRunContinuations ( _M_Impl - > _M_value ) ;
# endif
}
else
{
_M_Impl - > _M_tasks . push_back ( _TaskParam ) ;
}
}
std : : shared_ptr < details : : _Task_completion_event_impl < _ResultType > > _M_Impl ;
} ;
/// <summary>
/// The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied,
/// or start a task in response to an external event.
/// </summary>
/// <remarks>
/// Use a task created from a task completion event when your scenario requires you to create a task that will complete, and
/// thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must
/// have the same type as the task you create, and calling the set method on the task completion event with a value of that type
/// will cause the associated task to complete, and provide that value as a result to its continuations.
/// <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para>
/// <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para>
/// </remarks>
/// <seealso cref="task Class"/>
/**/
template < >
class task_completion_event < void >
{
public :
/// <summary>
/// Sets the task completion event.
/// </summary>
/// <returns>
/// The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set.
/// </returns>
/// <remarks>
/// In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the
/// task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the
/// tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have
/// a <typeparamref name="_ResultType"/> other than <c>void</c> will pass the value <paramref value="_Result"/> to their continuations.
/// </remarks>
/**/
bool set ( ) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
{
return _M_unitEvent . set ( details : : _Unit_type ( ) ) ;
}
# if _MSC_VER >= 1800
template < typename _E >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
bool set_exception ( _E _Except ) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
{
return _M_unitEvent . _Cancel ( std : : make_exception_ptr ( _Except ) , _CAPTURE_CALLSTACK ( ) ) ;
}
# endif
/// <summary>
/// Propagates an exception to all tasks associated with this event.
/// </summary>
/// <param>
/// The exception_ptr that indicates the exception to set this event with.
/// </param>
/**/
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
bool set_exception ( std : : exception_ptr _ExceptionPtr ) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
{
// It is important that _ReturnAddress() evaluate to the instruction after the call instruction for set_exception.
# if _MSC_VER >= 1800
return _M_unitEvent . _Cancel ( _ExceptionPtr , _CAPTURE_CALLSTACK ( ) ) ;
# else
return _M_unitEvent . _Cancel ( _ExceptionPtr , _ReturnAddress ( ) ) ;
# endif
}
/// <summary>
/// Cancel the task_completion_event. Any task created using this event will be marked as canceled if it has
/// not already been set.
/// </summary>
void _Cancel ( ) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
{
_M_unitEvent . _Cancel ( ) ;
}
/// <summary>
/// Cancel the task_completion_event with the exception holder provided. Any task created using this event will be canceled
/// with the same exception.
/// </summary>
void _Cancel ( const std : : shared_ptr < details : : _ExceptionHolder > & _ExHolder ) const
{
_M_unitEvent . _Cancel ( _ExHolder ) ;
}
/// <summary>
/// Method that stores an exception in the task completion event. This is used internally by when_any.
/// Note, this does not cancel the task completion event. A task completion event with a stored exception
/// can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present.
/// </summary>
bool _StoreException ( const std : : shared_ptr < details : : _ExceptionHolder > & _ExHolder ) const
{
return _M_unitEvent . _StoreException ( _ExHolder ) ;
}
/// <summary>
/// Test whether current event has been either Set, or Canceled.
/// </summary>
bool _IsTriggered ( ) const
{
return _M_unitEvent . _IsTriggered ( ) ;
}
private :
template < typename T > friend class task ; // task can register itself with the event by calling the private _RegisterTask
/// <summary>
/// Register a task with this event. This function is called when a task is constructed using
/// a task_completion_event.
/// </summary>
void _RegisterTask ( details : : _Task_ptr < details : : _Unit_type > : : _Type _TaskParam )
{
_M_unitEvent . _RegisterTask ( _TaskParam ) ;
}
// The void event contains an event a dummy type so common code can be used for events with void and non-void results.
task_completion_event < details : : _Unit_type > _M_unitEvent ;
} ;
namespace details
{
//
// Compile-time validation helpers
//
// Task constructor validation: issue helpful diagnostics for common user errors. Do not attempt full validation here.
//
// Anything callable is fine
template < typename _ReturnType , typename _Ty >
auto _IsValidTaskCtor ( _Ty _Param , int , int , int , int , int , int , int ) - > typename decltype ( _Param ( ) , std : : true_type ( ) ) ;
// Anything callable with a task return value is fine
template < typename _ReturnType , typename _Ty >
auto _IsValidTaskCtor ( _Ty _Param , int , int , int , int , int , int , . . . ) - > typename decltype ( _Param ( stdx : : declval < task < _ReturnType > * > ( ) ) , std : : true_type ( ) ) ;
// Anything callable with a return value is fine
template < typename _ReturnType , typename _Ty >
auto _IsValidTaskCtor ( _Ty _Param , int , int , int , int , int , . . . ) - > typename decltype ( _Param ( stdx : : declval < _ReturnType * > ( ) ) , std : : true_type ( ) ) ;
// Anything that has GetResults is fine: this covers AsyncAction*
template < typename _ReturnType , typename _Ty >
auto _IsValidTaskCtor ( _Ty _Param , int , int , int , int , . . . ) - > typename decltype ( _Param - > GetResults ( ) , std : : true_type ( ) ) ;
// Anything that has GetResults(TResult_abi*) is fine: this covers AsyncOperation*
template < typename _ReturnType , typename _Ty >
auto _IsValidTaskCtor ( _Ty _Param , int , int , int , . . . ) - > typename decltype ( _Param - > GetResults ( stdx : : declval < decltype ( _GetUnwrappedType ( stdx : : declval < _Ty > ( ) ) ) * > ( ) ) , std : : true_type ( ) ) ;
// Allow parameters with set: this covers task_completion_event
template < typename _ReturnType , typename _Ty >
auto _IsValidTaskCtor ( _Ty _Param , int , int , . . . ) - > typename decltype ( _Param . set ( stdx : : declval < _ReturnType > ( ) ) , std : : true_type ( ) ) ;
template < typename _ReturnType , typename _Ty >
auto _IsValidTaskCtor ( _Ty _Param , int , . . . ) - > typename decltype ( _Param . set ( ) , std : : true_type ( ) ) ;
// All else is invalid
template < typename _ReturnType , typename _Ty >
std : : false_type _IsValidTaskCtor ( _Ty _Param , . . . ) ;
template < typename _ReturnType , typename _Ty >
void _ValidateTaskConstructorArgs ( _Ty _Param )
{
( void ) _Param ;
static_assert ( std : : is_same < decltype ( details : : _IsValidTaskCtor < _ReturnType > ( _Param , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ) , std : : true_type > : : value ,
" incorrect argument for task constructor; can be a callable object, an asynchronous operation, or a task_completion_event "
) ;
static_assert ( ! ( std : : is_same < _Ty , _ReturnType > : : value & & details : : _IsIAsyncInfo < _Ty > : : _Value ) ,
" incorrect template argument for task; consider using the return type of the async operation " ) ;
}
// Helpers for create_async validation
//
// A parameter lambda taking no arguments is valid
template < typename _ReturnType , typename _Ty >
static auto _IsValidCreateAsync ( _Ty _Param , int , int , int , int , int , int , int , int ) - > typename decltype ( _Param ( ) , std : : true_type ( ) ) ;
// A parameter lambda taking a result argument is valid
template < typename _ReturnType , typename _Ty >
static auto _IsValidCreateAsync ( _Ty _Param , int , int , int , int , int , int , int , . . . ) - > typename decltype ( _Param ( stdx : : declval < _ReturnType * > ( ) ) , std : : true_type ( ) ) ;
// A parameter lambda taking an cancellation_token argument is valid
template < typename _ReturnType , typename _Ty >
static auto _IsValidCreateAsync ( _Ty _Param , int , int , int , int , int , int , . . . ) - > typename decltype ( _Param ( Concurrency : : cancellation_token : : none ( ) ) , std : : true_type ( ) ) ;
// A parameter lambda taking an cancellation_token argument and a result argument is valid
template < typename _ReturnType , typename _Ty >
static auto _IsValidCreateAsync ( _Ty _Param , int , int , int , int , int , . . . ) - > typename decltype ( _Param ( Concurrency : : cancellation_token : : none ( ) , stdx : : declval < _ReturnType * > ( ) ) , std : : true_type ( ) ) ;
// A parameter lambda taking a progress report argument is valid
template < typename _ReturnType , typename _Ty >
static auto _IsValidCreateAsync ( _Ty _Param , int , int , int , int , . . . ) - > typename decltype ( _Param ( details : : _ProgressReporterCtorArgType ( ) ) , std : : true_type ( ) ) ;
// A parameter lambda taking a progress report argument and a result argument is valid
template < typename _ReturnType , typename _Ty >
static auto _IsValidCreateAsync ( _Ty _Param , int , int , int , . . . ) - > typename decltype ( _Param ( details : : _ProgressReporterCtorArgType ( ) , stdx : : declval < _ReturnType * > ( ) ) , std : : true_type ( ) ) ;
// A parameter lambda taking a progress report and a cancellation_token argument is valid
template < typename _ReturnType , typename _Ty >
static auto _IsValidCreateAsync ( _Ty _Param , int , int , . . . ) - > typename decltype ( _Param ( details : : _ProgressReporterCtorArgType ( ) , Concurrency : : cancellation_token : : none ( ) ) , std : : true_type ( ) ) ;
// A parameter lambda taking a progress report and a cancellation_token argument and a result argument is valid
template < typename _ReturnType , typename _Ty >
static auto _IsValidCreateAsync ( _Ty _Param , int , . . . ) - > typename decltype ( _Param ( details : : _ProgressReporterCtorArgType ( ) , Concurrency : : cancellation_token : : none ( ) , stdx : : declval < _ReturnType * > ( ) ) , std : : true_type ( ) ) ;
// All else is invalid
template < typename _ReturnType , typename _Ty >
static std : : false_type _IsValidCreateAsync ( _Ty _Param , . . . ) ;
}
/// <summary>
/// The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously,
/// and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces
/// a result of type <typeparamref name="_ResultType"/> on successful completion. Tasks of type <c>task<void></c> produce no result.
/// A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using
/// continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns.
/// </summary>
/// <typeparam name="_ReturnType">
/// The result type of this task.
/// </typeparam>
/// <remarks>
/// For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.
/// </remarks>
/**/
template < typename _ReturnType >
class task
{
public :
/// <summary>
/// The type of the result an object of this class produces.
/// </summary>
/**/
typedef _ReturnType result_type ;
/// <summary>
/// Constructs a <c>task</c> object.
/// </summary>
/// <remarks>
/// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
/// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
/// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
/// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
/// completion event is set.</para>
/// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
/// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
/// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
/// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
/// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
/// and not when the lamda returns.</para>
/// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
/// without the need for locks.</para>
/// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
/// to Windows Store apps.</para>
/// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
task ( ) : _M_Impl ( nullptr )
{
// The default constructor should create a task with a nullptr impl. This is a signal that the
// task is not usable and should throw if any wait(), get() or then() APIs are used.
}
/// <summary>
/// Constructs a <c>task</c> object.
/// </summary>
/// <typeparam name="_Ty">
/// The type of the parameter from which the task is to be constructed.
/// </typeparam>
/// <param name="_Param">
/// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c>
/// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
/// object should be a type equivalent to <c>std::function<X(void)></c>, where X can be a variable of type <c>result_type</c>,
/// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
/// </param>
/// <param name="_Token">
/// The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives
/// the token <c>cancellation_token::none()</c>.
/// </param>
/// <remarks>
/// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
/// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
/// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
/// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
/// completion event is set.</para>
/// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
/// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
/// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
/// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
/// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
/// and not when the lamda returns.</para>
/// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
/// without the need for locks.</para>
/// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
/// to Windows Store apps.</para>
/// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Ty >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
explicit task ( _Ty _Param )
{
# if _MSC_VER >= 1800
task_options _TaskOptions ;
# endif
details : : _ValidateTaskConstructorArgs < _ReturnType , _Ty > ( _Param ) ;
# if _MSC_VER >= 1800
_CreateImpl ( _TaskOptions . get_cancellation_token ( ) . _GetImplValue ( ) , _TaskOptions . get_scheduler ( ) ) ;
# else
_CreateImpl ( Concurrency : : cancellation_token : : none ( ) . _GetImplValue ( ) ) ;
# endif
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor.
# if _MSC_VER >= 1800
_SetTaskCreationCallstack ( _CAPTURE_CALLSTACK ( ) ) ;
# else
_SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
# endif
_TaskInitMaybeFunctor ( _Param , details : : _IsCallable < _ReturnType > ( _Param , 0 , 0 , 0 ) ) ;
}
/// <summary>
/// Constructs a <c>task</c> object.
/// </summary>
/// <typeparam name="_Ty">
/// The type of the parameter from which the task is to be constructed.
/// </typeparam>
/// <param name="_Param">
/// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c>
/// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
/// object should be a type equivalent to <c>std::function<X(void)></c>, where X can be a variable of type <c>result_type</c>,
/// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
/// </param>
/// <param name="_Token">
/// The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives
/// the token <c>cancellation_token::none()</c>.
/// </param>
/// <remarks>
/// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
/// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
/// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
/// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
/// completion event is set.</para>
/// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
/// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
/// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
/// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
/// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
/// and not when the lamda returns.</para>
/// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
/// without the need for locks.</para>
/// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
/// to Windows Store apps.</para>
/// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Ty >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
# if _MSC_VER >= 1800
explicit task ( _Ty _Param , const task_options & _TaskOptions )
# else
explicit task ( _Ty _Param , Concurrency : : cancellation_token _Token )
# endif
{
details : : _ValidateTaskConstructorArgs < _ReturnType , _Ty > ( _Param ) ;
# if _MSC_VER >= 1800
_CreateImpl ( _TaskOptions . get_cancellation_token ( ) . _GetImplValue ( ) , _TaskOptions . get_scheduler ( ) ) ;
# else
_CreateImpl ( _Token . _GetImplValue ( ) ) ;
# endif
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor.
# if _MSC_VER >= 1800
_SetTaskCreationCallstack ( details : : _get_internal_task_options ( _TaskOptions ) . _M_hasPresetCreationCallstack ? details : : _get_internal_task_options ( _TaskOptions ) . _M_presetCreationCallstack : _CAPTURE_CALLSTACK ( ) ) ;
# else
_SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
# endif
_TaskInitMaybeFunctor ( _Param , details : : _IsCallable < _ReturnType > ( _Param , 0 , 0 , 0 ) ) ;
}
/// <summary>
/// Constructs a <c>task</c> object.
/// </summary>
/// <param name="_Other">
/// The source <c>task</c> object.
/// </param>
/// <remarks>
/// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
/// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
/// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
/// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
/// completion event is set.</para>
/// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
/// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
/// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
/// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
/// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
/// and not when the lamda returns.</para>
/// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
/// without the need for locks.</para>
/// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
/// to Windows Store apps.</para>
/// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
task ( const task & _Other ) : _M_Impl ( _Other . _M_Impl ) { }
/// <summary>
/// Constructs a <c>task</c> object.
/// </summary>
/// <param name="_Other">
/// The source <c>task</c> object.
/// </param>
/// <remarks>
/// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
/// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
/// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
/// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
/// completion event is set.</para>
/// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
/// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
/// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
/// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
/// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
/// and not when the lamda returns.</para>
/// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
/// without the need for locks.</para>
/// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
/// to Windows Store apps.</para>
/// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
task ( task & & _Other ) : _M_Impl ( std : : move ( _Other . _M_Impl ) ) { }
/// <summary>
/// Replaces the contents of one <c>task</c> object with another.
/// </summary>
/// <param name="_Other">
/// The source <c>task</c> object.
/// </param>
/// <remarks>
/// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
/// actual task as <paramref name="_Other"/> does.
/// </remarks>
/**/
task & operator = ( const task & _Other )
{
if ( this ! = & _Other )
{
_M_Impl = _Other . _M_Impl ;
}
return * this ;
}
/// <summary>
/// Replaces the contents of one <c>task</c> object with another.
/// </summary>
/// <param name="_Other">
/// The source <c>task</c> object.
/// </param>
/// <remarks>
/// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
/// actual task as <paramref name="_Other"/> does.
/// </remarks>
/**/
task & operator = ( task & & _Other )
{
if ( this ! = & _Other )
{
_M_Impl = std : : move ( _Other . _M_Impl ) ;
}
return * this ;
}
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
/// <typeparam name="_Function">
/// The type of the function object that will be invoked by this task.
/// </typeparam>
/// <param name="_Func">
/// The continuation function to execute when this task completes. This continuation function must take as input
/// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
/// of the result this task produces.
/// </param>
/// <returns>
/// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
/// </returns>
/// <remarks>
/// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
/// to Windows Store apps.
/// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Function >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
auto then ( const _Function & _Func ) const - > typename details : : _ContinuationTypeTraits < _Function , _ReturnType > : : _TaskOfType
{
# if _MSC_VER >= 1800
task_options _TaskOptions ;
details : : _get_internal_task_options ( _TaskOptions ) . _set_creation_callstack ( _CAPTURE_CALLSTACK ( ) ) ;
return _ThenImpl < _ReturnType , _Function > ( _Func , _TaskOptions ) ;
# else
auto _ContinuationTask = _ThenImpl < _ReturnType , _Function > ( _Func , nullptr , task_continuation_context : : use_default ( ) ) ;
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
_ContinuationTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
return _ContinuationTask ;
# endif
}
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
/// <typeparam name="_Function">
/// The type of the function object that will be invoked by this task.
/// </typeparam>
/// <param name="_Func">
/// The continuation function to execute when this task completes. This continuation function must take as input
/// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
/// of the result this task produces.
/// </param>
/// <param name="_CancellationToken">
/// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
/// the token of its antecedent task.
/// </param>
/// <returns>
/// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
/// </returns>
/// <remarks>
/// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
/// to Windows Store apps.
/// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Function >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
# if _MSC_VER >= 1800
auto then ( const _Function & _Func , task_options _TaskOptions ) const - > typename details : : _ContinuationTypeTraits < _Function , _ReturnType > : : _TaskOfType
# else
auto then ( const _Function & _Func , Concurrency : : cancellation_token _CancellationToken ) const - > typename details : : _ContinuationTypeTraits < _Function , _ReturnType > : : _TaskOfType
# endif
{
# if _MSC_VER >= 1800
details : : _get_internal_task_options ( _TaskOptions ) . _set_creation_callstack ( _CAPTURE_CALLSTACK ( ) ) ;
return _ThenImpl < _ReturnType , _Function > ( _Func , _TaskOptions ) ;
# else
auto _ContinuationTask = _ThenImpl < _ReturnType , _Function > ( _Func , _CancellationToken . _GetImplValue ( ) , task_continuation_context : : use_default ( ) ) ;
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
_ContinuationTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
return _ContinuationTask ;
# endif
}
# if _MSC_VER < 1800
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
/// <typeparam name="_Function">
/// The type of the function object that will be invoked by this task.
/// </typeparam>
/// <param name="_Func">
/// The continuation function to execute when this task completes. This continuation function must take as input
/// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
/// of the result this task produces.
/// </param>
/// <param name="_ContinuationContext">
/// A variable that specifies where the continuation should execute. This variable is only useful when used in a
/// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
/// </param>
/// <returns>
/// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
/// </returns>
/// <remarks>
/// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
/// to Windows Store apps.
/// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Function >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
auto then ( const _Function & _Func , task_continuation_context _ContinuationContext ) const - > typename details : : _ContinuationTypeTraits < _Function , _ReturnType > : : _TaskOfType
{
auto _ContinuationTask = _ThenImpl < _ReturnType , _Function > ( _Func , nullptr , _ContinuationContext ) ;
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
_ContinuationTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
return _ContinuationTask ;
}
# endif
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
/// <typeparam name="_Function">
/// The type of the function object that will be invoked by this task.
/// </typeparam>
/// <param name="_Func">
/// The continuation function to execute when this task completes. This continuation function must take as input
/// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
/// of the result this task produces.
/// </param>
/// <param name="_CancellationToken">
/// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
/// the token of its antecedent task.
/// </param>
/// <param name="_ContinuationContext">
/// A variable that specifies where the continuation should execute. This variable is only useful when used in a
/// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
/// </param>
/// <returns>
/// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
/// </returns>
/// <remarks>
/// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
/// to Windows Store apps.
/// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Function >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
auto then ( const _Function & _Func , Concurrency : : cancellation_token _CancellationToken , task_continuation_context _ContinuationContext ) const - > typename details : : _ContinuationTypeTraits < _Function , _ReturnType > : : _TaskOfType
{
# if _MSC_VER >= 1800
task_options _TaskOptions ( _CancellationToken , _ContinuationContext ) ;
details : : _get_internal_task_options ( _TaskOptions ) . _set_creation_callstack ( _CAPTURE_CALLSTACK ( ) ) ;
return _ThenImpl < _ReturnType , _Function > ( _Func , _TaskOptions ) ;
# else
auto _ContinuationTask = _ThenImpl < _ReturnType , _Function > ( _Func , _CancellationToken . _GetImplValue ( ) , _ContinuationContext ) ;
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
_ContinuationTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
return _ContinuationTask ;
# endif
}
/// <summary>
/// Waits for this task to reach a terminal state. It is possible for <c>wait</c> to execute the task inline, if all of the tasks
/// dependencies are satisfied, and it has not already been picked up for execution by a background worker.
/// </summary>
/// <returns>
/// A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception
/// during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception.
/// </returns>
/**/
task_status wait ( ) const
{
if ( _M_Impl = = nullptr )
{
throw Concurrency : : invalid_operation ( " wait() cannot be called on a default constructed task. " ) ;
}
return _M_Impl - > _Wait ( ) ;
}
/// <summary>
/// Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to
/// finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>.
/// </summary>
/// <returns>
/// The result of the task.
/// </returns>
/// <remarks>
/// If the task is canceled, a call to <c>get</c> will throw a <see cref="task_canceled Class">task_canceled</see> exception. If the task
/// encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception.
/// </remarks>
/**/
_ReturnType get ( ) const
{
if ( _M_Impl = = nullptr )
{
throw Concurrency : : invalid_operation ( " get() cannot be called on a default constructed task. " ) ;
}
if ( _M_Impl - > _Wait ( ) = = Concurrency : : canceled )
{
throw Concurrency : : task_canceled ( ) ;
}
return _M_Impl - > _GetResult ( ) ;
}
# if _MSC_VER >= 1800
/// <summary>
/// Determines if the task is completed.
/// </summary>
/// <returns>
/// True if the task has completed, false otherwise.
/// </returns>
/// <remarks>
/// The function returns true if the task is completed or canceled (with or without user exception).
/// </remarks>
bool is_done ( ) const
{
if ( ! _M_Impl )
{
throw Concurrency : : invalid_operation ( " is_done() cannot be called on a default constructed task. " ) ;
}
return _M_Impl - > _IsDone ( ) ;
}
/// <summary>
/// Returns the scheduler for this task
/// </summary>
/// <returns>
/// A pointer to the scheduler
/// </returns>
Concurrency : : scheduler_ptr scheduler ( ) const
{
if ( ! _M_Impl )
{
throw Concurrency : : invalid_operation ( " scheduler() cannot be called on a default constructed task. " ) ;
}
return _M_Impl - > _GetScheduler ( ) ;
}
# endif
/// <summary>
/// Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task.
/// </summary>
/// <returns>
/// <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise.
/// </returns>
/**/
bool is_apartment_aware ( ) const
{
if ( _M_Impl = = nullptr )
{
throw Concurrency : : invalid_operation ( " is_apartment_aware() cannot be called on a default constructed task. " ) ;
}
return _M_Impl - > _IsApartmentAware ( ) ;
}
/// <summary>
/// Determines whether two <c>task</c> objects represent the same internal task.
/// </summary>
/// <returns>
/// <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise.
/// </returns>
/**/
bool operator = = ( const task < _ReturnType > & _Rhs ) const
{
return ( _M_Impl = = _Rhs . _M_Impl ) ;
}
/// <summary>
/// Determines whether two <c>task</c> objects represent different internal tasks.
/// </summary>
/// <returns>
/// <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise.
/// </returns>
/**/
bool operator ! = ( const task < _ReturnType > & _Rhs ) const
{
return ! operator = = ( _Rhs ) ;
}
/// <summary>
/// Create an underlying task implementation.
/// </summary>
# if _MSC_VER >= 1800
void _CreateImpl ( Concurrency : : details : : _CancellationTokenState * _Ct , Concurrency : : scheduler_ptr _Scheduler )
# else
void _CreateImpl ( Concurrency : : details : : _CancellationTokenState * _Ct )
# endif
{
_CONCRT_ASSERT ( _Ct ! = nullptr ) ;
# if _MSC_VER >= 1800
_M_Impl = details : : _Task_ptr < _ReturnType > : : _Make ( _Ct , _Scheduler ) ;
# else
_M_Impl = details : : _Task_ptr < _ReturnType > : : _Make ( _Ct ) ;
# endif
if ( _Ct ! = Concurrency : : details : : _CancellationTokenState : : _None ( ) )
{
# if _MSC_VER >= 1800
_M_Impl - > _RegisterCancellation ( _M_Impl ) ;
# else
_M_Impl - > _RegisterCancellation ( ) ;
# endif
}
}
/// <summary>
/// Return the underlying implementation for this task.
/// </summary>
const typename details : : _Task_ptr < _ReturnType > : : _Type & _GetImpl ( ) const
{
return _M_Impl ;
}
/// <summary>
/// Set the implementation of the task to be the supplied implementaion.
/// </summary>
void _SetImpl ( const typename details : : _Task_ptr < _ReturnType > : : _Type & _Impl )
{
_CONCRT_ASSERT ( _M_Impl = = nullptr ) ;
_M_Impl = _Impl ;
}
/// <summary>
/// Set the implementation of the task to be the supplied implementaion using a move instead of a copy.
/// </summary>
void _SetImpl ( typename details : : _Task_ptr < _ReturnType > : : _Type & & _Impl )
{
_CONCRT_ASSERT ( _M_Impl = = nullptr ) ;
_M_Impl = std : : move ( _Impl ) ;
}
/// <summary>
/// Sets a property determining whether the task is apartment aware.
/// </summary>
void _SetAsync ( bool _Async = true )
{
_GetImpl ( ) - > _SetAsync ( _Async ) ;
}
/// <summary>
/// Sets a field in the task impl to the return address for calls to the task constructors and the then method.
/// </summary>
# if _MSC_VER >= 1800
void _SetTaskCreationCallstack ( const details : : _TaskCreationCallstack & _callstack )
{
_GetImpl ( ) - > _SetTaskCreationCallstack ( _callstack ) ;
}
# else
void _SetTaskCreationAddressHint ( void * _Address )
{
_GetImpl ( ) - > _SetTaskCreationAddressHint ( _Address ) ;
}
# endif
/// <summary>
/// An internal version of then that takes additional flags and always execute the continuation inline by default.
/// When _ForceInline is set to false, continuations inlining will be limited to default _DefaultAutoInline.
/// This function is Used for runtime internal continuations only.
/// </summary>
template < typename _Function >
# if _MSC_VER >= 1800
auto _Then ( const _Function & _Func , Concurrency : : details : : _CancellationTokenState * _PTokenState ,
details : : _TaskInliningMode _InliningMode = Concurrency : : details : : _ForceInline ) const - > typename details : : _ContinuationTypeTraits < _Function , _ReturnType > : : _TaskOfType
{
// inherit from antecedent
auto _Scheduler = _GetImpl ( ) - > _GetScheduler ( ) ;
return _ThenImpl < _ReturnType , _Function > ( _Func , _PTokenState , task_continuation_context : : use_default ( ) , _Scheduler , _CAPTURE_CALLSTACK ( ) , _InliningMode ) ;
}
# else
auto _Then ( const _Function & _Func , Concurrency : : details : : _CancellationTokenState * _PTokenState , bool _Aggregating ,
details : : _TaskInliningMode _InliningMode = Concurrency : : details : : _ForceInline ) const - > typename details : : _ContinuationTypeTraits < _Function , _ReturnType > : : _TaskOfType
{
return _ThenImpl < _ReturnType , _Function > ( _Func , _PTokenState , task_continuation_context : : use_default ( ) , _Aggregating , _InliningMode ) ;
}
# endif
private :
template < typename T > friend class task ;
// A helper class template that transforms an intial task lambda returns void into a lambda that returns a non-void type (details::_Unit_type is used
// to substitute for void). This is to minimize the special handling required for 'void'.
template < typename _RetType >
class _Init_func_transformer
{
public :
static auto _Perform ( std : : function < HRESULT ( _RetType * ) > _Func ) - > decltype ( _Func )
{
return _Func ;
}
} ;
template < >
class _Init_func_transformer < void >
{
public :
static auto _Perform ( std : : function < HRESULT ( void ) > _Func ) - > decltype ( details : : _MakeVoidToUnitFunc ( _Func ) )
{
return details : : _MakeVoidToUnitFunc ( _Func ) ;
}
} ;
// The task handle type used to construct an 'initial task' - a task with no dependents.
template < typename _InternalReturnType , typename _Function , typename _TypeSelection >
struct _InitialTaskHandle :
details : : _PPLTaskHandle < _ReturnType , _InitialTaskHandle < _InternalReturnType , _Function , _TypeSelection > , details : : _UnrealizedChore >
{
_Function _M_function ;
_InitialTaskHandle ( const typename details : : _Task_ptr < _ReturnType > : : _Type & _TaskImpl , const _Function & _Function ) : _M_function ( _Function ) , _PPLTaskHandle ( _TaskImpl )
{
}
virtual ~ _InitialTaskHandle ( ) { }
# if _MSC_VER >= 1800
template < typename _Func , typename _RetArg >
auto _LogWorkItemAndInvokeUserLambda ( _Func & & _func , _RetArg & & _retArg ) const - > decltype ( _func ( std : : forward < _RetArg > ( _retArg ) ) )
{
details : : _TaskWorkItemRAIILogger _LogWorkItem ( this - > _M_pTask - > _M_taskEventLogger ) ;
return _func ( std : : forward < _RetArg > ( _retArg ) ) ;
}
# endif
void _Perform ( ) const
{
_Init ( _TypeSelection ( ) ) ;
}
# if _MSC_VER >= 1800
void _SyncCancelAndPropagateException ( ) const
{
this - > _M_pTask - > _Cancel ( true ) ;
}
# endif
//
// Overload 0: returns _InternalReturnType
//
// This is the most basic task with no unwrapping
//
void _Init ( details : : _TypeSelectorNoAsync ) const
{
_ReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _Init_func_transformer < _InternalReturnType > : : _Perform ( _M_function ) , & retVal ) ;
# else
HRESULT hr = _Init_func_transformer < _InternalReturnType > : : _Perform ( _M_function ) ( & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
_M_pTask - > _FinalizeAndRunContinuations ( retVal ) ;
}
//
// Overload 1: returns IAsyncOperation<_InternalReturnType>*
// or
// returns task<_InternalReturnType>
//
// This is task whose functor returns an async operation or a task which will be unwrapped for continuation
// Depending on the output type, the right _AsyncInit gets invoked
//
void _Init ( details : : _TypeSelectorAsyncTask ) const
{
task < _InternalReturnType > retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _M_function , & retVal ) ;
# else
HRESULT hr = _M_function ( & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _ReturnType , _InternalReturnType > ( _M_pTask , retVal ) ;
}
void _Init ( details : : _TypeSelectorAsyncOperation ) const
{
_ReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _M_function , & retVal ) ;
# else
HRESULT hr = _M_function ( & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _ReturnType , _InternalReturnType > ( _M_pTask ,
Microsoft : : WRL : : Make < details : : _IAsyncOperationToAsyncOperationConverter < _InternalReturnType > > ( retVal ) . Get ( ) ) ;
}
//
// Overload 2: returns IAsyncAction*
//
// This is task whose functor returns an async action which will be unwrapped for continuation
//
void _Init ( details : : _TypeSelectorAsyncAction ) const
{
_ReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _M_function , & retVal ) ;
# else
HRESULT hr = _M_function ( & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _ReturnType , _InternalReturnType > ( _M_pTask , Microsoft : : WRL : : Make < details : : _IAsyncActionToAsyncOperationConverter > ( retVal ) . Get ( ) ) ;
}
//
// Overload 3: returns IAsyncOperationWithProgress<_InternalReturnType, _ProgressType>*
//
// This is task whose functor returns an async operation with progress which will be unwrapped for continuation
//
void _Init ( details : : _TypeSelectorAsyncOperationWithProgress ) const
{
typedef details : : _GetProgressType < decltype ( _M_function ( ) ) > : : _Value _ProgressType ;
_ReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _M_function , & retVal ) ;
# else
HRESULT hr = _M_function ( & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _ReturnType , _InternalReturnType > ( _M_pTask ,
Microsoft : : WRL : : Make < details : : _IAsyncOperationWithProgressToAsyncOperationConverter < _InternalReturnType , _ProgressType > > ( retVal ) . Get ( ) ) ;
}
//
// Overload 4: returns IAsyncActionWithProgress<_ProgressType>*
//
// This is task whose functor returns an async action with progress which will be unwrapped for continuation
//
void _Init ( details : : _TypeSelectorAsyncActionWithProgress ) const
{
typedef details : : _GetProgressType < decltype ( _M_function ( ) ) > : : _Value _ProgressType ;
_ReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _M_function , & retVal ) ;
# else
HRESULT hr = _M_function ( & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _ReturnType , _InternalReturnType > ( _M_pTask ,
Microsoft : : WRL : : Make < details : : _IAsyncActionWithProgressToAsyncOperationConverter < _ProgressType > > ( retVal ) . Get ( ) ) ;
}
} ;
/// <summary>
/// A helper class template that transforms a continuation lambda that either takes or returns void, or both, into a lambda that takes and returns a
/// non-void type (details::_Unit_type is used to substitute for void). This is to minimize the special handling required for 'void'.
/// </summary>
template < typename _InpType , typename _OutType >
class _Continuation_func_transformer
{
public :
static auto _Perform ( std : : function < HRESULT ( _InpType , _OutType * ) > _Func ) - > decltype ( _Func )
{
return _Func ;
}
} ;
template < typename _OutType >
class _Continuation_func_transformer < void , _OutType >
{
public :
static auto _Perform ( std : : function < HRESULT ( _OutType * ) > _Func ) - > decltype ( details : : _MakeUnitToTFunc < _OutType > ( _Func ) )
{
return details : : _MakeUnitToTFunc < _OutType > ( _Func ) ;
}
} ;
template < typename _InType >
class _Continuation_func_transformer < _InType , void >
{
public :
static auto _Perform ( std : : function < HRESULT ( _InType ) > _Func ) - > decltype ( details : : _MakeTToUnitFunc < _InType > ( _Func ) )
{
return details : : _MakeTToUnitFunc < _InType > ( _Func ) ;
}
} ;
template < >
class _Continuation_func_transformer < void , void >
{
public :
static auto _Perform ( std : : function < HRESULT ( void ) > _Func ) - > decltype ( details : : _MakeUnitToUnitFunc ( _Func ) )
{
return details : : _MakeUnitToUnitFunc ( _Func ) ;
}
} ;
/// <summary>
/// The task handle type used to create a 'continuation task'.
/// </summary>
template < typename _InternalReturnType , typename _ContinuationReturnType , typename _Function , typename _IsTaskBased , typename _TypeSelection >
struct _ContinuationTaskHandle :
details : : _PPLTaskHandle < typename details : : _NormalizeVoidToUnitType < _ContinuationReturnType > : : _Type ,
_ContinuationTaskHandle < _InternalReturnType , _ContinuationReturnType , _Function , _IsTaskBased , _TypeSelection > , details : : _ContinuationTaskHandleBase >
{
typedef typename details : : _NormalizeVoidToUnitType < _ContinuationReturnType > : : _Type _NormalizedContinuationReturnType ;
typename details : : _Task_ptr < _ReturnType > : : _Type _M_ancestorTaskImpl ;
_Function _M_function ;
_ContinuationTaskHandle ( const typename details : : _Task_ptr < _ReturnType > : : _Type & _AncestorImpl ,
const typename details : : _Task_ptr < _NormalizedContinuationReturnType > : : _Type & _ContinuationImpl ,
const _Function & _Func , const task_continuation_context & _Context , details : : _TaskInliningMode _InliningMode ) :
# if _MSC_VER >= 1800
details : : _PPLTaskHandle < typename details : : _NormalizeVoidToUnitType < _ContinuationReturnType > : : _Type ,
_ContinuationTaskHandle < _InternalReturnType , _ContinuationReturnType , _Function , _IsTaskBased , _TypeSelection > , details : : _ContinuationTaskHandleBase >
: : _PPLTaskHandle ( _ContinuationImpl )
, _M_ancestorTaskImpl ( _AncestorImpl )
, _M_function ( _Func )
# else
_M_ancestorTaskImpl ( _AncestorImpl ) , _PPLTaskHandle ( _ContinuationImpl ) , _M_function ( _Func )
# endif
{
_M_isTaskBasedContinuation = _IsTaskBased : : value ;
_M_continuationContext = _Context ;
_M_continuationContext . _Resolve ( _AncestorImpl - > _IsApartmentAware ( ) ) ;
_M_inliningMode = _InliningMode ;
}
virtual ~ _ContinuationTaskHandle ( ) { }
# if _MSC_VER >= 1800
template < typename _Func , typename _Arg , typename _RetArg >
auto _LogWorkItemAndInvokeUserLambda ( _Func & & _func , _Arg & & _value , _RetArg & & _retArg ) const - > decltype ( _func ( std : : forward < _Arg > ( _value ) , std : : forward < _RetArg > ( _retArg ) ) )
{
details : : _TaskWorkItemRAIILogger _LogWorkItem ( this - > _M_pTask - > _M_taskEventLogger ) ;
return _func ( std : : forward < _Arg > ( _value ) , std : : forward < _RetArg > ( _retArg ) ) ;
}
# endif
void _Perform ( ) const
{
_Continue ( _IsTaskBased ( ) , _TypeSelection ( ) ) ;
}
# if _MSC_VER >= 1800
void _SyncCancelAndPropagateException ( ) const
{
if ( _M_ancestorTaskImpl - > _HasUserException ( ) )
{
// If the ancestor encountered an exception, transfer the exception to the continuation
// This traverses down the tree to propagate the exception.
this - > _M_pTask - > _CancelWithExceptionHolder ( _M_ancestorTaskImpl - > _GetExceptionHolder ( ) , true ) ;
}
else
{
// If the ancestor was canceled, then your own execution should be canceled.
// This traverses down the tree to cancel it.
this - > _M_pTask - > _Cancel ( true ) ;
}
}
# endif
//
// Overload 0-0: _InternalReturnType -> _TaskType
//
// This is a straight task continuation which simply invokes its target with the ancestor's completion argument
//
void _Continue ( std : : false_type , details : : _TypeSelectorNoAsync ) const
{
_NormalizedContinuationReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _Continuation_func_transformer < _InternalReturnType , _ContinuationReturnType > : : _Perform ( _M_function ) , _M_ancestorTaskImpl - > _GetResult ( ) , & retVal ) ;
# else
HRESULT hr = _Continuation_func_transformer < _InternalReturnType , _ContinuationReturnType > : : _Perform ( _M_function ) ( _M_ancestorTaskImpl - > _GetResult ( ) , & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
_M_pTask - > _FinalizeAndRunContinuations ( retVal ) ;
}
//
// Overload 0-1: _InternalReturnType -> IAsyncOperation<_TaskType>*
// or
// _InternalReturnType -> task<_TaskType>
//
// This is a straight task continuation which returns an async operation or a task which will be unwrapped for continuation
// Depending on the output type, the right _AsyncInit gets invoked
//
void _Continue ( std : : false_type , details : : _TypeSelectorAsyncTask ) const
{
typedef typename details : : _FunctionTypeTraits < _Function , _InternalReturnType > : : _FuncRetType _FuncOutputType ;
_FuncOutputType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _Continuation_func_transformer < _InternalReturnType , _FuncOutputType > : : _Perform ( _M_function ) , _M_ancestorTaskImpl - > _GetResult ( ) , & retVal ) ;
# else
HRESULT hr = _Continuation_func_transformer < _InternalReturnType , _FuncOutputType > : : _Perform ( _M_function ) ( _M_ancestorTaskImpl - > _GetResult ( ) , & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _NormalizedContinuationReturnType , _ContinuationReturnType > (
_M_pTask ,
retVal
) ;
}
void _Continue ( std : : false_type , details : : _TypeSelectorAsyncOperation ) const
{
typedef typename details : : _FunctionTypeTraits < _Function , _InternalReturnType > : : _FuncRetType _FuncOutputType ;
_FuncOutputType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _Continuation_func_transformer < _InternalReturnType , _FuncOutputType > : : _Perform ( _M_function ) , _M_ancestorTaskImpl - > _GetResult ( ) , & retVal ) ;
# else
HRESULT hr = _Continuation_func_transformer < _InternalReturnType , _FuncOutputType > : : _Perform ( _M_function ) ( _M_ancestorTaskImpl - > _GetResult ( ) , & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _NormalizedContinuationReturnType , _ContinuationReturnType > (
_M_pTask ,
Microsoft : : WRL : : Make < details : : _IAsyncOperationToAsyncOperationConverter < _ContinuationReturnType > > ( retVal ) . Get ( ) ) ;
}
//
// Overload 0-2: _InternalReturnType -> IAsyncAction*
//
// This is a straight task continuation which returns an async action which will be unwrapped for continuation
//
void _Continue ( std : : false_type , details : : _TypeSelectorAsyncAction ) const
{
typedef details : : _FunctionTypeTraits < _Function , _InternalReturnType > : : _FuncRetType _FuncOutputType ;
_FuncOutputType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _Continuation_func_transformer < _InternalReturnType , _FuncOutputType > : : _Perform ( _M_function ) , _M_ancestorTaskImpl - > _GetResult ( ) , & retVal ) ;
# else
HRESULT hr = _Continuation_func_transformer < _InternalReturnType , _FuncOutputType > : : _Perform ( _M_function ) ( _M_ancestorTaskImpl - > _GetResult ( ) , & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _NormalizedContinuationReturnType , _ContinuationReturnType > (
_M_pTask ,
Microsoft : : WRL : : Make < details : : _IAsyncActionToAsyncOperationConverter > (
retVal ) . Get ( ) ) ;
}
//
// Overload 0-3: _InternalReturnType -> IAsyncOperationWithProgress<_TaskType, _ProgressType>*
//
// This is a straight task continuation which returns an async operation with progress which will be unwrapped for continuation
//
void _Continue ( std : : false_type , details : : _TypeSelectorAsyncOperationWithProgress ) const
{
typedef details : : _FunctionTypeTraits < _Function , _InternalReturnType > : : _FuncRetType _FuncOutputType ;
_FuncOutputType _OpWithProgress ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _Continuation_func_transformer < _InternalReturnType , _FuncOutputType > : : _Perform ( _M_function ) , _M_ancestorTaskImpl - > _GetResult ( ) , & _OpWithProgress ) ;
# else
HRESULT hr = _Continuation_func_transformer < _InternalReturnType , _FuncOutputType > : : _Perform ( _M_function ) ( _M_ancestorTaskImpl - > _GetResult ( ) , & _OpWithProgress ) ;
# endif
typedef details : : _GetProgressType < decltype ( _OpWithProgress ) > : : _Value _ProgressType ;
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _NormalizedContinuationReturnType , _ContinuationReturnType > (
_M_pTask ,
Microsoft : : WRL : : Make < details : : _IAsyncOperationWithProgressToAsyncOperationConverter < _ContinuationReturnType , _ProgressType > > ( _OpWithProgress ) . Get ( ) ) ;
}
//
// Overload 0-4: _InternalReturnType -> IAsyncActionWithProgress<_ProgressType>*
//
// This is a straight task continuation which returns an async action with progress which will be unwrapped for continuation
//
void _Continue ( std : : false_type , details : : _TypeSelectorAsyncActionWithProgress ) const
{
typedef details : : _FunctionTypeTraits < _Function , _InternalReturnType > : : _FuncRetType _FuncOutputType ;
_FuncOutputType _OpWithProgress ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _Continuation_func_transformer < _InternalReturnType , _FuncOutputType > : : _Perform ( _M_function ) , _M_ancestorTaskImpl - > _GetResult ( ) , & _OpWithProgress ) ;
# else
HRESULT hr = _Continuation_func_transformer < _InternalReturnType , _FuncOutputType > : : _Perform ( _M_function ) ( _M_ancestorTaskImpl - > _GetResult ( ) , & _OpWithProgress ) ;
# endif
typedef details : : _GetProgressType < decltype ( _OpWithProgress ) > : : _Value _ProgressType ;
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _NormalizedContinuationReturnType , _ContinuationReturnType > (
_M_pTask ,
Microsoft : : WRL : : Make < details : : _IAsyncActionWithProgressToAsyncOperationConverter < _ProgressType > > ( _OpWithProgress ) . Get ( ) ) ;
}
//
// Overload 1-0: task<_InternalReturnType> -> _TaskType
//
// This is an exception handling type of continuation which takes the task rather than the task's result.
//
void _Continue ( std : : true_type , details : : _TypeSelectorNoAsync ) const
{
typedef task < _InternalReturnType > _FuncInputType ;
task < _InternalReturnType > _ResultTask ;
_ResultTask . _SetImpl ( std : : move ( _M_ancestorTaskImpl ) ) ;
_NormalizedContinuationReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _Continuation_func_transformer < _FuncInputType , _ContinuationReturnType > : : _Perform ( _M_function ) , std : : move ( _ResultTask ) , & retVal ) ;
# else
HRESULT hr = _Continuation_func_transformer < _FuncInputType , _ContinuationReturnType > : : _Perform ( _M_function ) ( std : : move ( _ResultTask ) , & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
_M_pTask - > _FinalizeAndRunContinuations ( retVal ) ;
}
//
// Overload 1-1: task<_InternalReturnType> -> IAsyncOperation<_TaskType>^
// or
// task<_TaskType>
//
// This is an exception handling type of continuation which takes the task rather than
// the task's result. It also returns an async operation or a task which will be unwrapped
// for continuation
//
void _Continue ( std : : true_type , details : : _TypeSelectorAsyncTask ) const
{
// The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
task < _InternalReturnType > _ResultTask ;
_ResultTask . _SetImpl ( std : : move ( _M_ancestorTaskImpl ) ) ;
_ContinuationReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _M_function , std : : move ( _ResultTask ) , & retVal ) ;
# else
HRESULT hr = _M_function ( std : : move ( _ResultTask ) , & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _NormalizedContinuationReturnType , _ContinuationReturnType > ( _M_pTask , retVal ) ;
}
void _Continue ( std : : true_type , details : : _TypeSelectorAsyncOperation ) const
{
// The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
task < _InternalReturnType > _ResultTask ;
_ResultTask . _SetImpl ( std : : move ( _M_ancestorTaskImpl ) ) ;
_ContinuationReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _M_function , std : : move ( _ResultTask ) , & retVal ) ;
# else
HRESULT hr = _M_function ( std : : move ( _ResultTask ) , & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _NormalizedContinuationReturnType , _ContinuationReturnType > ( _M_pTask ,
Microsoft : : WRL : : Make < details : : _IAsyncOperationToAsyncOperationConverter < _ContinuationReturnType > > ( retVal ) ) ;
}
//
// Overload 1-2: task<_InternalReturnType> -> IAsyncAction*
//
// This is an exception handling type of continuation which takes the task rather than
// the task's result. It also returns an async action which will be unwrapped for continuation
//
void _Continue ( std : : true_type , details : : _TypeSelectorAsyncAction ) const
{
// The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
task < _InternalReturnType > _ResultTask ;
_ResultTask . _SetImpl ( std : : move ( _M_ancestorTaskImpl ) ) ;
_ContinuationReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _M_function , std : : move ( _ResultTask ) , & retVal ) ;
# else
HRESULT hr = _M_function ( std : : move ( _ResultTask ) , & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _NormalizedContinuationReturnType , _ContinuationReturnType > ( _M_pTask ,
Microsoft : : WRL : : Make < details : : _IAsyncActionToAsyncOperationConverter > ( retVal ) ) ;
}
//
// Overload 1-3: task<_InternalReturnType> -> IAsyncOperationWithProgress<_TaskType, _ProgressType>*
//
// This is an exception handling type of continuation which takes the task rather than
// the task's result. It also returns an async operation with progress which will be unwrapped
// for continuation
//
void _Continue ( std : : true_type , details : : _TypeSelectorAsyncOperationWithProgress ) const
{
// The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
task < _InternalReturnType > _ResultTask ;
_ResultTask . _SetImpl ( std : : move ( _M_ancestorTaskImpl ) ) ;
typedef details : : _GetProgressType < decltype ( _M_function ( _ResultTask ) ) > : : _Value _ProgressType ;
_ContinuationReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _M_function , std : : move ( _ResultTask ) , & retVal ) ;
# else
HRESULT hr = _M_function ( std : : move ( _ResultTask ) , & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _NormalizedContinuationReturnType , _ContinuationReturnType > ( _M_pTask ,
Microsoft : : WRL : : Make < details : : _IAsyncOperationWithProgressToAsyncOperationConverter < _ContinuationReturnType , _ProgressType > > ( retVal ) ) ;
}
//
// Overload 1-4: task<_InternalReturnType> -> IAsyncActionWithProgress<_ProgressType>*
//
// This is an exception handling type of continuation which takes the task rather than
// the task's result. It also returns an async operation with progress which will be unwrapped
// for continuation
//
void _Continue ( std : : true_type , details : : _TypeSelectorAsyncActionWithProgress ) const
{
// The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
task < _InternalReturnType > _ResultTask ;
_ResultTask . _SetImpl ( std : : move ( _M_ancestorTaskImpl ) ) ;
typedef details : : _GetProgressType < decltype ( _M_function ( _ResultTask ) ) > : : _Value _ProgressType ;
_ContinuationReturnType retVal ;
# if _MSC_VER >= 1800
HRESULT hr = _LogWorkItemAndInvokeUserLambda ( _M_function , std : : move ( _ResultTask ) , & retVal ) ;
# else
HRESULT hr = _M_function ( std : : move ( _ResultTask ) , & retVal ) ;
# endif
if ( FAILED ( hr ) ) throw std : : make_exception_ptr ( hr ) ;
details : : _Task_impl_base : : _AsyncInit < _NormalizedContinuationReturnType , _ContinuationReturnType > ( _M_pTask ,
Microsoft : : WRL : : Make < details : : _IAsyncActionWithProgressToAsyncOperationConverter < _ProgressType > > ( retVal ) ) ;
}
} ;
/// <summary>
/// Initializes a task using a lambda, function pointer or function object.
/// </summary>
template < typename _InternalReturnType , typename _Function >
void _TaskInitWithFunctor ( const _Function & _Func )
{
typedef details : : _InitFunctorTypeTraits < _InternalReturnType , details : : _FunctionTypeTraits < _Function , void > : : _FuncRetType > _Async_type_traits ;
_M_Impl - > _M_fFromAsync = _Async_type_traits : : _IsAsyncTask ;
_M_Impl - > _M_fUnwrappedTask = _Async_type_traits : : _IsUnwrappedTaskOrAsync ;
# if _MSC_VER >= 1800
_M_Impl - > _M_taskEventLogger . _LogScheduleTask ( false ) ;
# endif
_M_Impl - > _ScheduleTask ( new _InitialTaskHandle < _InternalReturnType , _Function , typename _Async_type_traits : : _AsyncKind > ( _GetImpl ( ) , _Func ) , Concurrency : : details : : _NoInline ) ;
}
/// <summary>
/// Initializes a task using a task completion event.
/// </summary>
void _TaskInitNoFunctor ( task_completion_event < _ReturnType > & _Event )
{
_Event . _RegisterTask ( _M_Impl ) ;
}
/// <summary>
/// Initializes a task using an asynchronous operation IAsyncOperation<T>*
/// </summary>
template < typename _Result , typename _OpType , typename _CompHandlerType , typename _ResultType >
void _TaskInitAsyncOp ( details : : _AsyncInfoImpl < _OpType , _CompHandlerType , _ResultType > * _AsyncOp )
{
_M_Impl - > _M_fFromAsync = true ;
# if _MSC_VER < 1800
_M_Impl - > _SetScheduledEvent ( ) ;
# endif
// Mark this task as started here since we can set the state in the constructor without acquiring a lock. Once _AsyncInit
// returns a completion could execute concurrently and the task must be fully initialized before that happens.
_M_Impl - > _M_TaskState = details : : _Task_impl_base : : _Started ;
// Pass the shared pointer into _AsyncInit for storage in the Async Callback.
details : : _Task_impl_base : : _AsyncInit < _ReturnType , _Result > ( _M_Impl , _AsyncOp ) ;
}
/// <summary>
/// Initializes a task using an asynchronous operation IAsyncOperation<T>*
/// </summary>
template < typename _Result >
void _TaskInitNoFunctor ( ABI : : Windows : : Foundation : : IAsyncOperation < _Result > * _AsyncOp )
{
_TaskInitAsyncOp < _Result > ( Microsoft : : WRL : : Make < details : : _IAsyncOperationToAsyncOperationConverter < _Result > > ( _AsyncOp ) . Get ( ) ) ;
}
/// <summary>
/// Initializes a task using an asynchronous operation with progress IAsyncOperationWithProgress<T, P>*
/// </summary>
template < typename _Result , typename _Progress >
void _TaskInitNoFunctor ( ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _Result , _Progress > * _AsyncOp )
{
_TaskInitAsyncOp < _Result > ( Microsoft : : WRL : : Make < details : : _IAsyncOperationWithProgressToAsyncOperationConverter < _Result , _Progress > > ( _AsyncOp ) . Get ( ) ) ;
}
/// <summary>
/// Initializes a task using a callable object.
/// </summary>
template < typename _Function >
void _TaskInitMaybeFunctor ( _Function & _Func , std : : true_type )
{
_TaskInitWithFunctor < _ReturnType , _Function > ( _Func ) ;
}
/// <summary>
/// Initializes a task using a non-callable object.
/// </summary>
template < typename _Ty >
void _TaskInitMaybeFunctor ( _Ty & _Param , std : : false_type )
{
_TaskInitNoFunctor ( _Param ) ;
}
# if _MSC_VER >= 1800
template < typename _InternalReturnType , typename _Function >
auto _ThenImpl ( const _Function & _Func , const task_options & _TaskOptions ) const - > typename details : : _ContinuationTypeTraits < _Function , _InternalReturnType > : : _TaskOfType
{
if ( ! _M_Impl )
{
throw Concurrency : : invalid_operation ( " then() cannot be called on a default constructed task. " ) ;
}
Concurrency : : details : : _CancellationTokenState * _PTokenState = _TaskOptions . has_cancellation_token ( ) ? _TaskOptions . get_cancellation_token ( ) . _GetImplValue ( ) : nullptr ;
auto _Scheduler = _TaskOptions . has_scheduler ( ) ? _TaskOptions . get_scheduler ( ) : _GetImpl ( ) - > _GetScheduler ( ) ;
auto _CreationStack = details : : _get_internal_task_options ( _TaskOptions ) . _M_hasPresetCreationCallstack ? details : : _get_internal_task_options ( _TaskOptions ) . _M_presetCreationCallstack : details : : _TaskCreationCallstack ( ) ;
return _ThenImpl < _InternalReturnType , _Function > ( _Func , _PTokenState , _TaskOptions . get_continuation_context ( ) , _Scheduler , _CreationStack ) ;
}
# endif
/// <summary>
/// The one and only implementation of then for void and non-void tasks.
/// </summary>
template < typename _InternalReturnType , typename _Function >
# if _MSC_VER >= 1800
auto _ThenImpl ( const _Function & _Func , Concurrency : : details : : _CancellationTokenState * _PTokenState , const task_continuation_context & _ContinuationContext , Concurrency : : scheduler_ptr _Scheduler , details : : _TaskCreationCallstack _CreationStack ,
details : : _TaskInliningMode _InliningMode = Concurrency : : details : : _NoInline ) const - > typename details : : _ContinuationTypeTraits < _Function , _InternalReturnType > : : _TaskOfType
# else
auto _ThenImpl ( const _Function & _Func , Concurrency : : details : : _CancellationTokenState * _PTokenState , const task_continuation_context & _ContinuationContext ,
bool _Aggregating = false , details : : _TaskInliningMode _InliningMode = Concurrency : : details : : _NoInline ) const - > typename details : : _ContinuationTypeTraits < _Function , _InternalReturnType > : : _TaskOfType
# endif
{
if ( _M_Impl = = nullptr )
{
throw Concurrency : : invalid_operation ( " then() cannot be called on a default constructed task. " ) ;
}
typedef details : : _FunctionTypeTraits < _Function , _InternalReturnType > _Function_type_traits ;
typedef details : : _TaskTypeTraits < typename _Function_type_traits : : _FuncRetType > _Async_type_traits ;
typedef typename _Async_type_traits : : _TaskRetType _TaskType ;
//
// A **nullptr** token state indicates that it was not provided by the user. In this case, we inherit the antecedent's token UNLESS this is a
// an exception handling continuation. In that case, we break the chain with a _None. That continuation is never canceled unless the user
// explicitly passes the same token.
//
if ( _PTokenState = = nullptr )
{
# if _MSC_VER >= 1800
if ( _Function_type_traits : : _Takes_task : : value )
# else
if ( _Function_type_traits : : _Takes_task ( ) )
# endif
{
_PTokenState = Concurrency : : details : : _CancellationTokenState : : _None ( ) ;
}
else
{
_PTokenState = _GetImpl ( ) - > _M_pTokenState ;
}
}
task < _TaskType > _ContinuationTask ;
# if _MSC_VER >= 1800
_ContinuationTask . _CreateImpl ( _PTokenState , _Scheduler ) ;
# else
_ContinuationTask . _CreateImpl ( _PTokenState ) ;
# endif
_ContinuationTask . _GetImpl ( ) - > _M_fFromAsync = ( _GetImpl ( ) - > _M_fFromAsync | | _Async_type_traits : : _IsAsyncTask ) ;
# if _MSC_VER < 1800
_ContinuationTask . _GetImpl ( ) - > _M_fRuntimeAggregate = _Aggregating ;
# endif
_ContinuationTask . _GetImpl ( ) - > _M_fUnwrappedTask = _Async_type_traits : : _IsUnwrappedTaskOrAsync ;
# if _MSC_VER >= 1800
_ContinuationTask . _SetTaskCreationCallstack ( _CreationStack ) ;
# endif
_GetImpl ( ) - > _ScheduleContinuation ( new _ContinuationTaskHandle < _InternalReturnType , _TaskType , _Function , typename _Function_type_traits : : _Takes_task , typename _Async_type_traits : : _AsyncKind > (
_GetImpl ( ) , _ContinuationTask . _GetImpl ( ) , _Func , _ContinuationContext , _InliningMode ) ) ;
return _ContinuationTask ;
}
// The underlying implementation for this task
typename details : : _Task_ptr < _ReturnType > : : _Type _M_Impl ;
} ;
/// <summary>
/// The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously,
/// and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces
/// a result of type <typeparamref name="_ResultType"/> on successful completion. Tasks of type <c>task<void></c> produce no result.
/// A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using
/// continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns.
/// </summary>
/// <remarks>
/// For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.
/// </remarks>
/**/
template < >
class task < void >
{
public :
/// <summary>
/// The type of the result an object of this class produces.
/// </summary>
/**/
typedef void result_type ;
/// <summary>
/// Constructs a <c>task</c> object.
/// </summary>
/// <remarks>
/// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
/// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
/// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
/// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
/// completion event is set.</para>
/// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
/// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
/// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
/// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
/// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
/// and not when the lamda returns.</para>
/// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
/// without the need for locks.</para>
/// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
/// to Windows Store apps.</para>
/// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
task ( ) : _M_unitTask ( )
{
// The default constructor should create a task with a nullptr impl. This is a signal that the
// task is not usable and should throw if any wait(), get() or then() APIs are used.
}
# if _MSC_VER < 1800
/// <summary>
/// Constructs a <c>task</c> object.
/// </summary>
/// <typeparam name="_Ty">
/// The type of the parameter from which the task is to be constructed.
/// </typeparam>
/// <param name="_Param">
/// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c>
/// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
/// object should be a type equivalent to <c>std::function<X(void)></c>, where X can be a variable of type <c>result_type</c>,
/// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
/// </param>
/// <remarks>
/// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
/// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
/// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
/// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
/// completion event is set.</para>
/// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
/// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
/// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
/// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
/// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
/// and not when the lamda returns.</para>
/// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
/// without the need for locks.</para>
/// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
/// to Windows Store apps.</para>
/// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Ty >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
explicit task ( _Ty _Param )
{
details : : _ValidateTaskConstructorArgs < void , _Ty > ( _Param ) ;
_M_unitTask . _CreateImpl ( Concurrency : : cancellation_token : : none ( ) . _GetImplValue ( ) ) ;
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor.
_M_unitTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
_TaskInitMaybeFunctor ( _Param , details : : _IsCallable < void > ( _Param , 0 , 0 , 0 ) ) ;
}
# endif
/// <summary>
/// Constructs a <c>task</c> object.
/// </summary>
/// <typeparam name="_Ty">
/// The type of the parameter from which the task is to be constructed.
/// </typeparam>
/// <param name="_Param">
/// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c>
/// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
/// object should be a type equivalent to <c>std::function<X(void)></c>, where X can be a variable of type <c>result_type</c>,
/// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
/// </param>
/// <param name="_Token">
/// The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives
/// the token <c>cancellation_token::none()</c>.
/// </param>
/// <remarks>
/// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
/// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
/// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
/// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
/// completion event is set.</para>
/// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
/// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
/// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
/// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
/// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
/// and not when the lamda returns.</para>
/// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
/// without the need for locks.</para>
/// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
/// to Windows Store apps.</para>
/// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Ty >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
# if _MSC_VER >= 1800
explicit task ( _Ty _Param , const task_options & _TaskOptions = task_options ( ) )
# else
explicit task ( _Ty _Param , Concurrency : : cancellation_token _CancellationToken )
# endif
{
details : : _ValidateTaskConstructorArgs < void , _Ty > ( _Param ) ;
# if _MSC_VER >= 1800
_M_unitTask . _CreateImpl ( _TaskOptions . get_cancellation_token ( ) . _GetImplValue ( ) , _TaskOptions . get_scheduler ( ) ) ;
# else
_M_unitTask . _CreateImpl ( _CancellationToken . _GetImplValue ( ) ) ;
# endif
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor.
# if _MSC_VER >= 1800
_M_unitTask . _SetTaskCreationCallstack ( details : : _get_internal_task_options ( _TaskOptions ) . _M_hasPresetCreationCallstack ? details : : _get_internal_task_options ( _TaskOptions ) . _M_presetCreationCallstack : _CAPTURE_CALLSTACK ( ) ) ;
# else
_M_unitTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
# endif
_TaskInitMaybeFunctor ( _Param , details : : _IsCallable < void > ( _Param , 0 , 0 , 0 ) ) ;
}
/// <summary>
/// Constructs a <c>task</c> object.
/// </summary>
/// <param name="_Other">
/// The source <c>task</c> object.
/// </param>
/// <remarks>
/// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
/// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
/// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
/// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
/// completion event is set.</para>
/// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
/// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
/// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
/// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
/// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
/// and not when the lamda returns.</para>
/// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
/// without the need for locks.</para>
/// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
/// to Windows Store apps.</para>
/// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
task ( const task & _Other ) : _M_unitTask ( _Other . _M_unitTask ) { }
/// <summary>
/// Constructs a <c>task</c> object.
/// </summary>
/// <param name="_Other">
/// The source <c>task</c> object.
/// </param>
/// <remarks>
/// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
/// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c>
/// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
/// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
/// completion event is set.</para>
/// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
/// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
/// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
/// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
/// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
/// and not when the lamda returns.</para>
/// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
/// without the need for locks.</para>
/// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
/// to Windows Store apps.</para>
/// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
task ( task & & _Other ) : _M_unitTask ( std : : move ( _Other . _M_unitTask ) ) { }
/// <summary>
/// Replaces the contents of one <c>task</c> object with another.
/// </summary>
/// <param name="_Other">
/// The source <c>task</c> object.
/// </param>
/// <remarks>
/// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
/// actual task as <paramref name="_Other"/> does.
/// </remarks>
/**/
task & operator = ( const task & _Other )
{
if ( this ! = & _Other )
{
_M_unitTask = _Other . _M_unitTask ;
}
return * this ;
}
/// <summary>
/// Replaces the contents of one <c>task</c> object with another.
/// </summary>
/// <param name="_Other">
/// The source <c>task</c> object.
/// </param>
/// <remarks>
/// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
/// actual task as <paramref name="_Other"/> does.
/// </remarks>
/**/
task & operator = ( task & & _Other )
{
if ( this ! = & _Other )
{
_M_unitTask = std : : move ( _Other . _M_unitTask ) ;
}
return * this ;
}
# if _MSC_VER < 1800
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
/// <typeparam name="_Function">
/// The type of the function object that will be invoked by this task.
/// </typeparam>
/// <param name="_Func">
/// The continuation function to execute when this task completes. This continuation function must take as input
/// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
/// of the result this task produces.
/// </param>
/// <returns>
/// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
/// </returns>
/// <remarks>
/// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
/// to Windows Store apps.
/// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Function >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
auto then ( const _Function & _Func ) const - > typename details : : _ContinuationTypeTraits < _Function , void > : : _TaskOfType
{
auto _ContinuationTask = _M_unitTask . _ThenImpl < void , _Function > ( _Func , nullptr , task_continuation_context : : use_default ( ) ) ;
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
_ContinuationTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
return _ContinuationTask ;
}
# endif
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
/// <typeparam name="_Function">
/// The type of the function object that will be invoked by this task.
/// </typeparam>
/// <param name="_Func">
/// The continuation function to execute when this task completes. This continuation function must take as input
/// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
/// of the result this task produces.
/// </param>
/// <param name="_CancellationToken">
/// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
/// the token of its antecedent task.
/// </param>
/// <returns>
/// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
/// </returns>
/// <remarks>
/// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
/// to Windows Store apps.
/// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Function >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
# if _MSC_VER >= 1800
auto then ( const _Function & _Func , task_options _TaskOptions = task_options ( ) ) const - > typename details : : _ContinuationTypeTraits < _Function , void > : : _TaskOfType
{
details : : _get_internal_task_options ( _TaskOptions ) . _set_creation_callstack ( _CAPTURE_CALLSTACK ( ) ) ;
return _M_unitTask . _ThenImpl < void , _Function > ( _Func , _TaskOptions ) ;
}
# else
auto then ( const _Function & _Func , Concurrency : : cancellation_token _CancellationToken ) const - > typename details : : _ContinuationTypeTraits < _Function , void > : : _TaskOfType
{
auto _ContinuationTask = _M_unitTask . _ThenImpl < void , _Function > ( _Func , _CancellationToken . _GetImplValue ( ) , task_continuation_context : : use_default ( ) ) ;
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
_ContinuationTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
return _ContinuationTask ;
}
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
/// <typeparam name="_Function">
/// The type of the function object that will be invoked by this task.
/// </typeparam>
/// <param name="_Func">
/// The continuation function to execute when this task completes. This continuation function must take as input
/// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
/// of the result this task produces.
/// </param>
/// <param name="_ContinuationContext">
/// A variable that specifies where the continuation should execute. This variable is only useful when used in a
/// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
/// </param>
/// <returns>
/// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
/// </returns>
/// <remarks>
/// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
/// to Windows Store apps.
/// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Function >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
auto then ( const _Function & _Func , task_continuation_context _ContinuationContext ) const - > typename details : : _ContinuationTypeTraits < _Function , void > : : _TaskOfType
{
auto _ContinuationTask = _M_unitTask . _ThenImpl < void , _Function > ( _Func , nullptr , _ContinuationContext ) ;
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
_ContinuationTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
return _ContinuationTask ;
}
# endif
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
/// <typeparam name="_Function">
/// The type of the function object that will be invoked by this task.
/// </typeparam>
/// <param name="_Func">
/// The continuation function to execute when this task completes. This continuation function must take as input
/// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
/// of the result this task produces.
/// </param>
/// <param name="_CancellationToken">
/// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
/// the token of its antecedent task.
/// </param>
/// <param name="_ContinuationContext">
/// A variable that specifies where the continuation should execute. This variable is only useful when used in a
/// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
/// </param>
/// <returns>
/// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
/// </returns>
/// <remarks>
/// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
/// to Windows Store apps.
/// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
/// </remarks>
/**/
template < typename _Function >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
# if _MSC_VER >= 1800
auto then ( const _Function & _Func , Concurrency : : cancellation_token _CancellationToken , task_continuation_context _ContinuationContext ) const - > typename details : : _ContinuationTypeTraits < _Function , void > : : _TaskOfType
{
task_options _TaskOptions ( _CancellationToken , _ContinuationContext ) ;
details : : _get_internal_task_options ( _TaskOptions ) . _set_creation_callstack ( _CAPTURE_CALLSTACK ( ) ) ;
return _M_unitTask . _ThenImpl < void , _Function > ( _Func , _TaskOptions ) ;
}
# else
auto then ( const _Function & _Func , Concurrency : : cancellation_token _CancellationToken , task_continuation_context _ContinuationContext ) const - > typename details : : _ContinuationTypeTraits < _Function , void > : : _TaskOfType
{
auto _ContinuationTask = _M_unitTask . _ThenImpl < void , _Function > ( _Func , _CancellationToken . _GetImplValue ( ) , _ContinuationContext ) ;
// Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
_ContinuationTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
return _ContinuationTask ;
}
# endif
/// <summary>
/// Waits for this task to reach a terminal state. It is possible for <c>wait</c> to execute the task inline, if all of the tasks
/// dependencies are satisfied, and it has not already been picked up for execution by a background worker.
/// </summary>
/// <returns>
/// A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception
/// during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception.
/// </returns>
/**/
task_status wait ( ) const
{
return _M_unitTask . wait ( ) ;
}
/// <summary>
/// Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to
/// finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>.
/// </summary>
/// <remarks>
/// If the task is canceled, a call to <c>get</c> will throw a <see cref="task_canceled Class">task_canceled</see> exception. If the task
/// encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception.
/// </remarks>
/**/
void get ( ) const
{
_M_unitTask . get ( ) ;
}
# if _MSC_VER >= 1800
/// <summary>
/// Determines if the task is completed.
/// </summary>
/// <returns>
/// True if the task has completed, false otherwise.
/// </returns>
/// <remarks>
/// The function returns true if the task is completed or canceled (with or without user exception).
/// </remarks>
bool is_done ( ) const
{
return _M_unitTask . is_done ( ) ;
}
/// <summary>
/// Returns the scheduler for this task
/// </summary>
/// <returns>
/// A pointer to the scheduler
/// </returns>
Concurrency : : scheduler_ptr scheduler ( ) const
{
return _M_unitTask . scheduler ( ) ;
}
# endif
/// <summary>
/// Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task.
/// </summary>
/// <returns>
/// <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise.
/// </returns>
/**/
bool is_apartment_aware ( ) const
{
return _M_unitTask . is_apartment_aware ( ) ;
}
/// <summary>
/// Determines whether two <c>task</c> objects represent the same internal task.
/// </summary>
/// <returns>
/// <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise.
/// </returns>
/**/
bool operator = = ( const task < void > & _Rhs ) const
{
return ( _M_unitTask = = _Rhs . _M_unitTask ) ;
}
/// <summary>
/// Determines whether two <c>task</c> objects represent different internal tasks.
/// </summary>
/// <returns>
/// <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise.
/// </returns>
/**/
bool operator ! = ( const task < void > & _Rhs ) const
{
return ! operator = = ( _Rhs ) ;
}
/// <summary>
/// Create an underlying task implementation.
/// </summary>
# if _MSC_VER >= 1800
void _CreateImpl ( Concurrency : : details : : _CancellationTokenState * _Ct , Concurrency : : scheduler_ptr _Scheduler )
{
_M_unitTask . _CreateImpl ( _Ct , _Scheduler ) ;
}
# else
void _CreateImpl ( Concurrency : : details : : _CancellationTokenState * _Ct )
{
_M_unitTask . _CreateImpl ( _Ct ) ;
}
# endif
/// <summary>
/// Return the underlying implementation for this task.
/// </summary>
const details : : _Task_ptr < details : : _Unit_type > : : _Type & _GetImpl ( ) const
{
return _M_unitTask . _M_Impl ;
}
/// <summary>
/// Set the implementation of the task to be the supplied implementaion.
/// </summary>
void _SetImpl ( const details : : _Task_ptr < details : : _Unit_type > : : _Type & _Impl )
{
_M_unitTask . _SetImpl ( _Impl ) ;
}
/// <summary>
/// Set the implementation of the task to be the supplied implementaion using a move instead of a copy.
/// </summary>
void _SetImpl ( details : : _Task_ptr < details : : _Unit_type > : : _Type & & _Impl )
{
_M_unitTask . _SetImpl ( std : : move ( _Impl ) ) ;
}
/// <summary>
/// Sets a property determining whether the task is apartment aware.
/// </summary>
void _SetAsync ( bool _Async = true )
{
_M_unitTask . _SetAsync ( _Async ) ;
}
/// <summary>
/// Sets a field in the task impl to the return address for calls to the task constructors and the then method.
/// </summary>
# if _MSC_VER >= 1800
void _SetTaskCreationCallstack ( const details : : _TaskCreationCallstack & _callstack )
{
_M_unitTask . _SetTaskCreationCallstack ( _callstack ) ;
}
# else
void _SetTaskCreationAddressHint ( void * _Address )
{
_M_unitTask . _SetTaskCreationAddressHint ( _Address ) ;
}
# endif
/// <summary>
/// An internal version of then that takes additional flags and executes the continuation inline. Used for runtime internal continuations only.
/// </summary>
template < typename _Function >
# if _MSC_VER >= 1800
auto _Then ( const _Function & _Func , Concurrency : : details : : _CancellationTokenState * _PTokenState ,
details : : _TaskInliningMode _InliningMode = Concurrency : : details : : _ForceInline ) const - > typename details : : _ContinuationTypeTraits < _Function , void > : : _TaskOfType
{
// inherit from antecedent
auto _Scheduler = _GetImpl ( ) - > _GetScheduler ( ) ;
return _M_unitTask . _ThenImpl < void , _Function > ( _Func , _PTokenState , task_continuation_context : : use_default ( ) , _Scheduler , _CAPTURE_CALLSTACK ( ) , _InliningMode ) ;
}
# else
auto _Then ( const _Function & _Func , Concurrency : : details : : _CancellationTokenState * _PTokenState ,
bool _Aggregating , details : : _TaskInliningMode _InliningMode = Concurrency : : details : : _ForceInline ) const - > typename details : : _ContinuationTypeTraits < _Function , void > : : _TaskOfType
{
return _M_unitTask . _ThenImpl < void , _Function > ( _Func , _PTokenState , task_continuation_context : : use_default ( ) , _Aggregating , _InliningMode ) ;
}
# endif
private :
template < typename T > friend class task ;
template < typename T > friend class task_completion_event ;
/// <summary>
/// Initializes a task using a task completion event.
/// </summary>
void _TaskInitNoFunctor ( task_completion_event < void > & _Event )
{
_M_unitTask . _TaskInitNoFunctor ( _Event . _M_unitEvent ) ;
}
/// <summary>
/// Initializes a task using an asynchronous action IAsyncAction*
/// </summary>
void _TaskInitNoFunctor ( ABI : : Windows : : Foundation : : IAsyncAction * _AsyncAction )
{
_M_unitTask . _TaskInitAsyncOp < details : : _Unit_type > ( Microsoft : : WRL : : Make < details : : _IAsyncActionToAsyncOperationConverter > ( _AsyncAction ) . Get ( ) ) ;
}
/// <summary>
/// Initializes a task using an asynchronous action with progress IAsyncActionWithProgress<_P>*
/// </summary>
template < typename _P >
void _TaskInitNoFunctor ( ABI : : Windows : : Foundation : : IAsyncActionWithProgress < _P > * _AsyncActionWithProgress )
{
_M_unitTask . _TaskInitAsyncOp < details : : _Unit_type > ( Microsoft : : WRL : : Make < details : : _IAsyncActionWithProgressToAsyncOperationConverter < _P > > ( _AsyncActionWithProgress ) . Get ( ) ) ;
}
/// <summary>
/// Initializes a task using a callable object.
/// </summary>
template < typename _Function >
void _TaskInitMaybeFunctor ( _Function & _Func , std : : true_type )
{
_M_unitTask . _TaskInitWithFunctor < void , _Function > ( _Func ) ;
}
/// <summary>
/// Initializes a task using a non-callable object.
/// </summary>
template < typename _T >
void _TaskInitMaybeFunctor ( _T & _Param , std : : false_type )
{
_TaskInitNoFunctor ( _Param ) ;
}
// The void task contains a task of a dummy type so common code can be used for tasks with void and non-void results.
task < details : : _Unit_type > _M_unitTask ;
} ;
namespace details
{
/// <summary>
/// The following type traits are used for the create_task function.
/// </summary>
// Unwrap task<T>
template < typename _Ty >
_Ty _GetUnwrappedType ( task < _Ty > ) ;
// Unwrap all supported types
template < typename _Ty >
auto _GetUnwrappedReturnType ( _Ty _Arg , int ) - > decltype ( _GetUnwrappedType ( _Arg ) ) ;
// fallback
template < typename _Ty >
_Ty _GetUnwrappedReturnType ( _Ty , . . . ) ;
/// <summary>
/// <c>_GetTaskType</c> functions will retrieve task type <c>T</c> in <c>task[T](Arg)</c>,
/// for given constructor argument <c>Arg</c> and its property "callable".
/// It will automatically unwrap argument to get the final return type if necessary.
/// </summary>
// Non-Callable
template < typename _Ty >
_Ty _GetTaskType ( task_completion_event < _Ty > , std : : false_type ) ;
// Non-Callable
template < typename _Ty >
auto _GetTaskType ( _Ty _NonFunc , std : : false_type ) - > decltype ( _GetUnwrappedType ( _NonFunc ) ) ;
// Callable
template < typename _Ty >
auto _GetTaskType ( _Ty _Func , std : : true_type ) - > decltype ( _GetUnwrappedReturnType ( stdx : : declval < _FunctionTypeTraits < _Ty , void > : : _FuncRetType > ( ) , 0 ) ) ;
// Special callable returns void
void _GetTaskType ( std : : function < HRESULT ( ) > , std : : true_type ) ;
struct _BadArgType { } ;
template < typename _ReturnType , typename _Ty >
auto _FilterValidTaskType ( _Ty _Param , int ) - > decltype ( _GetTaskType ( _Param , _IsCallable < _ReturnType > ( _Param , 0 , 0 , 0 ) ) ) ;
template < typename _ReturnType , typename _Ty >
_BadArgType _FilterValidTaskType ( _Ty _Param , . . . ) ;
template < typename _ReturnType , typename _Ty >
struct _TaskTypeFromParam
{
typedef decltype ( _FilterValidTaskType < _ReturnType > ( stdx : : declval < _Ty > ( ) , 0 ) ) _Type ;
} ;
}
/// <summary>
/// Creates a PPL <see cref="task Class">task</c> object. <c>create_task</c> can be used anywhere you would have used a task constructor.
/// It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks.
/// </summary>
/// <typeparam name="_Ty">
/// The type of the parameter from which the task is to be constructed.
/// </typeparam>
/// <param name="_Param">
/// The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c>
/// object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app.
/// </param>
/// <returns>
/// A new task of type <c>T</c>, that is inferred from <paramref name="_Param"/>.
/// </returns>
/// <remarks>
/// The first overload behaves like a task constructor that takes a single parameter.
/// <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not
/// allowed to pass in a different <c>task</c> object as the first parameter.</para>
/// <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name="_Param"/> is a <c>task_completion_event<T></c>,
/// a <c>task<T></c>, or a functor that returns either type <c>T</c> or <c>task<T></c>, the type of the created task is <c>task<T></c>.
/// <para>In a Windows Store app, if <paramref name="_Param"/> is of type Windows::Foundation::IAsyncOperation<T>^ or
/// Windows::Foundation::IAsyncOperationWithProgress<T,P>^, or a functor that returns either of those types, the created task will be of type <c>task<T></c>.
/// If <paramref name="_Param"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress<P>^, or a functor
/// that returns either of those types, the created task will have type <c>task<void></c>.</para>
/// </remarks>
/// <seealso cref="task Class"/>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _ReturnType , typename _Ty >
__declspec ( noinline )
# if _MSC_VER >= 1800
auto create_task ( _Ty _Param , task_options _TaskOptions = task_options ( ) ) - > task < typename details : : _TaskTypeFromParam < _ReturnType , _Ty > : : _Type >
# else
auto create_task ( _Ty _Param ) - > task < typename details : : _TaskTypeFromParam < _ReturnType , _Ty > : : _Type >
# endif
{
static_assert ( ! std : : is_same < typename details : : _TaskTypeFromParam < _ReturnType , _Ty > : : _Type , details : : _BadArgType > : : value ,
" incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event "
) ;
# if _MSC_VER >= 1800
details : : _get_internal_task_options ( _TaskOptions ) . _set_creation_callstack ( _CAPTURE_CALLSTACK ( ) ) ;
task < typename details : : _TaskTypeFromParam < _ReturnType , _Ty > : : _Type > _CreatedTask ( _Param , _TaskOptions ) ;
# else
task < typename details : : _TaskTypeFromParam < _ReturnType , _Ty > : : _Type > _CreatedTask ( _Param ) ;
// Ideally we would like to forceinline create_task, but __forceinline does nothing on debug builds. Therefore, we ask for no inlining
// and overwrite the creation address hint set by the task constructor. DO NOT REMOVE this next line from create_task. It is
// essential that _ReturnAddress() evaluate to the instruction right after the call to create_task in client code.
_CreatedTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
# endif
return _CreatedTask ;
}
/// <summary>
/// Creates a PPL <see cref="task Class">task</c> object. <c>create_task</c> can be used anywhere you would have used a task constructor.
/// It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks.
/// </summary>
/// <typeparam name="_Ty">
/// The type of the parameter from which the task is to be constructed.
/// </typeparam>
/// <param name="_Param">
/// The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c>
/// object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app.
/// </param>
/// <param name="_Token">
/// The cancellation token to associate with the task. When the source for this token is canceled, cancellation will be requested on the task.
/// </param>
/// <returns>
/// A new task of type <c>T</c>, that is inferred from <paramref name="_Param"/>.
/// </returns>
/// <remarks>
/// The first overload behaves like a task constructor that takes a single parameter.
/// <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not
/// allowed to pass in a different <c>task</c> object as the first parameter.</para>
/// <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name="_Param"/> is a <c>task_completion_event<T></c>,
/// a <c>task<T></c>, or a functor that returns either type <c>T</c> or <c>task<T></c>, the type of the created task is <c>task<T></c>.
/// <para>In a Windows Store app, if <paramref name="_Param"/> is of type Windows::Foundation::IAsyncOperation<T>^ or
/// Windows::Foundation::IAsyncOperationWithProgress<T,P>^, or a functor that returns either of those types, the created task will be of type <c>task<T></c>.
/// If <paramref name="_Param"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress<P>^, or a functor
/// that returns either of those types, the created task will have type <c>task<void></c>.</para>
/// </remarks>
/// <seealso cref="task Class"/>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
# if _MSC_VER >= 1800
template < typename _ReturnType >
__declspec ( noinline )
task < _ReturnType > create_task ( const task < _ReturnType > & _Task )
{
task < _ReturnType > _CreatedTask ( _Task ) ;
return _CreatedTask ;
}
# else
template < typename _ReturnType , typename _Ty >
__declspec ( noinline )
auto create_task ( _Ty _Param , Concurrency : : cancellation_token _Token ) - > task < typename details : : _TaskTypeFromParam < _ReturnType , _Ty > : : _Type >
{
static_assert ( ! std : : is_same < typename details : : _TaskTypeFromParam < _ReturnType , _Ty > : : _Type , details : : _BadArgType > : : value ,
" incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event "
) ;
task < typename details : : _TaskTypeFromParam < _ReturnType , _Ty > : : _Type > _CreatedTask ( _Param , _Token ) ;
// Ideally we would like to forceinline create_task, but __forceinline does nothing on debug builds. Therefore, we ask for no inlining
// and overwrite the creation address hint set by the task constructor. DO NOT REMOVE this next line from create_task. It is
// essential that _ReturnAddress() evaluate to the instruction right after the call to create_task in client code.
_CreatedTask . _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
return _CreatedTask ;
}
# endif
namespace details
{
template < typename _T >
task < typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncOperationSelector ( stdx : : declval < ABI : : Windows : : Foundation : : IAsyncOperation < _T > * > ( ) ) ) > : : type > _To_task_helper ( ABI : : Windows : : Foundation : : IAsyncOperation < _T > * op )
{
return task < _T > ( op ) ;
}
template < typename _T , typename _Progress >
task < typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncOperationWithProgressSelector ( stdx : : declval < ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _T , _Progress > * > ( ) ) ) > : : type > _To_task_helper ( ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _T , _Progress > * op )
{
return task < _T > ( op ) ;
}
inline task < void > _To_task_helper ( ABI : : Windows : : Foundation : : IAsyncAction * op )
{
return task < void > ( op ) ;
}
template < typename _Progress >
task < void > _To_task_helper ( ABI : : Windows : : Foundation : : IAsyncActionWithProgress < _Progress > * op )
{
return task < void > ( op ) ;
}
template < typename _ProgressType >
class _ProgressDispatcherBase
{
public :
virtual ~ _ProgressDispatcherBase ( )
{
}
virtual void _Report ( const _ProgressType & _Val ) = 0 ;
} ;
template < typename _ProgressType , typename _ClassPtrType >
class _ProgressDispatcher : public _ProgressDispatcherBase < _ProgressType >
{
public :
virtual ~ _ProgressDispatcher ( )
{
}
_ProgressDispatcher ( _ClassPtrType _Ptr ) : _M_ptr ( _Ptr )
{
}
virtual void _Report ( const _ProgressType & _Val )
{
_M_ptr - > _FireProgress ( _Val ) ;
}
private :
_ClassPtrType _M_ptr ;
} ;
} // namespace details
/// <summary>
/// The progress reporter class allows reporting progress notifications of a specific type. Each progress_reporter object is bound
/// to a particular asynchronous action or operation.
/// </summary>
/// <typeparam name="_ProgressType">
/// The payload type of each progress notification reported through the progress reporter.
/// </typeparam>
/// <remarks>
/// This type is only available to Windows Store apps.
/// </remarks>
/// <seealso cref="create_async Function"/>
/**/
template < typename _ProgressType >
class progress_reporter
{
typedef std : : shared_ptr < details : : _ProgressDispatcherBase < _ProgressType > > _PtrType ;
public :
/// <summary>
/// Sends a progress report to the asynchronous action or operation to which this progress reporter is bound.
/// </summary>
/// <param name="_Val">
/// The payload to report through a progress notification.
/// </param>
/**/
void report ( const _ProgressType & _Val ) const
{
_M_dispatcher - > _Report ( _Val ) ;
}
template < typename _ClassPtrType >
static progress_reporter _CreateReporter ( _ClassPtrType _Ptr )
{
progress_reporter _Reporter ;
details : : _ProgressDispatcherBase < _ProgressType > * _PDispatcher = new details : : _ProgressDispatcher < _ProgressType , _ClassPtrType > ( _Ptr ) ;
_Reporter . _M_dispatcher = _PtrType ( _PDispatcher ) ;
return _Reporter ;
}
progress_reporter ( ) { }
private :
progress_reporter ( details : : _ProgressReporterCtorArgType ) ;
_PtrType _M_dispatcher ;
} ;
namespace details
{
//
// maps internal definitions for AsyncStatus and defines states that are not client visible
//
enum _AsyncStatusInternal
{
_AsyncCreated = - 1 , // externally invisible
// client visible states (must match AsyncStatus exactly)
_AsyncStarted = ABI : : Windows : : Foundation : : AsyncStatus : : Started , // 0
_AsyncCompleted = ABI : : Windows : : Foundation : : AsyncStatus : : Completed , // 1
_AsyncCanceled = ABI : : Windows : : Foundation : : AsyncStatus : : Canceled , // 2
_AsyncError = ABI : : Windows : : Foundation : : AsyncStatus : : Error , // 3
// non-client visible internal states
_AsyncCancelPending ,
_AsyncClosed ,
_AsyncUndefined
} ;
//
// designates whether the "GetResults" method returns a single result (after complete fires) or multiple results
// (which are progressively consumable between Start state and before Close is called)
//
enum _AsyncResultType
{
SingleResult = 0x0001 ,
MultipleResults = 0x0002
} ;
template < typename _T >
struct _ProgressTypeTraits
{
static const bool _TakesProgress = false ;
typedef void _ProgressType ;
} ;
template < typename _T >
struct _ProgressTypeTraits < progress_reporter < _T > >
{
static const bool _TakesProgress = true ;
typedef typename _T _ProgressType ;
} ;
template < typename _T , bool bTakesToken = std : : is_same < _T , Concurrency : : cancellation_token > : : value , bool bTakesProgress = _ProgressTypeTraits < _T > : : _TakesProgress >
struct _TokenTypeTraits
{
static const bool _TakesToken = false ;
typedef typename _T _ReturnType ;
} ;
template < typename _T >
struct _TokenTypeTraits < _T , false , true >
{
static const bool _TakesToken = false ;
typedef void _ReturnType ;
} ;
template < typename _T >
struct _TokenTypeTraits < _T , true , false >
{
static const bool _TakesToken = true ;
typedef void _ReturnType ;
} ;
template < typename _T , size_t count = _FunctorTypeTraits < _T > : : _ArgumentCount >
struct _CAFunctorOptions
{
static const bool _TakesProgress = false ;
static const bool _TakesToken = false ;
typedef void _ProgressType ;
typedef void _ReturnType ;
} ;
template < typename _T >
struct _CAFunctorOptions < _T , 1 >
{
private :
typedef typename _FunctorTypeTraits < _T > : : _Argument1Type _Argument1Type ;
public :
static const bool _TakesProgress = _ProgressTypeTraits < _Argument1Type > : : _TakesProgress ;
static const bool _TakesToken = _TokenTypeTraits < _Argument1Type > : : _TakesToken ;
typedef typename _ProgressTypeTraits < _Argument1Type > : : _ProgressType _ProgressType ;
typedef typename _TokenTypeTraits < _Argument1Type > : : _ReturnType _ReturnType ;
} ;
template < typename _T >
struct _CAFunctorOptions < _T , 2 >
{
private :
typedef typename _FunctorTypeTraits < _T > : : _Argument1Type _Argument1Type ;
typedef typename _FunctorTypeTraits < _T > : : _Argument2Type _Argument2Type ;
public :
static const bool _TakesProgress = _ProgressTypeTraits < _Argument1Type > : : _TakesProgress ;
static const bool _TakesToken = ! _TakesProgress ? true : _TokenTypeTraits < _Argument2Type > : : _TakesToken ;
typedef typename _ProgressTypeTraits < _Argument1Type > : : _ProgressType _ProgressType ;
typedef typename _TokenTypeTraits < _Argument2Type > : : _ReturnType _ReturnType ;
} ;
template < typename _T >
struct _CAFunctorOptions < _T , 3 >
{
private :
typedef typename _FunctorTypeTraits < _T > : : _Argument1Type _Argument1Type ;
public :
static const bool _TakesProgress = true ;
static const bool _TakesToken = true ;
typedef typename _ProgressTypeTraits < _Argument1Type > : : _ProgressType _ProgressType ;
typedef typename _FunctorTypeTraits < _T > : : _Argument3Type _ReturnType ;
} ;
class _Zip
{
} ;
// ***************************************************************************
// Async Operation Task Generators
//
//
// Functor returns an IAsyncInfo - result needs to be wrapped in a task:
//
template < typename _AsyncSelector , typename _ReturnType >
struct _SelectorTaskGenerator
{
# if _MSC_VER >= 1800
template < typename _Function >
static task < _ReturnType > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < _ReturnType > ( _Func ( _pRet ) , _taskOptinos ) ;
}
template < typename _Function >
static task < _ReturnType > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < _ReturnType > ( _Func ( _Cts . get_token ( ) , _pRet ) , _taskOptinos ) ;
}
template < typename _Function , typename _ProgressObject >
static task < _ReturnType > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < _ReturnType > ( _Func ( _Progress , _pRet ) , _taskOptinos ) ;
}
template < typename _Function , typename _ProgressObject >
static task < _ReturnType > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < _ReturnType > ( _Func ( _Progress , _Cts . get_token ( ) , _pRet ) , _taskOptinos ) ;
}
# else
template < typename _Function >
static task < _ReturnType > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return task < _ReturnType > ( _Func ( _pRet ) , _Cts . get_token ( ) ) ;
}
template < typename _Function >
static task < _ReturnType > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return task < _ReturnType > ( _Func ( _Cts . get_token ( ) , _pRet ) , _Cts . get_token ( ) ) ;
}
template < typename _Function , typename _ProgressObject >
static task < _ReturnType > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return task < _ReturnType > ( _Func ( _Progress , _pRet ) , _Cts . get_token ( ) ) ;
}
template < typename _Function , typename _ProgressObject >
static task < _ReturnType > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return task < _ReturnType > ( _Func ( _Progress , _Cts . get_token ( ) , _pRet ) , _Cts . get_token ( ) ) ;
}
# endif
} ;
template < typename _AsyncSelector >
struct _SelectorTaskGenerator < _AsyncSelector , void >
{
# if _MSC_VER >= 1800
template < typename _Function >
static task < void > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < void > ( _Func ( ) , _taskOptinos ) ;
}
template < typename _Function >
static task < void > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < void > ( _Func ( _Cts . get_token ( ) ) , _taskOptinos ) ;
}
template < typename _Function , typename _ProgressObject >
static task < void > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < void > ( _Func ( _Progress ) , _taskOptinos ) ;
}
template < typename _Function , typename _ProgressObject >
static task < void > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < void > ( _Func ( _Progress , _Cts . get_token ( ) ) , _taskOptinos ) ;
}
# else
template < typename _Function >
static task < void > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts )
{
return task < void > ( _Func ( ) , _Cts . get_token ( ) ) ;
}
template < typename _Function >
static task < void > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts )
{
return task < void > ( _Func ( _Cts . get_token ( ) ) , _Cts . get_token ( ) ) ;
}
template < typename _Function , typename _ProgressObject >
static task < void > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts )
{
return task < void > ( _Func ( _Progress ) , _Cts . get_token ( ) ) ;
}
template < typename _Function , typename _ProgressObject >
static task < void > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts )
{
return task < void > ( _Func ( _Progress , _Cts . get_token ( ) ) , _Cts . get_token ( ) ) ;
}
# endif
} ;
# if _MSC_VER < 1800
// For create_async lambdas that return a (non-task) result, we oversubscriber the current task for the duration of the
// lambda.
struct _Task_generator_oversubscriber
{
_Task_generator_oversubscriber ( )
{
Concurrency : : details : : _Context : : _Oversubscribe ( true ) ;
}
~ _Task_generator_oversubscriber ( )
{
Concurrency : : details : : _Context : : _Oversubscribe ( false ) ;
}
} ;
# endif
//
// Functor returns a result - it needs to be wrapped in a task:
//
template < typename _ReturnType >
struct _SelectorTaskGenerator < details : : _TypeSelectorNoAsync , _ReturnType >
{
# if _MSC_VER >= 1800
# pragma warning(push)
# pragma warning(disable: 4702)
template < typename _Function >
static task < _ReturnType > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < _ReturnType > ( [ = ] ( _ReturnType * retVal ) - > HRESULT {
Concurrency : : details : : _Task_generator_oversubscriber_t _Oversubscriber ;
( _Oversubscriber ) ;
HRESULT hr = _Func ( _pRet ) ;
retVal = _pRet ;
return hr ;
} , _taskOptinos ) ;
}
# pragma warning(pop)
template < typename _Function >
static task < _ReturnType > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < _ReturnType > ( [ = ] ( _ReturnType * retVal ) - > HRESULT {
Concurrency : : details : : _Task_generator_oversubscriber_t _Oversubscriber ;
( _Oversubscriber ) ;
HRESULT hr = _Func ( _Cts . get_token ( ) , _pRet ) ;
retVal = _pRet ;
return hr ;
} , _taskOptinos ) ;
}
template < typename _Function , typename _ProgressObject >
static task < _ReturnType > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < _ReturnType > ( [ = ] ( _ReturnType * retVal ) - > HRESULT {
Concurrency : : details : : _Task_generator_oversubscriber_t _Oversubscriber ;
( _Oversubscriber ) ;
HRESULT hr = _Func ( _Progress , _pRet ) ;
retVal = _pRet ;
return hr ;
} , _taskOptinos ) ;
}
template < typename _Function , typename _ProgressObject >
static task < _ReturnType > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < _ReturnType > ( [ = ] ( _ReturnType * retVal ) - > HRESULT {
Concurrency : : details : : _Task_generator_oversubscriber_t _Oversubscriber ;
( _Oversubscriber ) ;
HRESULT hr = _Func ( _Progress , _Cts . get_token ( ) , _pRet ) ;
retVal = _pRet ;
return hr ;
} , _taskOptinos ) ;
}
# else
template < typename _Function >
static task < _ReturnType > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return task < _ReturnType > ( [ = ] ( _ReturnType * retVal ) - > HRESULT {
_Task_generator_oversubscriber _Oversubscriber ;
HRESULT hr = _Func ( _pRet ) ;
retVal = _pRet ;
return hr ;
} , _Cts . get_token ( ) ) ;
}
template < typename _Function >
static task < _ReturnType > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return task < _ReturnType > ( [ = ] ( _ReturnType * retVal ) - > HRESULT {
_Task_generator_oversubscriber _Oversubscriber ;
HRESULT hr = _Func ( _Cts . get_token ( ) , _pRet ) ;
retVal = _pRet ;
return hr ;
} , _Cts . get_token ( ) ) ;
}
template < typename _Function , typename _ProgressObject >
static task < _ReturnType > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return task < _ReturnType > ( [ = ] ( _ReturnType * retVal ) - > HRESULT {
_Task_generator_oversubscriber _Oversubscriber ;
HRESULT hr = _Func ( _Progress , _pRet ) ;
retVal = _pRet ;
return hr ;
} , _Cts . get_token ( ) ) ;
}
template < typename _Function , typename _ProgressObject >
static task < _ReturnType > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return task < _ReturnType > ( [ = ] ( _ReturnType * retVal ) - > HRESULT {
_Task_generator_oversubscriber _Oversubscriber ;
HRESULT hr = _Func ( _Progress , _Cts . get_token ( ) , _pRet ) ;
retVal = _pRet ;
return hr ;
} , _Cts . get_token ( ) ) ;
}
# endif
} ;
template < >
struct _SelectorTaskGenerator < details : : _TypeSelectorNoAsync , void >
{
# if _MSC_VER >= 1800
template < typename _Function >
static task < void > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < void > ( [ = ] ( ) - > HRESULT {
Concurrency : : details : : _Task_generator_oversubscriber_t _Oversubscriber ;
( _Oversubscriber ) ;
return _Func ( ) ;
} , _taskOptinos ) ;
}
template < typename _Function >
static task < void > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < void > ( [ = ] ( ) - > HRESULT {
Concurrency : : details : : _Task_generator_oversubscriber_t _Oversubscriber ;
( _Oversubscriber ) ;
return _Func ( _Cts . get_token ( ) ) ;
} , _taskOptinos ) ;
}
template < typename _Function , typename _ProgressObject >
static task < void > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < void > ( [ = ] ( ) - > HRESULT {
Concurrency : : details : : _Task_generator_oversubscriber_t _Oversubscriber ;
( _Oversubscriber ) ;
return _Func ( _Progress ) ;
} , _taskOptinos ) ;
}
template < typename _Function , typename _ProgressObject >
static task < void > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
{
task_options _taskOptinos ( _Cts . get_token ( ) ) ;
details : : _get_internal_task_options ( _taskOptinos ) . _set_creation_callstack ( _callstack ) ;
return task < void > ( [ = ] ( ) - > HRESULT {
Concurrency : : details : : _Task_generator_oversubscriber_t _Oversubscriber ;
( _Oversubscriber ) ;
return _Func ( _Progress , _Cts . get_token ( ) ) ;
} , _taskOptinos ) ;
}
# else
template < typename _Function >
static task < void > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts )
{
return task < void > ( [ = ] ( ) - > HRESULT {
_Task_generator_oversubscriber _Oversubscriber ;
return _Func ( ) ;
} , _Cts . get_token ( ) ) ;
}
template < typename _Function >
static task < void > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts )
{
return task < void > ( [ = ] ( ) - > HRESULT {
_Task_generator_oversubscriber _Oversubscriber ;
return _Func ( _Cts . get_token ( ) ) ;
} , _Cts . get_token ( ) ) ;
}
template < typename _Function , typename _ProgressObject >
static task < void > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts )
{
return task < void > ( [ = ] ( ) - > HRESULT {
_Task_generator_oversubscriber _Oversubscriber ;
return _Func ( _Progress ) ;
} , _Cts . get_token ( ) ) ;
}
template < typename _Function , typename _ProgressObject >
static task < void > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts )
{
return task < void > ( [ = ] ( ) - > HRESULT {
_Task_generator_oversubscriber _Oversubscriber ;
return _Func ( _Progress , _Cts . get_token ( ) ) ;
} , _Cts . get_token ( ) ) ;
}
# endif
} ;
//
// Functor returns a task - the task can directly be returned:
//
template < typename _ReturnType >
struct _SelectorTaskGenerator < details : : _TypeSelectorAsyncTask , _ReturnType >
{
template < typename _Function >
# if _MSC_VER >= 1800
static task < _ReturnType > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
# else
static task < _ReturnType > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
# endif
{
task < _ReturnType > _task ;
_Func ( & _task ) ;
return _task ;
}
template < typename _Function >
# if _MSC_VER >= 1800
static task < _ReturnType > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
# else
static task < _ReturnType > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
# endif
{
task < _ReturnType > _task ;
_Func ( _Cts . get_token ( ) , & _task ) ;
return _task ;
}
template < typename _Function , typename _ProgressObject >
# if _MSC_VER >= 1800
static task < _ReturnType > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
# else
static task < _ReturnType > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
# endif
{
task < _ReturnType > _task ;
_Func ( _Progress , & _task ) ;
return _task ;
}
template < typename _Function , typename _ProgressObject >
# if _MSC_VER >= 1800
static task < _ReturnType > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
# else
static task < _ReturnType > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
# endif
{
task < _ReturnType > _task ;
_Func ( _Progress , _Cts . get_token ( ) , & _task ) ;
return _task ;
}
} ;
template < >
struct _SelectorTaskGenerator < details : : _TypeSelectorAsyncTask , void >
{
template < typename _Function >
# if _MSC_VER >= 1800
static task < void > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
# else
static task < void > _GenerateTask_0 ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts )
# endif
{
task < void > _task ;
_Func ( & _task ) ;
return _task ;
}
template < typename _Function >
# if _MSC_VER >= 1800
static task < void > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
# else
static task < void > _GenerateTask_1C ( const _Function & _Func , Concurrency : : cancellation_token_source _Cts )
# endif
{
task < void > _task ;
_Func ( _Cts . get_token ( ) , & _task ) ;
return _task ;
}
template < typename _Function , typename _ProgressObject >
# if _MSC_VER >= 1800
static task < void > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
# else
static task < void > _GenerateTask_1P ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts )
# endif
{
task < void > _task ;
_Func ( _Progress , & _task ) ;
return _task ;
}
template < typename _Function , typename _ProgressObject >
# if _MSC_VER >= 1800
static task < void > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
# else
static task < void > _GenerateTask_2PC ( const _Function & _Func , const _ProgressObject & _Progress , Concurrency : : cancellation_token_source _Cts )
# endif
{
task < void > _task ;
_Func ( _Progress , _Cts . get_token ( ) , & _task ) ;
return _task ;
}
} ;
template < typename _Generator , bool _TakesToken , bool TakesProgress >
struct _TaskGenerator
{
} ;
template < typename _Generator >
struct _TaskGenerator < _Generator , false , false >
{
# if _MSC_VER >= 1800
template < typename _Function , typename _ClassPtr , typename _ProgressType >
static auto _GenerateTaskNoRet ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _callstack ) )
{
( void ) _Ptr ;
return _Generator : : _GenerateTask_0 ( _Func , _Cts , _callstack ) ;
}
template < typename _Function , typename _ClassPtr , typename _ProgressType , typename _ReturnType >
static auto _GenerateTask ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _pRet , _callstack ) )
{
return _Generator : : _GenerateTask_0 ( _Func , _Cts , _pRet , _callstack ) ;
}
# else
template < typename _Function , typename _ClassPtr , typename _ProgressType >
static auto _GenerateTaskNoRet ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts ) )
{
( void ) _Ptr ;
return _Generator : : _GenerateTask_0 ( _Func , _Cts ) ;
}
template < typename _Function , typename _ClassPtr , typename _ProgressType , typename _ReturnType >
static auto _GenerateTask ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _pRet ) )
{
return _Generator : : _GenerateTask_0 ( _Func , _Cts , _pRet ) ;
}
# endif
} ;
template < typename _Generator >
struct _TaskGenerator < _Generator , true , false >
{
# if _MSC_VER >= 1800
template < typename _Function , typename _ClassPtr , typename _ProgressType >
static auto _GenerateTaskNoRet ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _callstack ) )
{
return _Generator : : _GenerateTask_1C ( _Func , _Cts , _callstack ) ;
}
template < typename _Function , typename _ClassPtr , typename _ProgressType , typename _ReturnType >
static auto _GenerateTask ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _pRet , _callstack ) )
{
return _Generator : : _GenerateTask_1C ( _Func , _Cts , _pRet , _callstack ) ;
}
# else
template < typename _Function , typename _ClassPtr , typename _ProgressType >
static auto _GenerateTaskNoRet ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts ) )
{
return _Generator : : _GenerateTask_1C ( _Func , _Cts ) ;
}
template < typename _Function , typename _ClassPtr , typename _ProgressType , typename _ReturnType >
static auto _GenerateTask ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _pRet ) )
{
return _Generator : : _GenerateTask_1C ( _Func , _Cts , _pRet ) ;
}
# endif
} ;
template < typename _Generator >
struct _TaskGenerator < _Generator , false , true >
{
# if _MSC_VER >= 1800
template < typename _Function , typename _ClassPtr , typename _ProgressType >
static auto _GenerateTaskNoRet ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _callstack ) )
{
return _Generator : : _GenerateTask_1P ( _Func , progress_reporter < _ProgressType > : : _CreateReporter ( _Ptr ) , _Cts , _callstack ) ;
}
template < typename _Function , typename _ClassPtr , typename _ProgressType , typename _ReturnType >
static auto _GenerateTask ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _pRet , _callstack ) )
{
return _Generator : : _GenerateTask_1P ( _Func , progress_reporter < _ProgressType > : : _CreateReporter ( _Ptr ) , _Cts , _pRet , _callstack ) ;
}
# else
template < typename _Function , typename _ClassPtr , typename _ProgressType >
static auto _GenerateTaskNoRet ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts ) )
{
return _Generator : : _GenerateTask_1P ( _Func , progress_reporter < _ProgressType > : : _CreateReporter ( _Ptr ) , _Cts ) ;
}
template < typename _Function , typename _ClassPtr , typename _ProgressType , typename _ReturnType >
static auto _GenerateTask ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _pRet ) )
{
return _Generator : : _GenerateTask_1P ( _Func , progress_reporter < _ProgressType > : : _CreateReporter ( _Ptr ) , _Cts , _pRet ) ;
}
# endif
} ;
template < typename _Generator >
struct _TaskGenerator < _Generator , true , true >
{
# if _MSC_VER >= 1800
template < typename _Function , typename _ClassPtr , typename _ProgressType >
static auto _GenerateTaskNoRet ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _callstack ) )
{
return _Generator : : _GenerateTask_2PC ( _Func , progress_reporter < _ProgressType > : : _CreateReporter ( _Ptr ) , _Cts , _callstack ) ;
}
template < typename _Function , typename _ClassPtr , typename _ProgressType , typename _ReturnType >
static auto _GenerateTask ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _pRet , _callstack ) )
{
return _Generator : : _GenerateTask_2PC ( _Func , progress_reporter < _ProgressType > : : _CreateReporter ( _Ptr ) , _Cts , _pRet , _callstack ) ;
}
# else
template < typename _Function , typename _ClassPtr , typename _ProgressType >
static auto _GenerateTaskNoRet ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts ) )
{
return _Generator : : _GenerateTask_2PC ( _Func , progress_reporter < _ProgressType > : : _CreateReporter ( _Ptr ) , _Cts ) ;
}
template < typename _Function , typename _ClassPtr , typename _ProgressType , typename _ReturnType >
static auto _GenerateTask ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
- > decltype ( _Generator : : _GenerateTask_0 ( _Func , _Cts , _pRet ) )
{
return _Generator : : _GenerateTask_2PC ( _Func , progress_reporter < _ProgressType > : : _CreateReporter ( _Ptr ) , _Cts , _pRet ) ;
}
# endif
} ;
// ***************************************************************************
// Async Operation Attributes Classes
//
// These classes are passed through the hierarchy of async base classes in order to hold multiple attributes of a given async construct in
// a single container. An attribute class must define:
//
// Mandatory:
// -------------------------
//
// _AsyncBaseType : The Windows Runtime interface which is being implemented.
// _CompletionDelegateType : The Windows Runtime completion delegate type for the interface.
// _ProgressDelegateType : If _TakesProgress is true, the Windows Runtime progress delegate type for the interface. If it is false, an empty Windows Runtime type.
// _ReturnType : The return type of the async construct (void for actions / non-void for operations)
//
// _TakesProgress : An indication as to whether or not
//
// _Generate_Task : A function adapting the user's function into what's necessary to produce the appropriate task
//
// Optional:
// -------------------------
//
template < typename _Function , typename _ProgressType , typename _ReturnType , typename _TaskTraits , bool _TakesToken , bool _TakesProgress >
struct _AsyncAttributes
{
} ;
template < typename _Function , typename _ProgressType , typename _ReturnType , typename _TaskTraits , bool _TakesToken >
struct _AsyncAttributes < _Function , _ProgressType , _ReturnType , _TaskTraits , _TakesToken , true >
{
typedef typename ABI : : Windows : : Foundation : : IAsyncOperationWithProgress < _ReturnType , _ProgressType > _AsyncBaseType ;
typedef typename ABI : : Windows : : Foundation : : IAsyncOperationProgressHandler < _ReturnType , _ProgressType > _ProgressDelegateType ;
typedef typename ABI : : Windows : : Foundation : : IAsyncOperationWithProgressCompletedHandler < _ReturnType , _ProgressType > _CompletionDelegateType ;
typedef typename _ReturnType _ReturnType ;
typedef typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncOperationWithProgressSelector ( stdx : : declval < _AsyncBaseType * > ( ) ) ) > : : type _ReturnType_abi ;
typedef typename _ProgressType _ProgressType ;
typedef typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncOperationWithProgressProgressSelector ( stdx : : declval < _AsyncBaseType * > ( ) ) ) > : : type _ProgressType_abi ;
typedef typename _TaskTraits : : _AsyncKind _AsyncKind ;
typedef typename _SelectorTaskGenerator < _AsyncKind , _ReturnType > _SelectorTaskGenerator ;
typedef typename _TaskGenerator < _SelectorTaskGenerator , _TakesToken , true > _TaskGenerator ;
static const bool _TakesProgress = true ;
static const bool _TakesToken = _TakesToken ;
template < typename _Function , typename _ClassPtr >
# if _MSC_VER >= 1800
static task < typename _TaskTraits : : _TaskRetType > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
return _TaskGenerator : : _GenerateTask < _Function , _ClassPtr , _ProgressType_abi , _ReturnType > ( _Func , _Ptr , _Cts , _pRet , _callstack ) ;
}
# else
static task < typename _TaskTraits : : _TaskRetType > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return _TaskGenerator : : _GenerateTask < _Function , _ClassPtr , _ProgressType_abi , _ReturnType > ( _Func , _Ptr , _Cts , _pRet ) ;
}
# endif
} ;
template < typename _Function , typename _ProgressType , typename _ReturnType , typename _TaskTraits , bool _TakesToken >
struct _AsyncAttributes < _Function , _ProgressType , _ReturnType , _TaskTraits , _TakesToken , false >
{
typedef typename ABI : : Windows : : Foundation : : IAsyncOperation < _ReturnType > _AsyncBaseType ;
typedef _Zip _ProgressDelegateType ;
typedef typename ABI : : Windows : : Foundation : : IAsyncOperationCompletedHandler < _ReturnType > _CompletionDelegateType ;
typedef typename _ReturnType _ReturnType ;
typedef typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncOperationSelector ( stdx : : declval < _AsyncBaseType * > ( ) ) ) > : : type _ReturnType_abi ;
typedef typename _TaskTraits : : _AsyncKind _AsyncKind ;
typedef typename _SelectorTaskGenerator < _AsyncKind , _ReturnType > _SelectorTaskGenerator ;
typedef typename _TaskGenerator < _SelectorTaskGenerator , _TakesToken , false > _TaskGenerator ;
static const bool _TakesProgress = false ;
static const bool _TakesToken = _TakesToken ;
template < typename _Function , typename _ClassPtr >
# if _MSC_VER >= 1800
static task < typename _TaskTraits : : _TaskRetType > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
return _TaskGenerator : : _GenerateTask < _Function , _ClassPtr , _ProgressType , _ReturnType > ( _Func , _Ptr , _Cts , _pRet , _callstack ) ;
}
# else
static task < typename _TaskTraits : : _TaskRetType > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return _TaskGenerator : : _GenerateTask < _Function , _ClassPtr , _ProgressType , _ReturnType > ( _Func , _Ptr , _Cts , _pRet ) ;
}
# endif
} ;
template < typename _Function , typename _ProgressType , typename _TaskTraits , bool _TakesToken >
struct _AsyncAttributes < _Function , _ProgressType , void , _TaskTraits , _TakesToken , true >
{
typedef typename ABI : : Windows : : Foundation : : IAsyncActionWithProgress < _ProgressType > _AsyncBaseType ;
typedef typename ABI : : Windows : : Foundation : : IAsyncActionProgressHandler < _ProgressType > _ProgressDelegateType ;
typedef typename ABI : : Windows : : Foundation : : IAsyncActionWithProgressCompletedHandler < _ProgressType > _CompletionDelegateType ;
typedef void _ReturnType ;
typedef void _ReturnType_abi ;
typedef typename _ProgressType _ProgressType ;
typedef typename ABI : : Windows : : Foundation : : Internal : : GetAbiType < decltype ( _UnwrapAsyncActionWithProgressSelector ( stdx : : declval < _AsyncBaseType * > ( ) ) ) > : : type _ProgressType_abi ;
typedef typename _TaskTraits : : _AsyncKind _AsyncKind ;
typedef typename _SelectorTaskGenerator < _AsyncKind , _ReturnType > _SelectorTaskGenerator ;
typedef typename _TaskGenerator < _SelectorTaskGenerator , _TakesToken , true > _TaskGenerator ;
static const bool _TakesProgress = true ;
static const bool _TakesToken = _TakesToken ;
# if _MSC_VER >= 1800
template < typename _Function , typename _ClassPtr >
static task < void > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
{
return _TaskGenerator : : _GenerateTaskNoRet < _Function , _ClassPtr , _ProgressType_abi > ( _Func , _Ptr , _Cts , _callstack ) ;
}
template < typename _Function , typename _ClassPtr >
static task < task < void > > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
return _TaskGenerator : : _GenerateTask < _Function , _ClassPtr , _ProgressType_abi > ( _Func , _Ptr , _Cts , _pRet , _callstack ) ;
}
# else
template < typename _Function , typename _ClassPtr >
static task < void > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts )
{
return _TaskGenerator : : _GenerateTaskNoRet < _Function , _ClassPtr , _ProgressType_abi > ( _Func , _Ptr , _Cts ) ;
}
template < typename _Function , typename _ClassPtr >
static task < task < void > > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return _TaskGenerator : : _GenerateTask < _Function , _ClassPtr , _ProgressType_abi > ( _Func , _Ptr , _Cts , _pRet ) ;
}
# endif
} ;
template < typename _Function , typename _ProgressType , typename _TaskTraits , bool _TakesToken >
struct _AsyncAttributes < _Function , _ProgressType , void , _TaskTraits , _TakesToken , false >
{
typedef typename ABI : : Windows : : Foundation : : IAsyncAction _AsyncBaseType ;
typedef _Zip _ProgressDelegateType ;
typedef typename ABI : : Windows : : Foundation : : IAsyncActionCompletedHandler _CompletionDelegateType ;
typedef void _ReturnType ;
typedef void _ReturnType_abi ;
typedef typename _TaskTraits : : _AsyncKind _AsyncKind ;
typedef typename _SelectorTaskGenerator < _AsyncKind , _ReturnType > _SelectorTaskGenerator ;
typedef typename _TaskGenerator < _SelectorTaskGenerator , _TakesToken , false > _TaskGenerator ;
static const bool _TakesProgress = false ;
static const bool _TakesToken = _TakesToken ;
# if _MSC_VER >= 1800
template < typename _Function , typename _ClassPtr >
static task < void > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , const _TaskCreationCallstack & _callstack )
{
return _TaskGenerator : : _GenerateTaskNoRet < _Function , _ClassPtr , _ProgressType > ( _Func , _Ptr , _Cts , _callstack ) ;
}
template < typename _Function , typename _ClassPtr >
static task < task < void > > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet , const _TaskCreationCallstack & _callstack )
{
return _TaskGenerator : : _GenerateTask < _Function , _ClassPtr , _ProgressType > ( _Func , _Ptr , _Cts , _pRet , _callstack ) ;
}
# else
template < typename _Function , typename _ClassPtr >
static task < void > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts )
{
return _TaskGenerator : : _GenerateTaskNoRet < _Function , _ClassPtr , _ProgressType > ( _Func , _Ptr , _Cts ) ;
}
template < typename _Function , typename _ClassPtr >
static task < task < void > > _Generate_Task ( const _Function & _Func , _ClassPtr _Ptr , Concurrency : : cancellation_token_source _Cts , _ReturnType * _pRet )
{
return _TaskGenerator : : _GenerateTask < _Function , _ClassPtr , _ProgressType > ( _Func , _Ptr , _Cts , _pRet ) ;
}
# endif
} ;
template < typename _Function >
struct _AsyncLambdaTypeTraits
{
typedef typename _Unhat < typename _CAFunctorOptions < _Function > : : _ReturnType > : : _Value _ReturnType ;
typedef typename _FunctorTypeTraits < _Function > : : _Argument1Type _Argument1Type ;
typedef typename _CAFunctorOptions < _Function > : : _ProgressType _ProgressType ;
static const bool _TakesProgress = _CAFunctorOptions < _Function > : : _TakesProgress ;
static const bool _TakesToken = _CAFunctorOptions < _Function > : : _TakesToken ;
typedef typename _TaskTypeTraits < _ReturnType > _TaskTraits ;
typedef typename _AsyncAttributes < _Function , _ProgressType , typename _TaskTraits : : _TaskRetType , _TaskTraits , _TakesToken , _TakesProgress > _AsyncAttributes ;
} ;
// ***************************************************************************
// AsyncInfo (and completion) Layer:
//
# ifndef RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoBase_DEFINED
# define RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoBase_DEFINED
extern const __declspec ( selectany ) WCHAR RuntimeClass_Concurrency_winrt_details__AsyncInfoBase [ ] = L " Concurrency_winrt.details._AsyncInfoBase " ;
# endif
//
// Internal base class implementation for async operations (based on internal Windows representation for ABI level async operations)
//
template < typename _Attributes , _AsyncResultType resultType = SingleResult >
class _AsyncInfoBase abstract : public Microsoft : : WRL : : RuntimeClass <
Microsoft : : WRL : : RuntimeClassFlags < Microsoft : : WRL : : RuntimeClassType : : WinRt > , Microsoft : : WRL : : Implements < typename _Attributes : : _AsyncBaseType , ABI : : Windows : : Foundation : : IAsyncInfo > >
{
InspectableClass ( RuntimeClass_Concurrency_winrt_details__AsyncInfoBase , BaseTrust )
public :
_AsyncInfoBase ( ) :
_M_currentStatus ( _AsyncStatusInternal : : _AsyncCreated ) ,
_M_errorCode ( S_OK ) ,
_M_completeDelegate ( nullptr ) ,
_M_CompleteDelegateAssigned ( 0 ) ,
_M_CallbackMade ( 0 )
{
# if _MSC_VER < 1800
_M_id = Concurrency : : details : : _GetNextAsyncId ( ) ;
# else
_M_id = Concurrency : : details : : platform : : GetNextAsyncId ( ) ;
# endif
}
public :
virtual STDMETHODIMP GetResults ( typename _Attributes : : _ReturnType_abi * results )
{
( void ) results ;
return E_UNEXPECTED ;
}
virtual STDMETHODIMP get_Id ( unsigned int * id )
{
HRESULT hr = _CheckValidStateForAsyncInfoCall ( ) ;
if ( FAILED ( hr ) ) return hr ;
if ( ! id ) return E_POINTER ;
* id = _M_id ;
return S_OK ;
}
virtual STDMETHODIMP put_Id ( unsigned int id )
{
HRESULT hr = _CheckValidStateForAsyncInfoCall ( ) ;
if ( FAILED ( hr ) ) return hr ;
if ( id = = 0 )
{
return E_INVALIDARG ;
}
else if ( _M_currentStatus ! = _AsyncStatusInternal : : _AsyncCreated )
{
return E_ILLEGAL_METHOD_CALL ;
}
_M_id = id ;
return S_OK ;
}
virtual STDMETHODIMP get_Status ( ABI : : Windows : : Foundation : : AsyncStatus * status )
{
HRESULT hr = _CheckValidStateForAsyncInfoCall ( ) ;
if ( FAILED ( hr ) ) return hr ;
if ( ! status ) return E_POINTER ;
_AsyncStatusInternal _Current = _M_currentStatus ;
//
// Map our internal cancel pending to cancelled. This way "pending cancelled" looks to the outside as "cancelled" but
// can still transition to "completed" if the operation completes without acknowledging the cancellation request
//
switch ( _Current )
{
case _AsyncCancelPending :
_Current = _AsyncCanceled ;
break ;
case _AsyncCreated :
_Current = _AsyncStarted ;
break ;
default :
break ;
}
* status = static_cast < ABI : : Windows : : Foundation : : AsyncStatus > ( _Current ) ;
return S_OK ;
}
virtual STDMETHODIMP get_ErrorCode ( HRESULT * errorCode )
{
HRESULT hr = _CheckValidStateForAsyncInfoCall ( ) ;
if ( FAILED ( hr ) ) return hr ;
if ( ! hr ) return hr ;
* errorCode = _M_errorCode ;
return S_OK ;
}
virtual STDMETHODIMP get_Progress ( typename _Attributes : : _ProgressDelegateType * * _ProgressHandler )
{
return _GetOnProgress ( _ProgressHandler ) ;
}
virtual STDMETHODIMP put_Progress ( typename _Attributes : : _ProgressDelegateType * _ProgressHandler )
{
return _PutOnProgress ( _ProgressHandler ) ;
}
virtual STDMETHODIMP Cancel ( )
{
if ( _TransitionToState ( _AsyncCancelPending ) )
{
_OnCancel ( ) ;
}
return S_OK ;
}
virtual STDMETHODIMP Close ( )
{
if ( _TransitionToState ( _AsyncClosed ) )
{
_OnClose ( ) ;
}
else
{
if ( _M_currentStatus ! = _AsyncClosed ) // Closed => Closed transition is just ignored
{
return E_ILLEGAL_STATE_CHANGE ;
}
}
return S_OK ;
}
virtual STDMETHODIMP get_Completed ( typename _Attributes : : _CompletionDelegateType * * _CompleteHandler )
{
_CheckValidStateForDelegateCall ( ) ;
if ( ! _CompleteHandler ) return E_POINTER ;
* _CompleteHandler = _M_completeDelegate . Get ( ) ;
return S_OK ;
}
virtual STDMETHODIMP put_Completed ( typename _Attributes : : _CompletionDelegateType * _CompleteHandler )
{
_CheckValidStateForDelegateCall ( ) ;
// this delegate property is "write once"
if ( InterlockedIncrement ( & _M_CompleteDelegateAssigned ) = = 1 )
{
_M_completeDelegateContext = _ContextCallback : : _CaptureCurrent ( ) ;
_M_completeDelegate = _CompleteHandler ;
// Guarantee that the write of _M_completeDelegate is ordered with respect to the read of state below
// as perceived from _FireCompletion on another thread.
MemoryBarrier ( ) ;
if ( _IsTerminalState ( ) )
{
_FireCompletion ( ) ;
}
}
else
{
return E_ILLEGAL_DELEGATE_ASSIGNMENT ;
}
return S_OK ;
}
protected :
// _Start - this is not externally visible since async operations "hot start" before returning to the caller
STDMETHODIMP _Start ( )
{
if ( _TransitionToState ( _AsyncStarted ) )
{
_OnStart ( ) ;
}
else
{
return E_ILLEGAL_STATE_CHANGE ;
}
return S_OK ;
}
HRESULT _FireCompletion ( )
{
HRESULT hr = S_OK ;
_TryTransitionToCompleted ( ) ;
// we guarantee that completion can only ever be fired once
if ( _M_completeDelegate ! = nullptr & & InterlockedIncrement ( & _M_CallbackMade ) = = 1 )
{
hr = _M_completeDelegateContext . _CallInContext ( [ = ] ( ) - > HRESULT {
ABI : : Windows : : Foundation : : AsyncStatus status ;
HRESULT hr ;
if ( SUCCEEDED ( hr = this - > get_Status ( & status ) ) )
_M_completeDelegate - > Invoke ( ( _Attributes : : _AsyncBaseType * ) this , status ) ;
_M_completeDelegate = nullptr ;
return hr ;
} ) ;
}
return hr ;
}
virtual STDMETHODIMP _GetOnProgress ( typename _Attributes : : _ProgressDelegateType * * _ProgressHandler )
{
( void ) _ProgressHandler ;
return E_UNEXPECTED ;
}
virtual STDMETHODIMP _PutOnProgress ( typename _Attributes : : _ProgressDelegateType * _ProgressHandler )
{
( void ) _ProgressHandler ;
return E_UNEXPECTED ;
}
bool _TryTransitionToCompleted ( )
{
return _TransitionToState ( _AsyncStatusInternal : : _AsyncCompleted ) ;
}
bool _TryTransitionToCancelled ( )
{
return _TransitionToState ( _AsyncStatusInternal : : _AsyncCanceled ) ;
}
bool _TryTransitionToError ( const HRESULT error )
{
_InterlockedCompareExchange ( reinterpret_cast < volatile LONG * > ( & _M_errorCode ) , error , S_OK ) ;
return _TransitionToState ( _AsyncStatusInternal : : _AsyncError ) ;
}
// This method checks to see if the delegate properties can be
// modified in the current state and generates the appropriate
// error hr in the case of violation.
inline HRESULT _CheckValidStateForDelegateCall ( )
{
if ( _M_currentStatus = = _AsyncClosed )
{
return E_ILLEGAL_METHOD_CALL ;
}
return S_OK ;
}
// This method checks to see if results can be collected in the
// current state and generates the appropriate error hr in
// the case of a violation.
inline HRESULT _CheckValidStateForResultsCall ( )
{
_AsyncStatusInternal _Current = _M_currentStatus ;
if ( _Current = = _AsyncError )
{
return _M_errorCode ;
}
# pragma warning(push)
# pragma warning(disable: 4127) // Conditional expression is constant
// single result illegal before transition to Completed or Cancelled state
if ( resultType = = SingleResult )
# pragma warning(pop)
{
if ( _Current ! = _AsyncCompleted )
{
return E_ILLEGAL_METHOD_CALL ;
}
}
// multiple results can be called after Start has been called and before/after Completed
else if ( _Current ! = _AsyncStarted & &
_Current ! = _AsyncCancelPending & &
_Current ! = _AsyncCanceled & &
_Current ! = _AsyncCompleted )
{
return E_ILLEGAL_METHOD_CALL ;
}
return S_OK ;
}
// This method can be called by derived classes periodically to determine
// whether the asynchronous operation should continue processing or should
// be halted.
inline bool _ContinueAsyncOperation ( )
{
return _M_currentStatus = = _AsyncStarted ;
}
// These two methods are used to allow the async worker implementation do work on
// state transitions. No real "work" should be done in these methods. In other words
// they should not block for a long time on UI timescales.
virtual void _OnStart ( ) = 0 ;
virtual void _OnClose ( ) = 0 ;
virtual void _OnCancel ( ) = 0 ;
private :
// This method is used to check if calls to the AsyncInfo properties
// (id, status, errorcode) are legal in the current state. It also
// generates the appropriate error hr to return in the case of an
// illegal call.
inline HRESULT _CheckValidStateForAsyncInfoCall ( )
{
_AsyncStatusInternal _Current = _M_currentStatus ;
if ( _Current = = _AsyncClosed )
{
return E_ILLEGAL_METHOD_CALL ;
}
else if ( _Current = = _AsyncCreated )
{
return E_ASYNC_OPERATION_NOT_STARTED ;
}
return S_OK ;
}
inline bool _TransitionToState ( const _AsyncStatusInternal _NewState )
{
_AsyncStatusInternal _Current = _M_currentStatus ;
// This enforces the valid state transitions of the asynchronous worker object
// state machine.
switch ( _NewState )
{
case _AsyncStatusInternal : : _AsyncStarted :
if ( _Current ! = _AsyncCreated )
{
return false ;
}
break ;
case _AsyncStatusInternal : : _AsyncCompleted :
if ( _Current ! = _AsyncStarted & & _Current ! = _AsyncCancelPending )
{
return false ;
}
break ;
case _AsyncStatusInternal : : _AsyncCancelPending :
if ( _Current ! = _AsyncStarted )
{
return false ;
}
break ;
case _AsyncStatusInternal : : _AsyncCanceled :
if ( _Current ! = _AsyncStarted & & _Current ! = _AsyncCancelPending )
{
return false ;
}
break ;
case _AsyncStatusInternal : : _AsyncError :
if ( _Current ! = _AsyncStarted & & _Current ! = _AsyncCancelPending )
{
return false ;
}
break ;
case _AsyncStatusInternal : : _AsyncClosed :
if ( ! _IsTerminalState ( _Current ) )
{
return false ;
}
break ;
default :
return false ;
break ;
}
// attempt the transition to the new state
// Note: if currentStatus_ == _Current, then there was no intervening write
// by the async work object and the swap succeeded.
_AsyncStatusInternal _RetState = static_cast < _AsyncStatusInternal > (
_InterlockedCompareExchange ( reinterpret_cast < volatile LONG * > ( & _M_currentStatus ) ,
_NewState ,
static_cast < LONG > ( _Current ) ) ) ;
// ICE returns the former state, if the returned state and the
// state we captured at the beginning of this method are the same,
// the swap succeeded.
return ( _RetState = = _Current ) ;
}
inline bool _IsTerminalState ( )
{
return _IsTerminalState ( _M_currentStatus ) ;
}
inline bool _IsTerminalState ( _AsyncStatusInternal status )
{
return ( status = = _AsyncError | |
status = = _AsyncCanceled | |
status = = _AsyncCompleted | |
status = = _AsyncClosed ) ;
}
private :
_ContextCallback _M_completeDelegateContext ;
Microsoft : : WRL : : ComPtr < typename _Attributes : : _CompletionDelegateType > _M_completeDelegate ; //ComPtr cannot be volatile as it does not have volatile accessors
_AsyncStatusInternal volatile _M_currentStatus ;
HRESULT volatile _M_errorCode ;
unsigned int _M_id ;
long volatile _M_CompleteDelegateAssigned ;
long volatile _M_CallbackMade ;
} ;
// ***************************************************************************
// Progress Layer (optional):
//
template < typename _Attributes , bool _HasProgress , _AsyncResultType _ResultType = SingleResult >
class _AsyncProgressBase abstract : public _AsyncInfoBase < _Attributes , _ResultType >
{
} ;
template < typename _Attributes , _AsyncResultType _ResultType >
class _AsyncProgressBase < _Attributes , true , _ResultType > abstract : public _AsyncInfoBase < _Attributes , _ResultType >
{
public :
_AsyncProgressBase ( ) : _AsyncInfoBase < _Attributes , _ResultType > ( ) ,
_M_progressDelegate ( nullptr )
{
}
virtual STDMETHODIMP _GetOnProgress ( typename _Attributes : : _ProgressDelegateType * * _ProgressHandler ) override
{
HRESULT hr = _CheckValidStateForDelegateCall ( ) ;
if ( FAILED ( hr ) ) return hr ;
* _ProgressHandler = _M_progressDelegate ;
return S_OK ;
}
virtual STDMETHODIMP _PutOnProgress ( typename _Attributes : : _ProgressDelegateType * _ProgressHandler ) override
{
HRESULT hr = _CheckValidStateForDelegateCall ( ) ;
if ( FAILED ( hr ) ) return hr ;
_M_progressDelegate = _ProgressHandler ;
_M_progressDelegateContext = _ContextCallback : : _CaptureCurrent ( ) ;
return S_OK ;
}
public :
void _FireProgress ( const typename _Attributes : : _ProgressType_abi & _ProgressValue )
{
if ( _M_progressDelegate ! = nullptr )
{
_M_progressDelegateContext . _CallInContext ( [ = ] ( ) - > HRESULT {
_M_progressDelegate - > Invoke ( ( _Attributes : : _AsyncBaseType * ) this , _ProgressValue ) ;
return S_OK ;
} ) ;
}
}
private :
_ContextCallback _M_progressDelegateContext ;
typename _Attributes : : _ProgressDelegateType * _M_progressDelegate ;
} ;
template < typename _Attributes , _AsyncResultType _ResultType = SingleResult >
class _AsyncBaseProgressLayer abstract : public _AsyncProgressBase < _Attributes , _Attributes : : _TakesProgress , _ResultType >
{
} ;
// ***************************************************************************
// Task Adaptation Layer:
//
//
// _AsyncTaskThunkBase provides a bridge between IAsync<Action/Operation> and task.
//
template < typename _Attributes , typename _ReturnType >
class _AsyncTaskThunkBase abstract : public _AsyncBaseProgressLayer < _Attributes >
{
public :
//AsyncAction*
virtual STDMETHODIMP GetResults ( )
{
HRESULT hr = _CheckValidStateForResultsCall ( ) ;
if ( FAILED ( hr ) ) return hr ;
_M_task . get ( ) ;
return S_OK ;
}
public :
typedef task < _ReturnType > _TaskType ;
_AsyncTaskThunkBase ( const _TaskType & _Task )
: _M_task ( _Task )
{
}
_AsyncTaskThunkBase ( )
{
}
# if _MSC_VER < 1800
void _SetTaskCreationAddressHint ( void * _SourceAddressHint )
{
if ( ! ( std : : is_same < _Attributes : : _AsyncKind , _TypeSelectorAsyncTask > : : value ) )
{
// Overwrite the creation address with the return address of create_async unless the
// lambda returned a task. If the create async lambda returns a task, that task is reused and
// we want to preserve its creation address hint.
_M_task . _SetTaskCreationAddressHint ( _SourceAddressHint ) ;
}
}
# endif
protected :
virtual void _OnStart ( ) override
{
_M_task . then ( [ = ] ( _TaskType _Antecedent ) - > HRESULT {
try
{
_Antecedent . get ( ) ;
}
catch ( Concurrency : : task_canceled & )
{
_TryTransitionToCancelled ( ) ;
}
catch ( IRestrictedErrorInfo * & _Ex )
{
HRESULT hr ;
HRESULT _hr ;
hr = _Ex - > GetErrorDetails ( NULL , & _hr , NULL , NULL ) ;
if ( SUCCEEDED ( hr ) ) hr = _hr ;
_TryTransitionToError ( hr ) ;
}
catch ( . . . )
{
_TryTransitionToError ( E_FAIL ) ;
}
return _FireCompletion ( ) ;
} ) ;
}
protected :
_TaskType _M_task ;
Concurrency : : cancellation_token_source _M_cts ;
} ;
template < typename _Attributes , typename _ReturnType , typename _Return >
class _AsyncTaskReturn abstract : public _AsyncTaskThunkBase < _Attributes , _Return >
{
public :
//AsyncOperation*
virtual STDMETHODIMP GetResults ( _ReturnType * results )
{
HRESULT hr = _CheckValidStateForResultsCall ( ) ;
if ( FAILED ( hr ) ) return hr ;
_M_task . get ( ) ;
* results = _M_results ;
return S_OK ;
}
template < typename _Function >
# if _MSC_VER >= 1800
void DoCreateTask ( _Function _func , const _TaskCreationCallstack & _callstack )
{
_M_task = _Attributes : : _Generate_Task ( _func , this , _M_cts , & _M_results , _callstack ) ;
}
# else
void DoCreateTask ( _Function _func )
{
_M_task = _Attributes : : _Generate_Task ( _func , this , _M_cts , & _M_results ) ;
}
# endif
protected :
_ReturnType _M_results ;
} ;
template < typename _Attributes , typename _ReturnType >
class _AsyncTaskReturn < _Attributes , _ReturnType , void > abstract : public _AsyncTaskThunkBase < _Attributes , void >
{
public :
template < typename _Function >
# if _MSC_VER >= 1800
void DoCreateTask ( _Function _func , const _TaskCreationCallstack & _callstack )
{
_M_task = _Attributes : : _Generate_Task ( _func , this , _M_cts , _callstack ) ;
}
# else
void DoCreateTask ( _Function _func )
{
_M_task = _Attributes : : _Generate_Task ( _func , this , _M_cts ) ;
}
# endif
} ;
template < typename _Attributes >
class _AsyncTaskReturn < _Attributes , void , task < void > > abstract : public _AsyncTaskThunkBase < _Attributes , task < void > >
{
public :
template < typename _Function >
# if _MSC_VER >= 1800
void DoCreateTask ( _Function _func , const _TaskCreationCallstack & _callstack )
{
_M_task = _Attributes : : _Generate_Task ( _func , this , _M_cts , & _M_results , _callstack ) ;
}
# else
void DoCreateTask ( _Function _func )
{
_M_task = _Attributes : : _Generate_Task ( _func , this , _M_cts , & _M_results ) ;
}
# endif
protected :
task < void > _M_results ;
} ;
template < typename _Attributes >
class _AsyncTaskThunk : public _AsyncTaskReturn < _Attributes , typename _Attributes : : _ReturnType_abi , typename _Attributes : : _ReturnType >
{
public :
_AsyncTaskThunk ( const _TaskType & _Task ) :
_AsyncTaskThunkBase ( _Task )
{
}
_AsyncTaskThunk ( )
{
}
protected :
virtual void _OnClose ( ) override
{
}
virtual void _OnCancel ( ) override
{
_M_cts . cancel ( ) ;
}
} ;
// ***************************************************************************
// Async Creation Layer:
//
template < typename _Function >
class _AsyncTaskGeneratorThunk : public _AsyncTaskThunk < typename _AsyncLambdaTypeTraits < _Function > : : _AsyncAttributes >
{
public :
typedef typename _AsyncLambdaTypeTraits < _Function > : : _AsyncAttributes _Attributes ;
typedef typename _AsyncTaskThunk < _Attributes > _Base ;
typedef typename _Attributes : : _AsyncBaseType _AsyncBaseType ;
# if _MSC_VER >= 1800
_AsyncTaskGeneratorThunk ( const _Function & _Func , const _TaskCreationCallstack & _callstack ) : _M_func ( _Func ) , _M_creationCallstack ( _callstack )
# else
_AsyncTaskGeneratorThunk ( const _Function & _Func ) : _M_func ( _Func )
# endif
{
// Virtual call here is safe as the class is declared 'sealed'
_Start ( ) ;
}
protected :
//
// The only thing we must do different from the base class is we must spin the hot task on transition from Created->Started. Otherwise,
// let the base thunk handle everything.
//
virtual void _OnStart ( ) override
{
//
// Call the appropriate task generator to actually produce a task of the expected type. This might adapt the user lambda for progress reports,
// wrap the return result in a task, or allow for direct return of a task depending on the form of the lambda.
//
# if _MSC_VER >= 1800
DoCreateTask < _Function > ( _M_func , _M_creationCallstack ) ;
# else
DoCreateTask < _Function > ( _M_func ) ;
# endif
_Base : : _OnStart ( ) ;
}
virtual void _OnCancel ( ) override
{
_Base : : _OnCancel ( ) ;
}
private :
# if _MSC_VER >= 1800
_TaskCreationCallstack _M_creationCallstack ;
# endif
_Function _M_func ;
} ;
} // namespace details
/// <summary>
/// Creates a Windows Runtime asynchronous construct based on a user supplied lambda or function object. The return type of <c>create_async</c> is
/// one of either <c>IAsyncAction^</c>, <c>IAsyncActionWithProgress<TProgress>^</c>, <c>IAsyncOperation<TResult>^</c>, or
/// <c>IAsyncOperationWithProgress<TResult, TProgress>^</c> based on the signature of the lambda passed to the method.
/// </summary>
/// <param name="_Func">
/// The lambda or function object from which to create a Windows Runtime asynchronous construct.
/// </param>
/// <returns>
/// An asynchronous construct represented by an IAsyncAction^, IAsyncActionWithProgress<TProgress>^, IAsyncOperation<TResult>^, or an
/// IAsyncOperationWithProgress<TResult, TProgress>^. The interface returned depends on the signature of the lambda passed into the function.
/// </returns>
/// <remarks>
/// The return type of the lambda determines whether the construct is an action or an operation.
/// <para>Lambdas that return void cause the creation of actions. Lambdas that return a result of type <c>TResult</c> cause the creation of
/// operations of TResult.</para>
/// <para>The lambda may also return a <c>task<TResult></c> which encapsulates the aysnchronous work within itself or is the continuation of
/// a chain of tasks that represent the asynchronous work. In this case, the lambda itself is executed inline, since the tasks are the ones that
/// execute asynchronously, and the return type of the lambda is unwrapped to produce the asynchronous construct returned by <c>create_async</c>.
/// This implies that a lambda that returns a task<void> will cause the creation of actions, and a lambda that returns a task<TResult> will
/// cause the creation of operations of TResult.</para>
/// <para>The lambda may take either zero, one or two arguments. The valid arguments are <c>progress_reporter<TProgress></c> and
/// <c>cancellation_token</c>, in that order if both are used. A lambda without arguments causes the creation of an asynchronous construct without
/// the capability for progress reporting. A lambda that takes a progress_reporter<TProgress> will cause <c>create_async</c> to return an asynchronous
/// construct which reports progress of type TProgress each time the <c>report</c> method of the progress_reporter object is called. A lambda that
/// takes a cancellation_token may use that token to check for cancellation, or pass it to tasks that it creates so that cancellation of the
/// asynchronous construct causes cancellation of those tasks.</para>
/// <para>If the body of the lambda or function object returns a result (and not a task<TResult>), the lamdba will be executed
/// asynchronously within the process MTA in the context of a task the Runtime implicitly creates for it. The <c>IAsyncInfo::Cancel</c> method will
/// cause cancellation of the implicit task.</para>
/// <para>If the body of the lambda returns a task, the lamba executes inline, and by declaring the lambda to take an argument of type
/// <c>cancellation_token</c> you can trigger cancellation of any tasks you create within the lambda by passing that token in when you create them.
/// You may also use the <c>register_callback</c> method on the token to cause the Runtime to invoke a callback when you call <c>IAsyncInfo::Cancel</c> on
/// the async operation or action produced..</para>
/// <para>This function is only available to Windows Store apps.</para>
/// </remarks>
/// <seealso cref="task Class"/>
/// <seealso cref="progress_reporter Class"/>
/// <seealso cref="cancelation_token Class"/>
/**/
template < typename _ReturnType , typename _Function >
__declspec ( noinline ) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
details : : _AsyncTaskGeneratorThunk < _Function > * create_async ( const _Function & _Func )
{
static_assert ( std : : is_same < decltype ( details : : _IsValidCreateAsync < _ReturnType > ( _Func , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ) , std : : true_type > : : value ,
" argument to create_async must be a callable object taking zero, one, two or three arguments " ) ;
# if _MSC_VER >= 1800
Microsoft : : WRL : : ComPtr < details : : _AsyncTaskGeneratorThunk < _Function > > _AsyncInfo = Microsoft : : WRL : : Make < details : : _AsyncTaskGeneratorThunk < _Function > > ( _Func , _CAPTURE_CALLSTACK ( ) ) ;
# else
Microsoft : : WRL : : ComPtr < details : : _AsyncTaskGeneratorThunk < _Function > > _AsyncInfo = Microsoft : : WRL : : Make < details : : _AsyncTaskGeneratorThunk < _Function > > ( _Func ) ;
_AsyncInfo - > _SetTaskCreationAddressHint ( _ReturnAddress ( ) ) ;
# endif
return _AsyncInfo . Detach ( ) ;
}
namespace details
{
# if _MSC_VER < 1800
// Internal API which retrieves the next async id.
_CRTIMP2 unsigned int __cdecl _GetNextAsyncId ( ) ;
# endif
// Helper struct for when_all operators to know when tasks have completed
template < typename _Type >
struct _RunAllParam
{
_RunAllParam ( ) : _M_completeCount ( 0 ) , _M_numTasks ( 0 )
{
}
void _Resize ( size_t _Len , bool _SkipVector = false )
{
_M_numTasks = _Len ;
if ( ! _SkipVector )
# if _MSC_VER >= 1800
{
_M_vector . _Result . resize ( _Len ) ;
}
# else
_M_vector . resize ( _Len ) ;
_M_contexts . resize ( _Len ) ;
# endif
}
task_completion_event < _Unit_type > _M_completed ;
atomic_size_t _M_completeCount ;
# if _MSC_VER >= 1800
_ResultHolder < std : : vector < _Type > > _M_vector ;
_ResultHolder < _Type > _M_mergeVal ;
# else
std : : vector < _Type > _M_vector ;
std : : vector < _ContextCallback > _M_contexts ;
_Type _M_mergeVal ;
# endif
size_t _M_numTasks ;
} ;
# if _MSC_VER >= 1800
template < typename _Type >
struct _RunAllParam < std : : vector < _Type > >
{
_RunAllParam ( ) : _M_completeCount ( 0 ) , _M_numTasks ( 0 )
{
}
void _Resize ( size_t _Len , bool _SkipVector = false )
{
_M_numTasks = _Len ;
if ( ! _SkipVector )
{
_M_vector . resize ( _Len ) ;
}
}
task_completion_event < _Unit_type > _M_completed ;
std : : vector < _ResultHolder < std : : vector < _Type > > > _M_vector ;
atomic_size_t _M_completeCount ;
size_t _M_numTasks ;
} ;
# endif
// Helper struct specialization for void
template < >
# if _MSC_VER >= 1800
struct _RunAllParam < _Unit_type >
# else
struct _RunAllParam < void >
# endif
{
_RunAllParam ( ) : _M_completeCount ( 0 ) , _M_numTasks ( 0 )
{
}
void _Resize ( size_t _Len )
{
_M_numTasks = _Len ;
}
task_completion_event < _Unit_type > _M_completed ;
atomic_size_t _M_completeCount ;
size_t _M_numTasks ;
} ;
inline void _JoinAllTokens_Add ( const Concurrency : : cancellation_token_source & _MergedSrc , Concurrency : : details : : _CancellationTokenState * _PJoinedTokenState )
{
if ( _PJoinedTokenState ! = nullptr & & _PJoinedTokenState ! = Concurrency : : details : : _CancellationTokenState : : _None ( ) )
{
Concurrency : : cancellation_token _T = Concurrency : : cancellation_token : : _FromImpl ( _PJoinedTokenState ) ;
_T . register_callback ( [ = ] ( ) {
_MergedSrc . cancel ( ) ;
} ) ;
}
}
template < typename _ElementType , typename _Function , typename _TaskType >
void _WhenAllContinuationWrapper ( _RunAllParam < _ElementType > * _PParam , _Function _Func , task < _TaskType > & _Task )
{
if ( _Task . _GetImpl ( ) - > _IsCompleted ( ) )
{
_Func ( ) ;
# if _MSC_VER >= 1800
if ( Concurrency : : details : : atomic_increment ( _PParam - > _M_completeCount ) = = _PParam - > _M_numTasks )
# else
if ( _InterlockedIncrementSizeT ( & _PParam - > _M_completeCount ) = = _PParam - > _M_numTasks )
# endif
{
// Inline execute its direct continuation, the _ReturnTask
_PParam - > _M_completed . set ( _Unit_type ( ) ) ;
// It's safe to delete it since all usage of _PParam in _ReturnTask has been finished.
delete _PParam ;
}
}
else
{
_CONCRT_ASSERT ( _Task . _GetImpl ( ) - > _IsCanceled ( ) ) ;
if ( _Task . _GetImpl ( ) - > _HasUserException ( ) )
{
// _Cancel will return false if the TCE is already canceled with or without exception
_PParam - > _M_completed . _Cancel ( _Task . _GetImpl ( ) - > _GetExceptionHolder ( ) ) ;
}
else
{
_PParam - > _M_completed . _Cancel ( ) ;
}
# if _MSC_VER >= 1800
if ( Concurrency : : details : : atomic_increment ( _PParam - > _M_completeCount ) = = _PParam - > _M_numTasks )
# else
if ( _InterlockedIncrementSizeT ( & _PParam - > _M_completeCount ) = = _PParam - > _M_numTasks )
# endif
{
delete _PParam ;
}
}
}
template < typename _ElementType , typename _Iterator >
struct _WhenAllImpl
{
# if _MSC_VER >= 1800
static task < std : : vector < _ElementType > > _Perform ( const task_options & _TaskOptions , _Iterator _Begin , _Iterator _End )
# else
static task < std : : vector < _ElementType > > _Perform ( Concurrency : : details : : _CancellationTokenState * _PTokenState , _Iterator _Begin , _Iterator _End )
# endif
{
# if _MSC_VER >= 1800
Concurrency : : details : : _CancellationTokenState * _PTokenState = _TaskOptions . has_cancellation_token ( ) ? _TaskOptions . get_cancellation_token ( ) . _GetImplValue ( ) : nullptr ;
# endif
auto _PParam = new _RunAllParam < _ElementType > ( ) ;
Concurrency : : cancellation_token_source _MergedSource ;
// Step1: Create task completion event.
# if _MSC_VER >= 1800
task_options _Options ( _TaskOptions ) ;
_Options . set_cancellation_token ( _MergedSource . get_token ( ) ) ;
task < _Unit_type > _All_tasks_completed ( _PParam - > _M_completed , _Options ) ;
# else
task < _Unit_type > _All_tasks_completed ( _PParam - > _M_completed , _MergedSource . get_token ( ) ) ;
# endif
// The return task must be created before step 3 to enforce inline execution.
auto _ReturnTask = _All_tasks_completed . _Then ( [ = ] ( _Unit_type , std : : vector < _ElementType > * retVal ) - > HRESULT {
# if _MSC_VER >= 1800
* retVal = _PParam - > _M_vector . Get ( ) ;
# else
auto _Result = _PParam - > _M_vector ; // copy by value
size_t _Index = 0 ;
for ( auto _It = _Result . begin ( ) ; _It ! = _Result . end ( ) ; + + _It )
{
* _It = _ResultContext < _ElementType > : : _GetValue ( * _It , _PParam - > _M_contexts [ _Index + + ] , false ) ;
}
* retVal = _Result ;
# endif
return S_OK ;
# if _MSC_VER >= 1800
} , nullptr ) ;
# else
} , nullptr , true ) ;
# endif
// Step2: Combine and check tokens, and count elements in range.
if ( _PTokenState )
{
details : : _JoinAllTokens_Add ( _MergedSource , _PTokenState ) ;
_PParam - > _Resize ( static_cast < size_t > ( std : : distance ( _Begin , _End ) ) ) ;
}
else
{
size_t _TaskNum = 0 ;
for ( auto _PTask = _Begin ; _PTask ! = _End ; + + _PTask )
{
_TaskNum + + ;
details : : _JoinAllTokens_Add ( _MergedSource , _PTask - > _GetImpl ( ) - > _M_pTokenState ) ;
}
_PParam - > _Resize ( _TaskNum ) ;
}
// Step3: Check states of previous tasks.
if ( _Begin = = _End )
{
_PParam - > _M_completed . set ( _Unit_type ( ) ) ;
delete _PParam ;
}
else
{
size_t _Index = 0 ;
for ( auto _PTask = _Begin ; _PTask ! = _End ; + + _PTask )
{
if ( _PTask - > is_apartment_aware ( ) )
{
_ReturnTask . _SetAsync ( ) ;
}
_PTask - > _Then ( [ _PParam , _Index ] ( task < _ElementType > _ResultTask ) - > HRESULT {
# if _MSC_VER >= 1800
// Dev10 compiler bug
typedef _ElementType _ElementTypeDev10 ;
auto _PParamCopy = _PParam ;
auto _IndexCopy = _Index ;
auto _Func = [ _PParamCopy , _IndexCopy , & _ResultTask ] ( ) {
_PParamCopy - > _M_vector . _Result [ _IndexCopy ] = _ResultTask . _GetImpl ( ) - > _GetResult ( ) ;
} ;
# else
auto _Func = [ _PParam , _Index , & _ResultTask ] ( ) {
_PParam - > _M_vector [ _Index ] = _ResultTask . _GetImpl ( ) - > _GetResult ( ) ;
_PParam - > _M_contexts [ _Index ] = _ResultContext < _ElementType > : : _GetContext ( false ) ;
} ;
# endif
_WhenAllContinuationWrapper ( _PParam , _Func , _ResultTask ) ;
return S_OK ;
# if _MSC_VER >= 1800
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
# else
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) , false ) ;
# endif
_Index + + ;
}
}
return _ReturnTask ;
}
} ;
template < typename _ElementType , typename _Iterator >
struct _WhenAllImpl < std : : vector < _ElementType > , _Iterator >
{
# if _MSC_VER >= 1800
static task < std : : vector < _ElementType > > _Perform ( const task_options & _TaskOptions , _Iterator _Begin , _Iterator _End )
# else
static task < std : : vector < _ElementType > > _Perform ( Concurrency : : details : : _CancellationTokenState * _PTokenState , _Iterator _Begin , _Iterator _End )
# endif
{
# if _MSC_VER >= 1800
Concurrency : : details : : _CancellationTokenState * _PTokenState = _TaskOptions . has_cancellation_token ( ) ? _TaskOptions . get_cancellation_token ( ) . _GetImplValue ( ) : nullptr ;
# endif
auto _PParam = new _RunAllParam < std : : vector < _ElementType > > ( ) ;
Concurrency : : cancellation_token_source _MergedSource ;
// Step1: Create task completion event.
# if _MSC_VER >= 1800
task_options _Options ( _TaskOptions ) ;
_Options . set_cancellation_token ( _MergedSource . get_token ( ) ) ;
task < _Unit_type > _All_tasks_completed ( _PParam - > _M_completed , _Options ) ;
# else
task < _Unit_type > _All_tasks_completed ( _PParam - > _M_completed , _MergedSource . get_token ( ) ) ;
# endif
// The return task must be created before step 3 to enforce inline execution.
auto _ReturnTask = _All_tasks_completed . _Then ( [ = ] ( _Unit_type , std : : vector < _ElementType > * retVal ) - > HRESULT {
_CONCRT_ASSERT ( _PParam - > _M_completeCount = = _PParam - > _M_numTasks ) ;
std : : vector < _ElementType > _Result ;
for ( size_t _I = 0 ; _I < _PParam - > _M_numTasks ; _I + + )
{
# if _MSC_VER >= 1800
const std : : vector < _ElementType > & _Vec = _PParam - > _M_vector [ _I ] . Get ( ) ;
# else
std : : vector < _ElementType > & _Vec = _PParam - > _M_vector [ _I ] ;
for ( auto _It = _Vec . begin ( ) ; _It ! = _Vec . end ( ) ; + + _It )
{
* _It = _ResultContext < _ElementType > : : _GetValue ( * _It , _PParam - > _M_contexts [ _I ] , false ) ;
}
# endif
_Result . insert ( _Result . end ( ) , _Vec . begin ( ) , _Vec . end ( ) ) ;
}
* retVal = _Result ;
return S_OK ;
# if _MSC_VER >= 1800
} , nullptr ) ;
# else
} , nullptr , true ) ;
# endif
// Step2: Combine and check tokens, and count elements in range.
if ( _PTokenState )
{
details : : _JoinAllTokens_Add ( _MergedSource , _PTokenState ) ;
_PParam - > _Resize ( static_cast < size_t > ( std : : distance ( _Begin , _End ) ) ) ;
}
else
{
size_t _TaskNum = 0 ;
for ( auto _PTask = _Begin ; _PTask ! = _End ; + + _PTask )
{
_TaskNum + + ;
details : : _JoinAllTokens_Add ( _MergedSource , _PTask - > _GetImpl ( ) - > _M_pTokenState ) ;
}
_PParam - > _Resize ( _TaskNum ) ;
}
// Step3: Check states of previous tasks.
if ( _Begin = = _End )
{
_PParam - > _M_completed . set ( _Unit_type ( ) ) ;
delete _PParam ;
}
else
{
size_t _Index = 0 ;
for ( auto _PTask = _Begin ; _PTask ! = _End ; + + _PTask )
{
if ( _PTask - > is_apartment_aware ( ) )
{
_ReturnTask . _SetAsync ( ) ;
}
_PTask - > _Then ( [ _PParam , _Index ] ( task < std : : vector < _ElementType > > _ResultTask ) - > HRESULT {
# if _MSC_VER >= 1800
// Dev10 compiler bug
typedef _ElementType _ElementTypeDev10 ;
auto _PParamCopy = _PParam ;
auto _IndexCopy = _Index ;
auto _Func = [ _PParamCopy , _IndexCopy , & _ResultTask ] ( ) {
_PParamCopy - > _M_vector [ _IndexCopy ] . Set ( _ResultTask . _GetImpl ( ) - > _GetResult ( ) ) ;
} ;
# else
auto _Func = [ _PParam , _Index , & _ResultTask ] ( ) {
_PParam - > _M_vector [ _Index ] = _ResultTask . _GetImpl ( ) - > _GetResult ( ) ;
_PParam - > _M_contexts [ _Index ] = _ResultContext < _ElementType > : : _GetContext ( false ) ;
} ;
# endif
_WhenAllContinuationWrapper ( _PParam , _Func , _ResultTask ) ;
return S_OK ;
# if _MSC_VER >= 1800
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
# else
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) , false ) ;
# endif
_Index + + ;
}
}
return _ReturnTask ;
}
} ;
template < typename _Iterator >
struct _WhenAllImpl < void , _Iterator >
{
# if _MSC_VER >= 1800
static task < void > _Perform ( const task_options & _TaskOptions , _Iterator _Begin , _Iterator _End )
# else
static task < void > _Perform ( Concurrency : : details : : _CancellationTokenState * _PTokenState , _Iterator _Begin , _Iterator _End )
# endif
{
# if _MSC_VER >= 1800
Concurrency : : details : : _CancellationTokenState * _PTokenState = _TaskOptions . has_cancellation_token ( ) ? _TaskOptions . get_cancellation_token ( ) . _GetImplValue ( ) : nullptr ;
# endif
auto _PParam = new _RunAllParam < _Unit_type > ( ) ;
Concurrency : : cancellation_token_source _MergedSource ;
// Step1: Create task completion event.
# if _MSC_VER >= 1800
task_options _Options ( _TaskOptions ) ;
_Options . set_cancellation_token ( _MergedSource . get_token ( ) ) ;
task < _Unit_type > _All_tasks_completed ( _PParam - > _M_completed , _Options ) ;
# else
task < _Unit_type > _All_tasks_completed ( _PParam - > _M_completed , _MergedSource . get_token ( ) ) ;
# endif
// The return task must be created before step 3 to enforce inline execution.
auto _ReturnTask = _All_tasks_completed . _Then ( [ = ] ( _Unit_type ) - > HRESULT { return S_OK ;
# if _MSC_VER >= 1800
} , nullptr ) ;
# else
} , nullptr , false ) ;
# endif
// Step2: Combine and check tokens, and count elements in range.
if ( _PTokenState )
{
details : : _JoinAllTokens_Add ( _MergedSource , _PTokenState ) ;
_PParam - > _Resize ( static_cast < size_t > ( std : : distance ( _Begin , _End ) ) ) ;
}
else
{
size_t _TaskNum = 0 ;
for ( auto _PTask = _Begin ; _PTask ! = _End ; + + _PTask )
{
_TaskNum + + ;
details : : _JoinAllTokens_Add ( _MergedSource , _PTask - > _GetImpl ( ) - > _M_pTokenState ) ;
}
_PParam - > _Resize ( _TaskNum ) ;
}
// Step3: Check states of previous tasks.
if ( _Begin = = _End )
{
_PParam - > _M_completed . set ( _Unit_type ( ) ) ;
delete _PParam ;
}
else
{
for ( auto _PTask = _Begin ; _PTask ! = _End ; + + _PTask )
{
if ( _PTask - > is_apartment_aware ( ) )
{
_ReturnTask . _SetAsync ( ) ;
}
_PTask - > _Then ( [ _PParam ] ( task < void > _ResultTask ) - > HRESULT {
auto _Func = [ ] ( ) - > HRESULT { return S_OK ; } ;
_WhenAllContinuationWrapper ( _PParam , _Func , _ResultTask ) ;
return S_OK ;
# if _MSC_VER >= 1800
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
# else
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) , false ) ;
# endif
}
}
return _ReturnTask ;
}
} ;
template < typename _ReturnType >
task < std : : vector < _ReturnType > > _WhenAllVectorAndValue ( const task < std : : vector < _ReturnType > > & _VectorTask , const task < _ReturnType > & _ValueTask ,
bool _OutputVectorFirst )
{
auto _PParam = new _RunAllParam < _ReturnType > ( ) ;
Concurrency : : cancellation_token_source _MergedSource ;
// Step1: Create task completion event.
task < _Unit_type > _All_tasks_completed ( _PParam - > _M_completed , _MergedSource . get_token ( ) ) ;
// The return task must be created before step 3 to enforce inline execution.
auto _ReturnTask = _All_tasks_completed . _Then ( [ = ] ( _Unit_type , std : : vector < _ReturnType > * retVal ) - > HRESULT {
_CONCRT_ASSERT ( _PParam - > _M_completeCount = = 2 ) ;
# if _MSC_VER >= 1800
auto _Result = _PParam - > _M_vector . Get ( ) ; // copy by value
auto _mergeVal = _PParam - > _M_mergeVal . Get ( ) ;
# else
auto _Result = _PParam - > _M_vector ; // copy by value
for ( auto _It = _Result . begin ( ) ; _It ! = _Result . end ( ) ; + + _It )
{
* _It = _ResultContext < _ReturnType > : : _GetValue ( * _It , _PParam - > _M_contexts [ 0 ] , false ) ;
}
# endif
if ( _OutputVectorFirst = = true )
{
# if _MSC_VER >= 1800
_Result . push_back ( _mergeVal ) ;
# else
_Result . push_back ( _ResultContext < _ReturnType > : : _GetValue ( _PParam - > _M_mergeVal , _PParam - > _M_contexts [ 1 ] , false ) ) ;
# endif
}
else
{
# if _MSC_VER >= 1800
_Result . insert ( _Result . begin ( ) , _mergeVal ) ;
# else
_Result . insert ( _Result . begin ( ) , _ResultContext < _ReturnType > : : _GetValue ( _PParam - > _M_mergeVal , _PParam - > _M_contexts [ 1 ] , false ) ) ;
# endif
}
* retVal = _Result ;
return S_OK ;
} , nullptr , true ) ;
// Step2: Combine and check tokens.
_JoinAllTokens_Add ( _MergedSource , _VectorTask . _GetImpl ( ) - > _M_pTokenState ) ;
_JoinAllTokens_Add ( _MergedSource , _ValueTask . _GetImpl ( ) - > _M_pTokenState ) ;
// Step3: Check states of previous tasks.
_PParam - > _Resize ( 2 , true ) ;
if ( _VectorTask . is_apartment_aware ( ) | | _ValueTask . is_apartment_aware ( ) )
{
_ReturnTask . _SetAsync ( ) ;
}
_VectorTask . _Then ( [ _PParam ] ( task < std : : vector < _ReturnType > > _ResultTask ) - > HRESULT {
# if _MSC_VER >= 1800
// Dev10 compiler bug
typedef _ReturnType _ReturnTypeDev10 ;
auto _PParamCopy = _PParam ;
auto _Func = [ _PParamCopy , & _ResultTask ] ( ) {
auto _ResultLocal = _ResultTask . _GetImpl ( ) - > _GetResult ( ) ;
_PParamCopy - > _M_vector . Set ( _ResultLocal ) ;
} ;
# else
auto _Func = [ _PParam , & _ResultTask ] ( ) {
_PParam - > _M_vector = _ResultTask . _GetImpl ( ) - > _GetResult ( ) ;
_PParam - > _M_contexts [ 0 ] = _ResultContext < _ReturnType > : : _GetContext ( false ) ;
} ;
# endif
_WhenAllContinuationWrapper ( _PParam , _Func , _ResultTask ) ;
return S_OK ;
# if _MSC_VER >= 1800
} , _CancellationTokenState : : _None ( ) ) ;
# else
} , _CancellationTokenState : : _None ( ) , false ) ;
# endif
_ValueTask . _Then ( [ _PParam ] ( task < _ReturnType > _ResultTask ) - > HRESULT {
# if _MSC_VER >= 1800
// Dev10 compiler bug
typedef _ReturnType _ReturnTypeDev10 ;
auto _PParamCopy = _PParam ;
auto _Func = [ _PParamCopy , & _ResultTask ] ( ) {
auto _ResultLocal = _ResultTask . _GetImpl ( ) - > _GetResult ( ) ;
_PParamCopy - > _M_mergeVal . Set ( _ResultLocal ) ;
} ;
# else
auto _Func = [ _PParam , & _ResultTask ] ( ) {
_PParam - > _M_mergeVal = _ResultTask . _GetImpl ( ) - > _GetResult ( ) ;
_PParam - > _M_contexts [ 1 ] = _ResultContext < _ReturnType > : : _GetContext ( false ) ;
} ;
# endif
_WhenAllContinuationWrapper ( _PParam , _Func , _ResultTask ) ;
return S_OK ;
# if _MSC_VER >= 1800
} , _CancellationTokenState : : _None ( ) ) ;
# else
} , _CancellationTokenState : : _None ( ) , false ) ;
# endif
return _ReturnTask ;
}
} // namespace details
# if _MSC_VER < 1800
/// <summary>
/// Creates a task that will complete successfully when all of the tasks supplied as arguments complete successfully.
/// </summary>
/// <typeparam name="_Iterator">
/// The type of the input iterator.
/// </typeparam>
/// <param name="_Begin">
/// The position of the first element in the range of elements to be combined into the resulting task.
/// </param>
/// <param name="_End">
/// The position of the first element beyond the range of elements to be combined into the resulting task.
/// </param>
/// <returns>
/// A task that completes sucessfully when all of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output
/// task will also be a <c>task<void></c>.
/// </returns>
/// <remarks>
/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
/// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
/// </remarks>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _Iterator >
auto when_all ( _Iterator _Begin , _Iterator _End )
- > decltype ( details : : _WhenAllImpl < typename std : : iterator_traits < _Iterator > : : value_type : : result_type , _Iterator > : : _Perform ( nullptr , _Begin , _End ) )
{
typedef typename std : : iterator_traits < _Iterator > : : value_type : : result_type _ElementType ;
return details : : _WhenAllImpl < _ElementType , _Iterator > : : _Perform ( nullptr , _Begin , _End ) ;
}
# endif
/// <summary>
/// Creates a task that will complete successfully when all of the tasks supplied as arguments complete successfully.
/// </summary>
/// <typeparam name="_Iterator">
/// The type of the input iterator.
/// </typeparam>
/// <param name="_Begin">
/// The position of the first element in the range of elements to be combined into the resulting task.
/// </param>
/// <param name="_End">
/// The position of the first element beyond the range of elements to be combined into the resulting task.
/// </param>
/// <param name="_CancellationToken">
/// The cancellation token which controls cancellation of the returned task. If you do not provide a cancellation token, the resulting
/// task will be created with a token that is a combination of all the cancelable tokens (tokens created by methods other than
/// <c>cancellation_token::none()</c>of the tasks supplied.
/// </param>
/// <returns>
/// A task that completes sucessfully when all of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output
/// task will also be a <c>task<void></c>.
/// </returns>
/// <remarks>
/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
/// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
/// </remarks>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _Iterator >
# if _MSC_VER >= 1800
auto when_all ( _Iterator _Begin , _Iterator _End , const task_options & _TaskOptions = task_options ( ) )
- > decltype ( details : : _WhenAllImpl < typename std : : iterator_traits < _Iterator > : : value_type : : result_type , _Iterator > : : _Perform ( _TaskOptions , _Begin , _End ) )
{
typedef typename std : : iterator_traits < _Iterator > : : value_type : : result_type _ElementType ;
return details : : _WhenAllImpl < _ElementType , _Iterator > : : _Perform ( _TaskOptions , _Begin , _End ) ;
}
# else
auto when_all ( _Iterator _Begin , _Iterator _End , Concurrency : : cancellation_token _CancellationToken )
- > decltype ( details : : _WhenAllImpl < typename std : : iterator_traits < _Iterator > : : value_type : : result_type , _Iterator > : : _Perform ( _CancellationToken . _GetImplValue ( ) , _Begin , _End ) )
{
typedef typename std : : iterator_traits < _Iterator > : : value_type : : result_type _ElementType ;
return details : : _WhenAllImpl < _ElementType , _Iterator > : : _Perform ( _CancellationToken . _GetImplValue ( ) , _Begin , _End ) ;
}
# endif
/// <summary>
2015-05-23 21:26:18 +08:00
/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully.
2015-05-15 21:28:25 +08:00
/// </summary>
/// <typeparam name="_ReturnType">
/// The type of the returned task.
/// </typeparam>
/// <param name="_Lhs">
/// The first task to combine into the resulting task.
/// </param>
/// <param name="_Rhs">
/// The second task to combine into the resulting task.
/// </param>
/// <returns>
/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output
/// task will also be a <c>task<void></c>.
/// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator
/// produces a <c>task<std::vector<T>></c> if either one or both of the tasks are of type <c>task<std::vector<T>></c>.</para>
/// </returns>
/// <remarks>
/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
/// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
/// </remarks>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _ReturnType >
task < std : : vector < _ReturnType > > operator & & ( const task < _ReturnType > & _Lhs , const task < _ReturnType > & _Rhs )
{
task < _ReturnType > _PTasks [ 2 ] = { _Lhs , _Rhs } ;
return when_all ( _PTasks , _PTasks + 2 ) ;
}
/// <summary>
2015-05-23 21:26:18 +08:00
/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully.
2015-05-15 21:28:25 +08:00
/// </summary>
/// <typeparam name="_ReturnType">
/// The type of the returned task.
/// </typeparam>
/// <param name="_Lhs">
/// The first task to combine into the resulting task.
/// </param>
/// <param name="_Rhs">
/// The second task to combine into the resulting task.
/// </param>
/// <returns>
/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output
/// task will also be a <c>task<void></c>.
/// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator
/// produces a <c>task<std::vector<T>></c> if either one or both of the tasks are of type <c>task<std::vector<T>></c>.</para>
/// </returns>
/// <remarks>
/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
/// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
/// </remarks>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _ReturnType >
task < std : : vector < _ReturnType > > operator & & ( const task < std : : vector < _ReturnType > > & _Lhs , const task < _ReturnType > & _Rhs )
{
return details : : _WhenAllVectorAndValue ( _Lhs , _Rhs , true ) ;
}
/// <summary>
2015-05-23 21:26:18 +08:00
/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully.
2015-05-15 21:28:25 +08:00
/// </summary>
/// <typeparam name="_ReturnType">
/// The type of the returned task.
/// </typeparam>
/// <param name="_Lhs">
/// The first task to combine into the resulting task.
/// </param>
/// <param name="_Rhs">
/// The second task to combine into the resulting task.
/// </param>
/// <returns>
/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output
/// task will also be a <c>task<void></c>.
/// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator
/// produces a <c>task<std::vector<T>></c> if either one or both of the tasks are of type <c>task<std::vector<T>></c>.</para>
/// </returns>
/// <remarks>
/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
/// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
/// </remarks>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _ReturnType >
task < std : : vector < _ReturnType > > operator & & ( const task < _ReturnType > & _Lhs , const task < std : : vector < _ReturnType > > & _Rhs )
{
return details : : _WhenAllVectorAndValue ( _Rhs , _Lhs , false ) ;
}
/// <summary>
2015-05-23 21:26:18 +08:00
/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully.
2015-05-15 21:28:25 +08:00
/// </summary>
/// <typeparam name="_ReturnType">
/// The type of the returned task.
/// </typeparam>
/// <param name="_Lhs">
/// The first task to combine into the resulting task.
/// </param>
/// <param name="_Rhs">
/// The second task to combine into the resulting task.
/// </param>
/// <returns>
/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output
/// task will also be a <c>task<void></c>.
/// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator
/// produces a <c>task<std::vector<T>></c> if either one or both of the tasks are of type <c>task<std::vector<T>></c>.</para>
/// </returns>
/// <remarks>
/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
/// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
/// </remarks>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _ReturnType >
task < std : : vector < _ReturnType > > operator & & ( const task < std : : vector < _ReturnType > > & _Lhs , const task < std : : vector < _ReturnType > > & _Rhs )
{
task < std : : vector < _ReturnType > > _PTasks [ 2 ] = { _Lhs , _Rhs } ;
return when_all ( _PTasks , _PTasks + 2 ) ;
}
/// <summary>
2015-05-23 21:26:18 +08:00
/// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully.
2015-05-15 21:28:25 +08:00
/// </summary>
/// <typeparam name="_ReturnType">
/// The type of the returned task.
/// </typeparam>
/// <param name="_Lhs">
/// The first task to combine into the resulting task.
/// </param>
/// <param name="_Rhs">
/// The second task to combine into the resulting task.
/// </param>
/// <returns>
/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output
/// task will also be a <c>task<void></c>.
/// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator
/// produces a <c>task<std::vector<T>></c> if either one or both of the tasks are of type <c>task<std::vector<T>></c>.</para>
/// </returns>
/// <remarks>
/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
/// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
/// </remarks>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
inline task < void > operator & & ( const task < void > & _Lhs , const task < void > & _Rhs )
{
task < void > _PTasks [ 2 ] = { _Lhs , _Rhs } ;
return when_all ( _PTasks , _PTasks + 2 ) ;
}
namespace details
{
// Helper struct for when_any operators to know when tasks have completed
template < typename _CompletionType >
struct _RunAnyParam
{
_RunAnyParam ( ) : _M_completeCount ( 0 ) , _M_numTasks ( 0 ) , _M_exceptionRelatedToken ( nullptr ) , _M_fHasExplicitToken ( false )
{
}
~ _RunAnyParam ( )
{
if ( Concurrency : : details : : _CancellationTokenState : : _IsValid ( _M_exceptionRelatedToken ) )
_M_exceptionRelatedToken - > _Release ( ) ;
}
task_completion_event < _CompletionType > _M_Completed ;
Concurrency : : cancellation_token_source _M_cancellationSource ;
Concurrency : : details : : _CancellationTokenState * _M_exceptionRelatedToken ;
atomic_size_t _M_completeCount ;
size_t _M_numTasks ;
bool _M_fHasExplicitToken ;
} ;
template < typename _CompletionType , typename _Function , typename _TaskType >
void _WhenAnyContinuationWrapper ( _RunAnyParam < _CompletionType > * _PParam , const _Function & _Func , task < _TaskType > & _Task )
{
bool _IsTokenCancled = ! _PParam - > _M_fHasExplicitToken & & _Task . _GetImpl ( ) - > _M_pTokenState ! = Concurrency : : details : : _CancellationTokenState : : _None ( ) & & _Task . _GetImpl ( ) - > _M_pTokenState - > _IsCanceled ( ) ;
if ( _Task . _GetImpl ( ) - > _IsCompleted ( ) & & ! _IsTokenCancled )
{
_Func ( ) ;
# if _MSC_VER >= 1800
if ( Concurrency : : details : : atomic_increment ( _PParam - > _M_completeCount ) = = _PParam - > _M_numTasks )
# else
if ( _InterlockedIncrementSizeT ( & _PParam - > _M_completeCount ) = = _PParam - > _M_numTasks )
# endif
{
delete _PParam ;
}
}
else
{
_CONCRT_ASSERT ( _Task . _GetImpl ( ) - > _IsCanceled ( ) | | _IsTokenCancled ) ;
if ( _Task . _GetImpl ( ) - > _HasUserException ( ) & & ! _IsTokenCancled )
{
if ( _PParam - > _M_Completed . _StoreException ( _Task . _GetImpl ( ) - > _GetExceptionHolder ( ) ) )
{
// This can only enter once.
_PParam - > _M_exceptionRelatedToken = _Task . _GetImpl ( ) - > _M_pTokenState ;
_CONCRT_ASSERT ( _PParam - > _M_exceptionRelatedToken ) ;
// Deref token will be done in the _PParam destructor.
if ( _PParam - > _M_exceptionRelatedToken ! = Concurrency : : details : : _CancellationTokenState : : _None ( ) )
{
_PParam - > _M_exceptionRelatedToken - > _Reference ( ) ;
}
}
}
# if _MSC_VER >= 1800
if ( Concurrency : : details : : atomic_increment ( _PParam - > _M_completeCount ) = = _PParam - > _M_numTasks )
# else
if ( _InterlockedIncrementSizeT ( & _PParam - > _M_completeCount ) = = _PParam - > _M_numTasks )
# endif
{
// If no one has be completed so far, we need to make some final cancellation decision.
if ( ! _PParam - > _M_Completed . _IsTriggered ( ) )
{
// If we already explicit token, we can skip the token join part.
if ( ! _PParam - > _M_fHasExplicitToken )
{
if ( _PParam - > _M_exceptionRelatedToken )
{
details : : _JoinAllTokens_Add ( _PParam - > _M_cancellationSource , _PParam - > _M_exceptionRelatedToken ) ;
}
else
{
// If haven't captured any exception token yet, there was no exception for all those tasks,
// so just pick a random token (current one) for normal cancellation.
details : : _JoinAllTokens_Add ( _PParam - > _M_cancellationSource , _Task . _GetImpl ( ) - > _M_pTokenState ) ;
}
}
// Do exception cancellation or normal cancellation based on whether it has stored exception.
_PParam - > _M_Completed . _Cancel ( ) ;
}
delete _PParam ;
}
}
}
template < typename _ElementType , typename _Iterator >
struct _WhenAnyImpl
{
# if _MSC_VER >= 1800
static task < std : : pair < _ElementType , size_t > > _Perform ( const task_options & _TaskOptions , _Iterator _Begin , _Iterator _End )
# else
static task < std : : pair < _ElementType , size_t > > _Perform ( Concurrency : : details : : _CancellationTokenState * _PTokenState , _Iterator _Begin , _Iterator _End )
# endif
{
if ( _Begin = = _End )
{
throw Concurrency : : invalid_operation ( " when_any(begin, end) cannot be called on an empty container. " ) ;
}
# if _MSC_VER >= 1800
Concurrency : : details : : _CancellationTokenState * _PTokenState = _TaskOptions . has_cancellation_token ( ) ? _TaskOptions . get_cancellation_token ( ) . _GetImplValue ( ) : nullptr ;
# endif
auto _PParam = new _RunAnyParam < std : : pair < std : : pair < _ElementType , size_t > , Concurrency : : details : : _CancellationTokenState * > > ( ) ;
if ( _PTokenState )
{
details : : _JoinAllTokens_Add ( _PParam - > _M_cancellationSource , _PTokenState ) ;
_PParam - > _M_fHasExplicitToken = true ;
}
# if _MSC_VER >= 1800
task_options _Options ( _TaskOptions ) ;
_Options . set_cancellation_token ( _PParam - > _M_cancellationSource . get_token ( ) ) ;
task < std : : pair < std : : pair < _ElementType , size_t > , Concurrency : : details : : _CancellationTokenState * > > _Any_tasks_completed ( _PParam - > _M_Completed , _Options ) ;
# else
task < std : : pair < std : : pair < _ElementType , size_t > , Concurrency : : details : : _CancellationTokenState * > > _Any_tasks_completed ( _PParam - > _M_Completed , _PParam - > _M_cancellationSource . get_token ( ) ) ;
_Any_tasks_completed . _GetImpl ( ) - > _M_fRuntimeAggregate = true ;
# endif
// Keep a copy ref to the token source
auto _CancellationSource = _PParam - > _M_cancellationSource ;
_PParam - > _M_numTasks = static_cast < size_t > ( std : : distance ( _Begin , _End ) ) ;
size_t index = 0 ;
for ( auto _PTask = _Begin ; _PTask ! = _End ; + + _PTask )
{
if ( _PTask - > is_apartment_aware ( ) )
{
_Any_tasks_completed . _SetAsync ( ) ;
}
_PTask - > _Then ( [ _PParam , index ] ( task < _ElementType > _ResultTask ) - > HRESULT {
# if _MSC_VER >= 1800
auto _PParamCopy = _PParam ; // Dev10
auto _IndexCopy = index ; // Dev10
auto _Func = [ & _ResultTask , _PParamCopy , _IndexCopy ] ( ) {
_PParamCopy - > _M_Completed . set ( std : : make_pair ( std : : make_pair ( _ResultTask . _GetImpl ( ) - > _GetResult ( ) , _IndexCopy ) , _ResultTask . _GetImpl ( ) - > _M_pTokenState ) ) ;
} ;
# else
auto _Func = [ & _ResultTask , _PParam , index ] ( ) {
_PParam - > _M_Completed . set ( std : : make_pair ( std : : make_pair ( _ResultTask . _GetImpl ( ) - > _GetResult ( ) , index ) , _ResultTask . _GetImpl ( ) - > _M_pTokenState ) ) ;
} ;
# endif
_WhenAnyContinuationWrapper ( _PParam , _Func , _ResultTask ) ;
return S_OK ;
# if _MSC_VER >= 1800
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
# else
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) , false ) ;
# endif
index + + ;
}
// All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.
return _Any_tasks_completed . _Then ( [ = ] ( std : : pair < std : : pair < _ElementType , size_t > , Concurrency : : details : : _CancellationTokenState * > _Result , std : : pair < _ElementType , size_t > * retVal ) - > HRESULT {
_CONCRT_ASSERT ( _Result . second ) ;
if ( ! _PTokenState )
{
details : : _JoinAllTokens_Add ( _CancellationSource , _Result . second ) ;
}
* retVal = _Result . first ;
return S_OK ;
# if _MSC_VER >= 1800
} , nullptr ) ;
# else
} , nullptr , true ) ;
# endif
}
} ;
template < typename _Iterator >
struct _WhenAnyImpl < void , _Iterator >
{
# if _MSC_VER >= 1800
static task < size_t > _Perform ( const task_options & _TaskOptions , _Iterator _Begin , _Iterator _End )
# else
static task < size_t > _Perform ( Concurrency : : details : : _CancellationTokenState * _PTokenState , _Iterator _Begin , _Iterator _End )
# endif
{
if ( _Begin = = _End )
{
throw Concurrency : : invalid_operation ( " when_any(begin, end) cannot be called on an empty container. " ) ;
}
# if _MSC_VER >= 1800
Concurrency : : details : : _CancellationTokenState * _PTokenState = _TaskOptions . has_cancellation_token ( ) ? _TaskOptions . get_cancellation_token ( ) . _GetImplValue ( ) : nullptr ;
# endif
auto _PParam = new _RunAnyParam < std : : pair < size_t , Concurrency : : details : : _CancellationTokenState * > > ( ) ;
if ( _PTokenState )
{
details : : _JoinAllTokens_Add ( _PParam - > _M_cancellationSource , _PTokenState ) ;
_PParam - > _M_fHasExplicitToken = true ;
}
# if _MSC_VER >= 1800
task_options _Options ( _TaskOptions ) ;
_Options . set_cancellation_token ( _PParam - > _M_cancellationSource . get_token ( ) ) ;
task < std : : pair < size_t , _CancellationTokenState * > > _Any_tasks_completed ( _PParam - > _M_Completed , _Options ) ;
# else
task < std : : pair < size_t , Concurrency : : details : : _CancellationTokenState * > > _Any_tasks_completed ( _PParam - > _M_Completed , _PParam - > _M_cancellationSource . get_token ( ) ) ;
# endif
// Keep a copy ref to the token source
auto _CancellationSource = _PParam - > _M_cancellationSource ;
_PParam - > _M_numTasks = static_cast < size_t > ( std : : distance ( _Begin , _End ) ) ;
size_t index = 0 ;
for ( auto _PTask = _Begin ; _PTask ! = _End ; + + _PTask )
{
if ( _PTask - > is_apartment_aware ( ) )
{
_Any_tasks_completed . _SetAsync ( ) ;
}
_PTask - > _Then ( [ _PParam , index ] ( task < void > _ResultTask ) - > HRESULT {
# if _MSC_VER >= 1800
auto _PParamCopy = _PParam ; // Dev10
auto _IndexCopy = index ; // Dev10
auto _Func = [ & _ResultTask , _PParamCopy , _IndexCopy ] ( ) {
_PParamCopy - > _M_Completed . set ( std : : make_pair ( _IndexCopy , _ResultTask . _GetImpl ( ) - > _M_pTokenState ) ) ;
} ;
# else
auto _Func = [ & _ResultTask , _PParam , index ] ( ) {
_PParam - > _M_Completed . set ( std : : make_pair ( index , _ResultTask . _GetImpl ( ) - > _M_pTokenState ) ) ;
} ;
# endif
_WhenAnyContinuationWrapper ( _PParam , _Func , _ResultTask ) ;
return S_OK ;
# if _MSC_VER >= 1800
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
# else
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) , false ) ;
# endif
index + + ;
}
// All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.
return _Any_tasks_completed . _Then ( [ = ] ( std : : pair < size_t , Concurrency : : details : : _CancellationTokenState * > _Result , size_t * retVal ) - > HRESULT {
_CONCRT_ASSERT ( _Result . second ) ;
if ( ! _PTokenState )
{
details : : _JoinAllTokens_Add ( _CancellationSource , _Result . second ) ;
}
* retVal = _Result . first ;
return S_OK ;
# if _MSC_VER >= 1800
} , nullptr ) ;
# else
} , nullptr , false ) ;
# endif
}
} ;
} // namespace details
/// <summary>
/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.
/// </summary>
/// <typeparam name="_Iterator">
/// The type of the input iterator.
/// </typeparam>
/// <param name="_Begin">
/// The position of the first element in the range of elements to be combined into the resulting task.
/// </param>
/// <param name="_End">
/// The position of the first element beyond the range of elements to be combined into the resulting task.
/// </param>
/// <returns>
/// A task that completes successfully when any one of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::pair<T, size_t>>></c>, where the first element of the pair is the result
/// of the completing task, and the second element is the index of the task that finished. If the input tasks are of type <c>void</c>
/// the output is a <c>task<size_t></c>, where the result is the index of the completing task.
/// </returns>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _Iterator >
# if _MSC_VER >= 1800
auto when_any ( _Iterator _Begin , _Iterator _End , const task_options & _TaskOptions = task_options ( ) )
- > decltype ( details : : _WhenAnyImpl < typename std : : iterator_traits < _Iterator > : : value_type : : result_type , _Iterator > : : _Perform ( _TaskOptions , _Begin , _End ) )
{
typedef typename std : : iterator_traits < _Iterator > : : value_type : : result_type _ElementType ;
return details : : _WhenAnyImpl < _ElementType , _Iterator > : : _Perform ( _TaskOptions , _Begin , _End ) ;
}
# else
auto when_any ( _Iterator _Begin , _Iterator _End )
- > decltype ( details : : _WhenAnyImpl < typename std : : iterator_traits < _Iterator > : : value_type : : result_type , _Iterator > : : _Perform ( nullptr , _Begin , _End ) )
{
typedef typename std : : iterator_traits < _Iterator > : : value_type : : result_type _ElementType ;
return details : : _WhenAnyImpl < _ElementType , _Iterator > : : _Perform ( nullptr , _Begin , _End ) ;
}
# endif
/// <summary>
/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.
/// </summary>
/// <typeparam name="_Iterator">
/// The type of the input iterator.
/// </typeparam>
/// <param name="_Begin">
/// The position of the first element in the range of elements to be combined into the resulting task.
/// </param>
/// <param name="_End">
/// The position of the first element beyond the range of elements to be combined into the resulting task.
/// </param>
/// <param name="_CancellationToken">
/// The cancellation token which controls cancellation of the returned task. If you do not provide a cancellation token, the resulting
/// task will receive the cancellation token of the task that causes it to complete.
/// </param>
/// <returns>
/// A task that completes successfully when any one of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::pair<T, size_t>>></c>, where the first element of the pair is the result
/// of the completing task, and the second element is the index of the task that finished. If the input tasks are of type <c>void</c>
/// the output is a <c>task<size_t></c>, where the result is the index of the completing task.
/// </returns>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _Iterator >
auto when_any ( _Iterator _Begin , _Iterator _End , Concurrency : : cancellation_token _CancellationToken )
- > decltype ( details : : _WhenAnyImpl < typename std : : iterator_traits < _Iterator > : : value_type : : result_type , _Iterator > : : _Perform ( _CancellationToken . _GetImplValue ( ) , _Begin , _End ) )
{
typedef typename std : : iterator_traits < _Iterator > : : value_type : : result_type _ElementType ;
return details : : _WhenAnyImpl < _ElementType , _Iterator > : : _Perform ( _CancellationToken . _GetImplValue ( ) , _Begin , _End ) ;
}
/// <summary>
/// Creates a task that will complete successfully when either of the tasks supplied as arguments completes successfully.
/// </summary>
/// <typeparam name="_ReturnType">
/// The type of the returned task.
/// </typeparam>
/// <param name="_Lhs">
/// The first task to combine into the resulting task.
/// </param>
/// <param name="_Rhs">
/// The second task to combine into the resulting task.
/// </param>
/// <returns>
/// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::vector<T></c>. If the input tasks are of type <c>void</c> the output task
/// will also be a <c>task<void></c>.
/// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence
/// over ||, the operator|| produces a <c>task<std::vector<T>></c> if one of the tasks is of type <c>task<std::vector<T>></c>
/// and the other one is of type <c>task<T>.</para>
/// </returns>
/// <remarks>
/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,
/// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.
/// </remarks>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _ReturnType >
task < _ReturnType > operator | | ( const task < _ReturnType > & _Lhs , const task < _ReturnType > & _Rhs )
{
# if _MSC_VER >= 1800
auto _PParam = new details : : _RunAnyParam < std : : pair < _ReturnType , size_t > > ( ) ;
task < std : : pair < _ReturnType , size_t > > _Any_tasks_completed ( _PParam - > _M_Completed , _PParam - > _M_cancellationSource . get_token ( ) ) ;
// Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
// So that _PParam can be used before it getting deleted.
auto _ReturnTask = _Any_tasks_completed . _Then ( [ = ] ( std : : pair < _ReturnType , size_t > _Ret , _ReturnType * retVal ) - > HRESULT {
_CONCRT_ASSERT ( _Ret . second ) ;
details : : _JoinAllTokens_Add ( _PParam - > _M_cancellationSource , reinterpret_cast < Concurrency : : details : : _CancellationTokenState * > ( _Ret . second ) ) ;
* retVal = _Ret . first ;
return S_OK ;
} , nullptr ) ;
# else
auto _PParam = new details : : _RunAnyParam < std : : pair < _ReturnType , Concurrency : : details : : _CancellationTokenState * > > ( ) ;
task < std : : pair < _ReturnType , Concurrency : : details : : _CancellationTokenState * > > _Any_tasks_completed ( _PParam - > _M_Completed , _PParam - > _M_cancellationSource . get_token ( ) ) ;
// Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
// So that _PParam can be used before it getting deleted.
auto _ReturnTask = _Any_tasks_completed . _Then ( [ = ] ( std : : pair < _ReturnType , Concurrency : : details : : _CancellationTokenState * > _Ret , _ReturnType * retVal ) - > HRESULT {
_CONCRT_ASSERT ( _Ret . second ) ;
details : : _JoinAllTokens_Add ( _PParam - > _M_cancellationSource , _Ret . second ) ;
* retVal = _Ret . first ;
return S_OK ;
} , nullptr , false ) ;
# endif
if ( _Lhs . is_apartment_aware ( ) | | _Rhs . is_apartment_aware ( ) )
{
_ReturnTask . _SetAsync ( ) ;
}
_PParam - > _M_numTasks = 2 ;
auto _Continuation = [ _PParam ] ( task < _ReturnType > _ResultTask ) - > HRESULT {
# if _MSC_VER >= 1800
// Dev10 compiler bug
auto _PParamCopy = _PParam ;
auto _Func = [ & _ResultTask , _PParamCopy ] ( ) {
_PParamCopy - > _M_Completed . set ( std : : make_pair ( _ResultTask . _GetImpl ( ) - > _GetResult ( ) , reinterpret_cast < size_t > ( _ResultTask . _GetImpl ( ) - > _M_pTokenState ) ) ) ;
} ;
# else
auto _Func = [ & _ResultTask , _PParam ] ( ) {
_PParam - > _M_Completed . set ( std : : make_pair ( _ResultTask . _GetImpl ( ) - > _GetResult ( ) , _ResultTask . _GetImpl ( ) - > _M_pTokenState ) ) ;
} ;
# endif
_WhenAnyContinuationWrapper ( _PParam , _Func , _ResultTask ) ;
return S_OK ;
} ;
# if _MSC_VER >= 1800
_Lhs . _Then ( _Continuation , Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
_Rhs . _Then ( _Continuation , Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
# else
_Lhs . _Then ( _Continuation , Concurrency : : details : : _CancellationTokenState : : _None ( ) , false ) ;
_Rhs . _Then ( _Continuation , Concurrency : : details : : _CancellationTokenState : : _None ( ) , false ) ;
# endif
return _ReturnTask ;
}
/// <summary>
/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.
/// </summary>
/// <typeparam name="_ReturnType">
/// The type of the returned task.
/// </typeparam>
/// <param name="_Lhs">
/// The first task to combine into the resulting task.
/// </param>
/// <param name="_Rhs">
/// The second task to combine into the resulting task.
/// </param>
/// <returns>
/// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::vector<T></c>. If the input tasks are of type <c>void</c> the output task
/// will also be a <c>task<void></c>.
/// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence
/// over ||, the operator|| produces a <c>task<std::vector<T>></c> if one of the tasks is of type <c>task<std::vector<T>></c>
/// and the other one is of type <c>task<T>.</para>
/// </returns>
/// <remarks>
/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,
/// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.
/// </remarks>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _ReturnType >
task < std : : vector < _ReturnType > > operator | | ( const task < std : : vector < _ReturnType > > & _Lhs , const task < _ReturnType > & _Rhs )
{
auto _PParam = new details : : _RunAnyParam < std : : pair < std : : vector < _ReturnType > , Concurrency : : details : : _CancellationTokenState * > > ( ) ;
task < std : : pair < std : : vector < _ReturnType > , Concurrency : : details : : _CancellationTokenState * > > _Any_tasks_completed ( _PParam - > _M_Completed , _PParam - > _M_cancellationSource . get_token ( ) ) ;
# if _MSC_VER < 1800
_Any_tasks_completed . _GetImpl ( ) - > _M_fRuntimeAggregate = true ;
# endif
// Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
// So that _PParam can be used before it getting deleted.
auto _ReturnTask = _Any_tasks_completed . _Then ( [ = ] ( std : : pair < std : : vector < _ReturnType > , Concurrency : : details : : _CancellationTokenState * > _Ret , std : : vector < _ReturnType > * retVal ) - > HRESULT {
_CONCRT_ASSERT ( _Ret . second ) ;
details : : _JoinAllTokens_Add ( _PParam - > _M_cancellationSource , _Ret . second ) ;
* retVal = _Ret . first ;
return S_OK ;
} , nullptr , true ) ;
if ( _Lhs . is_apartment_aware ( ) | | _Rhs . is_apartment_aware ( ) )
{
_ReturnTask . _SetAsync ( ) ;
}
_PParam - > _M_numTasks = 2 ;
_Lhs . _Then ( [ _PParam ] ( task < std : : vector < _ReturnType > > _ResultTask ) - > HRESULT {
# if _MSC_VER >= 1800
// Dev10 compiler bug
auto _PParamCopy = _PParam ;
auto _Func = [ & _ResultTask , _PParamCopy ] ( ) {
auto _Result = _ResultTask . _GetImpl ( ) - > _GetResult ( ) ;
_PParamCopy - > _M_Completed . set ( std : : make_pair ( _Result , _ResultTask . _GetImpl ( ) - > _M_pTokenState ) ) ;
} ;
# else
auto _Func = [ & _ResultTask , _PParam ] ( ) {
std : : vector < _ReturnType > _Result = _ResultTask . _GetImpl ( ) - > _GetResult ( ) ;
_PParam - > _M_Completed . set ( std : : make_pair ( _Result , _ResultTask . _GetImpl ( ) - > _M_pTokenState ) ) ;
} ;
# endif
_WhenAnyContinuationWrapper ( _PParam , _Func , _ResultTask ) ;
return S_OK ;
# if _MSC_VER >= 1800
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
# else
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) , false ) ;
# endif
_Rhs . _Then ( [ _PParam ] ( task < _ReturnType > _ResultTask ) - > HRESULT {
# if _MSC_VER >= 1800
// Dev10 compiler bug
typedef _ReturnType _ReturnTypeDev10 ;
auto _PParamCopy = _PParam ;
auto _Func = [ & _ResultTask , _PParamCopy ] ( ) {
auto _Result = _ResultTask . _GetImpl ( ) - > _GetResult ( ) ;
std : : vector < _ReturnTypeDev10 > _Vec ;
_Vec . push_back ( _Result ) ;
_PParamCopy - > _M_Completed . set ( std : : make_pair ( _Vec , _ResultTask . _GetImpl ( ) - > _M_pTokenState ) ) ;
} ;
# else
auto _Func = [ & _ResultTask , _PParam ] ( ) {
_ReturnType _Result = _ResultTask . _GetImpl ( ) - > _GetResult ( ) ;
std : : vector < _ReturnType > _Vec ;
_Vec . push_back ( _Result ) ;
_PParam - > _M_Completed . set ( std : : make_pair ( _Vec , _ResultTask . _GetImpl ( ) - > _M_pTokenState ) ) ;
} ;
# endif
_WhenAnyContinuationWrapper ( _PParam , _Func , _ResultTask ) ;
return S_OK ;
# if _MSC_VER >= 1800
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
# else
} , Concurrency : : details : : _CancellationTokenState : : _None ( ) , false ) ;
# endif
return _ReturnTask ;
}
/// <summary>
/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.
/// </summary>
/// <typeparam name="_ReturnType">
/// The type of the returned task.
/// </typeparam>
/// <param name="_Lhs">
/// The first task to combine into the resulting task.
/// </param>
/// <param name="_Rhs">
/// The second task to combine into the resulting task.
/// </param>
/// <returns>
/// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::vector<T></c>. If the input tasks are of type <c>void</c> the output task
/// will also be a <c>task<void></c>.
/// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence
/// over ||, the operator|| produces a <c>task<std::vector<T>></c> if one of the tasks is of type <c>task<std::vector<T>></c>
/// and the other one is of type <c>task<T>.</para>
/// </returns>
/// <remarks>
/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,
/// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.
/// </remarks>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
template < typename _ReturnType >
task < std : : vector < _ReturnType > > operator | | ( const task < _ReturnType > & _Lhs , const task < std : : vector < _ReturnType > > & _Rhs )
{
return _Rhs | | _Lhs ;
}
/// <summary>
/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.
/// </summary>
/// <typeparam name="_ReturnType">
/// The type of the returned task.
/// </typeparam>
/// <param name="_Lhs">
/// The first task to combine into the resulting task.
/// </param>
/// <param name="_Rhs">
/// The second task to combine into the resulting task.
/// </param>
/// <returns>
/// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,
/// the output of this function will be a <c>task<std::vector<T></c>. If the input tasks are of type <c>void</c> the output task
/// will also be a <c>task<void></c>.
/// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence
/// over ||, the operator|| produces a <c>task<std::vector<T>></c> if one of the tasks is of type <c>task<std::vector<T>></c>
/// and the other one is of type <c>task<T>.</para>
/// </returns>
/// <remarks>
/// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,
/// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.
/// </remarks>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
inline task < void > operator | | ( const task < void > & _Lhs , const task < void > & _Rhs )
{
auto _PParam = new details : : _RunAnyParam < std : : pair < details : : _Unit_type , Concurrency : : details : : _CancellationTokenState * > > ( ) ;
task < std : : pair < details : : _Unit_type , Concurrency : : details : : _CancellationTokenState * > > _Any_task_completed ( _PParam - > _M_Completed , _PParam - > _M_cancellationSource . get_token ( ) ) ;
// Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
// So that _PParam can be used before it getting deleted.
auto _ReturnTask = _Any_task_completed . _Then ( [ = ] ( std : : pair < details : : _Unit_type , Concurrency : : details : : _CancellationTokenState * > _Ret ) - > HRESULT {
_CONCRT_ASSERT ( _Ret . second ) ;
details : : _JoinAllTokens_Add ( _PParam - > _M_cancellationSource , _Ret . second ) ;
return S_OK ;
# if _MSC_VER >= 1800
} , nullptr ) ;
# else
} , nullptr , false ) ;
# endif
if ( _Lhs . is_apartment_aware ( ) | | _Rhs . is_apartment_aware ( ) )
{
_ReturnTask . _SetAsync ( ) ;
}
_PParam - > _M_numTasks = 2 ;
auto _Continuation = [ _PParam ] ( task < void > _ResultTask ) mutable - > HRESULT {
// Dev10 compiler needs this.
auto _PParam1 = _PParam ;
auto _Func = [ & _ResultTask , _PParam1 ] ( ) {
_PParam1 - > _M_Completed . set ( std : : make_pair ( details : : _Unit_type ( ) , _ResultTask . _GetImpl ( ) - > _M_pTokenState ) ) ;
} ;
_WhenAnyContinuationWrapper ( _PParam , _Func , _ResultTask ) ;
return S_OK ;
} ;
# if _MSC_VER >= 1800
_Lhs . _Then ( _Continuation , Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
_Rhs . _Then ( _Continuation , Concurrency : : details : : _CancellationTokenState : : _None ( ) ) ;
# else
_Lhs . _Then ( _Continuation , Concurrency : : details : : _CancellationTokenState : : _None ( ) , false ) ;
_Rhs . _Then ( _Continuation , Concurrency : : details : : _CancellationTokenState : : _None ( ) , false ) ;
# endif
return _ReturnTask ;
}
# if _MSC_VER >= 1800
template < typename _Ty >
task < _Ty > task_from_result ( _Ty _Param , const task_options & _TaskOptions = task_options ( ) )
{
task_completion_event < _Ty > _Tce ;
_Tce . set ( _Param ) ;
return create_task < _Ty > ( _Tce , _TaskOptions ) ;
}
// Work around VS 2010 compiler bug
# if _MSC_VER == 1600
inline task < bool > task_from_result ( bool _Param )
{
task_completion_event < bool > _Tce ;
_Tce . set ( _Param ) ;
return create_task < bool > ( _Tce , task_options ( ) ) ;
}
# endif
inline task < void > task_from_result ( const task_options & _TaskOptions = task_options ( ) )
{
task_completion_event < void > _Tce ;
_Tce . set ( ) ;
return create_task < void > ( _Tce , _TaskOptions ) ;
}
template < typename _TaskType , typename _ExType >
task < _TaskType > task_from_exception ( _ExType _Exception , const task_options & _TaskOptions = task_options ( ) )
{
task_completion_event < _TaskType > _Tce ;
_Tce . set_exception ( _Exception ) ;
return create_task < _TaskType > ( _Tce , _TaskOptions ) ;
}
namespace details
{
/// <summary>
/// A convenient extension to Concurrency: loop until a condition is no longer met
/// </summary>
/// <param name="func">
/// A function representing the body of the loop. It will be invoked at least once and
/// then repetitively as long as it returns true.
/// </param>
inline
task < bool > do_while ( std : : function < task < bool > ( void ) > func )
{
task < bool > first = func ( ) ;
return first . then ( [ = ] ( bool guard , task < bool > * retVal ) - > HRESULT {
if ( guard )
* retVal = do_while ( func ) ;
else
* retVal = first ;
return S_OK ;
} ) ;
}
} // namespace details
# endif
} // namespace Concurrency_winrt
namespace concurrency_winrt = Concurrency_winrt ;
# pragma pop_macro("new")
# pragma warning(pop)
# pragma pack(pop)
# endif
# endif