#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.h"
+#endif
#include <windows.foundation.h>
#include <ctxtcall.h>
#ifndef _UITHREADCTXT_SUPPORT
-#ifdef WINAPI_FAMILY
+#ifdef WINAPI_FAMILY /*IFSTRIP=IGN*/
// It is safe to include winapifamily as WINAPI_FAMILY was defined by the user
#include <winapifamily.h>
#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
+#else /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */
#define _UITHREADCTXT_SUPPORT 1
-#endif
+#endif /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */
-#else
+#else /* WINAPI_FAMILY */
// Not supported without a WINAPI_FAMILY setting.
#define _UITHREADCTXT_SUPPORT 0
-#endif // #ifdef WINAPI_FAMILY
+#endif /* WINAPI_FAMILY */
-#endif // #ifndef _UITHREADCTXT_SUPPORT
+#endif /* _UITHREADCTXT_SUPPORT */
#if _UITHREADCTXT_SUPPORT
#include <uithreadctxt.h>
-#endif // _UITHREADCTXT_SUPPORT
+#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
-#define __is_valid_winrt_type(_Type) (std::is_void<_Type>::value || \
- std::is_same<_Type, BYTE>::value || \
- std::is_same<_Type, INT16>::value || \
- std::is_same<_Type, UINT16>::value || \
- std::is_same<_Type, INT32>::value || \
- std::is_same<_Type, UINT32>::value || \
- std::is_same<_Type, INT64>::value || \
- std::is_same<_Type, UINT64>::value || \
- std::is_same<_Type, FLOAT>::value || \
- std::is_same<_Type, DOUBLE>::value || \
- std::is_same<_Type, WCHAR>::value || \
- std::is_same<_Type, boolean>::value || \
- std::is_same<_Type, HSTRING>::value || \
- std::is_same<_Type, IInspectable *>::value || \
- std::is_same<_Type, GUID>::value || \
- std::is_same<_Type, ABI::Windows::Foundation::DateTime>::value || \
- std::is_same<_Type, ABI::Windows::Foundation::TimeSpan>::value || \
- std::is_same<_Type, ABI::Windows::Foundation::Point>::value || \
- std::is_same<_Type, ABI::Windows::Foundation::Size>::value || \
- std::is_same<_Type, ABI::Windows::Foundation::Rect>::value || \
- std::is_same<_Type, BYTE*>::value || \
- std::is_same<_Type, INT16*>::value || \
- std::is_same<_Type, UINT16*>::value || \
- std::is_same<_Type, INT32*>::value || \
- std::is_same<_Type, UINT32*>::value || \
- std::is_same<_Type, INT64*>::value || \
- std::is_same<_Type, UINT64*>::value || \
- std::is_same<_Type, FLOAT*>::value || \
- std::is_same<_Type, DOUBLE*>::value || \
- std::is_same<_Type, WCHAR*>::value || \
- std::is_same<_Type, boolean*>::value || \
- std::is_same<_Type, HSTRING*>::value || \
- std::is_same<_Type, IInspectable **>::value || \
- std::is_same<_Type, GUID*>::value || \
- std::is_same<_Type, ABI::Windows::Foundation::DateTime*>::value || \
- std::is_same<_Type, ABI::Windows::Foundation::TimeSpan*>::value || \
- std::is_same<_Type, ABI::Windows::Foundation::Point*>::value || \
- std::is_same<_Type, ABI::Windows::Foundation::Size*>::value || \
- std::is_same<_Type, ABI::Windows::Foundation::Rect*>::value)
+// 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,
/**/
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"/>
/// <seealso cref="cancellation_token Class"/>
/// <seealso cref="cancel_current_task Function"/>
/**/
-_CRTIMP2 bool __cdecl is_task_cancellation_requested();
+#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
/// <seealso cref="task Class"/>
/// <seealso cref="is_task_cancellation_requested"/>
/**/
-_CRTIMP2 __declspec(noreturn) void __cdecl cancel_current_task();
+//#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 {};
typedef _Type _Value;
};
- struct _NonUserType { public: int _Dummy; };
+ //struct _NonUserType { public: int _Dummy; };
template <typename _Type, bool _IsValueTypeOrRefType = __is_valid_winrt_type(_Type)>
struct _ValueTypeOrRefType
{
- typedef _NonUserType _Value;
+ typedef _Unit_type _Value;
};
template <typename _Type>
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 _Type>
struct _GetProgressType
{
- typedef decltype(_ProgressTypeSelector(std::declval<_Type>())) _Value;
+ typedef decltype(_ProgressTypeSelector(stdx::declval<_Type>())) _Value;
};
- template <template <typename> class F>
- struct conversion_tester
- {
- template <typename T>
- conversion_tester(const F<T> &);
- };
+ template <typename _T>
+ _TypeSelectorAsyncOperation _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperation<_T>*);
- template <template <typename, typename> class F>
- struct conversion_tester2
- {
- template <typename T0, typename T1>
- conversion_tester2(const F<T0, T1> &);
- };
+ _TypeSelectorAsyncAction _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncAction*);
- template <class From, template <typename> class To>
- struct is_instance_of
- {
- static const bool value = std::is_convertible<From, conversion_tester<To>>::value;
- };
+ template <typename _T1, typename _T2>
+ _TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*);
- template <class From, template <typename, typename> class To>
- struct is_instance_of2
- {
- static const bool value = std::is_convertible<From, conversion_tester2<To>>::value;
- };
+ template <typename _T>
+ _TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncActionWithProgress<_T>*);
template <typename _Type>
struct _IsIAsyncInfo
{
- static const bool _Value = std::is_same<ABI::Windows::Foundation::IAsyncAction*, typename _Unhat<_Type>::_Value>::value ||
- is_instance_of<_Type, ABI::Windows::Foundation::IAsyncOperation>::value ||
- is_instance_of2<_Type, ABI::Windows::Foundation::IAsyncOperationWithProgress>::value ||
- is_instance_of<_Type, ABI::Windows::Foundation::IAsyncActionWithProgress>::value;
+ 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 <typename _T>
- _TypeSelectorAsyncOperation _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperation<_T>*);
+ template <>
+ struct _IsIAsyncInfo<void>
+ {
+ static const bool _Value = false;
+ };
- _TypeSelectorAsyncAction _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncAction*);
+ template <typename _Ty>
+ _Ty _UnwrapAsyncOperationSelector(ABI::Windows::Foundation::IAsyncOperation_impl<_Ty>*);
- template <typename _T1, typename _T2>
- _TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*);
+ template <typename _Ty>
+ _Ty _UnwrapAsyncOperationSelector(...);
- template <typename _T>
- _TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncActionWithProgress<_T>*);
+ 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>*);
struct _TaskTypeTraits
{
typedef typename details::_UnwrapTaskType<_Type>::_Type _TaskRetType;
- typedef decltype(_AsyncOperationKindSelector(std::declval<_Type>())) _AsyncKind;
+ typedef _TaskRetType _TaskRetType_abi;
+ typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;
typedef typename details::_NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType;
static const bool _IsAsyncTask = _IsAsync;
template<typename _Type>
struct _TaskTypeTraits<_Type, true>
{
- typedef decltype(_ReturnAsyncOperationKindSelector(std::declval<_Type>())) _TaskRetType;
+ typedef decltype(_ReturnAsyncOperationKindSelector(stdx::declval<_Type>())) _TaskRetType;
+ typedef decltype(_GetUnwrappedType(stdx::declval<_Type>())) _TaskRetType_abi;
typedef _TaskRetType _NormalizedTaskRetType;
- typedef decltype(std::is_same<_Type, ABI::Windows::Foundation::IAsyncAction*>::value ? _TypeSelectorAsyncAction : _AsyncOperationKindSelector((_Type)nullptr)) _AsyncKind;
+ typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;
static const bool _IsAsyncTask = true;
static const bool _IsUnwrappedTaskOrAsync = details::_IsUnwrappedAsyncSelector<_AsyncKind>::_Value;
};
- template <typename _Function> auto _IsCallable(_Function _Func, int) -> decltype(_Func(), std::true_type()) { (void)_Func; return std::true_type(); }
- template <typename _Function> std::false_type _IsCallable(_Function, ...) { return std::false_type(); }
+ 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 _IsUnwrappedTaskOrAsync = false;
};
- template<typename _Type>
- task<_Type> _To_task(_Type t);
+ // ***************************************************************************
+ // Template type traits and helpers for async production APIs:
+ //
- task<void> _To_task();
+ struct _ZeroArgumentFunctor { };
+ struct _OneArgumentFunctor { };
+ struct _TwoArgumentFunctor { };
+ struct _ThreeArgumentFunctor { };
- struct _BadContinuationParamType{};
+ // ****************************************
+ // CLASS TYPES:
- template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)));
- template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, ...) -> decltype(_Func(t));
- template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, ...)->_BadContinuationParamType;
+ // mutable functions
+ // ********************
+ // THREE ARGUMENTS:
- template <typename _Function, typename _Type> auto _IsTaskHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)), std::true_type());
- template <typename _Function, typename _Type> std::false_type _IsTaskHelper(_Type t, _Function _Func, int, ...);
+ // non-void arg:
+ template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+ _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3));
- template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, int) -> decltype(_Func(_To_task()));
- template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, ...) -> decltype(_Func());
+ // non-void arg:
+ template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+ _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3));
- template <typename _Function> auto _VoidIsTaskHelper(_Function _Func, int, int) -> decltype(_Func(_To_task()), std::true_type());
- template <typename _Function> std::false_type _VoidIsTaskHelper(_Function _Func, int, ...);
+ // non-void arg:
+ template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+ _Arg3 _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3));
- template<typename _Function, typename _ExpectedParameterType>
- struct _FunctionTypeTraits
- {
- typedef decltype(_ReturnTypeHelper(std::declval<_ExpectedParameterType>(), std::declval<_Function>(), 0, 0)) _FuncRetType;
- static_assert(!std::is_same<_FuncRetType, _BadContinuationParamType>::value, "incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below)");
+ template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+ _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3));
- typedef decltype(_IsTaskHelper(std::declval<_ExpectedParameterType>(), std::declval<_Function>(), 0, 0)) _Takes_task;
- };
+ template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
+ _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3));
- template<typename _Function>
- struct _FunctionTypeTraits<_Function, void>
- {
- typedef decltype(_VoidReturnTypeHelper(std::declval<_Function>(), 0, 0)) _FuncRetType;
- typedef decltype(_VoidIsTaskHelper(std::declval<_Function>(), 0, 0)) _Takes_task;
- };
+ // ********************
+ // TWO ARGUMENTS:
- template<typename _Function, typename _ReturnType>
- struct _ContinuationTypeTraits
- {
- typedef typename task<typename _TaskTypeTraits<typename _FunctionTypeTraits<_Function, _ReturnType>::_FuncRetType>::_TaskRetType> _TaskOfType;
- };
+ // non-void arg:
+ template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
+ _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2));
- // _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;
- };
+ // non-void arg:
+ template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
+ _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2));
- 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<void()> & _Callback) :
- _M_func(_Callback)
- {
- }
+ // non-void arg:
+ template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
+ void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2));
- static void _Bridge(void *_PData)
- {
- _TaskProcThunk *_PThunk = reinterpret_cast<_TaskProcThunk *>(_PData);
- _PThunk->_M_func();
- delete _PThunk;
- }
- private:
- std::function<void()> _M_func;
- _TaskProcThunk& operator=(const _TaskProcThunk&);
- };
+ template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
+ _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2));
- /// <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>
- static void _ScheduleFuncWithAutoInline(const std::function<void()> & _Func, Concurrency::details::_TaskInliningMode _InliningMode)
- {
- Concurrency::details::_StackGuard _Guard;
- if (_Guard._ShouldInline(_InliningMode))
- {
- _Func();
- }
- else
- {
- Concurrency::details::_CurrentScheduler::_ScheduleTask(reinterpret_cast<Concurrency::TaskProc>(&_TaskProcThunk::_Bridge), new _TaskProcThunk(_Func));
- }
- }
- class _ContextCallback
- {
- typedef std::function<HRESULT(void)> _CallbackFunction;
+ template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
+ _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2));
- public:
+ // ********************
+ // ONE ARGUMENT:
- static _ContextCallback _CaptureCurrent()
- {
- _ContextCallback _Context;
- _Context._Capture();
- return _Context;
- }
+ // non-void arg:
+ template<typename _Class, typename _ReturnType, typename _Arg1>
+ _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1));
- ~_ContextCallback()
- {
- _Reset();
- }
+ // non-void arg:
+ template<typename _Class, typename _ReturnType, typename _Arg1>
+ void _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1));
- _ContextCallback(bool _DeferCapture = false)
- {
- if (_DeferCapture)
- {
- _M_context._M_captureMethod = _S_captureDeferred;
- }
- else
- {
- _M_context._M_pContextCallback = nullptr;
- }
- }
+ // non-void arg:
+ template<typename _Class, typename _ReturnType, typename _Arg1>
+ void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1));
- // 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;
+ template<typename _Class, typename _ReturnType, typename _Arg1>
+ _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1));
- if (_CaptureCurrent)
+ 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())
{
}
// Returns the origin information for the caller (runtime / Windows Runtime apartment as far as task continuations need know)
- bool _IsCurrentOriginSTA()
+ static bool _IsCurrentOriginSTA()
{
APTTYPE _AptType;
APTTYPEQUALIFIER _AptTypeQualifier;
union
{
- IContextCallback *_M_pContextCallback;
- size_t _M_captureMethod;
- } _M_context;
-
- static const size_t _S_captureDeferred = 1;
- };
-
- 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, bool bUnknown = __is_base_of(IUnknown, _Type)>
- struct winrt_type
- {
- };
- template<typename _Type>
- struct winrt_type<_Type, true>
- {
- static IUnknown* create(_Type* _ObjInCtx) {
- return reinterpret_cast<IUnknown*>(_ObjInCtx);
- }
- static IID getuuid() { return __uuidof(_Type); }
- };
- template <typename _Type>
- struct winrt_type<_Type, false>
- {
- static IUnknown* create(_Type* _ObjInCtx) {
- Microsoft::WRL::ComPtr<IInspectable> _PObj;
- Microsoft::WRL::ComPtr<IActivationFactory> objFactory;
- HRESULT hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), objFactory.ReleaseAndGetAddressOf());
- if (FAILED(hr)) return nullptr;
- Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValueStatics> spPropVal;
- if (SUCCEEDED(hr))
- hr = objFactory.As(&spPropVal);
- if (SUCCEEDED(hr)) {
- hr = winrt_type<_Type>::create(spPropVal.Get(), _ObjInCtx, _PObj.GetAddressOf());
- if (SUCCEEDED(hr))
- return reinterpret_cast<IUnknown*>(_PObj.Detach());
- }
- return nullptr;
- }
- static IID getuuid() { return __uuidof(ABI::Windows::Foundation::IPropertyValue); }
- };
-
- template<>
- struct winrt_type<void>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, void* _ObjInCtx, IInspectable** ppInsp) {
- (void)_ObjInCtx;
- return spPropVal->CreateEmpty(ppInsp);
- }
- };
- template<>
- struct winrt_type<BYTE>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, BYTE* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateUInt8(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<INT16>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, INT16* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateInt16(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<UINT16>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT16* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateUInt16(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<INT32>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, INT32* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateInt32(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<UINT32>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateUInt32(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<INT64>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, INT64* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateInt64(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<UINT64>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT64* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateUInt64(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<FLOAT>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, FLOAT* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateSingle(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<DOUBLE>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, DOUBLE* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateDouble(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<WCHAR>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, WCHAR* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateChar16(*_ObjInCtx, ppInsp);
- }
- };
- //template<>
- //struct winrt_type<boolean>
- //{
- // static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, boolean* _ObjInCtx, IInspectable** ppInsp) {
- // return spPropVal->CreateBoolean(*_ObjInCtx, ppInsp);
- // }
- //};
- template<>
- struct winrt_type<HSTRING>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, HSTRING* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateString(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<IInspectable*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, IInspectable** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateInspectable(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<GUID>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, GUID* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateGuid(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<ABI::Windows::Foundation::DateTime>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, ABI::Windows::Foundation::DateTime* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateDateTime(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<ABI::Windows::Foundation::TimeSpan>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, ABI::Windows::Foundation::TimeSpan* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateTimeSpan(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<ABI::Windows::Foundation::Point>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, ABI::Windows::Foundation::Point* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreatePoint(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<ABI::Windows::Foundation::Size>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, ABI::Windows::Foundation::Size* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateSize(*_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_type<ABI::Windows::Foundation::Rect>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, ABI::Windows::Foundation::Rect* _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateRect(*_ObjInCtx, ppInsp);
- }
- };
- template<typename _Type>
- struct winrt_array_type
- {
- static IUnknown* create(_Type* _ObjInCtx, size_t N) {
- Microsoft::WRL::ComPtr<IInspectable> _PObj;
- Microsoft::WRL::ComPtr<IActivationFactory> objFactory;
- HRESULT hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), objFactory.ReleaseAndGetAddressOf());
- if (FAILED(hr)) return nullptr;
- Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValueStatics> spPropVal;
- if (SUCCEEDED(hr))
- hr = objFactory.As(&spPropVal);
- if (SUCCEEDED(hr)) {
- hr = winrt_array_type<_Type>::create(spPropVal.Get(), N, _ObjInCtx, _PObj.GetAddressOf());
- if (SUCCEEDED(hr))
- return reinterpret_cast<IUnknown*>(_PObj.Detach());
- }
- return nullptr;
- }
- };
- template<>
- struct winrt_array_type<BYTE*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, BYTE** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateUInt8Array(__valueSize, *_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_array_type<INT16*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, INT16** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateInt16Array(__valueSize, *_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_array_type<UINT16*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, UINT16** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateUInt16Array(__valueSize, *_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_array_type<INT32*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, INT32** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateInt32Array(__valueSize, *_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_array_type<UINT32*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, UINT32** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateUInt32Array(__valueSize, *_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_array_type<INT64*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, INT64** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateInt64Array(__valueSize, *_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_array_type<UINT64*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, UINT64** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateUInt64Array(__valueSize, *_ObjInCtx, ppInsp);
- }
- };
- template<>
- struct winrt_array_type<FLOAT*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, FLOAT** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateSingleArray(__valueSize, *_ObjInCtx, ppInsp);
- }
+ IContextCallback *_M_pContextCallback;
+ size_t _M_captureMethod;
+ } _M_context;
+
+ static const size_t _S_captureDeferred = 1;
};
- template<>
- struct winrt_array_type<DOUBLE*>
+
+#if _MSC_VER >= 1800
+ template<typename _Type>
+ struct _ResultHolder
{
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, DOUBLE** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateDoubleArray(__valueSize, *_ObjInCtx, ppInsp);
+ void Set(const _Type& _type)
+ {
+ _Result = _type;
}
- };
- template<>
- struct winrt_array_type<WCHAR*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, WCHAR** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateChar16Array(__valueSize, *_ObjInCtx, ppInsp);
+
+ _Type Get()
+ {
+ return _Result;
}
+
+ _Type _Result;
};
- //template<>
- //struct winrt_array_type<boolean*>
- //{
- // static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, boolean** _ObjInCtx, IInspectable** ppInsp) {
- // return spPropVal->CreateBooleanArray(__valueSize, *_ObjInCtx, ppInsp);
- // }
- //};
- template<>
- struct winrt_array_type<HSTRING*>
+
+ template<typename _Type>
+ struct _ResultHolder<_Type*>
{
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, HSTRING** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateStringArray(__valueSize, *_ObjInCtx, ppInsp);
+ void Set(_Type* const & _type)
+ {
+ _M_Result = _type;
}
- };
- template<>
- struct winrt_array_type<IInspectable*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, IInspectable*** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateInspectableArray(__valueSize, *_ObjInCtx, ppInsp);
+
+ _Type* Get()
+ {
+ return _M_Result.Get();
}
+ private:
+ // ::Platform::Agile handle specialization of all hats
+ // including ::Platform::String and ::Platform::Array
+ Agile<_Type*> _M_Result;
};
- template<>
- struct winrt_array_type<GUID>
+
+ //
+ // The below are for composability with tasks auto-created from when_any / when_all / && / || constructs.
+ //
+ template<typename _Type>
+ struct _ResultHolder<std::vector<_Type*>>
{
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, GUID** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateGuidArray(__valueSize, *_ObjInCtx, ppInsp);
+ void Set(const std::vector<_Type*>& _type)
+ {
+ _Result.reserve(_type.size());
+
+ for (auto _PTask = _type.begin(); _PTask != _type.end(); ++_PTask)
+ {
+ _Result.emplace_back(*_PTask);
+ }
}
- };
- template<>
- struct winrt_array_type<ABI::Windows::Foundation::DateTime*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, ABI::Windows::Foundation::DateTime** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateDateTimeArray(__valueSize, *_ObjInCtx, ppInsp);
+
+ 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<>
- struct winrt_array_type<ABI::Windows::Foundation::TimeSpan*>
+
+ template<typename _Type>
+ struct _ResultHolder<std::pair<_Type*, void*> >
{
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, ABI::Windows::Foundation::TimeSpan** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateTimeSpanArray(__valueSize, *_ObjInCtx, ppInsp);
+ void Set(const std::pair<_Type*, size_t>& _type)
+ {
+ _M_Result = _type;
}
- };
- template<>
- struct winrt_array_type<ABI::Windows::Foundation::Point*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, ABI::Windows::Foundation::Point** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreatePointArray(__valueSize, *_ObjInCtx, ppInsp);
+
+ 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;
};
- template<>
- struct winrt_array_type<ABI::Windows::Foundation::Size*>
+#else
+ template<typename _Type>
+ struct _ResultContext
{
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, ABI::Windows::Foundation::Size** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateSizeArray(__valueSize, *_ObjInCtx, ppInsp);
+ static _ContextCallback _GetContext(bool /* _RuntimeAggregate */)
+ {
+ return _ContextCallback();
}
- };
- template<>
- struct winrt_array_type<ABI::Windows::Foundation::Rect*>
- {
- static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, ABI::Windows::Foundation::Rect** _ObjInCtx, IInspectable** ppInsp) {
- return spPropVal->CreateRectArray(__valueSize, *_ObjInCtx, ppInsp);
+
+ static _Type _GetValue(_Type _ObjInCtx, const _ContextCallback & /* _Ctx */, bool /* _RuntimeAggregate */)
+ {
+ return _ObjInCtx;
}
};
{
static _Type* _Perform(_Type* _ObjInCtx, const _ContextCallback& _Ctx)
{
- static_assert(__is_base_of(IUnknown, _Type) || __is_valid_winrt_type(_Type), "must be a COM or WinRT type");
+ 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;
}
};
- // Strings and arrays must be converted to IPropertyValue objects.
+ // 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)
}
}
};
+#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)
{
_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
}
}
{
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)
// 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;
// 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
};
- template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Function>
- struct _AsyncInfoCompletionHandler : public Microsoft::WRL::RuntimeClass<
- Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::ClassicCom>, _CompletionHandlerType>
- {
- MixInHelper()
- public:
- _AsyncInfoCompletionHandler(_Function func) : _M_function(func) {}
- STDMETHODIMP Invoke(_AsyncOperationType *asyncInfo, ABI::Windows::Foundation::AsyncStatus status)
- {
- return _M_function(asyncInfo, status);
- }
- protected:
- _Function _M_function;
- };
+#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
- template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Function>
- __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
- _AsyncInfoCompletionHandler<_AsyncOperationType, _CompletionHandlerType, _Function>* create_completionhandler(const _Function& _Func)
- {
- return Microsoft::WRL::Make<_AsyncInfoCompletionHandler<_AsyncOperationType, _CompletionHandlerType, _Function>>(_Func).Detach();
- }
/// <summary>
/// Base converter class for converting asynchronous interfaces to IAsyncOperation
/// </summary>
- template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Result>
+ 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<ABI::Windows::Foundation::IAsyncOperation<_Result>, Microsoft::WRL::AsyncBase<_CompletionHandlerType>>>
+ 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<ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>> _M_CompletedHandler;
+ Microsoft::WRL::ComPtr<_CompletionHandlerType> _M_CompletedHandler;
- _AsyncInfoImpl(_AsyncOperationType* _AsyncInfo) : _M_asyncInfo(_AsyncInfo), _M_asyncInfoContext(_ContextCallback::_CaptureCurrent()) {}
+ _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;
- if (SUCCEEDED(_M_asyncInfo.As(&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;
- if (SUCCEEDED(_M_asyncInfo.As(&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;
}
{
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;
}
{
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*) { throw std::runtime_error("derived class must implement"); }
+ virtual STDMETHODIMP GetResults(_Result_abi*) { throw std::runtime_error("derived class must implement"); }
- virtual STDMETHODIMP get_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>** handler)
+ virtual STDMETHODIMP get_Completed(_CompletionHandlerType** handler)
{
if (!handler) return E_POINTER;
_M_CompletedHandler.CopyTo(handler);
return S_OK;
}
- virtual STDMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>* value)
+ virtual STDMETHODIMP put_Completed(_CompletionHandlerType* value)
{
_M_CompletedHandler = value;
- return _M_asyncInfo->put_Completed(create_completionhandler<_AsyncOperationType, _CompletionHandlerType>([&](_AsyncOperationType*, ABI::Windows::Foundation::AsyncStatus status) -> HRESULT {
+ 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);
- return _M_CompletedHandler->Invoke(this, status);
- }));
+#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
}
};
/// Class _IAsyncOperationWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncOperationWithProgress<T> into IAsyncOperation<T>
/// </summary>
template<typename _Result, typename _Progress>
- struct _IAsyncOperationWithProgressToAsyncOperationConverter sealed :
+ struct _IAsyncOperationWithProgressToAsyncOperationConverter :
_AsyncInfoImpl<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>,
ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<_Result, _Progress>,
- _Result>
+ 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>(_Operation) {}
+ _Result_abi>(_Operation) {}
public:
- virtual STDMETHODIMP GetResults(_Result* results) override {
+ 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
}
};
/// <summary>
/// Class _IAsyncActionToAsyncOperationConverter is used to convert an instance of IAsyncAction into IAsyncOperation<_Unit_type>
/// </summary>
- struct _IAsyncActionToAsyncOperationConverter sealed :
+ struct _IAsyncActionToAsyncOperationConverter :
_AsyncInfoImpl<ABI::Windows::Foundation::IAsyncAction,
ABI::Windows::Foundation::IAsyncActionCompletedHandler,
_Unit_type>
{
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;
}
/// Class _IAsyncActionWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncActionWithProgress into IAsyncOperation<_Unit_type>
/// </summary>
template<typename _Progress>
- struct _IAsyncActionWithProgressToAsyncOperationConverter sealed :
+ struct _IAsyncActionWithProgressToAsyncOperationConverter :
_AsyncInfoImpl<ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>,
ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler<_Progress>,
_Unit_type>
public:
virtual STDMETHODIMP GetResults(_Unit_type* results) override
{
- if (!result) return E_POINTER;
+ 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;
}
}
};
+#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, typename _Result> struct _Task_impl;
+ template<typename _ReturnType> struct _Task_impl;
- template<typename _ReturnType, typename _Result = details::_Unit_type>
+ template<typename _ReturnType>
struct _Task_ptr
{
- typedef std::shared_ptr<_Task_impl<_ReturnType, _Result>> _Type;
- static _Type _Make(Concurrency::details::_CancellationTokenState * _Ct) { return std::make_shared<_Task_impl<_ReturnType, _Result>>(_Ct); }
+ 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 : Concurrency::details::_UnrealizedChore
+ struct _ContinuationTaskHandleBase : _UnrealizedChore
{
_ContinuationTaskHandleBase * _M_next;
task_continuation_context _M_continuationContext;
bool _M_isTaskBasedContinuation;
// This field gives inlining scheduling policy for current chore.
- Concurrency::details::_TaskInliningMode _M_inliningMode;
+ _TaskInliningMode _M_inliningMode;
virtual _Task_ptr_base _GetTaskImplBase() const = 0;
}
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.
{
_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
}
- virtual ~_PPLTaskHandle() {}
+#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 (!_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.
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)
+ 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.
_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;
{
_M_pTokenState->_Release();
}
-
+#if _MSC_VER < 1800
if (_M_pTaskCollection != nullptr)
{
_M_pTaskCollection->_Release();
_M_pTaskCollection = nullptr;
}
+#endif
}
task_status _Wait()
}
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
{
// 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 exception and canceled the task. Swallow the exception here.
_CONCRT_ASSERT(_IsCanceled());
}
- catch(IRestrictedErrorInfo*& _E)
+ catch (IRestrictedErrorInfo*& _E)
{
// Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.
if(!_HasUserException())
// 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
}
}
}
{
// 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()
_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 _HasUserException()
{
- return _M_exceptionHolder != nullptr;
+ 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());
{
_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;
{
_M_pTaskCreationAddressHint = _AddressHint;
}
-
+#endif
/// <summary>
/// Helper function to schedule the task on the Task Collection.
/// </summary>
/// <param name="_InliningMode">
/// The inlining scheduling policy for current _PTaskHandle.
/// </param>
- void _ScheduleTask(Concurrency::details::_UnrealizedChore * _PTaskHandle, Concurrency::details::_TaskInliningMode _InliningMode)
+ 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 &)
{
// 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>
// (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.
// 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())
{
{
_PTaskHandle->_M_inliningMode = Concurrency::details::_DefaultAutoInline;
}
- details::_ScheduleFuncWithAutoInline([_PTaskHandle]() {
+ 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();
//
try
{
- _PTaskHandle->_M_continuationContext._CallInContext([_PTaskHandle, _TaskImplPtr]() -> HRESULT {
- _TaskImplPtr->_ScheduleTask(_PTaskHandle, Concurrency::details::_ForceInline);
+ // 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)
+ catch (IRestrictedErrorInfo*& _E)
{
_TaskImplPtr->_CancelWithException(_E);
}
_TaskImplPtr->_CancelWithException(std::current_exception());
}
}
+ return S_OK;
}, _PTaskHandle->_M_inliningMode);
}
else
// 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
{
- Concurrency::critical_section::scoped_lock _LockHolder(_M_ContinuationsCritSec);
+ scoped_lock _LockHolder(_M_ContinuationsCritSec);
if (_IsCompleted() || (_IsCanceled() && _PTaskHandle->_M_isTaskBasedContinuation))
{
_Do = _Schedule;
return false;
}
- template<typename _ReturnType, typename _Result>
- static void _AsyncInit(const typename _Task_ptr<_ReturnType, _Result>::_Type & _OuterTask,
- ABI::Windows::Foundation::IAsyncOperation<_Result>* _AsyncOp)
+ 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(create_completionhandler<ABI::Windows::Foundation::IAsyncOperation<_Result>, ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>>(
- [_OuterTask](ABI::Windows::Foundation::IAsyncOperation<_Result>* _Operation, ABI::Windows::Foundation::AsyncStatus _Status) mutable -> HRESULT
+
+ _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;
+ HRESULT _hr;
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
- if (SUCCEEDED(_Operation->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf())) && SUCCEEDED(pAsyncInfo->get_ErrorCode(&hr)))
- _OuterTask->_CancelWithException(std::make_exception_ptr(hr));
+ 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);
- _Result results;
- if (SUCCEEDED(_Operation->GetResults(&results)))
+ _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
// 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, _Result>::_Type &>(_OuterTask).reset();
- return S_OK;
- }));
+ const_cast<_Task_ptr<_ReturnType>::_Type &>(_OuterTask).reset();
+ return hr;
+ }).Get());
_OuterTask->_SetUnwrappedAsyncOp(_AsyncOp);
}
template<typename _ReturnType, typename _InternalReturnType>
// 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) {
+ _UnwrappedTask._Then([_OuterTask](task<_InternalReturnType> _AncestorTask) -> HRESULT {
if (_AncestorTask._GetImpl()->_IsCompleted())
{
_OuterTask->_Cancel(true);
}
}
- }, nullptr, false, details::_DefaultAutoInline);
+ 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
- _TaskInternalState _M_TaskState;
+ 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;
typedef _ContinuationTaskHandleBase * _ContinuationList;
- Concurrency::critical_section _M_ContinuationsCritSec;
+ critical_section _M_ContinuationsCritSec;
_ContinuationList _M_Continuations;
// The cancellation token state.
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&);
};
- template<typename _ReturnType, typename _Result = details::_Unit_type>
+
+#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::IAsyncOperation<_Result> _AsyncOperationType;
+ 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 bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder> & _ExceptionHolder)
{
- bool _RunContinuations = false;
+ enum { _Nothing, _RunContinuations, _Cancel } _Do = _Nothing;
{
- Concurrency::critical_section::scoped_lock _LockHolder(_M_ContinuationsCritSec);
+ 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());
_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.
- _RunContinuations = true;
+ _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.
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.
- Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
- if (SUCCEEDED(_M_unwrapped_async_op.As(&pAsyncInfo)))
- pAsyncInfo->Cancel();
+ 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([=](){ _RunTaskContinuations(); }, Concurrency::details::_DefaultAutoInline);
+ details::_ScheduleFuncWithAutoInline([=]() -> HRESULT { _RunTaskContinuations(); return S_OK; }, Concurrency::details::_DefaultAutoInline);
}
+#if _MSC_VER >= 1800
+ break;
+ }
+#endif
}
return true;
}
void _FinalizeAndRunContinuations(_ReturnType _Result)
{
- _M_Result = _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
//
- Concurrency::critical_section::scoped_lock _LockHolder(_M_ContinuationsCritSec);
+ 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.
// 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();
}
//
//
bool _TransitionedToStarted()
{
- Concurrency::critical_section::scoped_lock _LockHolder(_M_ContinuationsCritSec);
+ 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;
}
}
void _SetUnwrappedAsyncOp(_AsyncOperationType* _AsyncOp)
{
- Concurrency::critical_section::scoped_lock _LockHolder(_M_ContinuationsCritSec);
+ 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());
- Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
- if (SUCCEEDED(_AsyncOp->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(&pAsyncInfo)))
- pAsyncInfo->Cancel();
+ 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)
// We need to protect the loop over the array, so concurrent_vector would not have helped
_TaskList _M_tasks;
- Concurrency::critical_section _M_taskListCritSec;
+ 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<_Unit_type(void)> _MakeVoidToUnitFunc(const std::function<void(void)>& _Func)
+ inline std::function<HRESULT(_Unit_type*)> _MakeVoidToUnitFunc(const std::function<HRESULT(void)>& _Func)
{
- return [=]() -> _Unit_type { _Func(); return _Unit_type(); };
+ return [=](_Unit_type* retVal) -> HRESULT { HRESULT hr = _Func(); *retVal = _Unit_type(); return hr; };
}
template <typename _Type>
- std::function<_Type(_Unit_type)> _MakeUnitToTFunc(const std::function<_Type(void)>& _Func)
+ std::function<HRESULT(_Unit_type, _Type*)> _MakeUnitToTFunc(const std::function<HRESULT(_Type*)>& _Func)
{
- return [=](_Unit_type) -> _Type { return _Func(); };
+ return [=](_Unit_type, _Type* retVal) -> HRESULT { HRESULT hr = _Func(retVal); return hr; };
}
template <typename _Type>
- std::function<_Unit_type(_Type)> _MakeTToUnitFunc(const std::function<void(_Type)>& _Func)
+ std::function<HRESULT(_Type, _Unit_type*)> _MakeTToUnitFunc(const std::function<HRESULT(_Type)>& _Func)
{
- return [=](_Type t) -> _Unit_type { _Func(t); return _Unit_type(); };
+ return[=](_Type t, _Unit_type* retVal) -> HRESULT { HRESULT hr = _Func(t); *retVal = _Unit_type(); return hr; };
}
- inline std::function<_Unit_type(_Unit_type)> _MakeUnitToUnitFunc(const std::function<void(void)>& _Func)
+ inline std::function<HRESULT(_Unit_type, _Unit_type*)> _MakeUnitToUnitFunc(const std::function<HRESULT(void)>& _Func)
{
- return [=](_Unit_type) -> _Unit_type { _Func(); return _Unit_type(); };
+ return [=](_Unit_type, _Unit_type* retVal) -> HRESULT { HRESULT hr = _Func(); *retVal = _Unit_type(); return hr; };
}
}
_TaskList _Tasks;
bool _RunContinuations = false;
{
- Concurrency::critical_section::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
+ 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);
{
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())
{
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.
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
/// 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);
/// 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
{
- Concurrency::critical_section::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
+ 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
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);
}
_TaskList _Tasks;
bool _Cancel = false;
{
- Concurrency::critical_section::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
+ details::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
_CONCRT_ASSERT(!_M_Impl->_M_fHasValue);
if (!_M_Impl->_M_fIsCanceled)
{
/// </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();
- Concurrency::critical_section::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
-
+#endif
//If an exception was already set on this event, then cancel the task with the stored exception.
if (_M_Impl->_HasUserException())
{
}
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
{
{
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.
__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.
+ // 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
//
// Anything callable is fine
template<typename _ReturnType, typename _Ty>
- auto _IsValidTaskCtor(_Ty _Param, int, int, int, int) -> typename decltype(_Param(), std::true_type());
+ auto _IsValidTaskCtor(_Ty _Param, int, int, int, int, int, int, int) -> typename decltype(_Param(), std::true_type());
- // Anything that has GetResults is fine: this covers all async operations
+ // Anything callable with a task return value is fine
template<typename _ReturnType, typename _Ty>
- auto _IsValidTaskCtor(_Ty _Param, int, int, int, ...) -> typename decltype(_Param->GetResults(), std::true_type());
+ 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(std::declval<_ReturnType>()), std::true_type());
+ 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());
void _ValidateTaskConstructorArgs(_Ty _Param)
{
(void)_Param;
- static_assert(std::is_same<decltype(_IsValidTaskCtor<_ReturnType>(_Param, 0, 0, 0, 0)), std::true_type>::value,
+ 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),
// Helpers for create_async validation
//
// A parameter lambda taking no arguments is valid
- template<typename _Ty>
- static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int) -> typename decltype(_Param(), std::true_type());
+ 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 _Ty>
- static auto _IsValidCreateAsync(_Ty _Param, int, int, int, ...) -> typename decltype(_Param(cancellation_token::none()), std::true_type());
+ 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 _Ty>
- static auto _IsValidCreateAsync(_Ty _Param, int, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType()), std::true_type());
+ 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 _Ty>
- static auto _IsValidCreateAsync(_Ty _Param, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType(), cancellation_token::none()), std::true_type());
+ 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 _Ty>
+ template<typename _ReturnType, typename _Ty>
static std::false_type _IsValidCreateAsync(_Ty _Param, ...);
}
/// 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>
__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());
-
- _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param, 0));
+#endif
+ _TaskInitMaybeFunctor(_Param, details::_IsCallable<_ReturnType>(_Param, 0, 0, 0));
}
/// <summary>
/**/
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());
-
- _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param, 0));
+#endif
+ _TaskInitMaybeFunctor(_Param, details::_IsCallable<_ReturnType>(_Param, 0, 0, 0));
}
/// <summary>
__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>
/**/
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>
_ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
return _ContinuationTask;
}
-
+#endif
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
__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>
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>
/// <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>
/// 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,
- Concurrency::details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
+ 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;
class _Init_func_transformer
{
public:
- static auto _Perform(std::function<_RetType(void)> _Func) -> decltype(_Func)
+ static auto _Perform(std::function<HRESULT(_RetType*)> _Func) -> decltype(_Func)
{
return _Func;
}
class _Init_func_transformer<void>
{
public:
- static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeVoidToUnitFunc(_Func))
+ 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>, Concurrency::details::_UnrealizedChore>
+ 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
//
//
void _Init(details::_TypeSelectorNoAsync) const
{
- _M_pTask->_FinalizeAndRunContinuations(_Init_func_transformer<_InternalReturnType>::_Perform(_M_function)());
+ _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>^ (only under /ZW)
+ // 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::_TypeSelectorAsyncOperationOrTask) const
+ 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
{
- details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask, _M_function());
+ _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());
}
//
//
void _Init(details::_TypeSelectorAsyncAction) const
{
- details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask, Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(_M_function()));
+ _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());
}
//
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>>(_M_function()));
+ Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_InternalReturnType, _ProgressType>>(retVal).Get());
}
//
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>>(_M_function()));
+ Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(retVal).Get());
}
};
class _Continuation_func_transformer
{
public:
- static auto _Perform(std::function<_OutType(_InpType)> _Func) -> decltype(_Func)
+ static auto _Perform(std::function<HRESULT(_InpType, _OutType*)> _Func) -> decltype(_Func)
{
return _Func;
}
class _Continuation_func_transformer<void, _OutType>
{
public:
- static auto _Perform(std::function<_OutType(void)> _Func) -> decltype(details::_MakeUnitToTFunc<_OutType>(_Func))
+ static auto _Perform(std::function<HRESULT(_OutType*)> _Func) -> decltype(details::_MakeUnitToTFunc<_OutType>(_Func))
{
return details::_MakeUnitToTFunc<_OutType>(_Func);
}
class _Continuation_func_transformer<_InType, void>
{
public:
- static auto _Perform(std::function<void(_InType)> _Func) -> decltype(details::_MakeTToUnitFunc<_InType>(_Func))
+ static auto _Perform(std::function<HRESULT(_InType)> _Func) -> decltype(details::_MakeTToUnitFunc<_InType>(_Func))
{
return details::_MakeTToUnitFunc<_InType>(_Func);
}
class _Continuation_func_transformer<void, void>
{
public:
- static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeUnitToUnitFunc(_Func))
+ static auto _Perform(std::function<HRESULT(void)> _Func) -> decltype(details::_MakeUnitToUnitFunc(_Func))
{
return details::_MakeUnitToUnitFunc(_Func);
}
_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, Concurrency::details::_TaskInliningMode _InliningMode) :
+ 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;
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
//
//
void _Continue(std::false_type, details::_TypeSelectorNoAsync) const
{
- _M_pTask->_FinalizeAndRunContinuations(_Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult()));
+ _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>^ (only uder /ZW)
+ // 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::_TypeSelectorAsyncOperationOrTask) const
+ 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,
- _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult())
+ 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*
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>(
- _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult())));
+ retVal).Get());
}
//
{
typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
- auto _OpWithProgress = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult());
+ _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));
+ Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>>(_OpWithProgress).Get());
}
//
{
typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
- auto _OpWithProgress = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult());
+ _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));
+ Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(_OpWithProgress).Get());
}
typedef task<_InternalReturnType> _FuncInputType;
task<_InternalReturnType> _ResultTask;
_ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
- _M_pTask->_FinalizeAndRunContinuations(_Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function)(std::move(_ResultTask)));
+ _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);
}
//
// 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::_TypeSelectorAsyncOperationOrTask) const
+ 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));
- details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask, _M_function(std::move(_ResultTask)));
+ _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));
}
//
// 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>(_M_function(std::move(_ResultTask))));
+ Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(retVal));
}
//
_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>>(_M_function(std::move(_ResultTask))));
+ Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>>(retVal));
}
//
_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>>(_M_function(std::move(_ResultTask))));
+ Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(retVal));
}
};
/// <summary>
template<typename _InternalReturnType, typename _Function>
void _TaskInitWithFunctor(const _Function& _Func)
{
- typedef details::_InitFunctorTypeTraits<_InternalReturnType, decltype(_Func())> _Async_type_traits;
+ 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);
}
{
_Event._RegisterTask(_M_Impl);
}
- /// <summary>
- /// Initializes a task using an asynchronous action IAsyncAction*
- /// </summary>
- void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncAction* _AsyncAction)
- {
- _TaskInitAsyncOp((ABI::Windows::Foundation::IAsyncOperation<details::_Unit_type>*)Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(_AsyncAction).Detach());
- }
/// <summary>
- /// Initializes a task using an asynchronous action with progress IAsyncActionWithProgress<_P>*
- /// </summary>
- template<typename _P>
- void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncActionWithProgress<_P>* _AsyncActionWithProgress)
- {
- _TaskInitAsyncOp(Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_P>>(_AsyncActionWithProgress).Detach());
- }
- /// <summary>
/// Initializes a task using an asynchronous operation IAsyncOperation<T>*
/// </summary>
- template<typename _Result>
- void _TaskInitAsyncOp(ABI::Windows::Foundation::IAsyncOperation<_Result>* _AsyncOp)
+ 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;
template<typename _Result>
void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncOperation<_Result>* _AsyncOp)
{
- _TaskInitAsyncOp(_AsyncOp);
+ _TaskInitAsyncOp<_Result>(Microsoft::WRL::Make<details::_IAsyncOperationToAsyncOperationConverter<_Result>>(_AsyncOp).Get());
}
/// <summary>
template<typename _Result, typename _Progress>
void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>* _AsyncOp)
{
- _TaskInitAsyncOp(Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_Result, _Progress>>(_AsyncOp).Detach());
+ _TaskInitAsyncOp<_Result>(Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_Result, _Progress>>(_AsyncOp).Get());
}
/// <summary>
/// Initializes a task using a callable object.
{
_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, Concurrency::details::_TaskInliningMode _InliningMode = Concurrency::details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
+ bool _Aggregating = false, details::_TaskInliningMode _InliningMode = Concurrency::details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
+#endif
{
if (_M_Impl == nullptr)
{
//
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();
}
}
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));
{
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 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>
// 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(_Param, 0));
+ _TaskInitMaybeFunctor(_Param, details::_IsCallable<void>(_Param, 0, 0, 0));
}
-
+#endif
/// <summary>
/// Constructs a <c>task</c> object.
/// </summary>
/**/
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());
-
- _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param, 0));
+#endif
+ _TaskInitMaybeFunctor(_Param, details::_IsCallable<void>(_Param, 0, 0, 0));
}
/// <summary>
}
return *this;
}
+#if _MSC_VER < 1800
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
_ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
return _ContinuationTask;
}
+#endif
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
/**/
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) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
+#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.
return _ContinuationTask;
}
+#endif
/// <summary>
/// Adds a continuation task to this task.
/// </summary>
/**/
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, void>::_TaskOfType
+#if _MSC_VER >= 1800
+ 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;
- }
+ 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
{
_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>
/// <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>
/// 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, Concurrency::details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
+ 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;
_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>
/// The following type traits are used for the create_task function.
/// </summary>
- // Unwrap functions for asyncOperations
- template<typename _Ty>
- HRESULT _GetUnwrappedType(ABI::Windows::Foundation::IAsyncOperation<_Ty>*);
-
- HRESULT _GetUnwrappedType(ABI::Windows::Foundation::IAsyncAction*);
-
- template<typename _Ty, typename _Progress>
- HRESULT _GetUnwrappedType(ABI::Windows::Foundation::IAsyncOperationWithProgress<_Ty, _Progress>*);
-
- template<typename _Progress>
- HRESULT _GetUnwrappedType(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>*);
-
// Unwrap task<T>
template<typename _Ty>
_Ty _GetUnwrappedType(task<_Ty>);
// Callable
template<typename _Ty>
- auto _GetTaskType(_Ty _Func, std::true_type) -> decltype(_GetUnwrappedReturnType(_Func(), 0));
+ auto _GetTaskType(_Ty _Func, std::true_type) -> decltype(_GetUnwrappedReturnType(stdx::declval<_FunctionTypeTraits<_Ty, void>::_FuncRetType>(), 0));
// Special callable returns void
- void _GetTaskType(std::function<void()>, std::true_type);
+ void _GetTaskType(std::function<HRESULT()>, std::true_type);
struct _BadArgType{};
- template<typename _Ty>
- auto _FilterValidTaskType(_Ty _Param, int) -> decltype(_GetTaskType(_Param, _IsCallable(_Param, 0)));
+ template<typename _ReturnType, typename _Ty>
+ auto _FilterValidTaskType(_Ty _Param, int) -> decltype(_GetTaskType(_Param, _IsCallable<_ReturnType>(_Param, 0, 0, 0)));
- template<typename _Ty>
+ template<typename _ReturnType, typename _Ty>
_BadArgType _FilterValidTaskType(_Ty _Param, ...);
- template<typename _Ty>
+ template<typename _ReturnType, typename _Ty>
struct _TaskTypeFromParam
{
- typedef decltype(_FilterValidTaskType(std::declval<_Ty>(), 0)) _Type;
+ typedef decltype(_FilterValidTaskType<_ReturnType>(stdx::declval<_Ty>(), 0)) _Type;
};
}
/// <seealso cref="task Class"/>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
-template<typename _Ty>
+template<typename _ReturnType, typename _Ty>
__declspec(noinline)
-auto create_task(_Ty _Param) -> task<typename details::_TaskTypeFromParam<_Ty>::_Type>
+#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<_Ty>::_Type, details::_BadArgType>::value,
+ 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<_Ty>::_Type> _CreatedTask(_Param);
+#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;
}
/// <seealso cref="task Class"/>
/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
-template<typename _Ty>
+#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<_Ty>::_Type>
+auto create_task(_Ty _Param, Concurrency::cancellation_token _Token) -> task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type>
{
- static_assert(!std::is_same<typename details::_TaskTypeFromParam<_Ty>::_Type, details::_BadArgType>::value,
+ 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<_Ty>::_Type> _CreatedTask(_Param, _Token);
+ 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<HRESULT> _To_task_helper(ABI::Windows::Foundation::IAsyncOperation<_T>* op)
+ 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<HRESULT>(op);
+ return task<_T>(op);
}
template<typename _T, typename _Progress>
- task<HRESULT> _To_task_helper(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T, _Progress>* op)
+ 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<HRESULT>(op);
+ return task<_T>(op);
}
- inline task<HRESULT> _To_task_helper(ABI::Windows::Foundation::IAsyncAction* op)
+ inline task<void> _To_task_helper(ABI::Windows::Foundation::IAsyncAction* op)
{
- return task<HRESULT>(op);
+ return task<void>(op);
}
template<typename _Progress>
- task<HRESULT> _To_task_helper(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>* op)
+ task<void> _To_task_helper(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>* op)
{
- return task<HRESULT>(op);
+ return task<void>(op);
}
template<typename _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 type traits and helpers for async production APIs:
- //
-
- struct _ZeroArgumentFunctor { };
- struct _OneArgumentFunctor { };
- struct _TwoArgumentFunctor { };
- struct _ThreeArgumentFunctor { };
-
- // ****************************************
- // CLASS TYPES:
-
- // ********************
- // 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:
+ _ProgressDispatcher(_ClassPtrType _Ptr) : _M_ptr(_Ptr)
+ {
+ }
- // void arg:
- template<typename _Class, typename _ReturnType>
- void _Arg1ClassHelperThunk(_ReturnType(_Class::*)() const);
+ virtual void _Report(const _ProgressType& _Val)
+ {
+ _M_ptr->_FireProgress(_Val);
+ }
- // void arg:
- template<typename _Class, typename _ReturnType>
- void _Arg2ClassHelperThunk(_ReturnType(_Class::*)() const);
+ private:
- // void arg:
- template<typename _Class, typename _ReturnType>
- void _Arg3ClassHelperThunk(_ReturnType(_Class::*)() const);
+ _ClassPtrType _M_ptr;
+ };
+} // namespace details
- // void arg:
- template<typename _Class, typename _ReturnType>
- _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)() const);
- template<typename _Class, typename _ReturnType>
- _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)() const);
+/// <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;
- // ****************************************
- // POINTER TYPES:
+public:
- // ********************
- // THREE ARGUMENTS:
+ /// <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 _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
+ 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() {}
- template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
+private:
+ progress_reporter(details::_ProgressReporterCtorArgType);
- template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _Arg3 _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
+ _PtrType _M_dispatcher;
+};
- template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
+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
+ };
- template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
+ //
+ // 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 _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
+ template<typename _T>
+ struct _ProgressTypeTraits
+ {
+ static const bool _TakesProgress = false;
+ typedef void _ProgressType;
+ };
- template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
+ template<typename _T>
+ struct _ProgressTypeTraits<progress_reporter<_T>>
+ {
+ static const bool _TakesProgress = true;
+ typedef typename _T _ProgressType;
+ };
- template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _Arg3 _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
+ 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 _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
+ template<typename _T>
+ struct _TokenTypeTraits<_T, false, true>
+ {
+ static const bool _TakesToken = false;
+ typedef void _ReturnType;
+ };
- template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
+ template<typename _T>
+ struct _TokenTypeTraits<_T, true, false>
+ {
+ static const bool _TakesToken = true;
+ typedef void _ReturnType;
+ };
- template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
+ 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 _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
+ template<typename _T>
+ struct _CAFunctorOptions<_T, 1>
+ {
+ private:
- template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _Arg3 _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
+ typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
- template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
+ public:
- template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
- _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
+ 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;
+ };
- // ********************
- // TWO ARGUMENTS:
+ template<typename _T>
+ struct _CAFunctorOptions<_T, 2>
+ {
+ private:
- template<typename _ReturnType, typename _Arg1, typename _Arg2>
- _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
+ typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
+ typedef typename _FunctorTypeTraits<_T>::_Argument2Type _Argument2Type;
- template<typename _ReturnType, typename _Arg1, typename _Arg2>
- _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
+ public:
- template<typename _ReturnType, typename _Arg1, typename _Arg2>
- void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
+ 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 _ReturnType, typename _Arg1, typename _Arg2>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
+ template<typename _T>
+ struct _CAFunctorOptions<_T, 3>
+ {
+ private:
- template<typename _ReturnType, typename _Arg1, typename _Arg2>
- _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2));
+ typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
- template<typename _ReturnType, typename _Arg1, typename _Arg2>
- _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
+ public:
- template<typename _ReturnType, typename _Arg1, typename _Arg2>
- _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
+ static const bool _TakesProgress = true;
+ static const bool _TakesToken = true;
+ typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
+ typedef typename _FunctorTypeTraits<_T>::_Argument3Type _ReturnType;
+ };
- template<typename _ReturnType, typename _Arg1, typename _Arg2>
- void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
+ class _Zip
+ {
+ };
- template<typename _ReturnType, typename _Arg1, typename _Arg2>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
+ // ***************************************************************************
+ // Async Operation Task Generators
+ //
- template<typename _ReturnType, typename _Arg1, typename _Arg2>
- _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2));
+ //
+ // 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 _ReturnType, typename _Arg1, typename _Arg2>
- _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
+ 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 _ReturnType, typename _Arg1, typename _Arg2>
- _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
+ 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 _ReturnType, typename _Arg1, typename _Arg2>
- void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
+ 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 _ReturnType, typename _Arg1, typename _Arg2>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
+ 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 _ReturnType, typename _Arg1, typename _Arg2>
- _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2));
+ 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());
+ }
- // ********************
- // ONE ARGUMENT:
+ 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 _ReturnType, typename _Arg1>
- _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
+ 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 _ReturnType, typename _Arg1>
- void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
+ 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 _ReturnType, typename _Arg1>
- void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
+ 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 _ReturnType, typename _Arg1>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
+ 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 _ReturnType, typename _Arg1>
- _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1));
+ 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 _ReturnType, typename _Arg1>
- _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
+ 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 _ReturnType, typename _Arg1>
- void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
+ 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
+ };
- template<typename _ReturnType, typename _Arg1>
- void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
+#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);
+ }
- template<typename _ReturnType, typename _Arg1>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
+ ~_Task_generator_oversubscriber()
+ {
+ Concurrency::details::_Context::_Oversubscribe(false);
+ }
+ };
+#endif
- template<typename _ReturnType, typename _Arg1>
- _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1));
+ //
+ // Functor returns a result - it needs to be wrapped in a task:
+ //
+ template<typename _ReturnType>
+ struct _SelectorTaskGenerator<details::_TypeSelectorNoAsync, _ReturnType>
+ {
+#if _MSC_VER >= 1800
- template<typename _ReturnType, typename _Arg1>
- _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
+#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 _ReturnType, typename _Arg1>
- void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
+ 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 _ReturnType, typename _Arg1>
- void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
+ 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 _ReturnType, typename _Arg1>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
+ 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 _ReturnType, typename _Arg1>
- _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1));
+ 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());
+ }
- // ********************
- // ZERO ARGUMENT:
+ 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 _ReturnType>
- void _Arg1PFNHelperThunk(_ReturnType(__cdecl *)());
+ 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<typename _ReturnType>
- void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)());
+ 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 _ReturnType>
- void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)());
+ 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 _ReturnType>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)());
+ 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 _ReturnType>
- _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)());
+ 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 _ReturnType>
- void _Arg1PFNHelperThunk(_ReturnType(__stdcall *)());
+ 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 _ReturnType>
- void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)());
+ 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 _ReturnType>
- void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)());
+ 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>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)());
+ 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 _ReturnType>
- _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)());
+ 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 _ReturnType>
- void _Arg1PFNHelperThunk(_ReturnType(__fastcall *)());
+ 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 _ReturnType>
- void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)());
+ 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<typename _ReturnType>
- void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)());
+ 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 _ReturnType>
- _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)());
+ 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 _ReturnType>
- _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)());
+ 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 _T>
- struct _FunctorArguments
- {
- static const size_t _Count = 0;
+ 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<>
- struct _FunctorArguments<_OneArgumentFunctor>
+ template<typename _Generator, bool _TakesToken, bool TakesProgress>
+ struct _TaskGenerator
{
- static const size_t _Count = 1;
};
- template<>
- struct _FunctorArguments<_TwoArgumentFunctor>
+ template<typename _Generator>
+ struct _TaskGenerator<_Generator, false, false>
{
- static const size_t _Count = 2;
+#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<>
- struct _FunctorArguments<_ThreeArgumentFunctor>
+ template<typename _Generator>
+ struct _TaskGenerator<_Generator, true, false>
{
- static const size_t _Count = 3;
+#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 _T>
- struct _FunctorTypeTraits
+ template<typename _Generator>
+ struct _TaskGenerator<_Generator, false, true>
{
- typedef decltype(_ArgumentCountHelper(&(_T::operator()))) _ArgumentCountType;
- static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;
+#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);
+ }
- 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 _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 _T>
- struct _FunctorTypeTraits<_T *>
+ template<typename _Generator>
+ struct _TaskGenerator<_Generator, true, true>
{
- typedef decltype(_ArgumentCountHelper(std::declval<_T*>())) _ArgumentCountType;
- static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;
+#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);
+ }
- typedef decltype(_ReturnTypePFNHelperThunk(std::declval<_T*>())) _ReturnType;
- typedef decltype(_Arg1PFNHelperThunk(std::declval<_T*>())) _Argument1Type;
- typedef decltype(_Arg2PFNHelperThunk(std::declval<_T*>())) _Argument2Type;
- typedef decltype(_Arg3PFNHelperThunk(std::declval<_T*>())) _Argument3Type;
+ 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
};
- template<typename _T>
- struct _ProgressTypeTraits
+ // ***************************************************************************
+ // 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
{
- static const bool _TakesProgress = false;
- typedef void _ProgressType;
};
- template<typename _T>
- struct _ProgressTypeTraits<progress_reporter<_T>>
+ 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;
- typedef typename _T _ProgressType;
- };
+ static const bool _TakesToken = _TakesToken;
- template<typename _T, bool bTakesToken = std::is_same<_T, Concurrency::cancellation_token_source>::value>
- struct _TokenTypeTraits
- {
- static const bool _TakesToken = false;
- typedef typename _T _ReturnType;
+ 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 _T>
- struct _TokenTypeTraits<_T, true>
+ template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>
+ struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, false>
{
- static const bool _TakesToken = true;
- typedef void _ReturnType;
- };
+ 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;
- 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;
+ 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 _T>
- struct _CAFunctorOptions<_T, 1>
+ template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>
+ struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, true>
{
- private:
-
- typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
+ 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;
- public:
+ static const bool _TakesProgress = true;
+ static const bool _TakesToken = _TakesToken;
- static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress;
- static const bool _TakesToken = _TokenTypeTraits<_Argument1Type>::_TakesToken;
- typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
- typedef typename _TokenTypeTraits<_Argument1Type>::_TakesToken::_ReturnType _ReturnType;
+#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 _T>
- struct _CAFunctorOptions<_T, 2>
+ template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>
+ struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, false>
{
- private:
-
- typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
- typedef typename _FunctorTypeTraits<_T>::_Argument2Type _Argument2Type;
+ 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;
- public:
+ static const bool _TakesProgress = false;
+ static const bool _TakesToken = _TakesToken;
- 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>::_TakesToken::_ReturnType _ReturnType;
+#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 _T>
- struct _CAFunctorOptions<_T, 3>
+ template<typename _Function>
+ struct _AsyncLambdaTypeTraits
{
- private:
-
- typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
-
- public:
+ 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 = true;
- static const bool _TakesToken = true;
- typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
- typedef typename _FunctorTypeTraits<_T>::_Argument3Type _ReturnType;
- };
+ static const bool _TakesProgress = _CAFunctorOptions<_Function>::_TakesProgress;
+ static const bool _TakesToken = _CAFunctorOptions<_Function>::_TakesToken;
- class _Zip
- {
+ typedef typename _TaskTypeTraits<_ReturnType> _TaskTraits;
+ typedef typename _AsyncAttributes<_Function, _ProgressType, typename _TaskTraits::_TaskRetType, _TaskTraits, _TakesToken, _TakesProgress> _AsyncAttributes;
};
-
// ***************************************************************************
- // Async Operation Task Generators
+ // 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
//
- // Functor returns an IAsyncInfo - result needs to be wrapped in a task:
+ // Internal base class implementation for async operations (based on internal Windows representation for ABI level async operations)
//
- template<typename _AsyncSelector, typename _ReturnType>
- struct _SelectorTaskGenerator
+ 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>>
{
- template<typename _Function>
- static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ 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)
{
- return task<HRESULT>(_Func(_pRet), _Cts.get_token());
+#if _MSC_VER < 1800
+ _M_id = Concurrency::details::_GetNextAsyncId();
+#else
+ _M_id = Concurrency::details::platform::GetNextAsyncId();
+#endif
}
-
- template<typename _Function>
- static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ public:
+ virtual STDMETHODIMP GetResults(typename _Attributes::_ReturnType_abi* results)
{
- return task<HRESULT>(_Func(_Cts.get_token(), _pRet), _Cts.get_token());
+ (void)results;
+ return E_UNEXPECTED;
}
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ virtual STDMETHODIMP get_Id(unsigned int* id)
{
- return task<HRESULT>(_Func(_Progress, _pRet), _Cts.get_token());
+ HRESULT hr = _CheckValidStateForAsyncInfoCall();
+ if (FAILED(hr)) return hr;
+ if (!id) return E_POINTER;
+ *id = _M_id;
+ return S_OK;
}
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ virtual STDMETHODIMP put_Id(unsigned int id)
{
- return task<HRESULT>(_Func(_Progress, _Cts.get_token(), _pRet), _Cts.get_token());
- }
- };
+ HRESULT hr = _CheckValidStateForAsyncInfoCall();
+ if (FAILED(hr)) return hr;
- template<typename _AsyncSelector>
- struct _SelectorTaskGenerator<_AsyncSelector, void>
- {
- template<typename _Function>
- static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
- {
- return task<HRESULT>(_Func(), _Cts.get_token());
- }
+ if (id == 0)
+ {
+ return E_INVALIDARG;
+ }
+ else if (_M_currentStatus != _AsyncStatusInternal::_AsyncCreated)
+ {
+ return E_ILLEGAL_METHOD_CALL;
+ }
- template<typename _Function>
- static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
- {
- return task<HRESULT>(_Func(_Cts.get_token()), _Cts.get_token());
+ _M_id = id;
+ return S_OK;
}
-
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
+ virtual STDMETHODIMP get_Status(ABI::Windows::Foundation::AsyncStatus* status)
{
- return task<HRESULT>(_Func(_Progress), _Cts.get_token());
- }
+ HRESULT hr = _CheckValidStateForAsyncInfoCall();
+ if (FAILED(hr)) return hr;
+ if (!status) return E_POINTER;
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
- {
- return task<HRESULT>(_Func(_Progress, _Cts.get_token()), _Cts.get_token());
- }
- };
+ _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;
+ }
- // 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);
+ *status = static_cast<ABI::Windows::Foundation::AsyncStatus>(_Current);
+ return S_OK;
}
- ~_Task_generator_oversubscriber()
+ virtual STDMETHODIMP get_ErrorCode(HRESULT* errorCode)
{
- Concurrency::details::_Context::_Oversubscribe(false);
+ HRESULT hr = _CheckValidStateForAsyncInfoCall();
+ if (FAILED(hr)) return hr;
+ if (!hr) return hr;
+ *errorCode = _M_errorCode;
+ return S_OK;
}
- };
-
- //
- // Functor returns a result - it needs to be wrapped in a task:
- //
- template<typename _ReturnType>
- struct _SelectorTaskGenerator<details::_TypeSelectorNoAsync, _ReturnType>
- {
- template<typename _Function>
- static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ virtual STDMETHODIMP get_Progress(typename _Attributes::_ProgressDelegateType** _ProgressHandler)
{
- return task<HRESULT>([=]() -> HRESULT {
- _Task_generator_oversubscriber _Oversubscriber;
- return _Func(_pRet);
- }, _Cts.get_token());
+ return _GetOnProgress(_ProgressHandler);
}
- template<typename _Function>
- static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ virtual STDMETHODIMP put_Progress(typename _Attributes::_ProgressDelegateType* _ProgressHandler)
{
- return task<HRESULT>([=]() -> HRESULT {
- _Task_generator_oversubscriber _Oversubscriber;
- return _Func(_Cts.get_token(), _pRet);
- }, _Cts.get_token());
+ return _PutOnProgress(_ProgressHandler);
}
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ virtual STDMETHODIMP Cancel()
{
- return task<HRESULT>([=]() -> HRESULT {
- _Task_generator_oversubscriber _Oversubscriber;
- return _Func(_Progress, _pRet);
- }, _Cts.get_token());
+ if (_TransitionToState(_AsyncCancelPending))
+ {
+ _OnCancel();
+ }
+ return S_OK;
}
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ virtual STDMETHODIMP Close()
{
- return task<HRESULT>([=]() -> HRESULT {
- _Task_generator_oversubscriber _Oversubscriber;
- return _Func(_Progress, _Cts.get_token(), _pRet);
- }, _Cts.get_token());
+ if (_TransitionToState(_AsyncClosed))
+ {
+ _OnClose();
+ }
+ else
+ {
+ if (_M_currentStatus != _AsyncClosed) // Closed => Closed transition is just ignored
+ {
+ return E_ILLEGAL_STATE_CHANGE;
+ }
+ }
+ return S_OK;
}
- };
- template<>
- struct _SelectorTaskGenerator<details::_TypeSelectorNoAsync, void>
- {
- template<typename _Function>
- static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
+ virtual STDMETHODIMP get_Completed(typename _Attributes::_CompletionDelegateType** _CompleteHandler)
{
- return task<HRESULT>([=]() -> HRESULT {
- _Task_generator_oversubscriber _Oversubscriber;
- return _Func();
- }, _Cts.get_token());
+ _CheckValidStateForDelegateCall();
+ if (!_CompleteHandler) return E_POINTER;
+ *_CompleteHandler = _M_completeDelegate.Get();
+ return S_OK;
}
- template<typename _Function>
- static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
+ virtual STDMETHODIMP put_Completed(typename _Attributes::_CompletionDelegateType* _CompleteHandler)
{
- return task<HRESULT>([=]() -> HRESULT {
- _Task_generator_oversubscriber _Oversubscriber;
- return _Func(_Cts.get_token());
- }, _Cts.get_token());
+ _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;
}
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
+ protected:
+ // _Start - this is not externally visible since async operations "hot start" before returning to the caller
+ STDMETHODIMP _Start()
{
- return task<HRESULT>([=]() -> HRESULT {
- _Task_generator_oversubscriber _Oversubscriber;
- return _Func(_Progress);
- }, _Cts.get_token());
+ if (_TransitionToState(_AsyncStarted))
+ {
+ _OnStart();
+ }
+ else
+ {
+ return E_ILLEGAL_STATE_CHANGE;
+ }
+ return S_OK;
}
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
+ HRESULT _FireCompletion()
{
- return task<HRESULT>([=]() -> HRESULT {
- _Task_generator_oversubscriber _Oversubscriber;
- return _Func(_Progress, _Cts.get_token());
- }, _Cts.get_token());
+ 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;
}
- };
- //
- // Functor returns a task - the task can directly be returned:
- //
- template<typename _ReturnType>
- struct _SelectorTaskGenerator<details::_TypeSelectorAsyncTask, _ReturnType>
- {
- template<typename _Function>
- static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ virtual STDMETHODIMP _GetOnProgress(typename _Attributes::_ProgressDelegateType** _ProgressHandler)
{
- return _Func(_pRet);
+ (void)_ProgressHandler;
+ return E_UNEXPECTED;
}
- template<typename _Function>
- static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ virtual STDMETHODIMP _PutOnProgress(typename _Attributes::_ProgressDelegateType* _ProgressHandler)
{
- return _Func(_Cts.get_token(), _pRet);
+ (void)_ProgressHandler;
+ return E_UNEXPECTED;
}
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+
+ bool _TryTransitionToCompleted()
{
- return _Func(_Progress, _pRet);
+ return _TransitionToState(_AsyncStatusInternal::_AsyncCompleted);
}
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ bool _TryTransitionToCancelled()
{
- return _Func(_Progress, _Cts.get_token(), _pRet);
+ return _TransitionToState(_AsyncStatusInternal::_AsyncCanceled);
}
- };
- template<>
- struct _SelectorTaskGenerator<details::_TypeSelectorAsyncTask, void>
- {
- template<typename _Function>
- static task<HRESULT> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
+ bool _TryTransitionToError(const HRESULT error)
{
- return _Func();
+ _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_errorCode), error, S_OK);
+ return _TransitionToState(_AsyncStatusInternal::_AsyncError);
}
- template<typename _Function>
- static task<HRESULT> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
+ // 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()
{
- return _Func(_Cts.get_token());
+ if (_M_currentStatus == _AsyncClosed)
+ {
+ return E_ILLEGAL_METHOD_CALL;
+ }
+ return S_OK;
}
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
+ // 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()
{
- return _Func(_Progress);
+ _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;
}
- template<typename _Function, typename _ProgressObject>
- static task<HRESULT> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
+ // 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 _Func(_Progress, _Cts.get_token());
+ return _M_currentStatus == _AsyncStarted;
}
- };
- template<typename _Generator, bool _TakesToken, bool TakesProgress>
- struct _TaskGenerator
- {
- };
+ // 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;
- template<typename _Generator>
- struct _TaskGenerator<_Generator, false, false>
- {
- template<typename _Function, typename _ClassPtr, typename _ProgressType>
- static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
- -> decltype(_Generator::_GenerateTask_0(_Func, _Cts))
- {
- (void)_Ptr;
- return _Generator::_GenerateTask_0(_Func, _Cts);
- }
+ private:
- 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))
+ // 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()
{
- return _Generator::_GenerateTask_0(_Func, _Cts, _pRet);
+ _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;
}
- };
- template<typename _Generator>
- struct _TaskGenerator<_Generator, true, false>
- {
- template<typename _Function, typename _ClassPtr, typename _ProgressType>
- static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
- -> decltype(_Generator::_GenerateTask_0(_Func, _Cts))
+ inline bool _TransitionToState(const _AsyncStatusInternal _NewState)
{
- return _Generator::_GenerateTask_1C(_Func, _Cts);
- }
+ _AsyncStatusInternal _Current = _M_currentStatus;
- 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);
- }
- };
+ // 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;
+ }
- template<typename _Generator>
- struct _TaskGenerator<_Generator, false, true>
- {
- template<typename _Function, typename _ClassPtr, typename _ProgressType>
- static auto _GenerateTask(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);
- }
+ // 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)));
- 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);
+ // 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);
}
- };
- template<typename _Generator>
- struct _TaskGenerator<_Generator, true, true>
- {
- template<typename _Function, typename _ClassPtr, typename _ProgressType>
- static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
- -> decltype(_Generator::_GenerateTask_0(_Func, _Cts))
+ inline bool _IsTerminalState()
{
- return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts);
+ return _IsTerminalState(_M_currentStatus);
}
- 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))
+ inline bool _IsTerminalState(_AsyncStatusInternal status)
{
- return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _pRet);
+ return (status == _AsyncError ||
+ status == _AsyncCanceled ||
+ status == _AsyncCompleted ||
+ status == _AsyncClosed);
}
- };
-
- // ***************************************************************************
- // 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
- {
- };
+ private:
- 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 _ProgressType _ProgressType;
- typedef typename _TaskTraits::_AsyncKind _AsyncKind;
- typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
- typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;
+ _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;
+ };
- static const bool _TakesProgress = true;
- static const bool _TakesToken = _TakesToken;
+ // ***************************************************************************
+ // Progress Layer (optional):
+ //
- template<typename _Function, typename _ClassPtr>
- static task<HRESULT> _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);
- }
+ template< typename _Attributes, bool _HasProgress, _AsyncResultType _ResultType = SingleResult >
+ class _AsyncProgressBase abstract : public _AsyncInfoBase<_Attributes, _ResultType>
+ {
};
- template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>
- struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, false>
+ template< typename _Attributes, _AsyncResultType _ResultType>
+ class _AsyncProgressBase<_Attributes, true, _ResultType> abstract : public _AsyncInfoBase<_Attributes, _ResultType>
{
- 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 _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;
+ public:
- template<typename _Function, typename _ClassPtr>
- static task<HRESULT> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
+ _AsyncProgressBase() : _AsyncInfoBase<_Attributes, _ResultType>(),
+ _M_progressDelegate(nullptr)
{
- return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType, _ReturnType>(_Func, _Ptr, _Cts, _pRet);
}
- };
-
- 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 typename _ProgressType _ProgressType;
- 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>
- static task<HRESULT> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
+ virtual STDMETHODIMP _GetOnProgress(typename _Attributes::_ProgressDelegateType** _ProgressHandler) override
{
- return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts);
+ HRESULT hr = _CheckValidStateForDelegateCall();
+ if (FAILED(hr)) return hr;
+ *_ProgressHandler = _M_progressDelegate;
+ return S_OK;
}
- };
- 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 typename _TaskTraits::_AsyncKind _AsyncKind;
- typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
- typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;
+ 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;
+ }
- static const bool _TakesProgress = false;
- static const bool _TakesToken = _TakesToken;
+ public:
- template<typename _Function, typename _ClassPtr>
- static task<HRESULT> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
+ void _FireProgress(const typename _Attributes::_ProgressType_abi& _ProgressValue)
{
- return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts);
+ if (_M_progressDelegate != nullptr)
+ {
+ _M_progressDelegateContext._CallInContext([=]() -> HRESULT {
+ _M_progressDelegate->Invoke((_Attributes::_AsyncBaseType*)this, _ProgressValue);
+ return S_OK;
+ });
+ }
}
- };
- template<typename _Function>
- struct _AsyncLambdaTypeTraits
- {
- typedef typename _CAFunctorOptions<_Function>::_ReturnType _ReturnType;
- typedef typename _FunctorTypeTraits<_Function>::_Argument1Type _Argument1Type;
- typedef typename _CAFunctorOptions<_Function>::_ProgressType _ProgressType;
+ private:
- static const bool _TakesProgress = _CAFunctorOptions<_Function>::_TakesProgress;
- static const bool _TakesToken = _CAFunctorOptions<_Function>::_TakesToken;
+ _ContextCallback _M_progressDelegateContext;
+ typename _Attributes::_ProgressDelegateType* _M_progressDelegate;
+ };
- typedef typename _TaskTypeTraits<_ReturnType> _TaskTraits;
- typedef typename _AsyncAttributes<_Function, _ProgressType, typename _TaskTraits::_TaskRetType, _TaskTraits, _TakesToken, _TakesProgress> _AsyncAttributes;
+ template<typename _Attributes, _AsyncResultType _ResultType = SingleResult>
+ class _AsyncBaseProgressLayer abstract : public _AsyncProgressBase<_Attributes, _Attributes::_TakesProgress, _ResultType>
+ {
};
+
// ***************************************************************************
- // AsyncInfo (and completion) Layer:
+ // Task Adaptation Layer:
//
//
- // Internal base class implementation for async operations (based on internal Windows representation for ABI level async operations)
+ // _AsyncTaskThunkBase provides a bridge between IAsync<Action/Operation> and task.
//
- 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>>
+ template<typename _Attributes, typename _ReturnType>
+ class _AsyncTaskThunkBase abstract : public _AsyncBaseProgressLayer<_Attributes>
{
public:
- _AsyncInfoBase() :
- _M_currentStatus(_AsyncStatusInternal::_AsyncCreated),
- _M_errorCode(S_OK),
- _M_completeDelegate(nullptr),
- _M_CompleteDelegateAssigned(0),
- _M_CallbackMade(0)
+
+ //AsyncAction*
+ virtual STDMETHODIMP GetResults()
{
-#if _MSC_VER < 1800
- _M_id = Concurrency::details::_GetNextAsyncId();
-#else
- _M_id = Concurrency::details::platform::GetNextAsyncId();
-#endif
+ HRESULT hr = _CheckValidStateForResultsCall();
+ if (FAILED(hr)) return hr;
+ _M_task.get();
+ return S_OK;
}
+ public:
+ typedef task<_ReturnType> _TaskType;
- virtual STDMETHODIMP GetResults(typename _Attributes::_ReturnType* results)
+ _AsyncTaskThunkBase(const _TaskType& _Task)
+ : _M_task(_Task)
{
- (void)results;
- return E_UNEXPECTED;
}
- public:
- STDMETHODIMP get_Id(unsigned int* id)
+ _AsyncTaskThunkBase()
{
- HRESULT hr = _CheckValidStateForAsyncInfoCall();
- if (FAILED(hr)) return hr;
- if (!id) return E_POINTER;
- *id = _M_id;
- return S_OK;
}
-
- STDMETHODIMP put_Id(unsigned int id)
+#if _MSC_VER < 1800
+ void _SetTaskCreationAddressHint(void* _SourceAddressHint)
{
- HRESULT hr = _CheckValidStateForAsyncInfoCall();
- if (FAILED(hr)) return hr;
-
- if (id == 0)
- {
- return E_INVALIDARG;
- }
- else if (_M_currentStatus != _AsyncStatusInternal::_AsyncCreated)
+ if (!(std::is_same<_Attributes::_AsyncKind, _TypeSelectorAsyncTask>::value))
{
- return E_ILLEGAL_METHOD_CALL;
+ // 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);
}
-
- _M_id = id;
- return S_OK;
}
- STDMETHODIMP get_Status(ABI::Windows::Foundation::AsyncStatus* status)
+#endif
+ protected:
+ virtual void _OnStart() override
{
- 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;
+ _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();
+ });
}
- STDMETHODIMP get_ErrorCode(HRESULT* errorCode)
+ 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 = _CheckValidStateForAsyncInfoCall();
+ HRESULT hr = _CheckValidStateForResultsCall();
if (FAILED(hr)) return hr;
- if (!hr) return hr;
- *errorCode = _M_errorCode;
+ _M_task.get();
+ *results = _M_results;
return S_OK;
}
-
- STDMETHODIMP get_Progress(typename _Attributes::_ProgressDelegateType** _ProgressHandler)
+ template <typename _Function>
+#if _MSC_VER >= 1800
+ void DoCreateTask(_Function _func, const _TaskCreationCallstack & _callstack)
{
- return _GetOnProgress(_ProgressHandler);
+ _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results, _callstack);
}
-
- STDMETHODIMP put_Progress(typename _Attributes::_ProgressDelegateType* _ProgressHandler)
+#else
+ void DoCreateTask(_Function _func)
{
- return _PutOnProgress(_ProgressHandler);
+ _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results);
}
+#endif
+ protected:
+ _ReturnType _M_results;
+ };
- STDMETHODIMP Cancel()
+ 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)
{
- if (_TransitionToState(_AsyncCancelPending))
- {
- _OnCancel();
- }
- return S_OK;
+ _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, _callstack);
}
-
- STDMETHODIMP Close()
+#else
+ void DoCreateTask(_Function _func)
{
- if (_TransitionToState(_AsyncClosed))
- {
- _OnClose();
- }
- else
- {
- if (_M_currentStatus != _AsyncClosed) // Closed => Closed transition is just ignored
- {
- return E_ILLEGAL_STATE_CHANGE;
- }
- }
- return S_OK;
+ _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);
}
-
- virtual STDMETHODIMP get_Completed(typename _Attributes::_CompletionDelegateType** _CompleteHandler)
+#else
+ void DoCreateTask(_Function _func)
{
- _CheckValidStateForDelegateCall();
- if (!_CompleteHandler) return E_POINTER;
- *_CompleteHandler = _M_completeDelegate;
- return S_OK;
+ _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results);
}
+#endif
+ protected:
+ task<void> _M_results;
+ };
- virtual STDMETHODIMP put_Completed(typename _Attributes::_CompletionDelegateType* _CompleteHandler)
+ template<typename _Attributes>
+ class _AsyncTaskThunk : public _AsyncTaskReturn<_Attributes, typename _Attributes::_ReturnType_abi, typename _Attributes::_ReturnType>
+ {
+ public:
+
+ _AsyncTaskThunk(const _TaskType& _Task) :
+ _AsyncTaskThunkBase(_Task)
{
- _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()
+ _AsyncTaskThunk()
{
- if (_TransitionToState(_AsyncStarted))
- {
- _OnStart();
- }
- else
- {
- return E_ILLEGAL_STATE_CHANGE;
- }
- return S_OK;
}
- void _FireCompletion()
- {
- _TryTransitionToCompleted();
+ protected:
- // we guarantee that completion can only ever be fired once
- if (_M_completeDelegate != nullptr && InterlockedIncrement(&_M_CallbackMade) == 1)
- {
- _M_completeDelegateContext._CallInContext([=]() -> HRESULT {
- ABI::Windows::Foundation::AsyncStatus status;
- if (SUCCEEDED(this->get_Status(&status)))
- _M_completeDelegate->Invoke((_Attributes::_AsyncBaseType*)this, status);
- _M_completeDelegate = nullptr;
- return S_OK;
- });
- }
+ virtual void _OnClose() override
+ {
}
- virtual STDMETHODIMP _GetOnProgress(typename _Attributes::_ProgressDelegateType** _ProgressHandler)
+ virtual void _OnCancel() override
{
- (void)_ProgressHandler;
- return E_UNEXPECTED;
+ _M_cts.cancel();
}
+ };
- virtual STDMETHODIMP _PutOnProgress(typename _Attributes::_ProgressDelegateType* _ProgressHandler)
+ // ***************************************************************************
+ // 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
{
- (void)_ProgressHandler;
- return E_UNEXPECTED;
+ // Virtual call here is safe as the class is declared 'sealed'
+ _Start();
}
+ protected:
- bool _TryTransitionToCompleted()
+ //
+ // 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
{
- return _TransitionToState(_AsyncStatusInternal::_AsyncCompleted);
+ //
+ // 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();
}
- bool _TryTransitionToCancelled()
+ virtual void _OnCancel() override
{
- return _TransitionToState(_AsyncStatusInternal::_AsyncCanceled);
+ _Base::_OnCancel();
}
- bool _TryTransitionToError(const HRESULT error)
+ 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)
{
- _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()
+ void _Resize(size_t _Len, bool _SkipVector = false)
{
- if (_M_currentStatus == _AsyncClosed)
+ _M_numTasks = _Len;
+ if (!_SkipVector)
+#if _MSC_VER >= 1800
{
- return E_ILLEGAL_METHOD_CALL;
+ _M_vector._Result.resize(_Len);
}
- return S_OK;
+#else
+ _M_vector.resize(_Len);
+ _M_contexts.resize(_Len);
+#endif
}
- // 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()
+ 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)
{
- _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)
+ void _Resize(size_t _Len, bool _SkipVector = false)
+ {
+ _M_numTasks = _Len;
+
+ if (!_SkipVector)
{
- return E_ILLEGAL_METHOD_CALL;
+ _M_vector.resize(_Len);
}
- 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()
+ 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)
{
- 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;
+ void _Resize(size_t _Len)
+ {
+ _M_numTasks = _Len;
+ }
- private:
+ task_completion_event<_Unit_type> _M_completed;
+ atomic_size_t _M_completeCount;
+ size_t _M_numTasks;
+ };
- // 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()
+ 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())
{
- _AsyncStatusInternal _Current = _M_currentStatus;
- if (_Current == _AsyncClosed)
+ _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
{
- return E_ILLEGAL_METHOD_CALL;
+ // 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 if (_Current == _AsyncCreated)
+ }
+ else
+ {
+ _CONCRT_ASSERT(_Task._GetImpl()->_IsCanceled());
+ if (_Task._GetImpl()->_HasUserException())
{
- return E_ASYNC_OPERATION_NOT_STARTED;
+ // _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;
}
- return S_OK;
}
+ }
- inline bool _TransitionToState(const _AsyncStatusInternal _NewState)
+ 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
{
- _AsyncStatusInternal _Current = _M_currentStatus;
+#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
- // This enforces the valid state transitions of the asynchronous worker object
- // state machine.
- switch (_NewState)
- {
- case _AsyncStatusInternal::_AsyncStarted:
- if (_Current != _AsyncCreated)
+ size_t _Index = 0;
+ for (auto _It = _Result.begin(); _It != _Result.end(); ++_It)
{
- return false;
+ *_It = _ResultContext<_ElementType>::_GetValue(*_It, _PParam->_M_contexts[_Index++], false);
}
- break;
- case _AsyncStatusInternal::_AsyncCompleted:
- if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
+ *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)
{
- return false;
+ _TaskNum++;
+ details::_JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);
}
- break;
- case _AsyncStatusInternal::_AsyncCancelPending:
- if (_Current != _AsyncStarted)
+ _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)
{
- return false;
+ 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++;
}
- break;
- case _AsyncStatusInternal::_AsyncCanceled:
- if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
+ }
+
+ 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++)
{
- return false;
+#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());
}
- break;
- case _AsyncStatusInternal::_AsyncError:
- if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
+ *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)
{
- return false;
+ _TaskNum++;
+ details::_JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);
}
- break;
- case _AsyncStatusInternal::_AsyncClosed:
- if (!_IsTerminalState(_Current))
+ _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)
{
- return false;
+ 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++;
}
- 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);
+ return _ReturnTask;
}
+ };
- inline bool _IsTerminalState()
+ 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
{
- return _IsTerminalState(_M_currentStatus);
- }
+#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
- inline bool _IsTerminalState(_AsyncStatusInternal status)
- {
- return (status == _AsyncError ||
- status == _AsyncCanceled ||
- status == _AsyncCompleted ||
- status == _AsyncClosed);
- }
+ // 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);
+ }
- private:
+ // 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();
+ }
- _ContextCallback _M_completeDelegateContext;
- typename _Attributes::_CompletionDelegateType* volatile _M_completeDelegate;
- _AsyncStatusInternal volatile _M_currentStatus;
- HRESULT volatile _M_errorCode;
- unsigned int _M_id;
- long volatile _M_CompleteDelegateAssigned;
- long volatile _M_CallbackMade;
- };
+ _PTask->_Then([_PParam](task<void> _ResultTask) -> HRESULT {
- // ***************************************************************************
- // Progress Layer (optional):
- //
+ 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
+ }
+ }
- template< typename _Attributes, bool _HasProgress, _AsyncResultType _ResultType = SingleResult >
- class _AsyncProgressBase abstract : public _AsyncInfoBase<_Attributes, _ResultType>
- {
+ return _ReturnTask;
+ }
};
- template< typename _Attributes, _AsyncResultType _ResultType>
- class _AsyncProgressBase<_Attributes, true, _ResultType> abstract : public _AsyncInfoBase<_Attributes, _ResultType>
- {
- public:
+ 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
- _AsyncProgressBase() : _AsyncInfoBase<_Attributes, _ResultType>(),
- _M_progressDelegate(nullptr)
- {
- }
+ 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);
- virtual STDMETHODIMP _GetOnProgress(typename _Attributes::_ProgressDelegateType** _ProgressHandler) override
+ // 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())
{
- HRESULT hr = _CheckValidStateForDelegateCall();
- if (FAILED(hr)) return hr;
- *_ProgressHandler = _M_progressDelegate;
- return S_OK;
+ _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
- virtual STDMETHODIMP _PutOnProgress(typename _Attributes::_ProgressDelegateType* _ProgressHandler) override
- {
- HRESULT hr = _CheckValidStateForDelegateCall();
- if (FAILED(hr)) return hr;
- _M_progressDelegate = _ProgressHandler;
- _M_progressDelegateContext = _ContextCallback::_CaptureCurrent();
+ _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
- public:
+ return _ReturnTask;
+ }
+} // namespace details
- void _FireProgress(const typename _Attributes::_ProgressType& _ProgressValue)
- {
- if (_M_progressDelegate != nullptr)
- {
- _M_progressDelegateContext._CallInContext([=] -> HRESULT {
- _M_progressDelegate((_Attributes::_AsyncBaseType*)this, _ProgressValue);
- return S_OK;
- });
- }
- }
+#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
- private:
+/// <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
- _ContextCallback _M_progressDelegateContext;
- typename _Attributes::_ProgressDelegateType* _M_progressDelegate;
- };
+/// <summary>
+/// Creates a task that will complete succesfully when both of the tasks supplied as arguments complete 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 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);
+}
- template<typename _Attributes, _AsyncResultType _ResultType = SingleResult>
- class _AsyncBaseProgressLayer abstract : public _AsyncProgressBase<_Attributes, _Attributes::_TakesProgress, _ResultType>
- {
- };
+/// <summary>
+/// Creates a task that will complete succesfully when both of the tasks supplied as arguments complete 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 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);
+}
- // ***************************************************************************
- // Task Adaptation Layer:
- //
+/// <summary>
+/// Creates a task that will complete succesfully when both of the tasks supplied as arguments complete 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 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);
+}
- //
- // _AsyncTaskThunkBase provides a bridge between IAsync<Action/Operation> and task.
- //
- template<typename _Attributes, typename _ReturnType>
- class _AsyncTaskThunkBase abstract : public _AsyncBaseProgressLayer<_Attributes>
- {
- public:
- STDMETHODIMP GetResults(_ReturnType* results)
- {
- HRESULT hr = _CheckValidStateForResultsCall();
- if (FAILED(hr)) return hr;
- hr = _M_task.get();
- if (SUCCEEDED(hr)) *results = _M_results;
- return hr;
- }
+/// <summary>
+/// Creates a task that will complete succesfully when both of the tasks supplied as arguments complete 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 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);
+}
- public:
- typedef task<HRESULT> _TaskType;
+/// <summary>
+/// Creates a task that will complete succesfully when both of the tasks supplied as arguments complete 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 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);
+}
- _AsyncTaskThunkBase(const _TaskType& _Task)
- : _M_task(_Task)
+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)
{
}
-
- _AsyncTaskThunkBase()
+ ~_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;
+ };
- void _SetTaskCreationAddressHint(void* _SourceAddressHint)
+ 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)
{
- if (!(std::is_same<_Attributes::_AsyncKind, _TypeSelectorAsyncTask>::value))
+ _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
{
- // 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);
+ delete _PParam;
}
}
- template <typename _Function>
- void DoCreateTask(_Function _func)
- {
- _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results);
- }
-
- protected:
- virtual void _OnStart() override
+ else
{
- _M_task.then([=](_TaskType _Antecedent) {
- try
- {
- _Antecedent.get();
- }
- catch (Concurrency::task_canceled&)
- {
- _TryTransitionToCancelled();
- }
- catch(IRestrictedErrorInfo*& _Ex)
+ _CONCRT_ASSERT(_Task._GetImpl()->_IsCanceled() || _IsTokenCancled);
+ if (_Task._GetImpl()->_HasUserException() && !_IsTokenCancled)
+ {
+ if (_PParam->_M_Completed._StoreException(_Task._GetImpl()->_GetExceptionHolder()))
{
- HRESULT hr;
- HRESULT _hr;
- hr = _Ex->GetErrorDetails(NULL, &_hr, NULL, NULL);
- if (SUCCEEDED(hr)) hr = _hr;
- _TryTransitionToError(hr);
+ // 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();
+ }
}
- catch (...)
+ }
+
+#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())
{
- _TryTransitionToError(E_FAIL);
+ // 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();
}
- _FireCompletion();
- });
+ delete _PParam;
+ }
}
+ }
- protected:
- _TaskType _M_task;
- _ReturnType _M_results;
- Concurrency::cancellation_token_source _M_cts;
- };
-
- template<typename _Attributes>
- class _AsyncTaskThunkBase<_Attributes, void> abstract : public _AsyncBaseProgressLayer<_Attributes>
+ template<typename _ElementType, typename _Iterator>
+ struct _WhenAnyImpl
{
- public:
- STDMETHODIMP GetResults()
- {
- HRESULT hr = _CheckValidStateForResultsCall();
- if (FAILED(hr)) return hr;
- hr = _M_task.get();
- return hr;
- }
- public:
- typedef task<HRESULT> _TaskType;
-
- _AsyncTaskThunkBase(const _TaskType& _Task)
- : _M_task(_Task)
- {
- }
-
- _AsyncTaskThunkBase()
+#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 *>>();
- void _SetTaskCreationAddressHint(void* _SourceAddressHint)
- {
- if (!(std::is_same<_Attributes::_AsyncKind, _TypeSelectorAsyncTask>::value))
+ if (_PTokenState)
{
- // 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);
+ details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState);
+ _PParam->_M_fHasExplicitToken = true;
}
- }
- template <typename _Function>
- void DoCreateTask(_Function _func)
- {
- _M_task = _Attributes::_Generate_Task(_func, this, _M_cts);
- }
- protected:
- virtual void _OnStart() override
- {
- _M_task.then([=](_TaskType _Antecedent) -> void {
- try
- {
- _Antecedent.get();
- }
- catch (Concurrency::task_canceled&)
+#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())
{
- _TryTransitionToCancelled();
+ _Any_tasks_completed._SetAsync();
}
- catch (...)
+
+ _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)
{
- _TryTransitionToError(E_FAIL);
+ details::_JoinAllTokens_Add(_CancellationSource, _Result.second);
}
- _FireCompletion();
- });
+ *retVal = _Result.first;
+ return S_OK;
+#if _MSC_VER >= 1800
+ }, nullptr);
+#else
+ }, nullptr, true);
+#endif
}
-
- protected:
- _TaskType _M_task;
- Concurrency::cancellation_token_source _M_cts;
};
- template<typename _Attributes>
- class _AsyncTaskThunk : public _AsyncTaskThunkBase<_Attributes, typename _Attributes::_ReturnType>
- {
- public:
+ 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;
+ }
- _AsyncTaskThunk(const _TaskType& _Task) :
- _AsyncTaskThunkBase(_Task)
- {
- }
+#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;
- _AsyncTaskThunk()
- {
- }
+ _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();
+ }
- protected:
+ _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
- virtual void _OnClose() override
- {
- }
+ index++;
+ }
- virtual void _OnCancel() override
- {
- _M_cts.cancel();
+ // 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
- // ***************************************************************************
- // Async Creation Layer:
- //
- template<typename _Function>
- class _AsyncTaskGeneratorThunk : public _AsyncTaskThunk<typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes>
- {
- public:
+/// <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
- typedef typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes _Attributes;
- typedef typename _AsyncTaskThunk<_Attributes> _Base;
- typedef typename _Attributes::_AsyncBaseType _AsyncBaseType;
+/// <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);
+}
- _AsyncTaskGeneratorThunk(const _Function& _Func) : _M_func(_Func)
- {
- // Virtual call here is safe as the class is declared 'sealed'
- _Start();
- }
+/// <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();
+ }
- protected:
+ _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;
+ };
- //
- // 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.
- //
+#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;
+}
- 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.
- //
- DoCreateTask<_Function>(_M_func);
- _Base::_OnStart();
- }
+/// <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 *>>();
- virtual void _OnCancel() override
- {
- _Base::_OnCancel();
- }
+ 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();
+ }
- private:
+ _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();
- _Function _M_func;
- };
-} // namespace details
+ 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 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.
+/// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.
/// </summary>
-/// <param name="_Func">
-/// The lambda or function object from which to create a Windows Runtime asynchronous construct.
+/// <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>
-/// 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.
+/// 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>
-/// 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>
+/// 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 Class"/>
-/// <seealso cref="progress_reporter Class"/>
-/// <seealso cref="cancelation_token Class"/>
+/// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
/**/
-template<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)
+template<typename _ReturnType>
+task<std::vector<_ReturnType>> operator||(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)
{
- static_assert(std::is_same<decltype(details::_IsValidCreateAsync(_Func, 0, 0, 0, 0)), std::true_type>::value,
- "argument to create_async must be a callable object taking zero, one or two arguments");
- Microsoft::WRL::ComPtr<details::_AsyncTaskGeneratorThunk<_Function>> _AsyncInfo = Microsoft::WRL::Make<details::_AsyncTaskGeneratorThunk<_Function>>(_Func);
- _AsyncInfo->_SetTaskCreationAddressHint(_ReturnAddress());
- return _AsyncInfo.Detach();
+ 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 warning(pop)
#pragma pack(pop)
#endif
+
+#endif