1 /***
2 * ==++==
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 * Modified for native C++ WRL support by Gregory Morse
7 *
8 * ==--==
9 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
10 *
11 * ppltasks_winrt.h
12 *
13 * Parallel Patterns Library - PPL Tasks
14 *
15 * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
16 ****/
17
18 #pragma once
19
20 #ifndef _PPLTASKS_WINRT_H
21 #define _PPLTASKS_WINRT_H
22
23 #include <concrt.h>
24 #include <ppltasks.h>
25 #if _MSC_VER >= 1800
26 #include <pplconcrt.h>
27
28 // Cannot build using a compiler that is older than dev10 SP1
29 #ifdef _MSC_VER
30 #if _MSC_FULL_VER < 160040219 /*IFSTRIP=IGN*/
31 #error ERROR: Visual Studio 2010 SP1 or later is required to build ppltasks
32 #endif /*IFSTRIP=IGN*/
33 #endif
34 #else
35 #include <ppl.h>
36 #endif
37 #include <functional>
38 #include <vector>
39 #include <utility>
40 #include <exception>
41 #if _MSC_VER >= 1800
42 #include <algorithm>
43 #endif
44
45 #ifndef __cplusplus_winrt
46
47 #include <wrl\implements.h>
48 #include <wrl\async.h>
49 #if _MSC_VER >= 1800
50 #include "agile_wrl.hpp"
51 #endif
52 #include <windows.foundation.h>
53 #include <ctxtcall.h>
54
55 #ifndef _UITHREADCTXT_SUPPORT
56
57 #ifdef WINAPI_FAMILY /*IFSTRIP=IGN*/
58
59 // It is safe to include winapifamily as WINAPI_FAMILY was defined by the user
60 #include <winapifamily.h>
61
62 #if WINAPI_FAMILY == WINAPI_FAMILY_APP /*IFSTRIP=IGN*/
63 // UI thread context support is not required for desktop and Windows Store apps
64 #define _UITHREADCTXT_SUPPORT 0
65 #elif WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP /*IFSTRIP=IGN*/
66 // UI thread context support is not required for desktop and Windows Store apps
67 #define _UITHREADCTXT_SUPPORT 0
68 #else /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */
69 #define _UITHREADCTXT_SUPPORT 1
70 #endif /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */
71
72 #else /* WINAPI_FAMILY */
73 // Not supported without a WINAPI_FAMILY setting.
74 #define _UITHREADCTXT_SUPPORT 0
75 #endif /* WINAPI_FAMILY */
76
77 #endif /* _UITHREADCTXT_SUPPORT */
78
79 #if _UITHREADCTXT_SUPPORT
80 #include <uithreadctxt.h>
81 #endif /* _UITHREADCTXT_SUPPORT */
82
83 #pragma detect_mismatch("_PPLTASKS_WITH_WINRT", "0")
84
85 #ifdef _DEBUG
86 #define _DBG_ONLY(X) X
87 #else
88 #define _DBG_ONLY(X)
89 #endif // #ifdef _DEBUG
90
91 // std::copy_exception changed to std::make_exception_ptr from VS 2010 to VS 11.
92 #ifdef _MSC_VER
93 #if _MSC_VER < 1700 /*IFSTRIP=IGN*/
94 namespace std
95 {
make_exception_ptr(_E _Except)96 template<class _E> exception_ptr make_exception_ptr(_E _Except)
97 {
98 return copy_exception(_Except);
99 }
100 }
101 #endif
102 #ifndef _PPLTASK_ASYNC_LOGGING
103 #if _MSC_VER >= 1800 && defined(__cplusplus_winrt)
104 #define _PPLTASK_ASYNC_LOGGING 1 // Only enable async logging under dev12 winrt
105 #else
106 #define _PPLTASK_ASYNC_LOGGING 0
107 #endif
108 #endif
109 #endif
110
111 #pragma pack(push,_CRT_PACKING)
112
113 #pragma warning(push)
114 #pragma warning(disable: 28197)
115 #pragma warning(disable: 4100) // Unreferenced formal parameter - needed for document generation
116 #if _MSC_VER >= 1800
117 #pragma warning(disable: 4127) // constant express in if condition - we use it for meta programming
118 #else
119 #pragma warning(disable: 4702) // Unreachable code - it is caused by user lambda throw exceptions
120 #endif
121
122 // All CRT public header files are required to be protected from the macro new
123 #pragma push_macro("new")
124 #undef new
125
126 // stuff ported from Dev11 CRT
127 // NOTE: this doesn't actually match std::declval. it behaves differently for void!
128 // so don't blindly change it to std::declval.
129 namespace stdx
130 {
131 template<class _T>
132 _T&& declval();
133 }
134
135 /// <summary>
136 /// The <c>Concurrency_winrt</c> namespace provides classes and functions that give you access to the Concurrency Runtime,
137 /// a concurrent programming framework for C++. For more information, see <see cref="Concurrency Runtime"/>.
138 /// </summary>
139 /**/
140 namespace Concurrency_winrt
141 {
142 // 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.
143 #ifndef PPL_TASK_SAVE_FRAME_COUNT
144 #ifdef _DEBUG
145 #define PPL_TASK_SAVE_FRAME_COUNT 10
146 #else
147 #define PPL_TASK_SAVE_FRAME_COUNT 1
148 #endif
149 #endif
150
151 /// <summary>
152 /// Helper macro to determine how many stack frames need to be saved. When any number less or equal to 1 is specified,
153 /// only one frame is captured and no stackwalk will be involved. Otherwise, the number of callstack frames will be captured.
154 /// </summary>
155 /// <ramarks>
156 /// This needs to be defined as a macro rather than a function so that if we're only gathering one frame, _ReturnAddress()
157 /// will evaluate to client code, rather than a helper function inside of _TaskCreationCallstack, itself.
158 /// </remarks>
159 #ifdef _CAPTURE_CALLSTACK
160 #undef _CAPTURE_CALLSTACK
161 #endif
162 #if PPL_TASK_SAVE_FRAME_COUNT > 1
163 #if !defined(_DEBUG)
164 #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!")
165 #define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())
166 #else
167 #define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureMultiFramesCallstack(PPL_TASK_SAVE_FRAME_COUNT)
168 #endif
169 #else
170 #define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())
171 #endif
172 /// <summary>
173
174 /// A type that represents the terminal state of a task. Valid values are <c>completed</c> and <c>canceled</c>.
175 /// </summary>
176 /// <seealso cref="task Class"/>
177 /**/
178 typedef Concurrency::task_group_status task_status;
179
180 template <typename _Type> class task;
181 template <> class task<void>;
182
183 /// <summary>
184 /// Returns an indication of whether the task that is currently executing has received a request to cancel its
185 /// execution. Cancellation is requested on a task if the task was created with a cancellation token, and
186 /// the token source associated with that token is canceled.
187 /// </summary>
188 /// <returns>
189 /// <c>true</c> if the currently executing task has received a request for cancellation, <c>false</c> otherwise.
190 /// </returns>
191 /// <remarks>
192 /// If you call this method in the body of a task and it returns <c>true</c>, you must respond with a call to
193 /// <see cref="cancel_current_task Function">cancel_current_task</see> to acknowledge the cancellation request,
194 /// after performing any cleanup you need. This will abort the execution of the task and cause it to enter into
195 /// the <c>canceled</c> state. If you do not respond and continue execution, or return instead of calling
196 /// <c>cancel_current_task</c>, the task will enter the <c>completed</c> state when it is done.
197 /// state.
198 /// <para>A task is not cancellable if it was created without a cancellation token.</para>
199 /// </remarks>
200 /// <seealso cref="task Class"/>
201 /// <seealso cref="cancellation_token_source Class"/>
202 /// <seealso cref="cancellation_token Class"/>
203 /// <seealso cref="cancel_current_task Function"/>
204 /**/
205 #if _MSC_VER >= 1800
is_task_cancellation_requested()206 inline bool __cdecl is_task_cancellation_requested()
207 {
208 return ::Concurrency::details::_TaskCollection_t::_Is_cancellation_requested();
209 }
210 #else
is_task_cancellation_requested()211 inline bool __cdecl is_task_cancellation_requested()
212 {
213 // ConcRT scheduler under the hood is using TaskCollection, which is same as task_group
214 return ::Concurrency::is_current_task_group_canceling();
215 }
216 #endif
217
218 /// <summary>
219 /// Cancels the currently executing task. This function can be called from within the body of a task to abort the
220 /// task's execution and cause it to enter the <c>canceled</c> state. While it may be used in response to
221 /// the <see cref="is_task_cancellation_requested Function">is_task_cancellation_requested</see> function, you may
222 /// also use it by itself, to initiate cancellation of the task that is currently executing.
223 /// <para>It is not a supported scenario to call this function if you are not within the body of a <c>task</c>.
224 /// Doing so will result in undefined behavior such as a crash or a hang in your application.</para>
225 /// </summary>
226 /// <seealso cref="task Class"/>
227 /// <seealso cref="is_task_cancellation_requested"/>
228 /**/
229 //#if _MSC_VER >= 1800
cancel_current_task()230 inline __declspec(noreturn) void __cdecl cancel_current_task()
231 {
232 throw Concurrency::task_canceled();
233 }
234 //#else
235 //_CRTIMP2 __declspec(noreturn) void __cdecl cancel_current_task();
236 //#endif
237
238 namespace details
239 {
240 #if _MSC_VER >= 1800
241 /// <summary>
242 /// Callstack container, which is used to capture and preserve callstacks in ppltasks.
243 /// Members of this class is examined by vc debugger, thus there will be no public access methods.
244 /// Please note that names of this class should be kept stable for debugger examining.
245 /// </summary>
246 class _TaskCreationCallstack
247 {
248 private:
249 // If _M_SingleFrame != nullptr, there will be only one frame of callstacks, which is stored in _M_SingleFrame;
250 // otherwise, _M_Frame will store all the callstack frames.
251 void* _M_SingleFrame;
252 std::vector<void *> _M_frames;
253 public:
_TaskCreationCallstack()254 _TaskCreationCallstack()
255 {
256 _M_SingleFrame = nullptr;
257 }
258
259 // Store one frame of callstack. This function works for both Debug / Release CRT.
_CaptureSingleFrameCallstack(void * _SingleFrame)260 static _TaskCreationCallstack _CaptureSingleFrameCallstack(void *_SingleFrame)
261 {
262 _TaskCreationCallstack _csc;
263 _csc._M_SingleFrame = _SingleFrame;
264 return _csc;
265 }
266
267 // Capture _CaptureFrames number of callstack frames. This function only work properly for Desktop or Debug CRT.
268 __declspec(noinline)
_CaptureMultiFramesCallstack(size_t _CaptureFrames)269 static _TaskCreationCallstack _CaptureMultiFramesCallstack(size_t _CaptureFrames)
270 {
271 _TaskCreationCallstack _csc;
272 _csc._M_frames.resize(_CaptureFrames);
273 // skip 2 frames to make sure callstack starts from user code
274 _csc._M_frames.resize(::Concurrency::details::platform::CaptureCallstack(&_csc._M_frames[0], 2, _CaptureFrames));
275 return _csc;
276 }
277 };
278 #endif
279 typedef UINT32 _Unit_type;
280
281 struct _TypeSelectorNoAsync {};
282 struct _TypeSelectorAsyncOperationOrTask {};
283 struct _TypeSelectorAsyncOperation : public _TypeSelectorAsyncOperationOrTask { };
284 struct _TypeSelectorAsyncTask : public _TypeSelectorAsyncOperationOrTask { };
285 struct _TypeSelectorAsyncAction {};
286 struct _TypeSelectorAsyncActionWithProgress {};
287 struct _TypeSelectorAsyncOperationWithProgress {};
288
289 template<typename _Ty>
290 struct _NormalizeVoidToUnitType
291 {
292 typedef _Ty _Type;
293 };
294
295 template<>
296 struct _NormalizeVoidToUnitType<void>
297 {
298 typedef _Unit_type _Type;
299 };
300
301 template<typename _T>
302 struct _IsUnwrappedAsyncSelector
303 {
304 static const bool _Value = true;
305 };
306
307 template<>
308 struct _IsUnwrappedAsyncSelector<_TypeSelectorNoAsync>
309 {
310 static const bool _Value = false;
311 };
312
313 template <typename _Ty>
314 struct _UnwrapTaskType
315 {
316 typedef _Ty _Type;
317 };
318
319 template <typename _Ty>
320 struct _UnwrapTaskType<task<_Ty>>
321 {
322 typedef _Ty _Type;
323 };
324
325 template <typename _T>
326 _TypeSelectorAsyncTask _AsyncOperationKindSelector(task<_T>);
327
328 _TypeSelectorNoAsync _AsyncOperationKindSelector(...);
329
330 template <typename _Type>
331 struct _Unhat
332 {
333 typedef _Type _Value;
334 };
335
336 template <typename _Type>
337 struct _Unhat<_Type*>
338 {
339 typedef _Type _Value;
340 };
341
342 //struct _NonUserType { public: int _Dummy; };
343
344 template <typename _Type, bool _IsValueTypeOrRefType = __is_valid_winrt_type(_Type)>
345 struct _ValueTypeOrRefType
346 {
347 typedef _Unit_type _Value;
348 };
349
350 template <typename _Type>
351 struct _ValueTypeOrRefType<_Type, true>
352 {
353 typedef _Type _Value;
354 };
355
356 template <typename _Ty>
357 _Ty _UnwrapAsyncActionWithProgressSelector(ABI::Windows::Foundation::IAsyncActionWithProgress_impl<_Ty>*);
358
359 template <typename _Ty>
360 _Ty _UnwrapAsyncActionWithProgressSelector(...);
361
362 template <typename _Ty, typename _Progress>
363 _Progress _UnwrapAsyncOperationWithProgressProgressSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress_impl<_Ty, _Progress>*);
364
365 template <typename _Ty, typename _Progress>
366 _Progress _UnwrapAsyncOperationWithProgressProgressSelector(...);
367
368 template <typename _T1, typename _T2>
369 _T2 _ProgressTypeSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*);
370
371 template <typename _T1>
372 _T1 _ProgressTypeSelector(ABI::Windows::Foundation::IAsyncActionWithProgress<_T1>*);
373
374 template <typename _Type>
375 struct _GetProgressType
376 {
377 typedef decltype(_ProgressTypeSelector(stdx::declval<_Type>())) _Value;
378 };
379
380 template <typename _T>
381 _TypeSelectorAsyncOperation _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperation<_T>*);
382
383 _TypeSelectorAsyncAction _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncAction*);
384
385 template <typename _T1, typename _T2>
386 _TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*);
387
388 template <typename _T>
389 _TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncActionWithProgress<_T>*);
390
391 template <typename _Type>
392 struct _IsIAsyncInfo
393 {
394 static const bool _Value = std::is_base_of<ABI::Windows::Foundation::IAsyncInfo, typename _Unhat<_Type>::_Value>::value ||
395 std::is_same<_TypeSelectorAsyncAction, decltype(details::_AsyncOperationKindSelector(stdx::declval<_Type>()))>::value ||
396 std::is_same<_TypeSelectorAsyncOperation, decltype(details::_AsyncOperationKindSelector(stdx::declval<_Type>()))>::value ||
397 std::is_same<_TypeSelectorAsyncOperationWithProgress, decltype(details::_AsyncOperationKindSelector(stdx::declval<_Type>()))>::value ||
398 std::is_same<_TypeSelectorAsyncActionWithProgress, decltype(details::_AsyncOperationKindSelector(stdx::declval<_Type>()))>::value;
399 };
400
401 template <>
402 struct _IsIAsyncInfo<void>
403 {
404 static const bool _Value = false;
405 };
406
407 template <typename _Ty>
408 _Ty _UnwrapAsyncOperationSelector(ABI::Windows::Foundation::IAsyncOperation_impl<_Ty>*);
409
410 template <typename _Ty>
411 _Ty _UnwrapAsyncOperationSelector(...);
412
413 template <typename _Ty, typename _Progress>
414 _Ty _UnwrapAsyncOperationWithProgressSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress_impl<_Ty, _Progress>*);
415
416 template <typename _Ty, typename _Progress>
417 _Ty _UnwrapAsyncOperationWithProgressSelector(...);
418
419 // Unwrap functions for asyncOperations
420 template<typename _Ty>
421 auto _GetUnwrappedType(ABI::Windows::Foundation::IAsyncOperation<_Ty>*) -> typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperation<_Ty>*>()))>::type;
422
423 void _GetUnwrappedType(ABI::Windows::Foundation::IAsyncAction*);
424
425 template<typename _Ty, typename _Progress>
426 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;
427
428 template<typename _Progress>
429 void _GetUnwrappedType(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>*);
430
431 template <typename _T>
432 _T _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperation<_T>*);
433
434 void _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncAction*);
435
436 template <typename _T1, typename _T2>
437 _T1 _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*);
438
439 template <typename _T>
440 void _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncActionWithProgress<_T>*);
441
442 class _ProgressReporterCtorArgType{};
443
444 template <typename _Type, bool _IsAsync = _IsIAsyncInfo<_Type>::_Value>
445 struct _TaskTypeTraits
446 {
447 typedef typename details::_UnwrapTaskType<_Type>::_Type _TaskRetType;
448 typedef _TaskRetType _TaskRetType_abi;
449 typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;
450 typedef typename details::_NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType;
451
452 static const bool _IsAsyncTask = _IsAsync;
453 static const bool _IsUnwrappedTaskOrAsync = details::_IsUnwrappedAsyncSelector<_AsyncKind>::_Value;
454 };
455
456 template<typename _Type>
457 struct _TaskTypeTraits<_Type, true>
458 {
459 typedef decltype(_ReturnAsyncOperationKindSelector(stdx::declval<_Type>())) _TaskRetType;
460 typedef decltype(_GetUnwrappedType(stdx::declval<_Type>())) _TaskRetType_abi;
461 typedef _TaskRetType _NormalizedTaskRetType;
462 typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;
463
464 static const bool _IsAsyncTask = true;
465 static const bool _IsUnwrappedTaskOrAsync = details::_IsUnwrappedAsyncSelector<_AsyncKind>::_Value;
466 };
467
_IsCallable(_Function _Func,int,int,int)468 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(); }
_IsCallable(_Function _Func,int,int,...)469 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(); }
_IsCallable(_Function _Func,int,...)470 template <typename _ReturnType, typename _Function> auto _IsCallable(_Function _Func, int, ...) -> decltype(_Func(), std::true_type()) { (void)_Func; return std::true_type(); }
_IsCallable(_Function,...)471 template <typename _ReturnType, typename _Function> std::false_type _IsCallable(_Function, ...) { return std::false_type(); }
472
473 template <>
474 struct _TaskTypeTraits<void>
475 {
476 typedef void _TaskRetType;
477 typedef void _TaskRetType_abi;
478 typedef _TypeSelectorNoAsync _AsyncKind;
479 typedef _Unit_type _NormalizedTaskRetType;
480
481 static const bool _IsAsyncTask = false;
482 static const bool _IsUnwrappedTaskOrAsync = false;
483 };
484
485 // ***************************************************************************
486 // Template type traits and helpers for async production APIs:
487 //
488
489 struct _ZeroArgumentFunctor { };
490 struct _OneArgumentFunctor { };
491 struct _TwoArgumentFunctor { };
492 struct _ThreeArgumentFunctor { };
493
494 // ****************************************
495 // CLASS TYPES:
496
497 // mutable functions
498 // ********************
499 // THREE ARGUMENTS:
500
501 // non-void arg:
502 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
503 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3));
504
505 // non-void arg:
506 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
507 _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3));
508
509 // non-void arg:
510 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
511 _Arg3 _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3));
512
513 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
514 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3));
515
516 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
517 _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3));
518
519 // ********************
520 // TWO ARGUMENTS:
521
522 // non-void arg:
523 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
524 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2));
525
526 // non-void arg:
527 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
528 _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2));
529
530 // non-void arg:
531 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
532 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2));
533
534 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
535 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2));
536
537 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
538 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2));
539
540 // ********************
541 // ONE ARGUMENT:
542
543 // non-void arg:
544 template<typename _Class, typename _ReturnType, typename _Arg1>
545 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1));
546
547 // non-void arg:
548 template<typename _Class, typename _ReturnType, typename _Arg1>
549 void _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1));
550
551 // non-void arg:
552 template<typename _Class, typename _ReturnType, typename _Arg1>
553 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1));
554
555 template<typename _Class, typename _ReturnType, typename _Arg1>
556 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1));
557
558 template<typename _Class, typename _ReturnType, typename _Arg1>
559 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1));
560
561 // ********************
562 // ZERO ARGUMENT:
563
564 // void arg:
565 template<typename _Class, typename _ReturnType>
566 void _Arg1ClassHelperThunk(_ReturnType(_Class::*)());
567
568 // void arg:
569 template<typename _Class, typename _ReturnType>
570 void _Arg2ClassHelperThunk(_ReturnType(_Class::*)());
571
572 // void arg:
573 template<typename _Class, typename _ReturnType>
574 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)());
575
576 // void arg:
577 template<typename _Class, typename _ReturnType>
578 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)());
579
580 template<typename _Class, typename _ReturnType>
581 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)());
582
583 // ********************
584 // THREE ARGUMENTS:
585
586 // non-void arg:
587 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
588 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const);
589
590 // non-void arg:
591 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
592 _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const);
593
594 // non-void arg:
595 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
596 _Arg3 _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const);
597
598 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
599 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const);
600
601 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
602 _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const);
603
604 // ********************
605 // TWO ARGUMENTS:
606
607 // non-void arg:
608 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
609 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const);
610
611 // non-void arg:
612 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
613 _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const);
614
615 // non-void arg:
616 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
617 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const);
618
619 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
620 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const);
621
622 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
623 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2) const);
624
625 // ********************
626 // ONE ARGUMENT:
627
628 // non-void arg:
629 template<typename _Class, typename _ReturnType, typename _Arg1>
630 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const);
631
632 // non-void arg:
633 template<typename _Class, typename _ReturnType, typename _Arg1>
634 void _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const);
635
636 // non-void arg:
637 template<typename _Class, typename _ReturnType, typename _Arg1>
638 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const);
639
640 template<typename _Class, typename _ReturnType, typename _Arg1>
641 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const);
642
643 template<typename _Class, typename _ReturnType, typename _Arg1>
644 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1) const);
645
646 // ********************
647 // ZERO ARGUMENT:
648
649 // void arg:
650 template<typename _Class, typename _ReturnType>
651 void _Arg1ClassHelperThunk(_ReturnType(_Class::*)() const);
652
653 // void arg:
654 template<typename _Class, typename _ReturnType>
655 void _Arg2ClassHelperThunk(_ReturnType(_Class::*)() const);
656
657 // void arg:
658 template<typename _Class, typename _ReturnType>
659 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)() const);
660
661 // void arg:
662 template<typename _Class, typename _ReturnType>
663 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)() const);
664
665 template<typename _Class, typename _ReturnType>
666 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)() const);
667
668 // ****************************************
669 // POINTER TYPES:
670
671 // ********************
672 // THREE ARGUMENTS:
673
674 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
675 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
676
677 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
678 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
679
680 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
681 _Arg3 _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
682
683 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
684 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
685
686 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
687 _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3));
688
689 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
690 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
691
692 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
693 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
694
695 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
696 _Arg3 _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
697
698 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
699 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
700
701 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
702 _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3));
703
704 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
705 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
706
707 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
708 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
709
710 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
711 _Arg3 _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
712
713 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
714 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
715
716 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3>
717 _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3));
718
719 // ********************
720 // TWO ARGUMENTS:
721
722 template<typename _ReturnType, typename _Arg1, typename _Arg2>
723 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
724
725 template<typename _ReturnType, typename _Arg1, typename _Arg2>
726 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
727
728 template<typename _ReturnType, typename _Arg1, typename _Arg2>
729 void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
730
731 template<typename _ReturnType, typename _Arg1, typename _Arg2>
732 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
733
734 template<typename _ReturnType, typename _Arg1, typename _Arg2>
735 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2));
736
737 template<typename _ReturnType, typename _Arg1, typename _Arg2>
738 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
739
740 template<typename _ReturnType, typename _Arg1, typename _Arg2>
741 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
742
743 template<typename _ReturnType, typename _Arg1, typename _Arg2>
744 void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
745
746 template<typename _ReturnType, typename _Arg1, typename _Arg2>
747 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
748
749 template<typename _ReturnType, typename _Arg1, typename _Arg2>
750 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2));
751
752 template<typename _ReturnType, typename _Arg1, typename _Arg2>
753 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
754
755 template<typename _ReturnType, typename _Arg1, typename _Arg2>
756 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
757
758 template<typename _ReturnType, typename _Arg1, typename _Arg2>
759 void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
760
761 template<typename _ReturnType, typename _Arg1, typename _Arg2>
762 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
763
764 template<typename _ReturnType, typename _Arg1, typename _Arg2>
765 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2));
766
767 // ********************
768 // ONE ARGUMENT:
769
770 template<typename _ReturnType, typename _Arg1>
771 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
772
773 template<typename _ReturnType, typename _Arg1>
774 void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
775
776 template<typename _ReturnType, typename _Arg1>
777 void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
778
779 template<typename _ReturnType, typename _Arg1>
780 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
781
782 template<typename _ReturnType, typename _Arg1>
783 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1));
784
785 template<typename _ReturnType, typename _Arg1>
786 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
787
788 template<typename _ReturnType, typename _Arg1>
789 void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
790
791 template<typename _ReturnType, typename _Arg1>
792 void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
793
794 template<typename _ReturnType, typename _Arg1>
795 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
796
797 template<typename _ReturnType, typename _Arg1>
798 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1));
799
800 template<typename _ReturnType, typename _Arg1>
801 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
802
803 template<typename _ReturnType, typename _Arg1>
804 void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
805
806 template<typename _ReturnType, typename _Arg1>
807 void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
808
809 template<typename _ReturnType, typename _Arg1>
810 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
811
812 template<typename _ReturnType, typename _Arg1>
813 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1));
814
815 // ********************
816 // ZERO ARGUMENT:
817
818 template<typename _ReturnType>
819 void _Arg1PFNHelperThunk(_ReturnType(__cdecl *)());
820
821 template<typename _ReturnType>
822 void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)());
823
824 template<typename _ReturnType>
825 void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)());
826
827 template<typename _ReturnType>
828 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)());
829
830 template<typename _ReturnType>
831 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)());
832
833 template<typename _ReturnType>
834 void _Arg1PFNHelperThunk(_ReturnType(__stdcall *)());
835
836 template<typename _ReturnType>
837 void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)());
838
839 template<typename _ReturnType>
840 void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)());
841
842 template<typename _ReturnType>
843 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)());
844
845 template<typename _ReturnType>
846 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)());
847
848 template<typename _ReturnType>
849 void _Arg1PFNHelperThunk(_ReturnType(__fastcall *)());
850
851 template<typename _ReturnType>
852 void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)());
853
854 template<typename _ReturnType>
855 void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)());
856
857 template<typename _ReturnType>
858 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)());
859
860 template<typename _ReturnType>
861 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)());
862
863 template<typename _T>
864 struct _FunctorArguments
865 {
866 static const size_t _Count = 0;
867 };
868
869 template<>
870 struct _FunctorArguments<_OneArgumentFunctor>
871 {
872 static const size_t _Count = 1;
873 };
874
875 template<>
876 struct _FunctorArguments<_TwoArgumentFunctor>
877 {
878 static const size_t _Count = 2;
879 };
880
881 template<>
882 struct _FunctorArguments<_ThreeArgumentFunctor>
883 {
884 static const size_t _Count = 3;
885 };
886
887 template<typename _T>
888 struct _FunctorTypeTraits
889 {
890 typedef decltype(_ArgumentCountHelper(&(_T::operator()))) _ArgumentCountType;
891 static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;
892
893 typedef decltype(_ReturnTypeClassHelperThunk(&(_T::operator()))) _ReturnType;
894 typedef decltype(_Arg1ClassHelperThunk(&(_T::operator()))) _Argument1Type;
895 typedef decltype(_Arg2ClassHelperThunk(&(_T::operator()))) _Argument2Type;
896 typedef decltype(_Arg3ClassHelperThunk(&(_T::operator()))) _Argument3Type;
897 };
898
899 template<typename _T>
900 struct _FunctorTypeTraits<_T *>
901 {
902 typedef decltype(_ArgumentCountHelper(stdx::declval<_T*>())) _ArgumentCountType;
903 static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;
904
905 typedef decltype(_ReturnTypePFNHelperThunk(stdx::declval<_T*>())) _ReturnType;
906 typedef decltype(_Arg1PFNHelperThunk(stdx::declval<_T*>())) _Argument1Type;
907 typedef decltype(_Arg2PFNHelperThunk(stdx::declval<_T*>())) _Argument2Type;
908 typedef decltype(_Arg3PFNHelperThunk(stdx::declval<_T*>())) _Argument3Type;
909 };
910
911 task<void> _To_task();
912
913 template <typename _Function> auto _IsVoidConversionHelper(_Function _Func, int) -> typename decltype(_Func(_To_task()), std::true_type());
914 template <typename _Function> std::false_type _IsVoidConversionHelper(_Function _Func, ...);
915
916 template <typename T> std::true_type _VoidIsTaskHelper(task<T> _Arg, int);
917 template <typename T> std::false_type _VoidIsTaskHelper(T _Arg, ...);
918
919 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>
920 struct _FunctionTypeTraits
921 {
922 typedef typename _Unhat<typename _FunctorTypeTraits<_Function>::_Argument2Type>::_Value _FuncRetType;
923 static_assert(std::is_same<typename _FunctorTypeTraits<_Function>::_Argument1Type, _ExpectedParameterType>::value ||
924 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)");
925
926 typedef decltype(_VoidIsTaskHelper(stdx::declval<_FunctorTypeTraits<_Function>::_Argument1Type>(), 0)) _Takes_task;
927 };
928
929 //if there is a continuation parameter, then must use void/no return value
930 template<typename _Function, typename _ExpectedParameterType, const bool _IsVoidConversion>
931 struct _FunctionTypeTraits<_Function, _ExpectedParameterType, _IsVoidConversion, 1>
932 {
933 typedef void _FuncRetType;
934 static_assert(std::is_same<typename _FunctorTypeTraits<_Function>::_Argument1Type, _ExpectedParameterType>::value ||
935 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)");
936
937 typedef decltype(_VoidIsTaskHelper(stdx::declval<_FunctorTypeTraits<_Function>::_Argument1Type>(), 0)) _Takes_task;
938 };
939
940 template<typename _Function>
941 struct _FunctionTypeTraits<_Function, void, true, 1>
942 {
943 typedef void _FuncRetType;
944 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)");
945
946 typedef decltype(_VoidIsTaskHelper(stdx::declval<_FunctorTypeTraits<_Function>::_Argument1Type>(), 0)) _Takes_task;
947 };
948
949 template<typename _Function>
950 struct _FunctionTypeTraits<_Function, void, false, 1>
951 {
952 typedef typename _Unhat<typename _FunctorTypeTraits<_Function>::_Argument1Type>::_Value _FuncRetType;
953
954 typedef std::false_type _Takes_task;
955 };
956
957 template<typename _Function, typename _ExpectedParameterType, const bool _IsVoidConversion>
958 struct _FunctionTypeTraits<_Function, _ExpectedParameterType, _IsVoidConversion, 0>
959 {
960 typedef void _FuncRetType;
961
962 typedef std::false_type _Takes_task;
963 };
964
965 template<typename _Function, typename _ReturnType>
966 struct _ContinuationTypeTraits
967 {
968 typedef typename task<typename _TaskTypeTraits<typename _FunctionTypeTraits<_Function, _ReturnType>::_FuncRetType>::_TaskRetType_abi> _TaskOfType;
969 };
970
971 // _InitFunctorTypeTraits is used to decide whether a task constructed with a lambda should be unwrapped. Depending on how the variable is
972 // declared, the constructor may or may not perform unwrapping. For eg.
973 //
974 // This declaration SHOULD NOT cause unwrapping
975 // task<task<void>> t1([]() -> task<void> {
976 // task<void> t2([]() {});
977 // return t2;
978 // });
979 //
980 // This declaration SHOULD cause unwrapping
981 // task<void>> t1([]() -> task<void> {
982 // task<void> t2([]() {});
983 // return t2;
984 // });
985 // 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.
986 template <typename _TaskType, typename _FuncRetType>
987 struct _InitFunctorTypeTraits
988 {
989 typedef typename _TaskTypeTraits<_FuncRetType>::_AsyncKind _AsyncKind;
990 static const bool _IsAsyncTask = _TaskTypeTraits<_FuncRetType>::_IsAsyncTask;
991 static const bool _IsUnwrappedTaskOrAsync = _TaskTypeTraits<_FuncRetType>::_IsUnwrappedTaskOrAsync;
992 };
993
994 template<typename T>
995 struct _InitFunctorTypeTraits<T, T>
996 {
997 typedef _TypeSelectorNoAsync _AsyncKind;
998 static const bool _IsAsyncTask = false;
999 static const bool _IsUnwrappedTaskOrAsync = false;
1000 };
1001 /// <summary>
1002 /// Helper object used for LWT invocation.
1003 /// </summary>
1004 struct _TaskProcThunk
1005 {
_TaskProcThunkConcurrency_winrt::details::_TaskProcThunk1006 _TaskProcThunk(const std::function<HRESULT(void)> & _Callback) :
1007 _M_func(_Callback)
1008 {
1009 }
1010
_BridgeConcurrency_winrt::details::_TaskProcThunk1011 static void __cdecl _Bridge(void *_PData)
1012 {
1013 _TaskProcThunk *_PThunk = reinterpret_cast<_TaskProcThunk *>(_PData);
1014 #if _MSC_VER >= 1800
1015 _Holder _ThunkHolder(_PThunk);
1016 #endif
1017 _PThunk->_M_func();
1018 #if _MSC_VER < 1800
1019 delete _PThunk;
1020 #endif
1021 }
1022 private:
1023 #if _MSC_VER >= 1800
1024 // RAII holder
1025 struct _Holder
1026 {
_HolderConcurrency_winrt::details::_TaskProcThunk::_Holder1027 _Holder(_TaskProcThunk * _PThunk) : _M_pThunk(_PThunk)
1028 {
1029 }
1030
~_HolderConcurrency_winrt::details::_TaskProcThunk::_Holder1031 ~_Holder()
1032 {
1033 delete _M_pThunk;
1034 }
1035
1036 _TaskProcThunk * _M_pThunk;
1037
1038 private:
1039 _Holder& operator=(const _Holder&);
1040 };
1041 #endif
1042 std::function<HRESULT(void)> _M_func;
1043 _TaskProcThunk& operator=(const _TaskProcThunk&);
1044 };
1045
1046 /// <summary>
1047 /// Schedule a functor with automatic inlining. Note that this is "fire and forget" scheduling, which cannot be
1048 /// waited on or canceled after scheduling.
1049 /// This schedule method will perform automatic inlining base on <paramref value="_InliningMode"/>.
1050 /// </summary>
1051 /// <param name="_Func">
1052 /// The user functor need to be scheduled.
1053 /// </param>
1054 /// <param name="_InliningMode">
1055 /// The inlining scheduling policy for current functor.
1056 /// </param>
1057 #if _MSC_VER >= 1800
1058 typedef Concurrency::details::_TaskInliningMode_t _TaskInliningMode;
1059 #else
1060 typedef Concurrency::details::_TaskInliningMode _TaskInliningMode;
1061 #endif
_ScheduleFuncWithAutoInline(const std::function<HRESULT (void)> & _Func,_TaskInliningMode _InliningMode)1062 static void _ScheduleFuncWithAutoInline(const std::function<HRESULT(void)> & _Func, _TaskInliningMode _InliningMode)
1063 {
1064 #if _MSC_VER >= 1800
1065 Concurrency::details::_TaskCollection_t::_RunTask(&_TaskProcThunk::_Bridge, new _TaskProcThunk(_Func), _InliningMode);
1066 #else
1067 Concurrency::details::_StackGuard _Guard;
1068 if (_Guard._ShouldInline(_InliningMode))
1069 {
1070 _Func();
1071 }
1072 else
1073 {
1074 Concurrency::details::_CurrentScheduler::_ScheduleTask(reinterpret_cast<Concurrency::TaskProc>(&_TaskProcThunk::_Bridge), new _TaskProcThunk(_Func));
1075 }
1076 #endif
1077 }
1078 class _ContextCallback
1079 {
1080 typedef std::function<HRESULT(void)> _CallbackFunction;
1081
1082 public:
1083
_CaptureCurrent()1084 static _ContextCallback _CaptureCurrent()
1085 {
1086 _ContextCallback _Context;
1087 _Context._Capture();
1088 return _Context;
1089 }
1090
~_ContextCallback()1091 ~_ContextCallback()
1092 {
1093 _Reset();
1094 }
1095
_ContextCallback(bool _DeferCapture=false)1096 _ContextCallback(bool _DeferCapture = false)
1097 {
1098 if (_DeferCapture)
1099 {
1100 _M_context._M_captureMethod = _S_captureDeferred;
1101 }
1102 else
1103 {
1104 _M_context._M_pContextCallback = nullptr;
1105 }
1106 }
1107
1108 // Resolves a context that was created as _S_captureDeferred based on the environment (ancestor, current context).
_Resolve(bool _CaptureCurrent)1109 void _Resolve(bool _CaptureCurrent)
1110 {
1111 if (_M_context._M_captureMethod == _S_captureDeferred)
1112 {
1113 _M_context._M_pContextCallback = nullptr;
1114
1115 if (_CaptureCurrent)
1116 {
1117 if (_IsCurrentOriginSTA())
1118 {
1119 _Capture();
1120 }
1121 #if _UITHREADCTXT_SUPPORT
1122 else
1123 {
1124 // This method will fail if not called from the UI thread.
1125 HRESULT _Hr = CaptureUiThreadContext(&_M_context._M_pContextCallback);
1126 if (FAILED(_Hr))
1127 {
1128 _M_context._M_pContextCallback = nullptr;
1129 }
1130 }
1131 #endif // _UITHREADCTXT_SUPPORT
1132 }
1133 }
1134 }
1135
_Capture()1136 void _Capture()
1137 {
1138 HRESULT _Hr = CoGetObjectContext(IID_IContextCallback, reinterpret_cast<void **>(&_M_context._M_pContextCallback));
1139 if (FAILED(_Hr))
1140 {
1141 _M_context._M_pContextCallback = nullptr;
1142 }
1143 }
1144
_ContextCallback(const _ContextCallback & _Src)1145 _ContextCallback(const _ContextCallback& _Src)
1146 {
1147 _Assign(_Src._M_context._M_pContextCallback);
1148 }
1149
_ContextCallback(_ContextCallback && _Src)1150 _ContextCallback(_ContextCallback&& _Src)
1151 {
1152 _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;
1153 _Src._M_context._M_pContextCallback = nullptr;
1154 }
1155
operator =(const _ContextCallback & _Src)1156 _ContextCallback& operator=(const _ContextCallback& _Src)
1157 {
1158 if (this != &_Src)
1159 {
1160 _Reset();
1161 _Assign(_Src._M_context._M_pContextCallback);
1162 }
1163 return *this;
1164 }
1165
operator =(_ContextCallback && _Src)1166 _ContextCallback& operator=(_ContextCallback&& _Src)
1167 {
1168 if (this != &_Src)
1169 {
1170 _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;
1171 _Src._M_context._M_pContextCallback = nullptr;
1172 }
1173 return *this;
1174 }
1175
_HasCapturedContext() const1176 bool _HasCapturedContext() const
1177 {
1178 _CONCRT_ASSERT(_M_context._M_captureMethod != _S_captureDeferred);
1179 return (_M_context._M_pContextCallback != nullptr);
1180 }
1181
_CallInContext(_CallbackFunction _Func) const1182 HRESULT _CallInContext(_CallbackFunction _Func) const
1183 {
1184 if (!_HasCapturedContext())
1185 {
1186 _Func();
1187 }
1188 else
1189 {
1190 ComCallData callData;
1191 ZeroMemory(&callData, sizeof(callData));
1192 callData.pUserDefined = reinterpret_cast<void *>(&_Func);
1193
1194 HRESULT _Hr = _M_context._M_pContextCallback->ContextCallback(&_Bridge, &callData, IID_ICallbackWithNoReentrancyToApplicationSTA, 5, nullptr);
1195 if (FAILED(_Hr))
1196 {
1197 return _Hr;
1198 }
1199 }
1200 return S_OK;
1201 }
1202
operator ==(const _ContextCallback & _Rhs) const1203 bool operator==(const _ContextCallback& _Rhs) const
1204 {
1205 return (_M_context._M_pContextCallback == _Rhs._M_context._M_pContextCallback);
1206 }
1207
operator !=(const _ContextCallback & _Rhs) const1208 bool operator!=(const _ContextCallback& _Rhs) const
1209 {
1210 return !(operator==(_Rhs));
1211 }
1212
1213 private:
1214
_Reset()1215 void _Reset()
1216 {
1217 if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)
1218 {
1219 _M_context._M_pContextCallback->Release();
1220 }
1221 }
1222
_Assign(IContextCallback * _PContextCallback)1223 void _Assign(IContextCallback *_PContextCallback)
1224 {
1225 _M_context._M_pContextCallback = _PContextCallback;
1226 if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)
1227 {
1228 _M_context._M_pContextCallback->AddRef();
1229 }
1230 }
1231
_Bridge(ComCallData * _PParam)1232 static HRESULT __stdcall _Bridge(ComCallData *_PParam)
1233 {
1234 _CallbackFunction *pFunc = reinterpret_cast<_CallbackFunction *>(_PParam->pUserDefined);
1235 return (*pFunc)();
1236 }
1237
1238 // Returns the origin information for the caller (runtime / Windows Runtime apartment as far as task continuations need know)
_IsCurrentOriginSTA()1239 static bool _IsCurrentOriginSTA()
1240 {
1241 APTTYPE _AptType;
1242 APTTYPEQUALIFIER _AptTypeQualifier;
1243
1244 HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);
1245 if (SUCCEEDED(hr))
1246 {
1247 // We determine the origin of a task continuation by looking at where .then is called, so we can tell whether
1248 // to need to marshal the continuation back to the originating apartment. If an STA thread is in executing in
1249 // a neutral aparment when it schedules a continuation, we will not marshal continuations back to the STA,
1250 // since variables used within a neutral apartment are expected to be apartment neutral.
1251 switch (_AptType)
1252 {
1253 case APTTYPE_MAINSTA:
1254 case APTTYPE_STA:
1255 return true;
1256 default:
1257 break;
1258 }
1259 }
1260 return false;
1261 }
1262
1263 union
1264 {
1265 IContextCallback *_M_pContextCallback;
1266 size_t _M_captureMethod;
1267 } _M_context;
1268
1269 static const size_t _S_captureDeferred = 1;
1270 };
1271
1272 #if _MSC_VER >= 1800
1273 template<typename _Type>
1274 struct _ResultHolder
1275 {
SetConcurrency_winrt::details::_ResultHolder1276 void Set(const _Type& _type)
1277 {
1278 _Result = _type;
1279 }
1280
GetConcurrency_winrt::details::_ResultHolder1281 _Type Get()
1282 {
1283 return _Result;
1284 }
1285
1286 _Type _Result;
1287 };
1288
1289 template<typename _Type>
1290 struct _ResultHolder<_Type*>
1291 {
SetConcurrency_winrt::details::_ResultHolder1292 void Set(_Type* const & _type)
1293 {
1294 _M_Result = _type;
1295 }
1296
GetConcurrency_winrt::details::_ResultHolder1297 _Type* Get()
1298 {
1299 return _M_Result.Get();
1300 }
1301 private:
1302 // ::Platform::Agile handle specialization of all hats
1303 // including ::Platform::String and ::Platform::Array
1304 Agile<_Type*> _M_Result;
1305 };
1306
1307 //
1308 // The below are for composability with tasks auto-created from when_any / when_all / && / || constructs.
1309 //
1310 template<typename _Type>
1311 struct _ResultHolder<std::vector<_Type*>>
1312 {
SetConcurrency_winrt::details::_ResultHolder1313 void Set(const std::vector<_Type*>& _type)
1314 {
1315 _Result.reserve(_type.size());
1316
1317 for (auto _PTask = _type.begin(); _PTask != _type.end(); ++_PTask)
1318 {
1319 _Result.emplace_back(*_PTask);
1320 }
1321 }
1322
GetConcurrency_winrt::details::_ResultHolder1323 std::vector<_Type*> Get()
1324 {
1325 // Return vectory<T^> with the objects that are marshaled in the proper appartment
1326 std::vector<_Type*> _Return;
1327 _Return.reserve(_Result.size());
1328
1329 for (auto _PTask = _Result.begin(); _PTask != _Result.end(); ++_PTask)
1330 {
1331 _Return.push_back(_PTask->Get()); // Agile will marshal the object to appropriate appartment if neccessary
1332 }
1333
1334 return _Return;
1335 }
1336
1337 std::vector< Agile<_Type*> > _Result;
1338 };
1339
1340 template<typename _Type>
1341 struct _ResultHolder<std::pair<_Type*, void*> >
1342 {
SetConcurrency_winrt::details::_ResultHolder1343 void Set(const std::pair<_Type*, size_t>& _type)
1344 {
1345 _M_Result = _type;
1346 }
1347
GetConcurrency_winrt::details::_ResultHolder1348 std::pair<_Type*, size_t> Get()
1349 {
1350 return std::make_pair(_M_Result.first, _M_Result.second);
1351 }
1352 private:
1353 std::pair<Agile<_Type*>, size_t> _M_Result;
1354 };
1355 #else
1356 template<typename _Type>
1357 struct _ResultContext
1358 {
_GetContextConcurrency_winrt::details::_ResultContext1359 static _ContextCallback _GetContext(bool /* _RuntimeAggregate */)
1360 {
1361 return _ContextCallback();
1362 }
1363
_GetValueConcurrency_winrt::details::_ResultContext1364 static _Type _GetValue(_Type _ObjInCtx, const _ContextCallback & /* _Ctx */, bool /* _RuntimeAggregate */)
1365 {
1366 return _ObjInCtx;
1367 }
1368 };
1369
1370 template<typename _Type, size_t N = 0, bool bIsArray = std::is_array<_Type>::value>
1371 struct _MarshalHelper
1372 {
1373 };
1374 template<typename _Type, size_t N>
1375 struct _MarshalHelper<_Type, N, true>
1376 {
_PerformConcurrency_winrt::details::_MarshalHelper1377 static _Type* _Perform(_Type(&_ObjInCtx)[N], const _ContextCallback& _Ctx)
1378 {
1379 static_assert(__is_valid_winrt_type(_Type*), "must be a WinRT array compatible type");
1380 if (_ObjInCtx == nullptr)
1381 {
1382 return nullptr;
1383 }
1384
1385 HRESULT _Hr;
1386 IStream * _PStream;
1387 _Ctx._CallInContext([&]() -> HRESULT {
1388 // It isn't safe to simply reinterpret_cast a hat type to IUnknown* because some types do not have a real vtable ptr.
1389 // Instead, we could to create a property value to make it "grow" the vtable ptr but instead primitives are not marshalled.
1390
1391 IUnknown * _PUnk = winrt_array_type::create(_ObjInCtx, N);
1392 _Hr = CoMarshalInterThreadInterfaceInStream(winrt_type<_Type>::getuuid(), _PUnk, &_PStream);
1393 return S_OK;
1394 });
1395
1396 // With an APPX manifest, this call should never fail.
1397 _CONCRT_ASSERT(SUCCEEDED(_Hr));
1398
1399 _Type* _Proxy;
1400 //
1401 // Cannot use IID_PPV_ARGS with ^ types.
1402 //
1403 _Hr = CoGetInterfaceAndReleaseStream(_PStream, winrt_type<_Type>::getuuid(), reinterpret_cast<void**>(&_Proxy));
1404 if (FAILED(_Hr))
1405 {
1406 throw std::make_exception_ptr(_Hr);
1407 }
1408 return _Proxy;
1409 }
1410 };
1411 template<typename _Type>
1412 struct _MarshalHelper<_Type, 0, false>
1413 {
_PerformConcurrency_winrt::details::_MarshalHelper1414 static _Type* _Perform(_Type* _ObjInCtx, const _ContextCallback& _Ctx)
1415 {
1416 static_assert(std::is_base_of<IUnknown, _Type>::value || __is_valid_winrt_type(_Type), "must be a COM or WinRT type");
1417 if (_ObjInCtx == nullptr)
1418 {
1419 return nullptr;
1420 }
1421
1422 HRESULT _Hr;
1423 IStream * _PStream;
1424 _Ctx._CallInContext([&]() -> HRESULT {
1425 // It isn't safe to simply reinterpret_cast a hat type to IUnknown* because some types do not have a real vtable ptr.
1426 // Instead, we could to create a property value to make it "grow" the vtable ptr but instead primitives are not marshalled.
1427
1428 IUnknown * _PUnk = winrt_type<_Type>::create(_ObjInCtx);
1429 _Hr = CoMarshalInterThreadInterfaceInStream(winrt_type<_Type>::getuuid(), _PUnk, &_PStream);
1430 return S_OK;
1431 });
1432
1433 // With an APPX manifest, this call should never fail.
1434 _CONCRT_ASSERT(SUCCEEDED(_Hr));
1435
1436 _Type* _Proxy;
1437 //
1438 // Cannot use IID_PPV_ARGS with ^ types.
1439 //
1440 _Hr = CoGetInterfaceAndReleaseStream(_PStream, winrt_type<_Type>::getuuid(), reinterpret_cast<void**>(&_Proxy));
1441 if (FAILED(_Hr))
1442 {
1443 throw std::make_exception_ptr(_Hr);
1444 }
1445 return _Proxy;
1446 }
1447 };
1448
1449 // Arrays must be converted to IPropertyValue objects.
1450
1451 template<>
1452 struct _MarshalHelper<HSTRING__>
1453 {
_PerformConcurrency_winrt::details::_MarshalHelper1454 static HSTRING _Perform(HSTRING _ObjInCtx, const _ContextCallback& _Ctx)
1455 {
1456 return _ObjInCtx;
1457 }
1458 };
1459
1460 template<typename _Type>
_Marshal(_Type * _ObjInCtx,const _ContextCallback & _Ctx)1461 _Type* _Marshal(_Type* _ObjInCtx, const _ContextCallback& _Ctx)
1462 {
1463 return _MarshalHelper<_Type>::_Perform(_ObjInCtx, _Ctx);
1464 }
1465
1466 template<typename _Type>
1467 struct _InContext
1468 {
_GetConcurrency_winrt::details::_InContext1469 static _Type _Get(_Type _ObjInCtx, const _ContextCallback& _Ctx)
1470 {
1471 return _ObjInCtx;
1472 }
1473 };
1474
1475 template<typename _Type>
1476 struct _InContext<_Type*>
1477 {
_GetConcurrency_winrt::details::_InContext1478 static _Type* _Get(_Type* _ObjInCtx, const _ContextCallback& _Ctx)
1479 {
1480 _ContextCallback _CurrentContext = _ContextCallback::_CaptureCurrent();
1481 if (!_Ctx._HasCapturedContext() || _Ctx == _CurrentContext)
1482 {
1483 return _ObjInCtx;
1484 }
1485
1486 //
1487 // The object is from another apartment. If it's marshalable, do so.
1488 //
1489 return _Marshal<_Type>(_ObjInCtx, _Ctx);
1490 }
1491 };
1492
1493 template<typename _Type>
1494 struct _ResultContext<_Type*>
1495 {
_GetValueConcurrency_winrt::details::_ResultContext1496 static _Type* _GetValue(_Type* _ObjInCtx, const _ContextCallback& _Ctx, bool /* _RuntimeAggregate */)
1497 {
1498 return _InContext<_Type*>::_Get(_ObjInCtx, _Ctx);
1499 }
1500
_GetContextConcurrency_winrt::details::_ResultContext1501 static _ContextCallback _GetContext(bool /* _RuntimeAggregate */)
1502 {
1503 return _ContextCallback::_CaptureCurrent();
1504 }
1505 };
1506
1507 //
1508 // The below are for composability with tasks auto-created from when_any / when_all / && / || constructs.
1509 //
1510 template<typename _Type>
1511 struct _ResultContext<std::vector<_Type*>>
1512 {
_GetValueConcurrency_winrt::details::_ResultContext1513 static std::vector<_Type*> _GetValue(std::vector<_Type*> _ObjInCtx, const _ContextCallback& _Ctx, bool _RuntimeAggregate)
1514 {
1515 if (!_RuntimeAggregate)
1516 {
1517 return _ObjInCtx;
1518 }
1519
1520 _ContextCallback _CurrentContext = _ContextCallback::_CaptureCurrent();
1521 if (!_Ctx._HasCapturedContext() || _Ctx == _CurrentContext)
1522 {
1523 return _ObjInCtx;
1524 }
1525
1526 for (auto _It = _ObjInCtx.begin(); _It != _ObjInCtx.end(); ++_It)
1527 {
1528 *_It = _Marshal<_Type>(*_It, _Ctx);
1529 }
1530
1531 return _ObjInCtx;
1532 }
1533
_GetContextConcurrency_winrt::details::_ResultContext1534 static _ContextCallback _GetContext(bool _RuntimeAggregate)
1535 {
1536 if (!_RuntimeAggregate)
1537 {
1538 return _ContextCallback();
1539 }
1540 else
1541 {
1542 return _ContextCallback::_CaptureCurrent();
1543 }
1544 }
1545 };
1546
1547 template<typename _Type>
1548 struct _ResultContext<std::pair<_Type*, size_t>>
1549 {
_GetValueConcurrency_winrt::details::_ResultContext1550 static std::pair<_Type*, size_t> _GetValue(std::pair<_Type*, size_t> _ObjInCtx, const _ContextCallback& _Ctx, bool _RuntimeAggregate)
1551 {
1552 if (!_RuntimeAggregate)
1553 {
1554 return _ObjInCtx;
1555 }
1556
1557 _ContextCallback _CurrentContext = _ContextCallback::_CaptureCurrent();
1558 if (!_Ctx._HasCapturedContext() || _Ctx == _CurrentContext)
1559 {
1560 return _ObjInCtx;
1561 }
1562
1563 return std::pair<_Type*, size_t>(_Marshal<_Type>(_ObjInCtx.first, _Ctx), _ObjInCtx.second);
1564 }
1565
_GetContextConcurrency_winrt::details::_ResultContext1566 static _ContextCallback _GetContext(bool _RuntimeAggregate)
1567 {
1568 if (!_RuntimeAggregate)
1569 {
1570 return _ContextCallback();
1571 }
1572 else
1573 {
1574 return _ContextCallback::_CaptureCurrent();
1575 }
1576 }
1577 };
1578 #endif
1579 // 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.
1580 // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception
1581 // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.
1582 struct _ExceptionHolder
1583 {
1584 #if _MSC_VER >= 1800
1585 private:
ReportUnhandledErrorConcurrency_winrt::details::_ExceptionHolder1586 void ReportUnhandledError()
1587 {
1588 if (_M_winRTException != nullptr)
1589 {
1590 throw _M_winRTException.Get();
1591 }
1592 }
1593 public:
_ExceptionHolderConcurrency_winrt::details::_ExceptionHolder1594 explicit _ExceptionHolder(const std::exception_ptr& _E, const _TaskCreationCallstack &_stackTrace) :
1595 _M_exceptionObserved(0), _M_stdException(_E), _M_stackTrace(_stackTrace)
1596 {
1597 }
1598
_ExceptionHolderConcurrency_winrt::details::_ExceptionHolder1599 explicit _ExceptionHolder(IRestrictedErrorInfo*& _E, const _TaskCreationCallstack &_stackTrace) :
1600 _M_exceptionObserved(0), _M_winRTException(_E), _M_stackTrace(_stackTrace)
1601 {
1602 }
1603 #else
1604 explicit _ExceptionHolder(const std::exception_ptr& _E, void* _SourceAddressHint) :
1605 _M_exceptionObserved(0), _M_stdException(_E), _M_disassembleMe(_SourceAddressHint)
1606 {
1607 }
1608
1609 explicit _ExceptionHolder(IRestrictedErrorInfo*& _E, void* _SourceAddressHint) :
1610 _M_exceptionObserved(0), _M_disassembleMe(_SourceAddressHint), _M_winRTException(_E)
1611 {
1612 }
1613 #endif
1614 __declspec(noinline)
~_ExceptionHolderConcurrency_winrt::details::_ExceptionHolder1615 ~_ExceptionHolder()
1616 {
1617 if (_M_exceptionObserved == 0)
1618 {
1619 #if _MSC_VER >= 1800
1620 // If you are trapped here, it means an exception thrown in task chain didn't get handled.
1621 // Please add task-based continuation to handle all exceptions coming from tasks.
1622 // this->_M_stackTrace keeps the creation callstack of the task generates this exception.
1623 _REPORT_PPLTASK_UNOBSERVED_EXCEPTION();
1624 #else
1625 // Disassemble at this->_M_disassembleMe to get to the source location right after either the creation of the task (constructor
1626 // or then method) that encountered this exception, or the set_exception call for a task_completion_event.
1627 Concurrency::details::_ReportUnobservedException();
1628 #endif
1629 }
1630 }
1631
_RethrowUserExceptionConcurrency_winrt::details::_ExceptionHolder1632 void _RethrowUserException()
1633 {
1634 if (_M_exceptionObserved == 0)
1635 {
1636 #if _MSC_VER >= 1800
1637 Concurrency::details::atomic_exchange(_M_exceptionObserved, 1l);
1638 #else
1639 _InterlockedExchange(&_M_exceptionObserved, 1);
1640 #endif
1641 }
1642
1643 if (_M_winRTException != nullptr)
1644 {
1645 throw _M_winRTException.Get();
1646 }
1647 std::rethrow_exception(_M_stdException);
1648 }
1649
1650 // A variable that remembers if this exception was every rethrown into user code (and hence handled by the user). Exceptions that
1651 // are unobserved when the exception holder is destructed will terminate the process.
1652 #if _MSC_VER >= 1800
1653 Concurrency::details::atomic_long _M_exceptionObserved;
1654 #else
1655 long volatile _M_exceptionObserved;
1656 #endif
1657
1658 // Either _M_stdException or _M_winRTException is populated based on the type of exception encountered.
1659 std::exception_ptr _M_stdException;
1660 Microsoft::WRL::ComPtr<IRestrictedErrorInfo> _M_winRTException;
1661
1662 // Disassembling this value will point to a source instruction right after a call instruction. If the call is to create_task,
1663 // a task constructor or the then method, the task created by that method is the one that encountered this exception. If the call
1664 // is to task_completion_event::set_exception, the set_exception method was the source of the exception.
1665 // DO NOT REMOVE THIS VARIABLE. It is extremely helpful for debugging.
1666 #if _MSC_VER >= 1800
1667 _TaskCreationCallstack _M_stackTrace;
1668 #else
1669 void* _M_disassembleMe;
1670 #endif
1671 };
1672
1673 #ifndef RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoImpl_DEFINED
1674 #define RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoImpl_DEFINED
1675 extern const __declspec(selectany) WCHAR RuntimeClass_Concurrency_winrt_details__AsyncInfoImpl[] = L"Concurrency_winrt.details._AsyncInfoImpl";
1676 #endif
1677
1678 /// <summary>
1679 /// Base converter class for converting asynchronous interfaces to IAsyncOperation
1680 /// </summary>
1681 template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Result_abi>
1682 struct _AsyncInfoImpl abstract : public Microsoft::WRL::RuntimeClass<
1683 Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRt>,
1684 Microsoft::WRL::Implements<Microsoft::WRL::AsyncBase<_CompletionHandlerType>>>
1685 {
1686 InspectableClass(RuntimeClass_Concurrency_winrt_details__AsyncInfoImpl, BaseTrust)
1687 public:
1688 // The async action, action with progress or operation with progress that this stub forwards to.
1689 #if _MSC_VER >= 1800
1690 Agile<_AsyncOperationType> _M_asyncInfo;
1691 #else
1692 Microsoft::WRL::ComPtr<_AsyncOperationType> _M_asyncInfo;
1693 // The context in which this async info is valid - may be different from the context where the completion handler runs,
1694 // and may require marshalling before it is used.
1695 _ContextCallback _M_asyncInfoContext;
1696 #endif
1697
1698 Microsoft::WRL::ComPtr<_CompletionHandlerType> _M_CompletedHandler;
1699
_AsyncInfoImplConcurrency_winrt::details::abstract1700 _AsyncInfoImpl(_AsyncOperationType* _AsyncInfo) : _M_asyncInfo(_AsyncInfo)
1701 #if _MSC_VER < 1800
1702 , _M_asyncInfoContext(_ContextCallback::_CaptureCurrent())
1703 #endif
1704 {}
1705
1706 public:
OnStartConcurrency_winrt::details::abstract1707 virtual HRESULT OnStart() { return S_OK; }
OnCancelConcurrency_winrt::details::abstract1708 virtual void OnCancel() {
1709 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
1710 HRESULT hr;
1711 #if _MSC_VER >= 1800
1712 if (SUCCEEDED(hr = _M_asyncInfo.Get()->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf())))
1713 #else
1714 if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo)))
1715 #endif
1716 pAsyncInfo->Cancel();
1717 else
1718 throw std::make_exception_ptr(hr);
1719 }
OnCloseConcurrency_winrt::details::abstract1720 virtual void OnClose() {
1721 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
1722 HRESULT hr;
1723 #if _MSC_VER >= 1800
1724 if (SUCCEEDED(hr = _M_asyncInfo.Get()->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf())))
1725 #else
1726 if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo)))
1727 #endif
1728 pAsyncInfo->Close();
1729 else
1730 throw std::make_exception_ptr(hr);
1731 }
1732
get_ErrorCodeConcurrency_winrt::details::abstract1733 virtual STDMETHODIMP get_ErrorCode(HRESULT* errorCode)
1734 {
1735 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
1736 HRESULT hr;
1737 #if _MSC_VER >= 1800
1738 if (SUCCEEDED(hr = _M_asyncInfo.Get()->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf())))
1739 #else
1740 if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo)))
1741 #endif
1742 return pAsyncInfo->get_ErrorCode(errorCode);
1743 return hr;
1744 }
1745
get_IdConcurrency_winrt::details::abstract1746 virtual STDMETHODIMP get_Id(UINT* id)
1747 {
1748 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
1749 HRESULT hr;
1750 #if _MSC_VER >= 1800
1751 if (SUCCEEDED(hr = _M_asyncInfo.Get()->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf())))
1752 #else
1753 if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo)))
1754 #endif
1755 return pAsyncInfo->get_Id(id);
1756 return hr;
1757 }
1758
get_StatusConcurrency_winrt::details::abstract1759 virtual STDMETHODIMP get_Status(ABI::Windows::Foundation::AsyncStatus *status)
1760 {
1761 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
1762 HRESULT hr;
1763 #if _MSC_VER >= 1800
1764 if (SUCCEEDED(hr = _M_asyncInfo.Get()->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf())))
1765 #else
1766 if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo)))
1767 #endif
1768 return pAsyncInfo->get_Status(status);
1769 return hr;
1770 }
1771
GetResultsConcurrency_winrt::details::abstract1772 virtual STDMETHODIMP GetResults(_Result_abi*) { throw std::runtime_error("derived class must implement"); }
1773
get_CompletedConcurrency_winrt::details::abstract1774 virtual STDMETHODIMP get_Completed(_CompletionHandlerType** handler)
1775 {
1776 if (!handler) return E_POINTER;
1777 _M_CompletedHandler.CopyTo(handler);
1778 return S_OK;
1779 }
1780
put_CompletedConcurrency_winrt::details::abstract1781 virtual STDMETHODIMP put_Completed(_CompletionHandlerType* value)
1782 {
1783 _M_CompletedHandler = value;
1784 Microsoft::WRL::ComPtr<_CompletionHandlerType> handler = Microsoft::WRL::Callback<_CompletionHandlerType>([&](_AsyncOperationType*, ABI::Windows::Foundation::AsyncStatus status) -> HRESULT {
1785 #if _MSC_VER < 1800
1786 // Update the saved _M_asyncInfo with a proxy valid in the current context if required. Some Windows APIs return an IAsyncInfo
1787 // that is only valid for the thread that called the API to retrieve. Since this completion handler can run on any thread, we
1788 // need to ensure that the async info is valid in the current apartment. _M_asyncInfo will be accessed via calls to 'this' inside
1789 // _AsyncInit.
1790 _M_asyncInfo = _ResultContext<_AsyncOperationType*>::_GetValue(_M_asyncInfo.Get(), _M_asyncInfoContext, false);
1791 #endif
1792 return _M_CompletedHandler->Invoke(_M_asyncInfo.Get(), status);
1793 });
1794 #if _MSC_VER >= 1800
1795 return _M_asyncInfo.Get()->put_Completed(handler.Get());
1796 #else
1797 return _M_asyncInfo->put_Completed(handler.Get());
1798 #endif
1799 }
1800 };
1801
1802 extern const __declspec(selectany) WCHAR RuntimeClass_IAsyncOperationToAsyncOperationConverter[] = L"_IAsyncOperationToAsyncOperationConverter";
1803
1804 /// <summary>
1805 /// Class _IAsyncOperationToAsyncOperationConverter is used to convert an instance of IAsyncOperationWithProgress<T> into IAsyncOperation<T>
1806 /// </summary>
1807 template<typename _Result>
1808 struct _IAsyncOperationToAsyncOperationConverter :
1809 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncOperation<_Result>,
1810 ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>,
1811 typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperation<_Result>*>()))>::type>
1812 {
1813 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperation<_Result>*>()))>::type _Result_abi;
1814
1815 InspectableClass(RuntimeClass_IAsyncOperationToAsyncOperationConverter, BaseTrust)
1816 public:
_IAsyncOperationToAsyncOperationConverterConcurrency_winrt::details::_IAsyncOperationToAsyncOperationConverter1817 _IAsyncOperationToAsyncOperationConverter(ABI::Windows::Foundation::IAsyncOperation<_Result>* _Operation) :
1818 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncOperation<_Result>,
1819 ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>,
1820 _Result_abi>(_Operation) {}
1821 public:
GetResultsConcurrency_winrt::details::_IAsyncOperationToAsyncOperationConverter1822 virtual STDMETHODIMP GetResults(_Result_abi* results) override {
1823 if (!results) return E_POINTER;
1824 #if _MSC_VER >= 1800
1825 return _M_asyncInfo.Get()->GetResults(results);
1826 #else
1827 return _M_asyncInfo->GetResults(results);
1828 #endif
1829 }
1830 };
1831
1832 extern const __declspec(selectany) WCHAR RuntimeClass_IAsyncOperationWithProgressToAsyncOperationConverter[] = L"_IAsyncOperationWithProgressToAsyncOperationConverter";
1833
1834 /// <summary>
1835 /// Class _IAsyncOperationWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncOperationWithProgress<T> into IAsyncOperation<T>
1836 /// </summary>
1837 template<typename _Result, typename _Progress>
1838 struct _IAsyncOperationWithProgressToAsyncOperationConverter :
1839 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>,
1840 ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<_Result, _Progress>,
1841 typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationWithProgressSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>*>()))>::type>
1842 {
1843 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationWithProgressSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>*>()))>::type _Result_abi;
1844
1845 InspectableClass(RuntimeClass_IAsyncOperationWithProgressToAsyncOperationConverter, BaseTrust)
1846 public:
_IAsyncOperationWithProgressToAsyncOperationConverterConcurrency_winrt::details::_IAsyncOperationWithProgressToAsyncOperationConverter1847 _IAsyncOperationWithProgressToAsyncOperationConverter(ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>* _Operation) :
1848 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>,
1849 ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<_Result, _Progress>,
1850 _Result_abi>(_Operation) {}
1851 public:
GetResultsConcurrency_winrt::details::_IAsyncOperationWithProgressToAsyncOperationConverter1852 virtual STDMETHODIMP GetResults(_Result_abi* results) override {
1853 if (!results) return E_POINTER;
1854 #if _MSC_VER >= 1800
1855 return _M_asyncInfo.Get()->GetResults(results);
1856 #else
1857 return _M_asyncInfo->GetResults(results);
1858 #endif
1859 }
1860 };
1861
1862 extern const __declspec(selectany) WCHAR RuntimeClass_IAsyncActionToAsyncOperationConverter[] = L"_IAsyncActionToAsyncOperationConverter";
1863
1864 /// <summary>
1865 /// Class _IAsyncActionToAsyncOperationConverter is used to convert an instance of IAsyncAction into IAsyncOperation<_Unit_type>
1866 /// </summary>
1867 struct _IAsyncActionToAsyncOperationConverter :
1868 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncAction,
1869 ABI::Windows::Foundation::IAsyncActionCompletedHandler,
1870 _Unit_type>
1871 {
1872 InspectableClass(RuntimeClass_IAsyncActionToAsyncOperationConverter, BaseTrust)
1873 public:
_IAsyncActionToAsyncOperationConverterConcurrency_winrt::details::_IAsyncActionToAsyncOperationConverter1874 _IAsyncActionToAsyncOperationConverter(ABI::Windows::Foundation::IAsyncAction* _Operation) :
1875 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncAction,
1876 ABI::Windows::Foundation::IAsyncActionCompletedHandler,
1877 _Unit_type>(_Operation) {}
1878
1879 public:
GetResultsConcurrency_winrt::details::_IAsyncActionToAsyncOperationConverter1880 virtual STDMETHODIMP GetResults(details::_Unit_type* results)
1881 {
1882 if (!results) return E_POINTER;
1883 // Invoke GetResults on the IAsyncAction to allow exceptions to be thrown to higher layers before returning a dummy value.
1884 #if _MSC_VER >= 1800
1885 HRESULT hr = _M_asyncInfo.Get()->GetResults();
1886 #else
1887 HRESULT hr = _M_asyncInfo->GetResults();
1888 #endif
1889 if (SUCCEEDED(hr)) *results = _Unit_type();
1890 return hr;
1891 }
1892 };
1893
1894 extern const __declspec(selectany) WCHAR RuntimeClass_IAsyncActionWithProgressToAsyncOperationConverter[] = L"_IAsyncActionWithProgressToAsyncOperationConverter";
1895
1896 /// <summary>
1897 /// Class _IAsyncActionWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncActionWithProgress into IAsyncOperation<_Unit_type>
1898 /// </summary>
1899 template<typename _Progress>
1900 struct _IAsyncActionWithProgressToAsyncOperationConverter :
1901 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>,
1902 ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler<_Progress>,
1903 _Unit_type>
1904 {
1905 InspectableClass(RuntimeClass_IAsyncActionWithProgressToAsyncOperationConverter, BaseTrust)
1906 public:
_IAsyncActionWithProgressToAsyncOperationConverterConcurrency_winrt::details::_IAsyncActionWithProgressToAsyncOperationConverter1907 _IAsyncActionWithProgressToAsyncOperationConverter(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>* _Action) :
1908 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>,
1909 ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler<_Progress>,
1910 _Unit_type>(_Action) {}
1911 public:
GetResultsConcurrency_winrt::details::_IAsyncActionWithProgressToAsyncOperationConverter1912 virtual STDMETHODIMP GetResults(_Unit_type* results) override
1913 {
1914 if (!results) return E_POINTER;
1915 // Invoke GetResults on the IAsyncActionWithProgress to allow exceptions to be thrown before returning a dummy value.
1916 #if _MSC_VER >= 1800
1917 HRESULT hr = _M_asyncInfo.Get()->GetResults();
1918 #else
1919 HRESULT hr = _M_asyncInfo->GetResults();
1920 #endif
1921 if (SUCCEEDED(hr)) *results = _Unit_type();
1922 return hr;
1923 }
1924 };
1925 }
1926
1927 /// <summary>
1928 /// The <c>task_continuation_context</c> class allows you to specify where you would like a continuation to be executed.
1929 /// It is only useful to use this class from a Windows Store app. For non-Windows Store apps, the task continuation's
1930 /// execution context is determined by the runtime, and not configurable.
1931 /// </summary>
1932 /// <seealso cref="task Class"/>
1933 /**/
1934 class task_continuation_context : public details::_ContextCallback
1935 {
1936 public:
1937
1938 /// <summary>
1939 /// Creates the default task continuation context.
1940 /// </summary>
1941 /// <returns>
1942 /// The default continuation context.
1943 /// </returns>
1944 /// <remarks>
1945 /// The default context is used if you don't specifiy a continuation context when you call the <c>then</c> method. In Windows
1946 /// applications for Windows 7 and below, as well as desktop applications on Windows 8 and higher, the runtime determines where
1947 /// task continuations will execute. However, in a Windows Store app, the default continuation context for a continuation on an
1948 /// apartment aware task is the apartment where <c>then</c> is invoked.
1949 /// <para>An apartment aware task is a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such
1950 /// a task. Therefore, if you schedule a continuation on an apartment aware task in a Windows Runtime STA, the continuation will execute in
1951 /// that STA.</para>
1952 /// <para>A continuation on a non-apartment aware task will execute in a context the Runtime chooses.</para>
1953 /// </remarks>
1954 /**/
use_default()1955 static task_continuation_context use_default()
1956 {
1957 // The callback context is created with the context set to CaptureDeferred and resolved when it is used in .then()
1958 return task_continuation_context(true); // sets it to deferred, is resolved in the constructor of _ContinuationTaskHandle
1959 }
1960
1961 /// <summary>
1962 /// Creates a task continuation context which allows the Runtime to choose the execution context for a continuation.
1963 /// </summary>
1964 /// <returns>
1965 /// A task continuation context that represents an arbitrary location.
1966 /// </returns>
1967 /// <remarks>
1968 /// When this continuation context is used the continuation will execute in a context the runtime chooses even if the antecedent task
1969 /// is apartment aware.
1970 /// <para><c>use_arbitrary</c> can be used to turn off the default behavior for a continuation on an apartment
1971 /// aware task created in an STA. </para>
1972 /// <para>This method is only available to Windows Store apps.</para>
1973 /// </remarks>
1974 /**/
use_arbitrary()1975 static task_continuation_context use_arbitrary()
1976 {
1977 task_continuation_context _Arbitrary(true);
1978 _Arbitrary._Resolve(false);
1979 return _Arbitrary;
1980 }
1981
1982 /// <summary>
1983 /// Returns a task continuation context object that represents the current execution context.
1984 /// </summary>
1985 /// <returns>
1986 /// The current execution context.
1987 /// </returns>
1988 /// <remarks>
1989 /// This method captures the caller's Windows Runtime context so that continuations can be executed in the right apartment.
1990 /// <para>The value returned by <c>use_current</c> can be used to indicate to the Runtime that the continuation should execute in
1991 /// the captured context (STA vs MTA) regardless of whether or not the antecedent task is apartment aware. An apartment aware task is
1992 /// a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such a task. </para>
1993 /// <para>This method is only available to Windows Store apps.</para>
1994 /// </remarks>
1995 /**/
use_current()1996 static task_continuation_context use_current()
1997 {
1998 task_continuation_context _Current(true);
1999 _Current._Resolve(true);
2000 return _Current;
2001 }
2002
2003 private:
2004
task_continuation_context(bool _DeferCapture=false)2005 task_continuation_context(bool _DeferCapture = false) : details::_ContextCallback(_DeferCapture)
2006 {
2007 }
2008 };
2009
2010 #if _MSC_VER >= 1800
2011 class task_options;
2012 namespace details
2013 {
2014 struct _Internal_task_options
2015 {
2016 bool _M_hasPresetCreationCallstack;
2017 _TaskCreationCallstack _M_presetCreationCallstack;
2018
_set_creation_callstackConcurrency_winrt::details::_Internal_task_options2019 void _set_creation_callstack(const _TaskCreationCallstack &_callstack)
2020 {
2021 _M_hasPresetCreationCallstack = true;
2022 _M_presetCreationCallstack = _callstack;
2023 }
_Internal_task_optionsConcurrency_winrt::details::_Internal_task_options2024 _Internal_task_options()
2025 {
2026 _M_hasPresetCreationCallstack = false;
2027 }
2028 };
2029
2030 inline _Internal_task_options &_get_internal_task_options(task_options &options);
2031 inline const _Internal_task_options &_get_internal_task_options(const task_options &options);
2032 }
2033 /// <summary>
2034 /// Represents the allowed options for creating a task
2035 /// </summary>
2036 class task_options
2037 {
2038 public:
2039
2040
2041 /// <summary>
2042 /// Default list of task creation options
2043 /// </summary>
task_options()2044 task_options()
2045 : _M_Scheduler(Concurrency::get_ambient_scheduler()),
2046 _M_CancellationToken(Concurrency::cancellation_token::none()),
2047 _M_ContinuationContext(task_continuation_context::use_default()),
2048 _M_HasCancellationToken(false),
2049 _M_HasScheduler(false)
2050 {
2051 }
2052
2053 /// <summary>
2054 /// Task option that specify a cancellation token
2055 /// </summary>
task_options(Concurrency::cancellation_token _Token)2056 task_options(Concurrency::cancellation_token _Token)
2057 : _M_Scheduler(Concurrency::get_ambient_scheduler()),
2058 _M_CancellationToken(_Token),
2059 _M_ContinuationContext(task_continuation_context::use_default()),
2060 _M_HasCancellationToken(true),
2061 _M_HasScheduler(false)
2062 {
2063 }
2064
2065 /// <summary>
2066 /// Task option that specify a continuation context. This is valid only for continuations (then)
2067 /// </summary>
task_options(task_continuation_context _ContinuationContext)2068 task_options(task_continuation_context _ContinuationContext)
2069 : _M_Scheduler(Concurrency::get_ambient_scheduler()),
2070 _M_CancellationToken(Concurrency::cancellation_token::none()),
2071 _M_ContinuationContext(_ContinuationContext),
2072 _M_HasCancellationToken(false),
2073 _M_HasScheduler(false)
2074 {
2075 }
2076
2077 /// <summary>
2078 /// Task option that specify a cancellation token and a continuation context. This is valid only for continuations (then)
2079 /// </summary>
task_options(Concurrency::cancellation_token _Token,task_continuation_context _ContinuationContext)2080 task_options(Concurrency::cancellation_token _Token, task_continuation_context _ContinuationContext)
2081 : _M_Scheduler(Concurrency::get_ambient_scheduler()),
2082 _M_CancellationToken(_Token),
2083 _M_ContinuationContext(_ContinuationContext),
2084 _M_HasCancellationToken(false),
2085 _M_HasScheduler(false)
2086 {
2087 }
2088
2089 /// <summary>
2090 /// Task option that specify a scheduler with shared lifetime
2091 /// </summary>
2092 template<typename _SchedType>
task_options(std::shared_ptr<_SchedType> _Scheduler)2093 task_options(std::shared_ptr<_SchedType> _Scheduler)
2094 : _M_Scheduler(std::move(_Scheduler)),
2095 _M_CancellationToken(cancellation_token::none()),
2096 _M_ContinuationContext(task_continuation_context::use_default()),
2097 _M_HasCancellationToken(false),
2098 _M_HasScheduler(true)
2099 {
2100 }
2101
2102 /// <summary>
2103 /// Task option that specify a scheduler reference
2104 /// </summary>
task_options(Concurrency::scheduler_interface & _Scheduler)2105 task_options(Concurrency::scheduler_interface& _Scheduler)
2106 : _M_Scheduler(&_Scheduler),
2107 _M_CancellationToken(Concurrency::cancellation_token::none()),
2108 _M_ContinuationContext(task_continuation_context::use_default()),
2109 _M_HasCancellationToken(false),
2110 _M_HasScheduler(true)
2111 {
2112 }
2113
2114 /// <summary>
2115 /// Task option that specify a scheduler
2116 /// </summary>
task_options(Concurrency::scheduler_ptr _Scheduler)2117 task_options(Concurrency::scheduler_ptr _Scheduler)
2118 : _M_Scheduler(std::move(_Scheduler)),
2119 _M_CancellationToken(Concurrency::cancellation_token::none()),
2120 _M_ContinuationContext(task_continuation_context::use_default()),
2121 _M_HasCancellationToken(false),
2122 _M_HasScheduler(true)
2123 {
2124 }
2125
2126 /// <summary>
2127 /// Task option copy constructor
2128 /// </summary>
task_options(const task_options & _TaskOptions)2129 task_options(const task_options& _TaskOptions)
2130 : _M_Scheduler(_TaskOptions.get_scheduler()),
2131 _M_CancellationToken(_TaskOptions.get_cancellation_token()),
2132 _M_ContinuationContext(_TaskOptions.get_continuation_context()),
2133 _M_HasCancellationToken(_TaskOptions.has_cancellation_token()),
2134 _M_HasScheduler(_TaskOptions.has_scheduler())
2135 {
2136 }
2137
2138 /// <summary>
2139 /// Sets the given token in the options
2140 /// </summary>
set_cancellation_token(Concurrency::cancellation_token _Token)2141 void set_cancellation_token(Concurrency::cancellation_token _Token)
2142 {
2143 _M_CancellationToken = _Token;
2144 _M_HasCancellationToken = true;
2145 }
2146
2147 /// <summary>
2148 /// Sets the given continuation context in the options
2149 /// </summary>
set_continuation_context(task_continuation_context _ContinuationContext)2150 void set_continuation_context(task_continuation_context _ContinuationContext)
2151 {
2152 _M_ContinuationContext = _ContinuationContext;
2153 }
2154
2155 /// <summary>
2156 /// Indicates whether a cancellation token was specified by the user
2157 /// </summary>
has_cancellation_token() const2158 bool has_cancellation_token() const
2159 {
2160 return _M_HasCancellationToken;
2161 }
2162
2163 /// <summary>
2164 /// Returns the cancellation token
2165 /// </summary>
get_cancellation_token() const2166 Concurrency::cancellation_token get_cancellation_token() const
2167 {
2168 return _M_CancellationToken;
2169 }
2170
2171 /// <summary>
2172 /// Returns the continuation context
2173 /// </summary>
get_continuation_context() const2174 task_continuation_context get_continuation_context() const
2175 {
2176 return _M_ContinuationContext;
2177 }
2178
2179 /// <summary>
2180 /// Indicates whether a scheduler n was specified by the user
2181 /// </summary>
has_scheduler() const2182 bool has_scheduler() const
2183 {
2184 return _M_HasScheduler;
2185 }
2186
2187 /// <summary>
2188 /// Returns the scheduler
2189 /// </summary>
get_scheduler() const2190 Concurrency::scheduler_ptr get_scheduler() const
2191 {
2192 return _M_Scheduler;
2193 }
2194
2195 private:
2196
2197 task_options const& operator=(task_options const& _Right);
2198 friend details::_Internal_task_options &details::_get_internal_task_options(task_options &);
2199 friend const details::_Internal_task_options &details::_get_internal_task_options(const task_options &);
2200
2201 Concurrency::scheduler_ptr _M_Scheduler;
2202 Concurrency::cancellation_token _M_CancellationToken;
2203 task_continuation_context _M_ContinuationContext;
2204 details::_Internal_task_options _M_InternalTaskOptions;
2205 bool _M_HasCancellationToken;
2206 bool _M_HasScheduler;
2207 };
2208 #endif
2209
2210 namespace details
2211 {
2212 #if _MSC_VER >= 1800
_get_internal_task_options(task_options & options)2213 inline _Internal_task_options & _get_internal_task_options(task_options &options)
2214 {
2215 return options._M_InternalTaskOptions;
2216 }
_get_internal_task_options(const task_options & options)2217 inline const _Internal_task_options & _get_internal_task_options(const task_options &options)
2218 {
2219 return options._M_InternalTaskOptions;
2220 }
2221 #endif
2222 struct _Task_impl_base;
2223 template<typename _ReturnType> struct _Task_impl;
2224
2225 template<typename _ReturnType>
2226 struct _Task_ptr
2227 {
2228 typedef std::shared_ptr<_Task_impl<_ReturnType>> _Type;
2229 #if _MSC_VER >= 1800
_MakeConcurrency_winrt::details::_Task_ptr2230 static _Type _Make(Concurrency::details::_CancellationTokenState * _Ct, Concurrency::scheduler_ptr _Scheduler_arg) { return std::make_shared<_Task_impl<_ReturnType>>(_Ct, _Scheduler_arg); }
2231 #else
_MakeConcurrency_winrt::details::_Task_ptr2232 static _Type _Make(Concurrency::details::_CancellationTokenState * _Ct) { return std::make_shared<_Task_impl<_ReturnType>>(_Ct); }
2233 #endif
2234 };
2235 #if _MSC_VER >= 1800
2236 typedef Concurrency::details::_TaskCollection_t::_TaskProcHandle_t _UnrealizedChore_t;
2237 typedef _UnrealizedChore_t _UnrealizedChore;
2238 typedef Concurrency::extensibility::scoped_critical_section_t scoped_lock;
2239 typedef Concurrency::extensibility::critical_section_t critical_section;
2240 typedef Concurrency::details::atomic_size_t atomic_size_t;
2241 #else
2242 typedef Concurrency::details::_UnrealizedChore _UnrealizedChore;
2243 typedef Concurrency::critical_section::scoped_lock scoped_lock;
2244 typedef Concurrency::critical_section critical_section;
2245 typedef volatile size_t atomic_size_t;
2246 #endif
2247 typedef std::shared_ptr<_Task_impl_base> _Task_ptr_base;
2248 // The weak-typed base task handler for continuation tasks.
2249 struct _ContinuationTaskHandleBase : _UnrealizedChore
2250 {
2251 _ContinuationTaskHandleBase * _M_next;
2252 task_continuation_context _M_continuationContext;
2253 bool _M_isTaskBasedContinuation;
2254
2255 // This field gives inlining scheduling policy for current chore.
2256 _TaskInliningMode _M_inliningMode;
2257
2258 virtual _Task_ptr_base _GetTaskImplBase() const = 0;
2259
_ContinuationTaskHandleBaseConcurrency_winrt::details::_ContinuationTaskHandleBase2260 _ContinuationTaskHandleBase() :
2261 _M_next(nullptr), _M_isTaskBasedContinuation(false), _M_continuationContext(task_continuation_context::use_default()), _M_inliningMode(Concurrency::details::_NoInline)
2262 {
2263 }
~_ContinuationTaskHandleBaseConcurrency_winrt::details::_ContinuationTaskHandleBase2264 virtual ~_ContinuationTaskHandleBase() {}
2265 };
2266 #if _MSC_VER >= 1800
2267 #if _PPLTASK_ASYNC_LOGGING
2268 // GUID used for identifying causality logs from PPLTask
2269 const ::Platform::Guid _PPLTaskCausalityPlatformID(0x7A76B220, 0xA758, 0x4E6E, 0xB0, 0xE0, 0xD7, 0xC6, 0xD7, 0x4A, 0x88, 0xFE);
2270
2271 __declspec(selectany) volatile long _isCausalitySupported = 0;
2272
_IsCausalitySupported()2273 inline bool _IsCausalitySupported()
2274 {
2275 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
2276 if (_isCausalitySupported == 0)
2277 {
2278 long _causality = 1;
2279 OSVERSIONINFOEX _osvi = {};
2280 _osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
2281
2282 // The Causality is supported on Windows version higher than Windows 8
2283 _osvi.dwMajorVersion = 6;
2284 _osvi.dwMinorVersion = 3;
2285
2286 DWORDLONG _conditionMask = 0;
2287 VER_SET_CONDITION(_conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
2288 VER_SET_CONDITION(_conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
2289
2290 if (::VerifyVersionInfo(&_osvi, VER_MAJORVERSION | VER_MINORVERSION, _conditionMask))
2291 {
2292 _causality = 2;
2293 }
2294
2295 _isCausalitySupported = _causality;
2296 return _causality == 2;
2297 }
2298
2299 return _isCausalitySupported == 2 ? true : false;
2300 #else
2301 return true;
2302 #endif
2303 }
2304
2305 // Stateful logger rests inside task_impl_base.
2306 struct _TaskEventLogger
2307 {
2308 _Task_impl_base *_M_task;
2309 bool _M_scheduled;
2310 bool _M_taskPostEventStarted;
2311
2312 // Log before scheduling task
_LogScheduleTaskConcurrency_winrt::details::_TaskEventLogger2313 void _LogScheduleTask(bool _isContinuation)
2314 {
2315 if (details::_IsCausalitySupported())
2316 {
2317 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCreation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
2318 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task),
2319 _isContinuation ? "Concurrency::PPLTask::ScheduleContinuationTask" : "Concurrency::PPLTask::ScheduleTask", 0);
2320 _M_scheduled = true;
2321 }
2322 }
2323
2324 // It will log the cancel event but not canceled state. _LogTaskCompleted will log the terminal state, which includes cancel state.
_LogCancelTaskConcurrency_winrt::details::_TaskEventLogger2325 void _LogCancelTask()
2326 {
2327 if (details::_IsCausalitySupported())
2328 {
2329 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationRelation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Important, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
2330 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalityRelation::Cancel);
2331
2332 }
2333 }
2334
2335 // Log when task reaches terminal state. Note: the task can reach a terminal state (by cancellation or exception) without having run
2336 void _LogTaskCompleted();
2337
2338 // Log when task body (which includes user lambda and other scheduling code) begin to run
_LogTaskExecutionStartedConcurrency_winrt::details::_TaskEventLogger2339 void _LogTaskExecutionStarted() { }
2340
2341 // Log when task body finish executing
_LogTaskExecutionCompletedConcurrency_winrt::details::_TaskEventLogger2342 void _LogTaskExecutionCompleted()
2343 {
2344 if (_M_taskPostEventStarted && details::_IsCausalitySupported())
2345 {
2346 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
2347 ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification);
2348 }
2349 }
2350
2351 // Log right before user lambda being invoked
_LogWorkItemStartedConcurrency_winrt::details::_TaskEventLogger2352 void _LogWorkItemStarted()
2353 {
2354 if (details::_IsCausalitySupported())
2355 {
2356 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
2357 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution);
2358 }
2359 }
2360
2361 // Log right after user lambda being invoked
_LogWorkItemCompletedConcurrency_winrt::details::_TaskEventLogger2362 void _LogWorkItemCompleted()
2363 {
2364 if (details::_IsCausalitySupported())
2365 {
2366 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
2367 ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution);
2368
2369 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
2370 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification);
2371 _M_taskPostEventStarted = true;
2372 }
2373 }
2374
_TaskEventLoggerConcurrency_winrt::details::_TaskEventLogger2375 _TaskEventLogger(_Task_impl_base *_task) : _M_task(_task)
2376 {
2377 _M_scheduled = false;
2378 _M_taskPostEventStarted = false;
2379 }
2380 };
2381
2382 // Exception safe logger for user lambda
2383 struct _TaskWorkItemRAIILogger
2384 {
2385 _TaskEventLogger &_M_logger;
_TaskWorkItemRAIILoggerConcurrency_winrt::details::_TaskWorkItemRAIILogger2386 _TaskWorkItemRAIILogger(_TaskEventLogger &_taskHandleLogger) : _M_logger(_taskHandleLogger)
2387 {
2388 _M_logger._LogWorkItemStarted();
2389 }
2390
~_TaskWorkItemRAIILoggerConcurrency_winrt::details::_TaskWorkItemRAIILogger2391 ~_TaskWorkItemRAIILogger()
2392 {
2393 _M_logger._LogWorkItemCompleted();
2394 }
2395 _TaskWorkItemRAIILogger &operator =(const _TaskWorkItemRAIILogger &); // cannot be assigned
2396 };
2397
2398 #else
_LogCancelTask(_Task_impl_base *)2399 inline void _LogCancelTask(_Task_impl_base *) {}
2400 struct _TaskEventLogger
2401 {
_LogScheduleTaskConcurrency_winrt::details::_TaskEventLogger2402 void _LogScheduleTask(bool) {}
_LogCancelTaskConcurrency_winrt::details::_TaskEventLogger2403 void _LogCancelTask() {}
_LogWorkItemStartedConcurrency_winrt::details::_TaskEventLogger2404 void _LogWorkItemStarted() {}
_LogWorkItemCompletedConcurrency_winrt::details::_TaskEventLogger2405 void _LogWorkItemCompleted() {}
_LogTaskExecutionStartedConcurrency_winrt::details::_TaskEventLogger2406 void _LogTaskExecutionStarted() {}
_LogTaskExecutionCompletedConcurrency_winrt::details::_TaskEventLogger2407 void _LogTaskExecutionCompleted() {}
_LogTaskCompletedConcurrency_winrt::details::_TaskEventLogger2408 void _LogTaskCompleted() {}
_TaskEventLoggerConcurrency_winrt::details::_TaskEventLogger2409 _TaskEventLogger(_Task_impl_base *) {}
2410 };
2411 struct _TaskWorkItemRAIILogger
2412 {
_TaskWorkItemRAIILoggerConcurrency_winrt::details::_TaskWorkItemRAIILogger2413 _TaskWorkItemRAIILogger(_TaskEventLogger &) {}
2414 };
2415 #endif
2416 #endif
2417 /// <summary>
2418 /// The _PPLTaskHandle is the strong-typed task handle base. All user task functions need to be wrapped in this task handler
2419 /// to be executable by PPL. By deriving from a different _BaseTaskHandle, it can be used for both initial tasks and continuation tasks.
2420 /// For initial tasks, _PPLTaskHandle will be derived from _UnrealizedChore, and for continuation tasks, it will be derived from
2421 /// _ContinuationTaskHandleBase. The life time of the _PPLTaskHandle object is be managed by runtime if task handle is scheduled.
2422 /// </summary>
2423 /// <typeparam name="_ReturnType">
2424 /// The result type of the _Task_impl.
2425 /// </typeparam>
2426 /// <typeparam name="_DerivedTaskHandle">
2427 /// The derived task handle class. The <c>operator ()</c> needs to be implemented.
2428 /// </typeparam>
2429 /// <typeparam name="_BaseTaskHandle">
2430 /// The base class from which _PPLTaskHandle should be derived. This is either _UnrealizedChore or _ContinuationTaskHandleBase.
2431 /// </typeparam>
2432 template<typename _ReturnType, typename _DerivedTaskHandle, typename _BaseTaskHandle>
2433 struct _PPLTaskHandle : _BaseTaskHandle
2434 {
_PPLTaskHandleConcurrency_winrt::details::_PPLTaskHandle2435 _PPLTaskHandle(const typename _Task_ptr<_ReturnType>::_Type & _PTask) : _M_pTask(_PTask)
2436 {
2437 #if _MSC_VER < 1800
2438 m_pFunction = reinterpret_cast <Concurrency::TaskProc> (&_UnrealizedChore::_InvokeBridge<_PPLTaskHandle>);
2439 _SetRuntimeOwnsLifetime(true);
2440 #endif
2441 }
~_PPLTaskHandleConcurrency_winrt::details::_PPLTaskHandle2442 virtual ~_PPLTaskHandle() {
2443 #if _MSC_VER >= 1800
2444 // Here is the sink of all task completion code paths
2445 _M_pTask->_M_taskEventLogger._LogTaskCompleted();
2446 #endif
2447 }
2448 #if _MSC_VER >= 1800
invokeConcurrency_winrt::details::_PPLTaskHandle2449 virtual void invoke() const
2450 #else
2451 void operator()() const
2452 #endif
2453 {
2454 // All exceptions should be rethrown to finish cleanup of the task collection. They will be caught and handled
2455 // by the runtime.
2456 _CONCRT_ASSERT(_M_pTask != nullptr);
2457 if (!_M_pTask->_TransitionedToStarted()) {
2458 #if _MSC_VER >= 1800
2459 static_cast<const _DerivedTaskHandle *>(this)->_SyncCancelAndPropagateException();
2460 #endif
2461 return;
2462 }
2463 #if _MSC_VER >= 1800
2464 _M_pTask->_M_taskEventLogger._LogTaskExecutionStarted();
2465 #endif
2466 try
2467 {
2468 // All derived task handle must implement this contract function.
2469 static_cast<const _DerivedTaskHandle *>(this)->_Perform();
2470 }
2471 catch (const Concurrency::task_canceled &)
2472 {
2473 _M_pTask->_Cancel(true);
2474 #if _MSC_VER < 1800
2475 throw;
2476 #endif
2477 }
2478 catch (const Concurrency::details::_Interruption_exception &)
2479 {
2480 _M_pTask->_Cancel(true);
2481 #if _MSC_VER < 1800
2482 throw;
2483 #endif
2484 }
2485 catch (IRestrictedErrorInfo*& _E)
2486 {
2487 _M_pTask->_CancelWithException(_E);
2488 #if _MSC_VER < 1800
2489 throw;
2490 #endif
2491 }
2492 catch (...)
2493 {
2494 _M_pTask->_CancelWithException(std::current_exception());
2495 #if _MSC_VER < 1800
2496 throw;
2497 #endif
2498 }
2499 #if _MSC_VER >= 1800
2500 _M_pTask->_M_taskEventLogger._LogTaskExecutionCompleted();
2501 #endif
2502 }
2503
2504 // Cast _M_pTask pointer to "type-less" _Task_impl_base pointer, which can be used in _ContinuationTaskHandleBase.
2505 // The return value should be automatically optimized by R-value ref.
_GetTaskImplBaseConcurrency_winrt::details::_PPLTaskHandle2506 _Task_ptr_base _GetTaskImplBase() const
2507 {
2508 return _M_pTask;
2509 }
2510
2511 typename _Task_ptr<_ReturnType>::_Type _M_pTask;
2512
2513 private:
2514 _PPLTaskHandle const & operator=(_PPLTaskHandle const&); // no assignment operator
2515 };
2516
2517 /// <summary>
2518 /// The base implementation of a first-class task. This class contains all the non-type specific
2519 /// implementation details of the task.
2520 /// </summary>
2521 /**/
2522 struct _Task_impl_base
2523 {
2524 enum _TaskInternalState
2525 {
2526 // Tracks the state of the task, rather than the task collection on which the task is scheduled
2527 _Created,
2528 _Started,
2529 _PendingCancel,
2530 _Completed,
2531 _Canceled
2532 };
2533 #if _MSC_VER >= 1800
_Task_impl_baseConcurrency_winrt::details::_Task_impl_base2534 _Task_impl_base(Concurrency::details::_CancellationTokenState * _PTokenState, Concurrency::scheduler_ptr _Scheduler_arg)
2535 : _M_TaskState(_Created),
2536 _M_fFromAsync(false), _M_fUnwrappedTask(false),
2537 _M_pRegistration(nullptr), _M_Continuations(nullptr), _M_TaskCollection(_Scheduler_arg),
2538 _M_taskEventLogger(this)
2539 #else
2540 _Task_impl_base(Concurrency::details::_CancellationTokenState * _PTokenState) : _M_TaskState(_Created),
2541 _M_fFromAsync(false), _M_fRuntimeAggregate(false), _M_fUnwrappedTask(false),
2542 _M_pRegistration(nullptr), _M_Continuations(nullptr), _M_pTaskCollection(nullptr),
2543 _M_pTaskCreationAddressHint(nullptr)
2544 #endif
2545 {
2546 // Set cancelation token
2547 _M_pTokenState = _PTokenState;
2548 _CONCRT_ASSERT(_M_pTokenState != nullptr);
2549 if (_M_pTokenState != Concurrency::details::_CancellationTokenState::_None())
2550 _M_pTokenState->_Reference();
2551
2552 }
2553
~_Task_impl_baseConcurrency_winrt::details::_Task_impl_base2554 virtual ~_Task_impl_base()
2555 {
2556 _CONCRT_ASSERT(_M_pTokenState != nullptr);
2557 if (_M_pTokenState != Concurrency::details::_CancellationTokenState::_None())
2558 {
2559 _M_pTokenState->_Release();
2560 }
2561 #if _MSC_VER < 1800
2562 if (_M_pTaskCollection != nullptr)
2563 {
2564 _M_pTaskCollection->_Release();
2565 _M_pTaskCollection = nullptr;
2566 }
2567 #endif
2568 }
2569
_WaitConcurrency_winrt::details::_Task_impl_base2570 task_status _Wait()
2571 {
2572 bool _DoWait = true;
2573
2574 if (_IsNonBlockingThread())
2575 {
2576 // In order to prevent Windows Runtime STA threads from blocking the UI, calling task.wait() task.get() is illegal
2577 // if task has not been completed.
2578 if (!_IsCompleted() && !_IsCanceled())
2579 {
2580 throw Concurrency::invalid_operation("Illegal to wait on a task in a Windows Runtime STA");
2581 }
2582 else
2583 {
2584 // Task Continuations are 'scheduled' *inside* the chore that is executing on the ancestors's task group. If a continuation
2585 // needs to be marshalled to a different apartment, instead of scheduling, we make a synchronous cross apartment COM
2586 // call to execute the continuation. If it then happens to do something which waits on the ancestor (say it calls .get(), which
2587 // task based continuations are wont to do), waiting on the task group results in on the chore that is making this
2588 // synchronous callback, which causes a deadlock. To avoid this, we test the state ancestor's event , and we will NOT wait on
2589 // if it has finished execution (which means now we are on the inline synchronous callback).
2590 _DoWait = false;
2591 }
2592 }
2593 if (_DoWait)
2594 {
2595 #if _MSC_VER < 1800
2596 // Wait for the task to be actually scheduled, otherwise the underlying task collection
2597 // might not be created yet. If we don't wait, we will miss the chance to inline this task.
2598 _M_Scheduled.wait();
2599
2600
2601 // A PPL task created by a task_completion_event does not have an underlying TaskCollection. For
2602 // These tasks, a call to wait should wait for the event to be set. The TaskCollection must either
2603 // be nullptr or allocated (the setting of _M_Scheduled) ensures that.
2604 #endif
2605 // If this task was created from a Windows Runtime async operation, do not attempt to inline it. The
2606 // async operation will take place on a thread in the appropriate apartment Simply wait for the completed
2607 // event to be set.
2608 #if _MSC_VER >= 1800
2609 if (_M_fFromAsync)
2610 #else
2611 if ((_M_pTaskCollection == nullptr) || _M_fFromAsync)
2612 #endif
2613 {
2614 #if _MSC_VER >= 1800
2615 _M_TaskCollection._Wait();
2616 #else
2617 _M_Completed.wait();
2618 #endif
2619 }
2620 else
2621 {
2622 // Wait on the task collection to complete. The task collection is guaranteed to still be
2623 // valid since the task must be still within scope so that the _Task_impl_base destructor
2624 // has not yet been called. This call to _Wait potentially inlines execution of work.
2625 try
2626 {
2627 // Invoking wait on a task collection resets the state of the task collection. This means that
2628 // if the task collection itself were canceled, or had encountered an exception, only the first
2629 // call to wait will receive this status. However, both cancellation and exceptions flowing through
2630 // tasks set state in the task impl itself.
2631
2632 // When it returns cancelled, either work chore or the cancel thread should already have set task's state
2633 // properly -- cancelled state or completed state (because there was no interruption point).
2634 // For tasks with unwrapped tasks, we should not change the state of current task, since the unwrapped task are still running.
2635 #if _MSC_VER >= 1800
2636 _M_TaskCollection._RunAndWait();
2637 #else
2638 _M_pTaskCollection->_RunAndWait();
2639 #endif
2640 }
2641 catch (Concurrency::details::_Interruption_exception&)
2642 {
2643 // The _TaskCollection will never be an interruption point since it has a none token.
2644 _CONCRT_ASSERT(false);
2645 }
2646 catch (Concurrency::task_canceled&)
2647 {
2648 // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task
2649 // must be called from code that is executed within the task (throwing it from parallel work created by and waited
2650 // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen
2651 // the exception and canceled the task. Swallow the exception here.
2652 _CONCRT_ASSERT(_IsCanceled());
2653 }
2654 catch (IRestrictedErrorInfo*& _E)
2655 {
2656 // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.
2657 if(!_HasUserException())
2658 {
2659 _CancelWithException(_E);
2660 }
2661 // Rethrow will mark the exception as observed.
2662 _M_exceptionHolder->_RethrowUserException();
2663 }
2664 catch (...)
2665 {
2666 // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.
2667 if (!_HasUserException())
2668 {
2669 _CancelWithException(std::current_exception());
2670 }
2671 // Rethrow will mark the exception as observed.
2672 _M_exceptionHolder->_RethrowUserException();
2673 }
2674
2675 // If the lambda body for this task (executed or waited upon in _RunAndWait above) happened to return a task
2676 // which is to be unwrapped and plumbed to the output of this task, we must not only wait on the lambda body, we must
2677 // wait on the **INNER** body. It is in theory possible that we could inline such if we plumb a series of things through;
2678 // however, this takes the tact of simply waiting upon the completion signal.
2679 if (_M_fUnwrappedTask)
2680 {
2681 #if _MSC_VER >= 1800
2682 _M_TaskCollection._Wait();
2683 #else
2684 _M_Completed.wait();
2685 #endif
2686 }
2687 }
2688 }
2689
2690 if (_HasUserException())
2691 {
2692 _M_exceptionHolder->_RethrowUserException();
2693 }
2694 else if (_IsCanceled())
2695 {
2696 return Concurrency::canceled;
2697 }
2698 _CONCRT_ASSERT(_IsCompleted());
2699 return Concurrency::completed;
2700 }
2701 /// <summary>
2702 /// Requests cancellation on the task and schedules continuations if the task can be transitioned to a terminal state.
2703 /// </summary>
2704 /// <param name="_SynchronousCancel">
2705 /// Set to true if the cancel takes place as a result of the task body encountering an exception, or because an ancestor or task_completion_event the task
2706 /// was registered with were canceled with an exception. A synchronous cancel is one that assures the task could not be running on a different thread at
2707 /// the time the cancellation is in progress. An asynchronous cancel is one where the thread performing the cancel has no control over the thread that could
2708 /// be executing the task, that is the task could execute concurrently while the cancellation is in progress.
2709 /// </param>
2710 /// <param name="_UserException">
2711 /// Whether an exception other than the internal runtime cancellation exceptions caused this cancellation.
2712 /// </param>
2713 /// <param name="_PropagatedFromAncestor">
2714 /// Whether this exception came from an ancestor task or a task_completion_event as opposed to an exception that was encountered by the task itself. Only valid when
2715 /// _UserException is set to true.
2716 /// </param>
2717 /// <param name="_ExHolder">
2718 /// The exception holder that represents the exception. Only valid when _UserException is set to true.
2719 /// </param>
2720 virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder>& _ExHolder) = 0;
2721
_CancelConcurrency_winrt::details::_Task_impl_base2722 bool _Cancel(bool _SynchronousCancel)
2723 {
2724 // Send in a dummy value for exception. It is not used when the first parameter is false.
2725 return _CancelAndRunContinuations(_SynchronousCancel, false, false, _M_exceptionHolder);
2726 }
2727
_CancelWithExceptionHolderConcurrency_winrt::details::_Task_impl_base2728 bool _CancelWithExceptionHolder(const std::shared_ptr<_ExceptionHolder>& _ExHolder, bool _PropagatedFromAncestor)
2729 {
2730 // This task was canceled because an ancestor task encountered an exception.
2731 return _CancelAndRunContinuations(true, true, _PropagatedFromAncestor, _ExHolder);
2732 }
2733
_CancelWithExceptionConcurrency_winrt::details::_Task_impl_base2734 bool _CancelWithException(IRestrictedErrorInfo*& _Exception)
2735 {
2736 // This task was canceled because the task body encountered an exception.
2737 _CONCRT_ASSERT(!_HasUserException());
2738 #if _MSC_VER >= 1800
2739 return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack()));
2740 #else
2741 return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationAddressHint()));
2742 #endif
2743 }
_CancelWithExceptionConcurrency_winrt::details::_Task_impl_base2744 bool _CancelWithException(const std::exception_ptr& _Exception)
2745 {
2746 // This task was canceled because the task body encountered an exception.
2747 _CONCRT_ASSERT(!_HasUserException());
2748 #if _MSC_VER >= 1800
2749 return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack()));
2750 #else
2751 return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationAddressHint()));
2752 #endif
2753 }
2754
2755 #if _MSC_VER >= 1800
_RegisterCancellationConcurrency_winrt::details::_Task_impl_base2756 void _RegisterCancellation(std::weak_ptr<_Task_impl_base> _WeakPtr)
2757 #else
2758 void _RegisterCancellation()
2759 #endif
2760 {
2761 _CONCRT_ASSERT(Concurrency::details::_CancellationTokenState::_IsValid(_M_pTokenState));
2762 #if _MSC_VER >= 1800
2763 auto _CancellationCallback = [_WeakPtr](){
2764 // Taking ownership of the task prevents dead lock during destruction
2765 // if the destructor waits for the cancellations to be finished
2766 auto _task = _WeakPtr.lock();
2767 if (_task != nullptr)
2768 _task->_Cancel(false);
2769 };
2770
2771 _M_pRegistration = new Concurrency::details::_CancellationTokenCallback<decltype(_CancellationCallback)>(_CancellationCallback);
2772 _M_pTokenState->_RegisterCallback(_M_pRegistration);
2773 #else
2774 _M_pRegistration = _M_pTokenState->_RegisterCallback(reinterpret_cast<Concurrency::TaskProc>(&_CancelViaToken), (_Task_impl_base *)this);
2775 #endif
2776 }
2777
_DeregisterCancellationConcurrency_winrt::details::_Task_impl_base2778 void _DeregisterCancellation()
2779 {
2780 if (_M_pRegistration != nullptr)
2781 {
2782 _M_pTokenState->_DeregisterCallback(_M_pRegistration);
2783 _M_pRegistration->_Release();
2784 _M_pRegistration = nullptr;
2785 }
2786 }
2787 #if _MSC_VER < 1800
_CancelViaTokenConcurrency_winrt::details::_Task_impl_base2788 static void _CancelViaToken(_Task_impl_base *_PImpl)
2789 {
2790 _PImpl->_Cancel(false);
2791 }
2792 #endif
_IsCreatedConcurrency_winrt::details::_Task_impl_base2793 bool _IsCreated()
2794 {
2795 return (_M_TaskState == _Created);
2796 }
2797
_IsStartedConcurrency_winrt::details::_Task_impl_base2798 bool _IsStarted()
2799 {
2800 return (_M_TaskState == _Started);
2801 }
2802
_IsPendingCancelConcurrency_winrt::details::_Task_impl_base2803 bool _IsPendingCancel()
2804 {
2805 return (_M_TaskState == _PendingCancel);
2806 }
2807
_IsCompletedConcurrency_winrt::details::_Task_impl_base2808 bool _IsCompleted()
2809 {
2810 return (_M_TaskState == _Completed);
2811 }
2812
_IsCanceledConcurrency_winrt::details::_Task_impl_base2813 bool _IsCanceled()
2814 {
2815 return (_M_TaskState == _Canceled);
2816 }
2817
_HasUserExceptionConcurrency_winrt::details::_Task_impl_base2818 bool _HasUserException()
2819 {
2820 return static_cast<bool>(_M_exceptionHolder);
2821 }
2822 #if _MSC_VER < 1800
_SetScheduledEventConcurrency_winrt::details::_Task_impl_base2823 void _SetScheduledEvent()
2824 {
2825 _M_Scheduled.set();
2826 }
2827 #endif
_GetExceptionHolderConcurrency_winrt::details::_Task_impl_base2828 const std::shared_ptr<_ExceptionHolder>& _GetExceptionHolder()
2829 {
2830 _CONCRT_ASSERT(_HasUserException());
2831 return _M_exceptionHolder;
2832 }
2833
_IsApartmentAwareConcurrency_winrt::details::_Task_impl_base2834 bool _IsApartmentAware()
2835 {
2836 return _M_fFromAsync;
2837 }
2838
_SetAsyncConcurrency_winrt::details::_Task_impl_base2839 void _SetAsync(bool _Async = true)
2840 {
2841 _M_fFromAsync = _Async;
2842 }
2843 #if _MSC_VER >= 1800
_GetTaskCreationCallstackConcurrency_winrt::details::_Task_impl_base2844 _TaskCreationCallstack _GetTaskCreationCallstack()
2845 {
2846 return _M_pTaskCreationCallstack;
2847 }
2848
_SetTaskCreationCallstackConcurrency_winrt::details::_Task_impl_base2849 void _SetTaskCreationCallstack(const _TaskCreationCallstack &_Callstack)
2850 {
2851 _M_pTaskCreationCallstack = _Callstack;
2852 }
2853 #else
_GetTaskCreationAddressHintConcurrency_winrt::details::_Task_impl_base2854 void* _GetTaskCreationAddressHint()
2855 {
2856 return _M_pTaskCreationAddressHint;
2857 }
2858
_SetTaskCreationAddressHintConcurrency_winrt::details::_Task_impl_base2859 void _SetTaskCreationAddressHint(void* _AddressHint)
2860 {
2861 _M_pTaskCreationAddressHint = _AddressHint;
2862 }
2863 #endif
2864 /// <summary>
2865 /// Helper function to schedule the task on the Task Collection.
2866 /// </summary>
2867 /// <param name="_PTaskHandle">
2868 /// The task chore handle that need to be executed.
2869 /// </param>
2870 /// <param name="_InliningMode">
2871 /// The inlining scheduling policy for current _PTaskHandle.
2872 /// </param>
_ScheduleTaskConcurrency_winrt::details::_Task_impl_base2873 void _ScheduleTask(_UnrealizedChore * _PTaskHandle, _TaskInliningMode _InliningMode)
2874 {
2875 #if _MSC_VER < 1800
2876 // Construct the task collection; We use none token to provent it becoming interruption point.
2877 _M_pTaskCollection = Concurrency::details::_AsyncTaskCollection::_NewCollection(Concurrency::details::_CancellationTokenState::_None());
2878 // _M_pTaskCollection->_ScheduleWithAutoInline will schedule the chore onto AsyncTaskCollection with automatic inlining, in a way that honors cancellation etc.
2879 #endif
2880 try
2881 {
2882 #if _MSC_VER >= 1800
2883 _M_TaskCollection._ScheduleTask(_PTaskHandle, _InliningMode);
2884 #else
2885 // Do not need to check its returning state, more details please refer to _Wait method.
2886 _M_pTaskCollection->_ScheduleWithAutoInline(_PTaskHandle, _InliningMode);
2887 #endif
2888 }
2889 catch (const Concurrency::task_canceled &)
2890 {
2891 // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task
2892 // must be called from code that is executed within the task (throwing it from parallel work created by and waited
2893 // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen
2894 // the exception and canceled the task. Swallow the exception here.
2895 _CONCRT_ASSERT(_IsCanceled());
2896 }
2897 catch (const Concurrency::details::_Interruption_exception &)
2898 {
2899 // The _TaskCollection will never be an interruption point since it has a none token.
2900 _CONCRT_ASSERT(false);
2901 }
2902 catch (...)
2903 {
2904 // This exception could only have come from within the chore body. It should've been caught
2905 // and the task should be canceled with exception. Swallow the exception here.
2906 _CONCRT_ASSERT(_HasUserException());
2907 }
2908 #if _MSC_VER < 1800
2909 // Set the event in case anyone is waiting to notify that this task has been scheduled. In the case where we
2910 // execute the chore inline, the event should be set after the chore has executed, to prevent a different thread
2911 // performing a wait on the task from waiting on the task collection before the chore is actually added to it,
2912 // and thereby returning from the wait() before the chore has executed.
2913 _SetScheduledEvent();
2914 #endif
2915 }
2916
2917 /// <summary>
2918 /// Function executes a continuation. This function is recorded by a parent task implementation
2919 /// when a continuation is created in order to execute later.
2920 /// </summary>
2921 /// <param name="_PTaskHandle">
2922 /// The continuation task chore handle that need to be executed.
2923 /// </param>
2924 /**/
_RunContinuationConcurrency_winrt::details::_Task_impl_base2925 void _RunContinuation(_ContinuationTaskHandleBase * _PTaskHandle)
2926 {
2927 _Task_ptr_base _ImplBase = _PTaskHandle->_GetTaskImplBase();
2928 if (_IsCanceled() && !_PTaskHandle->_M_isTaskBasedContinuation)
2929 {
2930 if (_HasUserException())
2931 {
2932 // If the ancestor encountered an exception, transfer the exception to the continuation
2933 // This traverses down the tree to propagate the exception.
2934 _ImplBase->_CancelWithExceptionHolder(_GetExceptionHolder(), true);
2935 }
2936 else
2937 {
2938 // If the ancestor was canceled, then your own execution should be canceled.
2939 // This traverses down the tree to cancel it.
2940 _ImplBase->_Cancel(true);
2941 }
2942 }
2943 else
2944 {
2945 // This can only run when the ancestor has completed or it's a task based continuation that fires when a task is canceled
2946 // (with or without a user exception).
2947 _CONCRT_ASSERT(_IsCompleted() || _PTaskHandle->_M_isTaskBasedContinuation);
2948
2949 #if _MSC_VER >= 1800
2950 _CONCRT_ASSERT(!_ImplBase->_IsCanceled());
2951 return _ImplBase->_ScheduleContinuationTask(_PTaskHandle);
2952 #else
2953 // If it has been canceled here (before starting), do nothing. The guy firing cancel will do the clean up.
2954 if (!_ImplBase->_IsCanceled())
2955 {
2956 return _ImplBase->_ScheduleContinuationTask(_PTaskHandle);
2957 }
2958 #endif
2959 }
2960
2961 // If the handle is not scheduled, we need to manually delete it.
2962 delete _PTaskHandle;
2963 }
2964
2965 // Schedule a continuation to run
_ScheduleContinuationTaskConcurrency_winrt::details::_Task_impl_base2966 void _ScheduleContinuationTask(_ContinuationTaskHandleBase * _PTaskHandle)
2967 {
2968 #if _MSC_VER >= 1800
2969 _M_taskEventLogger._LogScheduleTask(true);
2970 #endif
2971 // Ensure that the continuation runs in proper context (this might be on a Concurrency Runtime thread or in a different Windows Runtime apartment)
2972 if (_PTaskHandle->_M_continuationContext._HasCapturedContext())
2973 {
2974 // For those continuations need to be scheduled inside captured context, we will try to apply automatic inlining to their inline modes,
2975 // if they haven't been specified as _ForceInline yet. This change will encourage those continuations to be executed inline so that reduce
2976 // the cost of marshaling.
2977 // For normal continuations we won't do any change here, and their inline policies are completely decided by ._ThenImpl method.
2978 if (_PTaskHandle->_M_inliningMode != Concurrency::details::_ForceInline)
2979 {
2980 _PTaskHandle->_M_inliningMode = Concurrency::details::_DefaultAutoInline;
2981 }
2982 details::_ScheduleFuncWithAutoInline([_PTaskHandle]() -> HRESULT {
2983 // Note that we cannot directly capture "this" pointer, instead, we should use _TaskImplPtr, a shared_ptr to the _Task_impl_base.
2984 // Because "this" pointer will be invalid as soon as _PTaskHandle get deleted. _PTaskHandle will be deleted after being scheduled.
2985 auto _TaskImplPtr = _PTaskHandle->_GetTaskImplBase();
2986 if (details::_ContextCallback::_CaptureCurrent() == _PTaskHandle->_M_continuationContext)
2987 {
2988 _TaskImplPtr->_ScheduleTask(_PTaskHandle, Concurrency::details::_ForceInline);
2989 }
2990 else
2991 {
2992 //
2993 // It's entirely possible that the attempt to marshal the call into a differing context will fail. In this case, we need to handle
2994 // the exception and mark the continuation as canceled with the appropriate exception. There is one slight hitch to this:
2995 //
2996 // NOTE: COM's legacy behavior is to swallow SEH exceptions and marshal them back as HRESULTS. This will in effect turn an SEH into
2997 // a C++ exception that gets tagged on the task. One unfortunate result of this is that various pieces of the task infrastructure will
2998 // not be in a valid state after this in /EHsc (due to the lack of destructors running, etc...).
2999 //
3000 try
3001 {
3002 // Dev10 compiler needs this!
3003 auto _PTaskHandle1 = _PTaskHandle;
3004 _PTaskHandle->_M_continuationContext._CallInContext([_PTaskHandle1, _TaskImplPtr]() -> HRESULT {
3005 _TaskImplPtr->_ScheduleTask(_PTaskHandle1, Concurrency::details::_ForceInline);
3006 return S_OK;
3007 });
3008 }
3009 catch (IRestrictedErrorInfo*& _E)
3010 {
3011 _TaskImplPtr->_CancelWithException(_E);
3012 }
3013 catch (...)
3014 {
3015 _TaskImplPtr->_CancelWithException(std::current_exception());
3016 }
3017 }
3018 return S_OK;
3019 }, _PTaskHandle->_M_inliningMode);
3020 }
3021 else
3022 {
3023 _ScheduleTask(_PTaskHandle, _PTaskHandle->_M_inliningMode);
3024 }
3025 }
3026
3027 /// <summary>
3028 /// Schedule the actual continuation. This will either schedule the function on the continuation task's implementation
3029 /// if the task has completed or append it to a list of functions to execute when the task actually does complete.
3030 /// </summary>
3031 /// <typeparam name="_FuncInputType">
3032 /// The input type of the task.
3033 /// </typeparam>
3034 /// <typeparam name="_FuncOutputType">
3035 /// The output type of the task.
3036 /// </typeparam>
3037 /**/
_ScheduleContinuationConcurrency_winrt::details::_Task_impl_base3038 void _ScheduleContinuation(_ContinuationTaskHandleBase * _PTaskHandle)
3039 {
3040 enum { _Nothing, _Schedule, _Cancel, _CancelWithException } _Do = _Nothing;
3041
3042 // If the task has canceled, cancel the continuation. If the task has completed, execute the continuation right away.
3043 // Otherwise, add it to the list of pending continuations
3044 {
3045 scoped_lock _LockHolder(_M_ContinuationsCritSec);
3046 if (_IsCompleted() || (_IsCanceled() && _PTaskHandle->_M_isTaskBasedContinuation))
3047 {
3048 _Do = _Schedule;
3049 }
3050 else if (_IsCanceled())
3051 {
3052 if (_HasUserException())
3053 {
3054 _Do = _CancelWithException;
3055 }
3056 else
3057 {
3058 _Do = _Cancel;
3059 }
3060 }
3061 else
3062 {
3063 // chain itself on the continuation chain.
3064 _PTaskHandle->_M_next = _M_Continuations;
3065 _M_Continuations = _PTaskHandle;
3066 }
3067 }
3068
3069 // Cancellation and execution of continuations should be performed after releasing the lock. Continuations off of
3070 // async tasks may execute inline.
3071 switch (_Do)
3072 {
3073 case _Schedule:
3074 {
3075 _PTaskHandle->_GetTaskImplBase()->_ScheduleContinuationTask(_PTaskHandle);
3076 break;
3077 }
3078 case _Cancel:
3079 {
3080 // If the ancestor was canceled, then your own execution should be canceled.
3081 // This traverses down the tree to cancel it.
3082 _PTaskHandle->_GetTaskImplBase()->_Cancel(true);
3083
3084 delete _PTaskHandle;
3085 break;
3086 }
3087 case _CancelWithException:
3088 {
3089 // If the ancestor encountered an exception, transfer the exception to the continuation
3090 // This traverses down the tree to propagate the exception.
3091 _PTaskHandle->_GetTaskImplBase()->_CancelWithExceptionHolder(_GetExceptionHolder(), true);
3092
3093 delete _PTaskHandle;
3094 break;
3095 }
3096 case _Nothing:
3097 default:
3098 // In this case, we have inserted continuation to continuation chain,
3099 // nothing more need to be done, just leave.
3100 break;
3101 }
3102 }
3103
_RunTaskContinuationsConcurrency_winrt::details::_Task_impl_base3104 void _RunTaskContinuations()
3105 {
3106 // The link list can no longer be modified at this point,
3107 // since all following up continuations will be scheduled by themselves.
3108 _ContinuationList _Cur = _M_Continuations, _Next;
3109 _M_Continuations = nullptr;
3110 while (_Cur)
3111 {
3112 // Current node might be deleted after running,
3113 // so we must fetch the next first.
3114 _Next = _Cur->_M_next;
3115 _RunContinuation(_Cur);
3116 _Cur = _Next;
3117 }
3118 }
_IsNonBlockingThreadConcurrency_winrt::details::_Task_impl_base3119 static bool _IsNonBlockingThread()
3120 {
3121 APTTYPE _AptType;
3122 APTTYPEQUALIFIER _AptTypeQualifier;
3123
3124 HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);
3125 //
3126 // If it failed, it's not a Windows Runtime/COM initialized thread. This is not a failure.
3127 //
3128 if (SUCCEEDED(hr))
3129 {
3130 switch (_AptType)
3131 {
3132 case APTTYPE_STA:
3133 case APTTYPE_MAINSTA:
3134 return true;
3135 break;
3136 case APTTYPE_NA:
3137 switch (_AptTypeQualifier)
3138 {
3139 // A thread executing in a neutral apartment is either STA or MTA. To find out if this thread is allowed
3140 // to wait, we check the app qualifier. If it is an STA thread executing in a neutral apartment, waiting
3141 // is illegal, because the thread is responsible for pumping messages and waiting on a task could take the
3142 // thread out of circulation for a while.
3143 case APTTYPEQUALIFIER_NA_ON_STA:
3144 case APTTYPEQUALIFIER_NA_ON_MAINSTA:
3145 return true;
3146 break;
3147 }
3148 break;
3149 }
3150 }
3151 #if _UITHREADCTXT_SUPPORT
3152 // This method is used to throw an exepection in _Wait() if called within STA. We
3153 // want the same behavior if _Wait is called on the UI thread.
3154 if (SUCCEEDED(CaptureUiThreadContext(nullptr)))
3155 {
3156 return true;
3157 }
3158 #endif // _UITHREADCTXT_SUPPORT
3159
3160 return false;
3161 }
3162
3163 template<typename _ReturnType, typename _Result, typename _OpType, typename _CompHandlerType, typename _ResultType>
_AsyncInitConcurrency_winrt::details::_Task_impl_base3164 static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type & _OuterTask,
3165 _AsyncInfoImpl<_OpType, _CompHandlerType, _ResultType>* _AsyncOp)
3166 {
3167 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_GetUnwrappedType(stdx::declval<_OpType*>()))>::type _Result_abi;
3168 // This method is invoked either when a task is created from an existing async operation or
3169 // when a lambda that creates an async operation executes.
3170
3171 // If the outer task is pending cancel, cancel the async operation before setting the completed handler. The COM reference on
3172 // the IAsyncInfo object will be released when all *references to the operation go out of scope.
3173
3174 // This assertion uses the existence of taskcollection to determine if the task was created from an event.
3175 // That is no longer valid as even tasks created from a user lambda could have no underlying taskcollection
3176 // when a custom scheduler is used.
3177 #if _MSC_VER < 1800
3178 _CONCRT_ASSERT(((_OuterTask->_M_pTaskCollection == nullptr) || _OuterTask->_M_fUnwrappedTask) && !_OuterTask->_IsCanceled());
3179 #endif
3180
3181 // Pass the shared_ptr by value into the lambda instead of using 'this'.
3182
3183 _AsyncOp->put_Completed(Microsoft::WRL::Callback<_CompHandlerType>(
3184 [_OuterTask, _AsyncOp](_OpType* _Operation, ABI::Windows::Foundation::AsyncStatus _Status) mutable -> HRESULT
3185 {
3186 HRESULT hr = S_OK;
3187 if (_Status == ABI::Windows::Foundation::AsyncStatus::Canceled)
3188 {
3189 _OuterTask->_Cancel(true);
3190 }
3191 else if (_Status == ABI::Windows::Foundation::AsyncStatus::Error)
3192 {
3193 HRESULT _hr;
3194 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo;
3195 if (SUCCEEDED(hr = _Operation->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf())) && SUCCEEDED(hr = pAsyncInfo->get_ErrorCode(&_hr)))
3196 _OuterTask->_CancelWithException(std::make_exception_ptr(_hr));
3197 }
3198 else
3199 {
3200 _CONCRT_ASSERT(_Status == ABI::Windows::Foundation::AsyncStatus::Completed);
3201 _NormalizeVoidToUnitType<_Result_abi>::_Type results;
3202 if (SUCCEEDED(hr = _AsyncOp->GetResults(&results)))
3203 _OuterTask->_FinalizeAndRunContinuations(results);
3204 }
3205 // Take away this shared pointers reference on the task instead of waiting for the delegate to be released. It could
3206 // be released on a different thread after a delay, and not releasing the reference here could cause the tasks to hold
3207 // on to resources longer than they should. As an example, without this reset, writing to a file followed by reading from
3208 // it using the Windows Runtime Async APIs causes a sharing violation.
3209 // Using const_cast is the workaround for failed mutable keywords
3210 const_cast<_Task_ptr<_ReturnType>::_Type &>(_OuterTask).reset();
3211 return hr;
3212 }).Get());
3213 _OuterTask->_SetUnwrappedAsyncOp(_AsyncOp);
3214 }
3215 template<typename _ReturnType, typename _InternalReturnType>
_AsyncInitConcurrency_winrt::details::_Task_impl_base3216 static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type& _OuterTask, const task<_InternalReturnType> & _UnwrappedTask)
3217 {
3218 _CONCRT_ASSERT(_OuterTask->_M_fUnwrappedTask && !_OuterTask->_IsCanceled());
3219 //
3220 // We must ensure that continuations off _OuterTask (especially exception handling ones) continue to function in the
3221 // presence of an exception flowing out of the inner task _UnwrappedTask. This requires an exception handling continuation
3222 // off the inner task which does the appropriate funnelling to the outer one. We use _Then instead of then to prevent
3223 // the exception from being marked as observed by our internal continuation. This continuation must be scheduled regardless
3224 // of whether or not the _OuterTask task is canceled.
3225 //
3226 _UnwrappedTask._Then([_OuterTask](task<_InternalReturnType> _AncestorTask) -> HRESULT {
3227
3228 if (_AncestorTask._GetImpl()->_IsCompleted())
3229 {
3230 _OuterTask->_FinalizeAndRunContinuations(_AncestorTask._GetImpl()->_GetResult());
3231 }
3232 else
3233 {
3234 _CONCRT_ASSERT(_AncestorTask._GetImpl()->_IsCanceled());
3235 if (_AncestorTask._GetImpl()->_HasUserException())
3236 {
3237 // Set _PropagatedFromAncestor to false, since _AncestorTask is not an ancestor of _UnwrappedTask.
3238 // Instead, it is the enclosing task.
3239 _OuterTask->_CancelWithExceptionHolder(_AncestorTask._GetImpl()->_GetExceptionHolder(), false);
3240 }
3241 else
3242 {
3243 _OuterTask->_Cancel(true);
3244 }
3245 }
3246 return S_OK;
3247 #if _MSC_VER >= 1800
3248 }, nullptr, Concurrency::details::_DefaultAutoInline);
3249 #else
3250 }, nullptr, false, Concurrency::details::_DefaultAutoInline);
3251 #endif
3252 }
3253
3254 #if _MSC_VER >= 1800
3255 Concurrency::scheduler_ptr _GetScheduler() const
3256 {
3257 return _M_TaskCollection._GetScheduler();
3258 }
3259 #else
3260 Concurrency::event _M_Completed;
3261 Concurrency::event _M_Scheduled;
3262 #endif
3263
3264 // Tracks the internal state of the task
3265 volatile _TaskInternalState _M_TaskState;
3266 // 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
3267 // async operation or async action that is unwrapped by the runtime.
3268 bool _M_fFromAsync;
3269 #if _MSC_VER < 1800
3270 // 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
3271 // the contained T^s if we create the vector or pair, such as on a when_any or a when_all operation.
3272 bool _M_fRuntimeAggregate;
3273 #endif
3274 // Set to true when a continuation unwraps a task or async operation.
3275 bool _M_fUnwrappedTask;
3276
3277 // 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.
3278 // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception
3279 // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.
3280 std::shared_ptr<_ExceptionHolder> _M_exceptionHolder;
3281
3282 typedef _ContinuationTaskHandleBase * _ContinuationList;
3283
3284 critical_section _M_ContinuationsCritSec;
3285 _ContinuationList _M_Continuations;
3286
3287 // The cancellation token state.
3288 Concurrency::details::_CancellationTokenState * _M_pTokenState;
3289
3290 // The registration on the token.
3291 Concurrency::details::_CancellationTokenRegistration * _M_pRegistration;
3292
3293 // The async task collection wrapper
3294 #if _MSC_VER >= 1800
3295 Concurrency::details::_TaskCollection_t _M_TaskCollection;
3296
3297 // Callstack for function call (constructor or .then) that created this task impl.
3298 _TaskCreationCallstack _M_pTaskCreationCallstack;
3299
3300 _TaskEventLogger _M_taskEventLogger;
3301 #else
3302 Concurrency::details::_AsyncTaskCollection * _M_pTaskCollection;
3303
3304 // Points to the source code instruction right after the function call (constructor or .then) that created this task impl.
3305 void* _M_pTaskCreationAddressHint;
3306 #endif
3307
3308 private:
3309 // Must not be copied by value:
3310 _Task_impl_base(const _Task_impl_base&);
3311 _Task_impl_base const & operator=(_Task_impl_base const&);
3312 };
3313
3314 #if _MSC_VER >= 1800
3315 #if _PPLTASK_ASYNC_LOGGING
3316 inline void _TaskEventLogger::_LogTaskCompleted()
3317 {
3318 if (_M_scheduled)
3319 {
3320 ::Windows::Foundation::AsyncStatus _State;
3321 if (_M_task->_IsCompleted())
3322 _State = ::Windows::Foundation::AsyncStatus::Completed;
3323 else if (_M_task->_HasUserException())
3324 _State = ::Windows::Foundation::AsyncStatus::Error;
3325 else
3326 _State = ::Windows::Foundation::AsyncStatus::Canceled;
3327
3328 if (details::_IsCausalitySupported())
3329 {
3330 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
3331 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), _State);
3332 }
3333 }
3334 }
3335 #endif
3336 #endif
3337
3338 template<typename _ReturnType>
3339 struct _Task_impl : public _Task_impl_base
3340 {
3341 typedef ABI::Windows::Foundation::IAsyncInfo _AsyncOperationType;
3342 #if _MSC_VER >= 1800
3343 _Task_impl(Concurrency::details::_CancellationTokenState * _Ct, Concurrency::scheduler_ptr _Scheduler_arg)
3344 : _Task_impl_base(_Ct, _Scheduler_arg)
3345 #else
3346 _Task_impl(Concurrency::details::_CancellationTokenState * _Ct) : _Task_impl_base(_Ct)
3347 #endif
3348 {
3349 _M_unwrapped_async_op = nullptr;
3350 }
3351 virtual ~_Task_impl()
3352 {
3353 // We must invoke _DeregisterCancellation in the derived class destructor. Calling it in the base class destructor could cause
3354 // a partially initialized _Task_impl to be in the list of registrations for a cancellation token.
3355 _DeregisterCancellation();
3356 }
3357 virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder> & _ExceptionHolder)
3358 {
3359 enum { _Nothing, _RunContinuations, _Cancel } _Do = _Nothing;
3360 {
3361 scoped_lock _LockHolder(_M_ContinuationsCritSec);
3362 if (_UserException)
3363 {
3364 _CONCRT_ASSERT(_SynchronousCancel && !_IsCompleted());
3365 // If the state is _Canceled, the exception has to be coming from an ancestor.
3366 _CONCRT_ASSERT(!_IsCanceled() || _PropagatedFromAncestor);
3367 #if _MSC_VER < 1800
3368 // If the state is _Started or _PendingCancel, the exception cannot be coming from an ancestor.
3369 _CONCRT_ASSERT((!_IsStarted() && !_IsPendingCancel()) || !_PropagatedFromAncestor);
3370 #endif
3371 // We should not be canceled with an exception more than once.
3372 _CONCRT_ASSERT(!_HasUserException());
3373
3374 if (_M_TaskState == _Canceled)
3375 {
3376 // If the task has finished cancelling there should not be any continuation records in the array.
3377 return false;
3378 }
3379 else
3380 {
3381 _CONCRT_ASSERT(_M_TaskState != _Completed);
3382 _M_exceptionHolder = _ExceptionHolder;
3383 }
3384 }
3385 else
3386 {
3387 // Completed is a non-cancellable state, and if this is an asynchronous cancel, we're unable to do better than the last async cancel
3388 // which is to say, cancellation is already initiated, so return early.
3389 if (_IsCompleted() || _IsCanceled() || (_IsPendingCancel() && !_SynchronousCancel))
3390 {
3391 _CONCRT_ASSERT(!_IsCompleted() || !_HasUserException());
3392 return false;
3393 }
3394 _CONCRT_ASSERT(!_SynchronousCancel || !_HasUserException());
3395 }
3396
3397 #if _MSC_VER >= 1800
3398 if (_SynchronousCancel)
3399 #else
3400 if (_SynchronousCancel || _IsCreated())
3401 #endif
3402 {
3403 // Be aware that this set must be done BEFORE _M_Scheduled being set, or race will happen between this and wait()
3404 _M_TaskState = _Canceled;
3405 #if _MSC_VER < 1800
3406 _M_Scheduled.set();
3407 #endif
3408
3409 // Cancellation completes the task, so all dependent tasks must be run to cancel them
3410 // They are canceled when they begin running (see _RunContinuation) and see that their
3411 // ancestor has been canceled.
3412 _Do = _RunContinuations;
3413 }
3414 else
3415 {
3416 #if _MSC_VER >= 1800
3417 _CONCRT_ASSERT(!_UserException);
3418
3419 if (_IsStarted())
3420 {
3421 // should not initiate cancellation under a lock
3422 _Do = _Cancel;
3423 }
3424
3425 // The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore).
3426 // In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from
3427 // _Started to _PendingCancel before it can move to _Canceled when it is finished executing.
3428 _M_TaskState = _PendingCancel;
3429
3430 _M_taskEventLogger._LogCancelTask();
3431 }
3432 }
3433
3434 switch (_Do)
3435 {
3436 case _Cancel:
3437 {
3438 #else
3439 _CONCRT_ASSERT(_IsStarted() && !_UserException);
3440 #endif
3441 // The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore).
3442 // In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from
3443 // _Started to _PendingCancel before it can move to _Canceled when it is finished executing.
3444 _M_TaskState = _PendingCancel;
3445 if (_M_unwrapped_async_op != nullptr)
3446 {
3447 // We will only try to cancel async operation but not unwrapped tasks, since unwrapped tasks cannot be canceled without its token.
3448 if (_M_unwrapped_async_op) _M_unwrapped_async_op->Cancel();
3449 }
3450 #if _MSC_VER >= 1800
3451 _M_TaskCollection._Cancel();
3452 break;
3453 #else
3454 // Optimistic trying for cancelation
3455 if (_M_pTaskCollection != nullptr)
3456 {
3457 _M_pTaskCollection->_Cancel();
3458 }
3459 #endif
3460 }
3461 #if _MSC_VER < 1800
3462 }
3463 #endif
3464
3465 // Only execute continuations and mark the task as completed if we were able to move the task to the _Canceled state.
3466 #if _MSC_VER >= 1800
3467 case _RunContinuations:
3468 {
3469 _M_TaskCollection._Complete();
3470 #else
3471 if (_RunContinuations)
3472 {
3473 _M_Completed.set();
3474 #endif
3475
3476 if (_M_Continuations)
3477 {
3478 // Scheduling cancellation with automatic inlining.
3479 details::_ScheduleFuncWithAutoInline([=]() -> HRESULT { _RunTaskContinuations(); return S_OK; }, Concurrency::details::_DefaultAutoInline);
3480 }
3481 #if _MSC_VER >= 1800
3482 break;
3483 }
3484 #endif
3485 }
3486 return true;
3487 }
3488 void _FinalizeAndRunContinuations(_ReturnType _Result)
3489 {
3490
3491 #if _MSC_VER >= 1800
3492 _M_Result.Set(_Result);
3493 #else
3494 _M_Result = _Result;
3495 _M_ResultContext = _ResultContext<_ReturnType>::_GetContext(_M_fRuntimeAggregate);
3496 #endif
3497 {
3498 //
3499 // Hold this lock to ensure continuations being concurrently either get added
3500 // to the _M_Continuations vector or wait for the result
3501 //
3502 scoped_lock _LockHolder(_M_ContinuationsCritSec);
3503
3504 // A task could still be in the _Created state if it was created with a task_completion_event.
3505 // It could also be in the _Canceled state for the same reason.
3506 _CONCRT_ASSERT(!_HasUserException() && !_IsCompleted());
3507 if (_IsCanceled())
3508 {
3509 return;
3510 }
3511
3512 // Always transition to "completed" state, even in the face of unacknowledged pending cancellation
3513 _M_TaskState = _Completed;
3514 }
3515 #if _MSC_VER >= 1800
3516 _M_TaskCollection._Complete();
3517 #else
3518 _M_Completed.set();
3519 #endif
3520 _RunTaskContinuations();
3521 }
3522 //
3523 // This method is invoked when the starts executing. The task returns early if this method returns true.
3524 //
3525 bool _TransitionedToStarted()
3526 {
3527 scoped_lock _LockHolder(_M_ContinuationsCritSec);
3528 #if _MSC_VER >= 1800
3529 // Canceled state could only result from antecedent task's canceled state, but that code path will not reach here.
3530 _ASSERT(!_IsCanceled());
3531 if (_IsPendingCancel())
3532 #else
3533 if (_IsCanceled())
3534 #endif
3535 {
3536 return false;
3537 }
3538 _CONCRT_ASSERT(_IsCreated());
3539 _M_TaskState = _Started;
3540 return true;
3541 }
3542 void _SetUnwrappedAsyncOp(_AsyncOperationType* _AsyncOp)
3543 {
3544 scoped_lock _LockHolder(_M_ContinuationsCritSec);
3545 // Cancel the async operation if the task itself is canceled, since the thread that canceled the task missed it.
3546 if (_IsPendingCancel())
3547 {
3548 _CONCRT_ASSERT(!_IsCanceled());
3549 if (_AsyncOp) _AsyncOp->Cancel();
3550 }
3551 else
3552 {
3553 _M_unwrapped_async_op = _AsyncOp;
3554 }
3555 }
3556 #if _MSC_VER >= 1800
3557 // Return true if the task has reached a terminal state
3558 bool _IsDone()
3559 {
3560 return _IsCompleted() || _IsCanceled();
3561 }
3562 #endif
3563 _ReturnType _GetResult()
3564 {
3565 #if _MSC_VER >= 1800
3566 return _M_Result.Get();
3567 #else
3568 return _ResultContext<_ReturnType>::_GetValue(_M_Result, _M_ResultContext, _M_fRuntimeAggregate);
3569 #endif
3570 }
3571 #if _MSC_VER >= 1800
3572 _ResultHolder<_ReturnType> _M_Result; // this means that the result type must have a public default ctor.
3573 #else
3574 _ReturnType _M_Result; // this means that the result type must have a public default ctor.
3575 #endif
3576 Microsoft::WRL::ComPtr<_AsyncOperationType> _M_unwrapped_async_op;
3577 #if _MSC_VER < 1800
3578 _ContextCallback _M_ResultContext;
3579 #endif
3580 };
3581
3582 template<typename _ResultType>
3583 struct _Task_completion_event_impl
3584 {
3585 #if _MSC_VER >= 1800
3586 private:
3587 _Task_completion_event_impl(const _Task_completion_event_impl&);
3588 _Task_completion_event_impl& operator=(const _Task_completion_event_impl&);
3589
3590 public:
3591 #endif
3592 typedef std::vector<typename _Task_ptr<_ResultType>::_Type> _TaskList;
3593
3594 _Task_completion_event_impl() : _M_fHasValue(false), _M_fIsCanceled(false)
3595 {
3596 }
3597
3598 bool _HasUserException()
3599 {
3600 return _M_exceptionHolder != nullptr;
3601 }
3602
3603 ~_Task_completion_event_impl()
3604 {
3605 for (auto _TaskIt = _M_tasks.begin(); _TaskIt != _M_tasks.end(); ++_TaskIt)
3606 {
3607 _CONCRT_ASSERT(!_M_fHasValue && !_M_fIsCanceled);
3608 // Cancel the tasks since the event was never signaled or canceled.
3609 (*_TaskIt)->_Cancel(true);
3610 }
3611 }
3612
3613 // We need to protect the loop over the array, so concurrent_vector would not have helped
3614 _TaskList _M_tasks;
3615 critical_section _M_taskListCritSec;
3616 #if _MSC_VER >= 1800
3617 _ResultHolder<_ResultType> _M_value;
3618 #else
3619 _ResultType _M_value;
3620 #endif
3621 std::shared_ptr<_ExceptionHolder> _M_exceptionHolder;
3622 bool _M_fHasValue;
3623 bool _M_fIsCanceled;
3624 };
3625
3626 // Utility method for dealing with void functions
3627 inline std::function<HRESULT(_Unit_type*)> _MakeVoidToUnitFunc(const std::function<HRESULT(void)>& _Func)
3628 {
3629 return [=](_Unit_type* retVal) -> HRESULT { HRESULT hr = _Func(); *retVal = _Unit_type(); return hr; };
3630 }
3631
3632 template <typename _Type>
3633 std::function<HRESULT(_Unit_type, _Type*)> _MakeUnitToTFunc(const std::function<HRESULT(_Type*)>& _Func)
3634 {
3635 return [=](_Unit_type, _Type* retVal) -> HRESULT { HRESULT hr = _Func(retVal); return hr; };
3636 }
3637
3638 template <typename _Type>
3639 std::function<HRESULT(_Type, _Unit_type*)> _MakeTToUnitFunc(const std::function<HRESULT(_Type)>& _Func)
3640 {
3641 return[=](_Type t, _Unit_type* retVal) -> HRESULT { HRESULT hr = _Func(t); *retVal = _Unit_type(); return hr; };
3642 }
3643
3644 inline std::function<HRESULT(_Unit_type, _Unit_type*)> _MakeUnitToUnitFunc(const std::function<HRESULT(void)>& _Func)
3645 {
3646 return [=](_Unit_type, _Unit_type* retVal) -> HRESULT { HRESULT hr = _Func(); *retVal = _Unit_type(); return hr; };
3647 }
3648 }
3649
3650
3651 /// <summary>
3652 /// The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied,
3653 /// or start a task in response to an external event.
3654 /// </summary>
3655 /// <typeparam name="_ResultType">
3656 /// The result type of this <c>task_completion_event</c> class.
3657 /// </typeparam>
3658 /// <remarks>
3659 /// Use a task created from a task completion event when your scenario requires you to create a task that will complete, and
3660 /// thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must
3661 /// have the same type as the task you create, and calling the set method on the task completion event with a value of that type
3662 /// will cause the associated task to complete, and provide that value as a result to its continuations.
3663 /// <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para>
3664 /// <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para>
3665 /// </remarks>
3666 /// <seealso cref="task Class"/>
3667 /**/
3668 template<typename _ResultType>
3669 class task_completion_event
3670 {
3671 public:
3672 /// <summary>
3673 /// Constructs a <c>task_completion_event</c> object.
3674 /// </summary>
3675 /**/
3676 task_completion_event() : _M_Impl(std::make_shared<details::_Task_completion_event_impl<_ResultType>>())
3677 {
3678 }
3679
3680 /// <summary>
3681 /// Sets the task completion event.
3682 /// </summary>
3683 /// <param name="_Result">
3684 /// The result to set this event with.
3685 /// </param>
3686 /// <returns>
3687 /// The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set.
3688 /// </returns>
3689 /// <remarks>
3690 /// In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the
3691 /// task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the
3692 /// tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have
3693 /// a <typeparamref name="_ResultType"/> other than <c>void</c> will pass the value <paramref value="_Result"/> to their continuations.
3694 /// </remarks>
3695 /**/
3696 bool set(_ResultType _Result) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
3697 {
3698 // Subsequent sets are ignored. This makes races to set benign: the first setter wins and all others are ignored.
3699 if (_IsTriggered())
3700 {
3701 return false;
3702 }
3703
3704 _TaskList _Tasks;
3705 bool _RunContinuations = false;
3706 {
3707 details::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
3708
3709 if (!_IsTriggered())
3710 {
3711 #if _MSC_VER >= 1800
3712 _M_Impl->_M_value.Set(_Result);
3713 #else
3714 _M_Impl->_M_value = _Result;
3715 #endif
3716 _M_Impl->_M_fHasValue = true;
3717
3718 _Tasks.swap(_M_Impl->_M_tasks);
3719 _RunContinuations = true;
3720 }
3721 }
3722
3723 if (_RunContinuations)
3724 {
3725 for (auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt)
3726 {
3727 #if _MSC_VER >= 1800
3728 // If current task was cancelled by a cancellation_token, it would be in cancel pending state.
3729 if ((*_TaskIt)->_IsPendingCancel())
3730 (*_TaskIt)->_Cancel(true);
3731 else
3732 {
3733 // Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all
3734 // if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we
3735 // need to run continuations after the lock is released.
3736 (*_TaskIt)->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get());
3737 }
3738 #else
3739 // Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all
3740 // if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we
3741 // need to run continuations after the lock is released.
3742 (*_TaskIt)->_FinalizeAndRunContinuations(_M_Impl->_M_value);
3743 #endif
3744 }
3745 if (_M_Impl->_HasUserException())
3746 {
3747 _M_Impl->_M_exceptionHolder.reset();
3748 }
3749 return true;
3750 }
3751
3752 return false;
3753 }
3754 #if _MSC_VER >= 1800
3755
3756 template<typename _E>
3757 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
3758 bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
3759 {
3760 // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.
3761 return _Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK());
3762 }
3763 #endif
3764
3765 /// <summary>
3766 /// Propagates an exception to all tasks associated with this event.
3767 /// </summary>
3768 /// <param>
3769 /// The exception_ptr that indicates the exception to set this event with.
3770 /// </param>
3771 /**/
3772 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
3773 bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
3774 {
3775 // It is important that _ReturnAddress() evaluate to the instruction after the call instruction for set_exception.
3776 #if _MSC_VER >= 1800
3777 return _Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK());
3778 #else
3779 return _Cancel(_ExceptionPtr, _ReturnAddress());
3780 #endif
3781 }
3782
3783 /// <summary>
3784 /// Internal method to cancel the task_completion_event. Any task created using this event will be marked as canceled if it has
3785 /// not already been set.
3786 /// </summary>
3787 bool _Cancel() const
3788 {
3789 // Cancel with the stored exception if one exists.
3790 return _CancelInternal();
3791 }
3792
3793 /// <summary>
3794 /// Internal method to cancel the task_completion_event with the exception provided. Any task created using this event will be canceled
3795 /// with the same exception.
3796 /// </summary>
3797 template<typename _ExHolderType>
3798 #if _MSC_VER >= 1800
3799 bool _Cancel(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack()) const
3800 #else
3801 bool _Cancel(_ExHolderType _ExHolder, void* _SetExceptionAddressHint = nullptr) const
3802 #endif
3803 {
3804 (void)_SetExceptionAddressHint;
3805 bool _Canceled;
3806 #if _MSC_VER >= 1800
3807 if(_StoreException(_ExHolder, _SetExceptionAddressHint))
3808 #else
3809 if (_StoreException(_ExHolder))
3810 #endif
3811 {
3812 _Canceled = _CancelInternal();
3813 _CONCRT_ASSERT(_Canceled);
3814 }
3815 else
3816 {
3817 _Canceled = false;
3818 }
3819 return _Canceled;
3820 }
3821
3822 /// <summary>
3823 /// Internal method that stores an exception in the task completion event. This is used internally by when_any.
3824 /// Note, this does not cancel the task completion event. A task completion event with a stored exception
3825 /// can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present.
3826 /// </summary>
3827 template<typename _ExHolderType>
3828 #if _MSC_VER >= 1800
3829 bool _StoreException(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack()) const
3830 #else
3831 bool _StoreException(_ExHolderType _ExHolder, void* _SetExceptionAddressHint = nullptr) const
3832 #endif
3833 {
3834 details::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
3835 if (!_IsTriggered() && !_M_Impl->_HasUserException())
3836 {
3837 // Create the exception holder only if we have ensured there we will be successful in setting it onto the
3838 // task completion event. Failing to do so will result in an unobserved task exception.
3839 _M_Impl->_M_exceptionHolder = _ToExceptionHolder(_ExHolder, _SetExceptionAddressHint);
3840 return true;
3841 }
3842 return false;
3843 }
3844
3845 /// <summary>
3846 /// Tests whether current event has been either Set, or Canceled.
3847 /// </summary>
3848 bool _IsTriggered() const
3849 {
3850 return _M_Impl->_M_fHasValue || _M_Impl->_M_fIsCanceled;
3851 }
3852
3853 private:
3854
3855 #if _MSC_VER >= 1800
3856 static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder, const details::_TaskCreationCallstack&)
3857 #else
3858 static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder, void*)
3859 #endif
3860 {
3861 return _ExHolder;
3862 }
3863
3864 #if _MSC_VER >= 1800
3865 static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(std::exception_ptr _ExceptionPtr, const details::_TaskCreationCallstack &_SetExceptionAddressHint)
3866 #else
3867 static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(std::exception_ptr _ExceptionPtr, void* _SetExceptionAddressHint)
3868 #endif
3869 {
3870 return std::make_shared<details::_ExceptionHolder>(_ExceptionPtr, _SetExceptionAddressHint);
3871 }
3872
3873 template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask
3874 template <typename T> friend class task_completion_event;
3875
3876 typedef typename details::_Task_completion_event_impl<_ResultType>::_TaskList _TaskList;
3877
3878 /// <summary>
3879 /// Cancels the task_completion_event.
3880 /// </summary>
3881 bool _CancelInternal() const
3882 {
3883 // Cancellation of task completion events is an internal only utility. Our usage is such that _CancelInternal
3884 // will never be invoked if the task completion event has been set.
3885 _CONCRT_ASSERT(!_M_Impl->_M_fHasValue);
3886 if (_M_Impl->_M_fIsCanceled)
3887 {
3888 return false;
3889 }
3890
3891 _TaskList _Tasks;
3892 bool _Cancel = false;
3893 {
3894 details::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
3895 _CONCRT_ASSERT(!_M_Impl->_M_fHasValue);
3896 if (!_M_Impl->_M_fIsCanceled)
3897 {
3898 _M_Impl->_M_fIsCanceled = true;
3899 _Tasks.swap(_M_Impl->_M_tasks);
3900 _Cancel = true;
3901 }
3902 }
3903
3904 bool _UserException = _M_Impl->_HasUserException();
3905
3906 if (_Cancel)
3907 {
3908 for (auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt)
3909 {
3910 // Need to call this after the lock is released. See comments in set().
3911 if (_UserException)
3912 {
3913 (*_TaskIt)->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);
3914 }
3915 else
3916 {
3917 (*_TaskIt)->_Cancel(true);
3918 }
3919 }
3920 }
3921 return _Cancel;
3922 }
3923
3924 /// <summary>
3925 /// Register a task with this event. This function is called when a task is constructed using
3926 /// a task_completion_event.
3927 /// </summary>
3928 void _RegisterTask(const typename details::_Task_ptr<_ResultType>::_Type & _TaskParam)
3929 {
3930 details::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec);
3931 #if _MSC_VER < 1800
3932 _TaskParam->_SetScheduledEvent();
3933 #endif
3934 //If an exception was already set on this event, then cancel the task with the stored exception.
3935 if (_M_Impl->_HasUserException())
3936 {
3937 _TaskParam->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);
3938 }
3939 else if (_M_Impl->_M_fHasValue)
3940 {
3941 #if _MSC_VER >= 1800
3942 _TaskParam->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get());
3943 #else
3944 _TaskParam->_FinalizeAndRunContinuations(_M_Impl->_M_value);
3945 #endif
3946 }
3947 else
3948 {
3949 _M_Impl->_M_tasks.push_back(_TaskParam);
3950 }
3951 }
3952
3953 std::shared_ptr<details::_Task_completion_event_impl<_ResultType>> _M_Impl;
3954 };
3955
3956 /// <summary>
3957 /// The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied,
3958 /// or start a task in response to an external event.
3959 /// </summary>
3960 /// <remarks>
3961 /// Use a task created from a task completion event when your scenario requires you to create a task that will complete, and
3962 /// thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must
3963 /// have the same type as the task you create, and calling the set method on the task completion event with a value of that type
3964 /// will cause the associated task to complete, and provide that value as a result to its continuations.
3965 /// <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para>
3966 /// <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para>
3967 /// </remarks>
3968 /// <seealso cref="task Class"/>
3969 /**/
3970 template<>
3971 class task_completion_event<void>
3972 {
3973 public:
3974 /// <summary>
3975 /// Sets the task completion event.
3976 /// </summary>
3977 /// <returns>
3978 /// The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set.
3979 /// </returns>
3980 /// <remarks>
3981 /// In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the
3982 /// task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the
3983 /// tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have
3984 /// a <typeparamref name="_ResultType"/> other than <c>void</c> will pass the value <paramref value="_Result"/> to their continuations.
3985 /// </remarks>
3986 /**/
3987 bool set() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
3988 {
3989 return _M_unitEvent.set(details::_Unit_type());
3990 }
3991 #if _MSC_VER >= 1800
3992
3993 template<typename _E>
3994 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
3995 bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
3996 {
3997 return _M_unitEvent._Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK());
3998 }
3999 #endif
4000
4001 /// <summary>
4002 /// Propagates an exception to all tasks associated with this event.
4003 /// </summary>
4004 /// <param>
4005 /// The exception_ptr that indicates the exception to set this event with.
4006 /// </param>
4007 /**/
4008 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
4009 bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
4010 {
4011 // It is important that _ReturnAddress() evaluate to the instruction after the call instruction for set_exception.
4012 #if _MSC_VER >= 1800
4013 return _M_unitEvent._Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK());
4014 #else
4015 return _M_unitEvent._Cancel(_ExceptionPtr, _ReturnAddress());
4016 #endif
4017 }
4018
4019 /// <summary>
4020 /// Cancel the task_completion_event. Any task created using this event will be marked as canceled if it has
4021 /// not already been set.
4022 /// </summary>
4023 void _Cancel() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
4024 {
4025 _M_unitEvent._Cancel();
4026 }
4027
4028 /// <summary>
4029 /// Cancel the task_completion_event with the exception holder provided. Any task created using this event will be canceled
4030 /// with the same exception.
4031 /// </summary>
4032 void _Cancel(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const
4033 {
4034 _M_unitEvent._Cancel(_ExHolder);
4035 }
4036
4037 /// <summary>
4038 /// Method that stores an exception in the task completion event. This is used internally by when_any.
4039 /// Note, this does not cancel the task completion event. A task completion event with a stored exception
4040 /// can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present.
4041 /// </summary>
4042 bool _StoreException(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const
4043 {
4044 return _M_unitEvent._StoreException(_ExHolder);
4045 }
4046
4047 /// <summary>
4048 /// Test whether current event has been either Set, or Canceled.
4049 /// </summary>
4050 bool _IsTriggered() const
4051 {
4052 return _M_unitEvent._IsTriggered();
4053 }
4054
4055 private:
4056 template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask
4057
4058 /// <summary>
4059 /// Register a task with this event. This function is called when a task is constructed using
4060 /// a task_completion_event.
4061 /// </summary>
4062 void _RegisterTask(details::_Task_ptr<details::_Unit_type>::_Type _TaskParam)
4063 {
4064 _M_unitEvent._RegisterTask(_TaskParam);
4065 }
4066
4067 // The void event contains an event a dummy type so common code can be used for events with void and non-void results.
4068 task_completion_event<details::_Unit_type> _M_unitEvent;
4069 };
4070 namespace details
4071 {
4072 //
4073 // Compile-time validation helpers
4074 //
4075
4076 // Task constructor validation: issue helpful diagnostics for common user errors. Do not attempt full validation here.
4077 //
4078 // Anything callable is fine
4079 template<typename _ReturnType, typename _Ty>
4080 auto _IsValidTaskCtor(_Ty _Param, int, int, int, int, int, int, int) -> typename decltype(_Param(), std::true_type());
4081
4082 // Anything callable with a task return value is fine
4083 template<typename _ReturnType, typename _Ty>
4084 auto _IsValidTaskCtor(_Ty _Param, int, int, int, int, int, int, ...) -> typename decltype(_Param(stdx::declval<task<_ReturnType>*>()), std::true_type());
4085
4086 // Anything callable with a return value is fine
4087 template<typename _ReturnType, typename _Ty>
4088 auto _IsValidTaskCtor(_Ty _Param, int, int, int, int, int, ...) -> typename decltype(_Param(stdx::declval<_ReturnType*>()), std::true_type());
4089
4090 // Anything that has GetResults is fine: this covers AsyncAction*
4091 template<typename _ReturnType, typename _Ty>
4092 auto _IsValidTaskCtor(_Ty _Param, int, int, int, int, ...) -> typename decltype(_Param->GetResults(), std::true_type());
4093
4094 // Anything that has GetResults(TResult_abi*) is fine: this covers AsyncOperation*
4095 template<typename _ReturnType, typename _Ty>
4096 auto _IsValidTaskCtor(_Ty _Param, int, int, int, ...) -> typename decltype(_Param->GetResults(stdx::declval<decltype(_GetUnwrappedType(stdx::declval<_Ty>()))*>()), std::true_type());
4097
4098 // Allow parameters with set: this covers task_completion_event
4099 template<typename _ReturnType, typename _Ty>
4100 auto _IsValidTaskCtor(_Ty _Param, int, int, ...) -> typename decltype(_Param.set(stdx::declval<_ReturnType>()), std::true_type());
4101
4102 template<typename _ReturnType, typename _Ty>
4103 auto _IsValidTaskCtor(_Ty _Param, int, ...) -> typename decltype(_Param.set(), std::true_type());
4104
4105 // All else is invalid
4106 template<typename _ReturnType, typename _Ty>
4107 std::false_type _IsValidTaskCtor(_Ty _Param, ...);
4108
4109 template<typename _ReturnType, typename _Ty>
4110 void _ValidateTaskConstructorArgs(_Ty _Param)
4111 {
4112 (void)_Param;
4113 static_assert(std::is_same<decltype(details::_IsValidTaskCtor<_ReturnType>(_Param, 0, 0, 0, 0, 0, 0, 0)), std::true_type>::value,
4114 "incorrect argument for task constructor; can be a callable object, an asynchronous operation, or a task_completion_event"
4115 );
4116 static_assert(!(std::is_same<_Ty, _ReturnType>::value && details::_IsIAsyncInfo<_Ty>::_Value),
4117 "incorrect template argument for task; consider using the return type of the async operation");
4118 }
4119 // Helpers for create_async validation
4120 //
4121 // A parameter lambda taking no arguments is valid
4122 template<typename _ReturnType, typename _Ty>
4123 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int, int, int, int, int) -> typename decltype(_Param(), std::true_type());
4124
4125 // A parameter lambda taking a result argument is valid
4126 template<typename _ReturnType, typename _Ty>
4127 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int, int, int, int, ...) -> typename decltype(_Param(stdx::declval<_ReturnType*>()), std::true_type());
4128
4129 // A parameter lambda taking an cancellation_token argument is valid
4130 template<typename _ReturnType, typename _Ty>
4131 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int, int, int, ...) -> typename decltype(_Param(Concurrency::cancellation_token::none()), std::true_type());
4132
4133 // A parameter lambda taking an cancellation_token argument and a result argument is valid
4134 template<typename _ReturnType, typename _Ty>
4135 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int, int, ...) -> typename decltype(_Param(Concurrency::cancellation_token::none(), stdx::declval<_ReturnType*>()), std::true_type());
4136
4137 // A parameter lambda taking a progress report argument is valid
4138 template<typename _ReturnType, typename _Ty>
4139 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType()), std::true_type());
4140
4141 // A parameter lambda taking a progress report argument and a result argument is valid
4142 template<typename _ReturnType, typename _Ty>
4143 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType(), stdx::declval<_ReturnType*>()), std::true_type());
4144
4145 // A parameter lambda taking a progress report and a cancellation_token argument is valid
4146 template<typename _ReturnType, typename _Ty>
4147 static auto _IsValidCreateAsync(_Ty _Param, int, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType(), Concurrency::cancellation_token::none()), std::true_type());
4148
4149 // A parameter lambda taking a progress report and a cancellation_token argument and a result argument is valid
4150 template<typename _ReturnType, typename _Ty>
4151 static auto _IsValidCreateAsync(_Ty _Param, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType(), Concurrency::cancellation_token::none(), stdx::declval<_ReturnType*>()), std::true_type());
4152
4153 // All else is invalid
4154 template<typename _ReturnType, typename _Ty>
4155 static std::false_type _IsValidCreateAsync(_Ty _Param, ...);
4156 }
4157
4158 /// <summary>
4159 /// The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously,
4160 /// and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces
4161 /// a result of type <typeparamref name="_ResultType"/> on successful completion. Tasks of type <c>task<void></c> produce no result.
4162 /// A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using
4163 /// continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns.
4164 /// </summary>
4165 /// <typeparam name="_ReturnType">
4166 /// The result type of this task.
4167 /// </typeparam>
4168 /// <remarks>
4169 /// For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.
4170 /// </remarks>
4171 /**/
4172 template<typename _ReturnType>
4173 class task
4174 {
4175 public:
4176 /// <summary>
4177 /// The type of the result an object of this class produces.
4178 /// </summary>
4179 /**/
4180 typedef _ReturnType result_type;
4181
4182 /// <summary>
4183 /// Constructs a <c>task</c> object.
4184 /// </summary>
4185 /// <remarks>
4186 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
4187 /// 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>
4188 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
4189 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
4190 /// completion event is set.</para>
4191 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
4192 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
4193 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
4194 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
4195 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
4196 /// and not when the lamda returns.</para>
4197 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
4198 /// without the need for locks.</para>
4199 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
4200 /// to Windows Store apps.</para>
4201 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
4202 /// </remarks>
4203 /**/
4204 task() : _M_Impl(nullptr)
4205 {
4206 // The default constructor should create a task with a nullptr impl. This is a signal that the
4207 // task is not usable and should throw if any wait(), get() or then() APIs are used.
4208 }
4209
4210 /// <summary>
4211 /// Constructs a <c>task</c> object.
4212 /// </summary>
4213 /// <typeparam name="_Ty">
4214 /// The type of the parameter from which the task is to be constructed.
4215 /// </typeparam>
4216 /// <param name="_Param">
4217 /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c>
4218 /// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
4219 /// 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>,
4220 /// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
4221 /// </param>
4222 /// <param name="_Token">
4223 /// The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives
4224 /// the token <c>cancellation_token::none()</c>.
4225 /// </param>
4226 /// <remarks>
4227 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
4228 /// 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>
4229 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
4230 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
4231 /// completion event is set.</para>
4232 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
4233 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
4234 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
4235 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
4236 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
4237 /// and not when the lamda returns.</para>
4238 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
4239 /// without the need for locks.</para>
4240 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
4241 /// to Windows Store apps.</para>
4242 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
4243 /// </remarks>
4244 /**/
4245 template<typename _Ty>
4246 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
4247 explicit task(_Ty _Param)
4248 {
4249 #if _MSC_VER >= 1800
4250 task_options _TaskOptions;
4251 #endif
4252 details::_ValidateTaskConstructorArgs<_ReturnType, _Ty>(_Param);
4253
4254 #if _MSC_VER >= 1800
4255 _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());
4256 #else
4257 _CreateImpl(Concurrency::cancellation_token::none()._GetImplValue());
4258 #endif
4259 // 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.
4260 #if _MSC_VER >= 1800
4261 _SetTaskCreationCallstack(_CAPTURE_CALLSTACK());
4262 #else
4263 _SetTaskCreationAddressHint(_ReturnAddress());
4264 #endif
4265 _TaskInitMaybeFunctor(_Param, details::_IsCallable<_ReturnType>(_Param, 0, 0, 0));
4266 }
4267
4268 /// <summary>
4269 /// Constructs a <c>task</c> object.
4270 /// </summary>
4271 /// <typeparam name="_Ty">
4272 /// The type of the parameter from which the task is to be constructed.
4273 /// </typeparam>
4274 /// <param name="_Param">
4275 /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c>
4276 /// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
4277 /// 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>,
4278 /// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
4279 /// </param>
4280 /// <param name="_Token">
4281 /// The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives
4282 /// the token <c>cancellation_token::none()</c>.
4283 /// </param>
4284 /// <remarks>
4285 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
4286 /// 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>
4287 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
4288 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
4289 /// completion event is set.</para>
4290 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
4291 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
4292 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
4293 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
4294 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
4295 /// and not when the lamda returns.</para>
4296 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
4297 /// without the need for locks.</para>
4298 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
4299 /// to Windows Store apps.</para>
4300 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
4301 /// </remarks>
4302 /**/
4303 template<typename _Ty>
4304 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
4305 #if _MSC_VER >= 1800
4306 explicit task(_Ty _Param, const task_options &_TaskOptions)
4307 #else
4308 explicit task(_Ty _Param, Concurrency::cancellation_token _Token)
4309 #endif
4310 {
4311 details::_ValidateTaskConstructorArgs<_ReturnType, _Ty>(_Param);
4312
4313 #if _MSC_VER >= 1800
4314 _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());
4315 #else
4316 _CreateImpl(_Token._GetImplValue());
4317 #endif
4318 // 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.
4319 #if _MSC_VER >= 1800
4320 _SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK());
4321 #else
4322 _SetTaskCreationAddressHint(_ReturnAddress());
4323 #endif
4324 _TaskInitMaybeFunctor(_Param, details::_IsCallable<_ReturnType>(_Param, 0, 0, 0));
4325 }
4326
4327 /// <summary>
4328 /// Constructs a <c>task</c> object.
4329 /// </summary>
4330 /// <param name="_Other">
4331 /// The source <c>task</c> object.
4332 /// </param>
4333 /// <remarks>
4334 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
4335 /// 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>
4336 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
4337 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
4338 /// completion event is set.</para>
4339 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
4340 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
4341 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
4342 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
4343 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
4344 /// and not when the lamda returns.</para>
4345 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
4346 /// without the need for locks.</para>
4347 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
4348 /// to Windows Store apps.</para>
4349 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
4350 /// </remarks>
4351 /**/
4352 task(const task& _Other) : _M_Impl(_Other._M_Impl) {}
4353
4354 /// <summary>
4355 /// Constructs a <c>task</c> object.
4356 /// </summary>
4357 /// <param name="_Other">
4358 /// The source <c>task</c> object.
4359 /// </param>
4360 /// <remarks>
4361 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
4362 /// 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>
4363 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
4364 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
4365 /// completion event is set.</para>
4366 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
4367 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
4368 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
4369 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
4370 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
4371 /// and not when the lamda returns.</para>
4372 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
4373 /// without the need for locks.</para>
4374 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
4375 /// to Windows Store apps.</para>
4376 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
4377 /// </remarks>
4378 /**/
4379 task(task&& _Other) : _M_Impl(std::move(_Other._M_Impl)) {}
4380
4381 /// <summary>
4382 /// Replaces the contents of one <c>task</c> object with another.
4383 /// </summary>
4384 /// <param name="_Other">
4385 /// The source <c>task</c> object.
4386 /// </param>
4387 /// <remarks>
4388 /// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
4389 /// actual task as <paramref name="_Other"/> does.
4390 /// </remarks>
4391 /**/
4392 task& operator=(const task& _Other)
4393 {
4394 if (this != &_Other)
4395 {
4396 _M_Impl = _Other._M_Impl;
4397 }
4398 return *this;
4399 }
4400
4401 /// <summary>
4402 /// Replaces the contents of one <c>task</c> object with another.
4403 /// </summary>
4404 /// <param name="_Other">
4405 /// The source <c>task</c> object.
4406 /// </param>
4407 /// <remarks>
4408 /// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
4409 /// actual task as <paramref name="_Other"/> does.
4410 /// </remarks>
4411 /**/
4412 task& operator=(task&& _Other)
4413 {
4414 if (this != &_Other)
4415 {
4416 _M_Impl = std::move(_Other._M_Impl);
4417 }
4418 return *this;
4419 }
4420
4421 /// <summary>
4422 /// Adds a continuation task to this task.
4423 /// </summary>
4424 /// <typeparam name="_Function">
4425 /// The type of the function object that will be invoked by this task.
4426 /// </typeparam>
4427 /// <param name="_Func">
4428 /// The continuation function to execute when this task completes. This continuation function must take as input
4429 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
4430 /// of the result this task produces.
4431 /// </param>
4432 /// <returns>
4433 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
4434 /// </returns>
4435 /// <remarks>
4436 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
4437 /// to Windows Store apps.
4438 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
4439 /// </remarks>
4440 /**/
4441 template<typename _Function>
4442 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
4443 auto then(const _Function& _Func) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
4444 {
4445 #if _MSC_VER >= 1800
4446 task_options _TaskOptions;
4447 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
4448 return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
4449 #else
4450 auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, nullptr, task_continuation_context::use_default());
4451 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
4452 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
4453 return _ContinuationTask;
4454 #endif
4455 }
4456
4457 /// <summary>
4458 /// Adds a continuation task to this task.
4459 /// </summary>
4460 /// <typeparam name="_Function">
4461 /// The type of the function object that will be invoked by this task.
4462 /// </typeparam>
4463 /// <param name="_Func">
4464 /// The continuation function to execute when this task completes. This continuation function must take as input
4465 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
4466 /// of the result this task produces.
4467 /// </param>
4468 /// <param name="_CancellationToken">
4469 /// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
4470 /// the token of its antecedent task.
4471 /// </param>
4472 /// <returns>
4473 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
4474 /// </returns>
4475 /// <remarks>
4476 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
4477 /// to Windows Store apps.
4478 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
4479 /// </remarks>
4480 /**/
4481 template<typename _Function>
4482 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
4483 #if _MSC_VER >= 1800
4484 auto then(const _Function& _Func, task_options _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
4485 #else
4486 auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
4487 #endif
4488 {
4489 #if _MSC_VER >= 1800
4490 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
4491 return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
4492 #else
4493 auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, _CancellationToken._GetImplValue(), task_continuation_context::use_default());
4494 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
4495 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
4496 return _ContinuationTask;
4497 #endif
4498 }
4499 #if _MSC_VER < 1800
4500 /// <summary>
4501 /// Adds a continuation task to this task.
4502 /// </summary>
4503 /// <typeparam name="_Function">
4504 /// The type of the function object that will be invoked by this task.
4505 /// </typeparam>
4506 /// <param name="_Func">
4507 /// The continuation function to execute when this task completes. This continuation function must take as input
4508 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
4509 /// of the result this task produces.
4510 /// </param>
4511 /// <param name="_ContinuationContext">
4512 /// A variable that specifies where the continuation should execute. This variable is only useful when used in a
4513 /// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
4514 /// </param>
4515 /// <returns>
4516 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
4517 /// </returns>
4518 /// <remarks>
4519 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
4520 /// to Windows Store apps.
4521 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
4522 /// </remarks>
4523 /**/
4524 template<typename _Function>
4525 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
4526 auto then(const _Function& _Func, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
4527 {
4528 auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, nullptr, _ContinuationContext);
4529 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
4530 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
4531 return _ContinuationTask;
4532 }
4533 #endif
4534 /// <summary>
4535 /// Adds a continuation task to this task.
4536 /// </summary>
4537 /// <typeparam name="_Function">
4538 /// The type of the function object that will be invoked by this task.
4539 /// </typeparam>
4540 /// <param name="_Func">
4541 /// The continuation function to execute when this task completes. This continuation function must take as input
4542 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
4543 /// of the result this task produces.
4544 /// </param>
4545 /// <param name="_CancellationToken">
4546 /// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
4547 /// the token of its antecedent task.
4548 /// </param>
4549 /// <param name="_ContinuationContext">
4550 /// A variable that specifies where the continuation should execute. This variable is only useful when used in a
4551 /// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
4552 /// </param>
4553 /// <returns>
4554 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
4555 /// </returns>
4556 /// <remarks>
4557 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
4558 /// to Windows Store apps.
4559 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
4560 /// </remarks>
4561 /**/
4562 template<typename _Function>
4563 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
4564 auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
4565 {
4566 #if _MSC_VER >= 1800
4567 task_options _TaskOptions(_CancellationToken, _ContinuationContext);
4568 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
4569 return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
4570 #else
4571 auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, _CancellationToken._GetImplValue(), _ContinuationContext);
4572 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
4573 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
4574 return _ContinuationTask;
4575 #endif
4576 }
4577
4578 /// <summary>
4579 /// 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
4580 /// dependencies are satisfied, and it has not already been picked up for execution by a background worker.
4581 /// </summary>
4582 /// <returns>
4583 /// A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception
4584 /// during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception.
4585 /// </returns>
4586 /**/
4587 task_status wait() const
4588 {
4589 if (_M_Impl == nullptr)
4590 {
4591 throw Concurrency::invalid_operation("wait() cannot be called on a default constructed task.");
4592 }
4593
4594 return _M_Impl->_Wait();
4595 }
4596
4597 /// <summary>
4598 /// Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to
4599 /// finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>.
4600 /// </summary>
4601 /// <returns>
4602 /// The result of the task.
4603 /// </returns>
4604 /// <remarks>
4605 /// If the task is canceled, a call to <c>get</c> will throw a <see cref="task_canceled Class">task_canceled</see> exception. If the task
4606 /// encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception.
4607 /// </remarks>
4608 /**/
4609 _ReturnType get() const
4610 {
4611 if (_M_Impl == nullptr)
4612 {
4613 throw Concurrency::invalid_operation("get() cannot be called on a default constructed task.");
4614 }
4615
4616 if (_M_Impl->_Wait() == Concurrency::canceled)
4617 {
4618 throw Concurrency::task_canceled();
4619 }
4620
4621 return _M_Impl->_GetResult();
4622 }
4623 #if _MSC_VER >= 1800
4624 /// <summary>
4625 /// Determines if the task is completed.
4626 /// </summary>
4627 /// <returns>
4628 /// True if the task has completed, false otherwise.
4629 /// </returns>
4630 /// <remarks>
4631 /// The function returns true if the task is completed or canceled (with or without user exception).
4632 /// </remarks>
4633 bool is_done() const
4634 {
4635 if (!_M_Impl)
4636 {
4637 throw Concurrency::invalid_operation("is_done() cannot be called on a default constructed task.");
4638 }
4639
4640 return _M_Impl->_IsDone();
4641 }
4642
4643 /// <summary>
4644 /// Returns the scheduler for this task
4645 /// </summary>
4646 /// <returns>
4647 /// A pointer to the scheduler
4648 /// </returns>
4649 Concurrency::scheduler_ptr scheduler() const
4650 {
4651 if (!_M_Impl)
4652 {
4653 throw Concurrency::invalid_operation("scheduler() cannot be called on a default constructed task.");
4654 }
4655
4656 return _M_Impl->_GetScheduler();
4657 }
4658 #endif
4659 /// <summary>
4660 /// Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task.
4661 /// </summary>
4662 /// <returns>
4663 /// <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise.
4664 /// </returns>
4665 /**/
4666 bool is_apartment_aware() const
4667 {
4668 if (_M_Impl == nullptr)
4669 {
4670 throw Concurrency::invalid_operation("is_apartment_aware() cannot be called on a default constructed task.");
4671 }
4672 return _M_Impl->_IsApartmentAware();
4673 }
4674
4675 /// <summary>
4676 /// Determines whether two <c>task</c> objects represent the same internal task.
4677 /// </summary>
4678 /// <returns>
4679 /// <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise.
4680 /// </returns>
4681 /**/
4682 bool operator==(const task<_ReturnType>& _Rhs) const
4683 {
4684 return (_M_Impl == _Rhs._M_Impl);
4685 }
4686
4687 /// <summary>
4688 /// Determines whether two <c>task</c> objects represent different internal tasks.
4689 /// </summary>
4690 /// <returns>
4691 /// <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise.
4692 /// </returns>
4693 /**/
4694 bool operator!=(const task<_ReturnType>& _Rhs) const
4695 {
4696 return !operator==(_Rhs);
4697 }
4698
4699 /// <summary>
4700 /// Create an underlying task implementation.
4701 /// </summary>
4702 #if _MSC_VER >= 1800
4703 void _CreateImpl(Concurrency::details::_CancellationTokenState * _Ct, Concurrency::scheduler_ptr _Scheduler)
4704 #else
4705 void _CreateImpl(Concurrency::details::_CancellationTokenState * _Ct)
4706 #endif
4707 {
4708 _CONCRT_ASSERT(_Ct != nullptr);
4709 #if _MSC_VER >= 1800
4710 _M_Impl = details::_Task_ptr<_ReturnType>::_Make(_Ct, _Scheduler);
4711 #else
4712 _M_Impl = details::_Task_ptr<_ReturnType>::_Make(_Ct);
4713 #endif
4714 if (_Ct != Concurrency::details::_CancellationTokenState::_None())
4715 {
4716 #if _MSC_VER >= 1800
4717 _M_Impl->_RegisterCancellation(_M_Impl);
4718 #else
4719 _M_Impl->_RegisterCancellation();
4720 #endif
4721 }
4722 }
4723
4724 /// <summary>
4725 /// Return the underlying implementation for this task.
4726 /// </summary>
4727 const typename details::_Task_ptr<_ReturnType>::_Type & _GetImpl() const
4728 {
4729 return _M_Impl;
4730 }
4731
4732 /// <summary>
4733 /// Set the implementation of the task to be the supplied implementaion.
4734 /// </summary>
4735 void _SetImpl(const typename details::_Task_ptr<_ReturnType>::_Type & _Impl)
4736 {
4737 _CONCRT_ASSERT(_M_Impl == nullptr);
4738 _M_Impl = _Impl;
4739 }
4740
4741 /// <summary>
4742 /// Set the implementation of the task to be the supplied implementaion using a move instead of a copy.
4743 /// </summary>
4744 void _SetImpl(typename details::_Task_ptr<_ReturnType>::_Type && _Impl)
4745 {
4746 _CONCRT_ASSERT(_M_Impl == nullptr);
4747 _M_Impl = std::move(_Impl);
4748 }
4749
4750 /// <summary>
4751 /// Sets a property determining whether the task is apartment aware.
4752 /// </summary>
4753 void _SetAsync(bool _Async = true)
4754 {
4755 _GetImpl()->_SetAsync(_Async);
4756 }
4757
4758 /// <summary>
4759 /// Sets a field in the task impl to the return address for calls to the task constructors and the then method.
4760 /// </summary>
4761 #if _MSC_VER >= 1800
4762 void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack)
4763 {
4764 _GetImpl()->_SetTaskCreationCallstack(_callstack);
4765 }
4766 #else
4767 void _SetTaskCreationAddressHint(void* _Address)
4768 {
4769 _GetImpl()->_SetTaskCreationAddressHint(_Address);
4770 }
4771 #endif
4772 /// <summary>
4773 /// An internal version of then that takes additional flags and always execute the continuation inline by default.
4774 /// When _ForceInline is set to false, continuations inlining will be limited to default _DefaultAutoInline.
4775 /// This function is Used for runtime internal continuations only.
4776 /// </summary>
4777 template<typename _Function>
4778 #if _MSC_VER >= 1800
4779 auto _Then(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState,
4780 details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
4781 {
4782 // inherit from antecedent
4783 auto _Scheduler = _GetImpl()->_GetScheduler();
4784
4785 return _ThenImpl<_ReturnType, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);
4786 }
4787 #else
4788 auto _Then(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState, bool _Aggregating,
4789 details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
4790 {
4791 return _ThenImpl<_ReturnType, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Aggregating, _InliningMode);
4792 }
4793 #endif
4794
4795 private:
4796 template <typename T> friend class task;
4797
4798 // A helper class template that transforms an intial task lambda returns void into a lambda that returns a non-void type (details::_Unit_type is used
4799 // to substitute for void). This is to minimize the special handling required for 'void'.
4800 template<typename _RetType>
4801 class _Init_func_transformer
4802 {
4803 public:
4804 static auto _Perform(std::function<HRESULT(_RetType*)> _Func) -> decltype(_Func)
4805 {
4806 return _Func;
4807 }
4808 };
4809
4810 template<>
4811 class _Init_func_transformer<void>
4812 {
4813 public:
4814 static auto _Perform(std::function<HRESULT(void)> _Func) -> decltype(details::_MakeVoidToUnitFunc(_Func))
4815 {
4816 return details::_MakeVoidToUnitFunc(_Func);
4817 }
4818 };
4819
4820 // The task handle type used to construct an 'initial task' - a task with no dependents.
4821 template <typename _InternalReturnType, typename _Function, typename _TypeSelection>
4822 struct _InitialTaskHandle :
4823 details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore>
4824 {
4825 _Function _M_function;
4826 _InitialTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _TaskImpl, const _Function & _Function) : _M_function(_Function), _PPLTaskHandle(_TaskImpl)
4827 {
4828 }
4829 virtual ~_InitialTaskHandle() {}
4830
4831 #if _MSC_VER >= 1800
4832 template <typename _Func, typename _RetArg>
4833 auto _LogWorkItemAndInvokeUserLambda(_Func && _func, _RetArg && _retArg) const -> decltype(_func(std::forward<_RetArg>(_retArg)))
4834 {
4835 details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger);
4836 return _func(std::forward<_RetArg>(_retArg));
4837 }
4838 #endif
4839
4840 void _Perform() const
4841 {
4842 _Init(_TypeSelection());
4843 }
4844 #if _MSC_VER >= 1800
4845
4846 void _SyncCancelAndPropagateException() const
4847 {
4848 this->_M_pTask->_Cancel(true);
4849 }
4850 #endif
4851 //
4852 // Overload 0: returns _InternalReturnType
4853 //
4854 // This is the most basic task with no unwrapping
4855 //
4856 void _Init(details::_TypeSelectorNoAsync) const
4857 {
4858 _ReturnType retVal;
4859 #if _MSC_VER >= 1800
4860 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Init_func_transformer<_InternalReturnType>::_Perform(_M_function), &retVal);
4861 #else
4862 HRESULT hr = _Init_func_transformer<_InternalReturnType>::_Perform(_M_function)(&retVal);
4863 #endif
4864 if (FAILED(hr)) throw std::make_exception_ptr(hr);
4865 _M_pTask->_FinalizeAndRunContinuations(retVal);
4866 }
4867
4868 //
4869 // Overload 1: returns IAsyncOperation<_InternalReturnType>*
4870 // or
4871 // returns task<_InternalReturnType>
4872 //
4873 // This is task whose functor returns an async operation or a task which will be unwrapped for continuation
4874 // Depending on the output type, the right _AsyncInit gets invoked
4875 //
4876 void _Init(details::_TypeSelectorAsyncTask) const
4877 {
4878 task<_InternalReturnType> retVal;
4879 #if _MSC_VER >= 1800
4880 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, &retVal);
4881 #else
4882 HRESULT hr = _M_function(&retVal);
4883 #endif
4884 if (FAILED(hr)) throw std::make_exception_ptr(hr);
4885 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask, retVal);
4886 }
4887 void _Init(details::_TypeSelectorAsyncOperation) const
4888 {
4889 _ReturnType retVal;
4890 #if _MSC_VER >= 1800
4891 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, &retVal);
4892 #else
4893 HRESULT hr = _M_function(&retVal);
4894 #endif
4895 if (FAILED(hr)) throw std::make_exception_ptr(hr);
4896 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask,
4897 Microsoft::WRL::Make<details::_IAsyncOperationToAsyncOperationConverter<_InternalReturnType>>(retVal).Get());
4898 }
4899
4900 //
4901 // Overload 2: returns IAsyncAction*
4902 //
4903 // This is task whose functor returns an async action which will be unwrapped for continuation
4904 //
4905 void _Init(details::_TypeSelectorAsyncAction) const
4906 {
4907 _ReturnType retVal;
4908 #if _MSC_VER >= 1800
4909 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, &retVal);
4910 #else
4911 HRESULT hr = _M_function(&retVal);
4912 #endif
4913 if (FAILED(hr)) throw std::make_exception_ptr(hr);
4914 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask, Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(retVal).Get());
4915 }
4916
4917 //
4918 // Overload 3: returns IAsyncOperationWithProgress<_InternalReturnType, _ProgressType>*
4919 //
4920 // This is task whose functor returns an async operation with progress which will be unwrapped for continuation
4921 //
4922 void _Init(details::_TypeSelectorAsyncOperationWithProgress) const
4923 {
4924 typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;
4925 _ReturnType retVal;
4926 #if _MSC_VER >= 1800
4927 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, &retVal);
4928 #else
4929 HRESULT hr = _M_function(&retVal);
4930 #endif
4931 if (FAILED(hr)) throw std::make_exception_ptr(hr);
4932 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask,
4933 Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_InternalReturnType, _ProgressType>>(retVal).Get());
4934 }
4935
4936 //
4937 // Overload 4: returns IAsyncActionWithProgress<_ProgressType>*
4938 //
4939 // This is task whose functor returns an async action with progress which will be unwrapped for continuation
4940 //
4941 void _Init(details::_TypeSelectorAsyncActionWithProgress) const
4942 {
4943 typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;
4944 _ReturnType retVal;
4945 #if _MSC_VER >= 1800
4946 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, &retVal);
4947 #else
4948 HRESULT hr = _M_function(&retVal);
4949 #endif
4950 if (FAILED(hr)) throw std::make_exception_ptr(hr);
4951 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask,
4952 Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(retVal).Get());
4953 }
4954 };
4955
4956 /// <summary>
4957 /// A helper class template that transforms a continuation lambda that either takes or returns void, or both, into a lambda that takes and returns a
4958 /// non-void type (details::_Unit_type is used to substitute for void). This is to minimize the special handling required for 'void'.
4959 /// </summary>
4960 template<typename _InpType, typename _OutType>
4961 class _Continuation_func_transformer
4962 {
4963 public:
4964 static auto _Perform(std::function<HRESULT(_InpType, _OutType*)> _Func) -> decltype(_Func)
4965 {
4966 return _Func;
4967 }
4968 };
4969
4970 template<typename _OutType>
4971 class _Continuation_func_transformer<void, _OutType>
4972 {
4973 public:
4974 static auto _Perform(std::function<HRESULT(_OutType*)> _Func) -> decltype(details::_MakeUnitToTFunc<_OutType>(_Func))
4975 {
4976 return details::_MakeUnitToTFunc<_OutType>(_Func);
4977 }
4978 };
4979
4980 template<typename _InType>
4981 class _Continuation_func_transformer<_InType, void>
4982 {
4983 public:
4984 static auto _Perform(std::function<HRESULT(_InType)> _Func) -> decltype(details::_MakeTToUnitFunc<_InType>(_Func))
4985 {
4986 return details::_MakeTToUnitFunc<_InType>(_Func);
4987 }
4988 };
4989
4990 template<>
4991 class _Continuation_func_transformer<void, void>
4992 {
4993 public:
4994 static auto _Perform(std::function<HRESULT(void)> _Func) -> decltype(details::_MakeUnitToUnitFunc(_Func))
4995 {
4996 return details::_MakeUnitToUnitFunc(_Func);
4997 }
4998 };
4999 /// <summary>
5000 /// The task handle type used to create a 'continuation task'.
5001 /// </summary>
5002 template <typename _InternalReturnType, typename _ContinuationReturnType, typename _Function, typename _IsTaskBased, typename _TypeSelection>
5003 struct _ContinuationTaskHandle :
5004 details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,
5005 _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>
5006 {
5007 typedef typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type _NormalizedContinuationReturnType;
5008
5009 typename details::_Task_ptr<_ReturnType>::_Type _M_ancestorTaskImpl;
5010 _Function _M_function;
5011
5012 _ContinuationTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _AncestorImpl,
5013 const typename details::_Task_ptr<_NormalizedContinuationReturnType>::_Type & _ContinuationImpl,
5014 const _Function & _Func, const task_continuation_context & _Context, details::_TaskInliningMode _InliningMode) :
5015 #if _MSC_VER >= 1800
5016 details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,
5017 _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>
5018 ::_PPLTaskHandle(_ContinuationImpl)
5019 , _M_ancestorTaskImpl(_AncestorImpl)
5020 , _M_function(_Func)
5021 #else
5022 _M_ancestorTaskImpl(_AncestorImpl), _PPLTaskHandle(_ContinuationImpl), _M_function(_Func)
5023 #endif
5024 {
5025 _M_isTaskBasedContinuation = _IsTaskBased::value;
5026 _M_continuationContext = _Context;
5027 _M_continuationContext._Resolve(_AncestorImpl->_IsApartmentAware());
5028 _M_inliningMode = _InliningMode;
5029 }
5030
5031 virtual ~_ContinuationTaskHandle() {}
5032
5033 #if _MSC_VER >= 1800
5034 template <typename _Func, typename _Arg, typename _RetArg>
5035 auto _LogWorkItemAndInvokeUserLambda(_Func && _func, _Arg && _value, _RetArg && _retArg) const -> decltype(_func(std::forward<_Arg>(_value), std::forward<_RetArg>(_retArg)))
5036 {
5037 details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger);
5038 return _func(std::forward<_Arg>(_value), std::forward<_RetArg>(_retArg));
5039 }
5040 #endif
5041
5042 void _Perform() const
5043 {
5044 _Continue(_IsTaskBased(), _TypeSelection());
5045 }
5046
5047 #if _MSC_VER >= 1800
5048 void _SyncCancelAndPropagateException() const
5049 {
5050 if (_M_ancestorTaskImpl->_HasUserException())
5051 {
5052 // If the ancestor encountered an exception, transfer the exception to the continuation
5053 // This traverses down the tree to propagate the exception.
5054 this->_M_pTask->_CancelWithExceptionHolder(_M_ancestorTaskImpl->_GetExceptionHolder(), true);
5055 }
5056 else
5057 {
5058 // If the ancestor was canceled, then your own execution should be canceled.
5059 // This traverses down the tree to cancel it.
5060 this->_M_pTask->_Cancel(true);
5061 }
5062 }
5063 #endif
5064
5065 //
5066 // Overload 0-0: _InternalReturnType -> _TaskType
5067 //
5068 // This is a straight task continuation which simply invokes its target with the ancestor's completion argument
5069 //
5070 void _Continue(std::false_type, details::_TypeSelectorNoAsync) const
5071 {
5072 _NormalizedContinuationReturnType retVal;
5073 #if _MSC_VER >= 1800
5074 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &retVal);
5075 #else
5076 HRESULT hr =_Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &retVal);
5077 #endif
5078 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5079 _M_pTask->_FinalizeAndRunContinuations(retVal);
5080 }
5081
5082 //
5083 // Overload 0-1: _InternalReturnType -> IAsyncOperation<_TaskType>*
5084 // or
5085 // _InternalReturnType -> task<_TaskType>
5086 //
5087 // This is a straight task continuation which returns an async operation or a task which will be unwrapped for continuation
5088 // Depending on the output type, the right _AsyncInit gets invoked
5089 //
5090 void _Continue(std::false_type, details::_TypeSelectorAsyncTask) const
5091 {
5092 typedef typename details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
5093 _FuncOutputType retVal;
5094 #if _MSC_VER >= 1800
5095 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &retVal);
5096 #else
5097 HRESULT hr = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &retVal);
5098 #endif
5099 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5100 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
5101 _M_pTask,
5102 retVal
5103 );
5104 }
5105 void _Continue(std::false_type, details::_TypeSelectorAsyncOperation) const
5106 {
5107 typedef typename details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
5108 _FuncOutputType retVal;
5109 #if _MSC_VER >= 1800
5110 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &retVal);
5111 #else
5112 HRESULT hr = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &retVal);
5113 #endif
5114 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5115 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
5116 _M_pTask,
5117 Microsoft::WRL::Make<details::_IAsyncOperationToAsyncOperationConverter<_ContinuationReturnType>>(retVal).Get());
5118 }
5119
5120 //
5121 // Overload 0-2: _InternalReturnType -> IAsyncAction*
5122 //
5123 // This is a straight task continuation which returns an async action which will be unwrapped for continuation
5124 //
5125 void _Continue(std::false_type, details::_TypeSelectorAsyncAction) const
5126 {
5127 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
5128 _FuncOutputType retVal;
5129 #if _MSC_VER >= 1800
5130 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &retVal);
5131 #else
5132 HRESULT hr = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &retVal);
5133 #endif
5134 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5135 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
5136 _M_pTask,
5137 Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(
5138 retVal).Get());
5139 }
5140
5141 //
5142 // Overload 0-3: _InternalReturnType -> IAsyncOperationWithProgress<_TaskType, _ProgressType>*
5143 //
5144 // This is a straight task continuation which returns an async operation with progress which will be unwrapped for continuation
5145 //
5146 void _Continue(std::false_type, details::_TypeSelectorAsyncOperationWithProgress) const
5147 {
5148 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
5149
5150 _FuncOutputType _OpWithProgress;
5151 #if _MSC_VER >= 1800
5152 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &_OpWithProgress);
5153 #else
5154 HRESULT hr = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &_OpWithProgress);
5155 #endif
5156 typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;
5157
5158 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5159 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
5160 _M_pTask,
5161 Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>>(_OpWithProgress).Get());
5162 }
5163
5164 //
5165 // Overload 0-4: _InternalReturnType -> IAsyncActionWithProgress<_ProgressType>*
5166 //
5167 // This is a straight task continuation which returns an async action with progress which will be unwrapped for continuation
5168 //
5169 void _Continue(std::false_type, details::_TypeSelectorAsyncActionWithProgress) const
5170 {
5171 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
5172
5173 _FuncOutputType _OpWithProgress;
5174 #if _MSC_VER >= 1800
5175 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &_OpWithProgress);
5176 #else
5177 HRESULT hr = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &_OpWithProgress);
5178 #endif
5179 typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;
5180
5181 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5182 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
5183 _M_pTask,
5184 Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(_OpWithProgress).Get());
5185 }
5186
5187
5188 //
5189 // Overload 1-0: task<_InternalReturnType> -> _TaskType
5190 //
5191 // This is an exception handling type of continuation which takes the task rather than the task's result.
5192 //
5193 void _Continue(std::true_type, details::_TypeSelectorNoAsync) const
5194 {
5195 typedef task<_InternalReturnType> _FuncInputType;
5196 task<_InternalReturnType> _ResultTask;
5197 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
5198 _NormalizedContinuationReturnType retVal;
5199 #if _MSC_VER >= 1800
5200 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function), std::move(_ResultTask), &retVal);
5201 #else
5202 HRESULT hr = _Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function)(std::move(_ResultTask), &retVal);
5203 #endif
5204 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5205 _M_pTask->_FinalizeAndRunContinuations(retVal);
5206 }
5207
5208 //
5209 // Overload 1-1: task<_InternalReturnType> -> IAsyncOperation<_TaskType>^
5210 // or
5211 // task<_TaskType>
5212 //
5213 // This is an exception handling type of continuation which takes the task rather than
5214 // the task's result. It also returns an async operation or a task which will be unwrapped
5215 // for continuation
5216 //
5217 void _Continue(std::true_type, details::_TypeSelectorAsyncTask) const
5218 {
5219 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
5220 task<_InternalReturnType> _ResultTask;
5221 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
5222 _ContinuationReturnType retVal;
5223 #if _MSC_VER >= 1800
5224 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask), &retVal);
5225 #else
5226 HRESULT hr = _M_function(std::move(_ResultTask), &retVal);
5227 #endif
5228 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5229 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask, retVal);
5230 }
5231 void _Continue(std::true_type, details::_TypeSelectorAsyncOperation) const
5232 {
5233 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
5234 task<_InternalReturnType> _ResultTask;
5235 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
5236 _ContinuationReturnType retVal;
5237 #if _MSC_VER >= 1800
5238 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask), &retVal);
5239 #else
5240 HRESULT hr = _M_function(std::move(_ResultTask), &retVal);
5241 #endif
5242 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5243 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask,
5244 Microsoft::WRL::Make<details::_IAsyncOperationToAsyncOperationConverter<_ContinuationReturnType>>(retVal));
5245 }
5246
5247 //
5248 // Overload 1-2: task<_InternalReturnType> -> IAsyncAction*
5249 //
5250 // This is an exception handling type of continuation which takes the task rather than
5251 // the task's result. It also returns an async action which will be unwrapped for continuation
5252 //
5253 void _Continue(std::true_type, details::_TypeSelectorAsyncAction) const
5254 {
5255 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
5256 task<_InternalReturnType> _ResultTask;
5257 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
5258 _ContinuationReturnType retVal;
5259 #if _MSC_VER >= 1800
5260 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask), &retVal);
5261 #else
5262 HRESULT hr = _M_function(std::move(_ResultTask), &retVal);
5263 #endif
5264 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5265 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask,
5266 Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(retVal));
5267 }
5268
5269 //
5270 // Overload 1-3: task<_InternalReturnType> -> IAsyncOperationWithProgress<_TaskType, _ProgressType>*
5271 //
5272 // This is an exception handling type of continuation which takes the task rather than
5273 // the task's result. It also returns an async operation with progress which will be unwrapped
5274 // for continuation
5275 //
5276 void _Continue(std::true_type, details::_TypeSelectorAsyncOperationWithProgress) const
5277 {
5278 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
5279 task<_InternalReturnType> _ResultTask;
5280 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
5281
5282 typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;
5283 _ContinuationReturnType retVal;
5284 #if _MSC_VER >= 1800
5285 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask), &retVal);
5286 #else
5287 HRESULT hr = _M_function(std::move(_ResultTask), &retVal);
5288 #endif
5289 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5290 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask,
5291 Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>>(retVal));
5292 }
5293
5294 //
5295 // Overload 1-4: task<_InternalReturnType> -> IAsyncActionWithProgress<_ProgressType>*
5296 //
5297 // This is an exception handling type of continuation which takes the task rather than
5298 // the task's result. It also returns an async operation with progress which will be unwrapped
5299 // for continuation
5300 //
5301 void _Continue(std::true_type, details::_TypeSelectorAsyncActionWithProgress) const
5302 {
5303 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
5304 task<_InternalReturnType> _ResultTask;
5305 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
5306
5307 typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;
5308 _ContinuationReturnType retVal;
5309 #if _MSC_VER >= 1800
5310 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask), &retVal);
5311 #else
5312 HRESULT hr = _M_function(std::move(_ResultTask), &retVal);
5313 #endif
5314 if (FAILED(hr)) throw std::make_exception_ptr(hr);
5315 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask,
5316 Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(retVal));
5317 }
5318 };
5319 /// <summary>
5320 /// Initializes a task using a lambda, function pointer or function object.
5321 /// </summary>
5322 template<typename _InternalReturnType, typename _Function>
5323 void _TaskInitWithFunctor(const _Function& _Func)
5324 {
5325 typedef details::_InitFunctorTypeTraits<_InternalReturnType, details::_FunctionTypeTraits<_Function, void>::_FuncRetType> _Async_type_traits;
5326
5327 _M_Impl->_M_fFromAsync = _Async_type_traits::_IsAsyncTask;
5328 _M_Impl->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;
5329 #if _MSC_VER >= 1800
5330 _M_Impl->_M_taskEventLogger._LogScheduleTask(false);
5331 #endif
5332 _M_Impl->_ScheduleTask(new _InitialTaskHandle<_InternalReturnType, _Function, typename _Async_type_traits::_AsyncKind>(_GetImpl(), _Func), Concurrency::details::_NoInline);
5333 }
5334
5335 /// <summary>
5336 /// Initializes a task using a task completion event.
5337 /// </summary>
5338 void _TaskInitNoFunctor(task_completion_event<_ReturnType>& _Event)
5339 {
5340 _Event._RegisterTask(_M_Impl);
5341 }
5342
5343 /// <summary>
5344 /// Initializes a task using an asynchronous operation IAsyncOperation<T>*
5345 /// </summary>
5346 template<typename _Result, typename _OpType, typename _CompHandlerType, typename _ResultType>
5347 void _TaskInitAsyncOp(details::_AsyncInfoImpl<_OpType, _CompHandlerType, _ResultType>* _AsyncOp)
5348 {
5349 _M_Impl->_M_fFromAsync = true;
5350 #if _MSC_VER < 1800
5351 _M_Impl->_SetScheduledEvent();
5352 #endif
5353 // Mark this task as started here since we can set the state in the constructor without acquiring a lock. Once _AsyncInit
5354 // returns a completion could execute concurrently and the task must be fully initialized before that happens.
5355 _M_Impl->_M_TaskState = details::_Task_impl_base::_Started;
5356 // Pass the shared pointer into _AsyncInit for storage in the Async Callback.
5357 details::_Task_impl_base::_AsyncInit<_ReturnType, _Result>(_M_Impl, _AsyncOp);
5358 }
5359
5360 /// <summary>
5361 /// Initializes a task using an asynchronous operation IAsyncOperation<T>*
5362 /// </summary>
5363 template<typename _Result>
5364 void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncOperation<_Result>* _AsyncOp)
5365 {
5366 _TaskInitAsyncOp<_Result>(Microsoft::WRL::Make<details::_IAsyncOperationToAsyncOperationConverter<_Result>>(_AsyncOp).Get());
5367 }
5368
5369 /// <summary>
5370 /// Initializes a task using an asynchronous operation with progress IAsyncOperationWithProgress<T, P>*
5371 /// </summary>
5372 template<typename _Result, typename _Progress>
5373 void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>* _AsyncOp)
5374 {
5375 _TaskInitAsyncOp<_Result>(Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_Result, _Progress>>(_AsyncOp).Get());
5376 }
5377 /// <summary>
5378 /// Initializes a task using a callable object.
5379 /// </summary>
5380 template<typename _Function>
5381 void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)
5382 {
5383 _TaskInitWithFunctor<_ReturnType, _Function>(_Func);
5384 }
5385
5386 /// <summary>
5387 /// Initializes a task using a non-callable object.
5388 /// </summary>
5389 template<typename _Ty>
5390 void _TaskInitMaybeFunctor(_Ty & _Param, std::false_type)
5391 {
5392 _TaskInitNoFunctor(_Param);
5393 }
5394 #if _MSC_VER >= 1800
5395 template<typename _InternalReturnType, typename _Function>
5396 auto _ThenImpl(const _Function& _Func, const task_options& _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
5397 {
5398 if (!_M_Impl)
5399 {
5400 throw Concurrency::invalid_operation("then() cannot be called on a default constructed task.");
5401 }
5402
5403 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
5404 auto _Scheduler = _TaskOptions.has_scheduler() ? _TaskOptions.get_scheduler() : _GetImpl()->_GetScheduler();
5405 auto _CreationStack = details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : details::_TaskCreationCallstack();
5406 return _ThenImpl<_InternalReturnType, _Function>(_Func, _PTokenState, _TaskOptions.get_continuation_context(), _Scheduler, _CreationStack);
5407 }
5408 #endif
5409 /// <summary>
5410 /// The one and only implementation of then for void and non-void tasks.
5411 /// </summary>
5412 template<typename _InternalReturnType, typename _Function>
5413 #if _MSC_VER >= 1800
5414 auto _ThenImpl(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState, const task_continuation_context& _ContinuationContext, Concurrency::scheduler_ptr _Scheduler, details::_TaskCreationCallstack _CreationStack,
5415 details::_TaskInliningMode _InliningMode = Concurrency::details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
5416 #else
5417 auto _ThenImpl(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState, const task_continuation_context& _ContinuationContext,
5418 bool _Aggregating = false, details::_TaskInliningMode _InliningMode = Concurrency::details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
5419 #endif
5420 {
5421 if (_M_Impl == nullptr)
5422 {
5423 throw Concurrency::invalid_operation("then() cannot be called on a default constructed task.");
5424 }
5425
5426 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType> _Function_type_traits;
5427 typedef details::_TaskTypeTraits<typename _Function_type_traits::_FuncRetType> _Async_type_traits;
5428 typedef typename _Async_type_traits::_TaskRetType _TaskType;
5429
5430 //
5431 // A **nullptr** token state indicates that it was not provided by the user. In this case, we inherit the antecedent's token UNLESS this is a
5432 // an exception handling continuation. In that case, we break the chain with a _None. That continuation is never canceled unless the user
5433 // explicitly passes the same token.
5434 //
5435 if (_PTokenState == nullptr)
5436 {
5437 #if _MSC_VER >= 1800
5438 if (_Function_type_traits::_Takes_task::value)
5439 #else
5440 if (_Function_type_traits::_Takes_task())
5441 #endif
5442 {
5443 _PTokenState = Concurrency::details::_CancellationTokenState::_None();
5444 }
5445 else
5446 {
5447 _PTokenState = _GetImpl()->_M_pTokenState;
5448 }
5449 }
5450
5451 task<_TaskType> _ContinuationTask;
5452 #if _MSC_VER >= 1800
5453 _ContinuationTask._CreateImpl(_PTokenState, _Scheduler);
5454 #else
5455 _ContinuationTask._CreateImpl(_PTokenState);
5456 #endif
5457 _ContinuationTask._GetImpl()->_M_fFromAsync = (_GetImpl()->_M_fFromAsync || _Async_type_traits::_IsAsyncTask);
5458 #if _MSC_VER < 1800
5459 _ContinuationTask._GetImpl()->_M_fRuntimeAggregate = _Aggregating;
5460 #endif
5461 _ContinuationTask._GetImpl()->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;
5462 #if _MSC_VER >= 1800
5463 _ContinuationTask._SetTaskCreationCallstack(_CreationStack);
5464 #endif
5465 _GetImpl()->_ScheduleContinuation(new _ContinuationTaskHandle<_InternalReturnType, _TaskType, _Function, typename _Function_type_traits::_Takes_task, typename _Async_type_traits::_AsyncKind>(
5466 _GetImpl(), _ContinuationTask._GetImpl(), _Func, _ContinuationContext, _InliningMode));
5467
5468 return _ContinuationTask;
5469 }
5470
5471 // The underlying implementation for this task
5472 typename details::_Task_ptr<_ReturnType>::_Type _M_Impl;
5473 };
5474
5475 /// <summary>
5476 /// The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously,
5477 /// and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces
5478 /// a result of type <typeparamref name="_ResultType"/> on successful completion. Tasks of type <c>task<void></c> produce no result.
5479 /// A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using
5480 /// continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns.
5481 /// </summary>
5482 /// <remarks>
5483 /// For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.
5484 /// </remarks>
5485 /**/
5486 template<>
5487 class task<void>
5488 {
5489 public:
5490 /// <summary>
5491 /// The type of the result an object of this class produces.
5492 /// </summary>
5493 /**/
5494 typedef void result_type;
5495
5496 /// <summary>
5497 /// Constructs a <c>task</c> object.
5498 /// </summary>
5499 /// <remarks>
5500 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
5501 /// 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>
5502 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
5503 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
5504 /// completion event is set.</para>
5505 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
5506 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
5507 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
5508 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
5509 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
5510 /// and not when the lamda returns.</para>
5511 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
5512 /// without the need for locks.</para>
5513 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
5514 /// to Windows Store apps.</para>
5515 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
5516 /// </remarks>
5517 /**/
5518 task() : _M_unitTask()
5519 {
5520 // The default constructor should create a task with a nullptr impl. This is a signal that the
5521 // task is not usable and should throw if any wait(), get() or then() APIs are used.
5522 }
5523 #if _MSC_VER < 1800
5524 /// <summary>
5525 /// Constructs a <c>task</c> object.
5526 /// </summary>
5527 /// <typeparam name="_Ty">
5528 /// The type of the parameter from which the task is to be constructed.
5529 /// </typeparam>
5530 /// <param name="_Param">
5531 /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c>
5532 /// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
5533 /// 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>,
5534 /// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
5535 /// </param>
5536 /// <remarks>
5537 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
5538 /// 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>
5539 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
5540 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
5541 /// completion event is set.</para>
5542 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
5543 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
5544 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
5545 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
5546 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
5547 /// and not when the lamda returns.</para>
5548 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
5549 /// without the need for locks.</para>
5550 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
5551 /// to Windows Store apps.</para>
5552 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
5553 /// </remarks>
5554 /**/
5555 template<typename _Ty>
5556 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
5557 explicit task(_Ty _Param)
5558 {
5559 details::_ValidateTaskConstructorArgs<void, _Ty>(_Param);
5560
5561 _M_unitTask._CreateImpl(Concurrency::cancellation_token::none()._GetImplValue());
5562 // 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.
5563 _M_unitTask._SetTaskCreationAddressHint(_ReturnAddress());
5564
5565 _TaskInitMaybeFunctor(_Param, details::_IsCallable<void>(_Param, 0, 0, 0));
5566 }
5567 #endif
5568 /// <summary>
5569 /// Constructs a <c>task</c> object.
5570 /// </summary>
5571 /// <typeparam name="_Ty">
5572 /// The type of the parameter from which the task is to be constructed.
5573 /// </typeparam>
5574 /// <param name="_Param">
5575 /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c>
5576 /// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function
5577 /// 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>,
5578 /// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps.
5579 /// </param>
5580 /// <param name="_Token">
5581 /// The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives
5582 /// the token <c>cancellation_token::none()</c>.
5583 /// </param>
5584 /// <remarks>
5585 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
5586 /// 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>
5587 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
5588 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
5589 /// completion event is set.</para>
5590 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
5591 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
5592 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
5593 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
5594 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
5595 /// and not when the lamda returns.</para>
5596 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
5597 /// without the need for locks.</para>
5598 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
5599 /// to Windows Store apps.</para>
5600 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
5601 /// </remarks>
5602 /**/
5603 template<typename _Ty>
5604 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
5605 #if _MSC_VER >= 1800
5606 explicit task(_Ty _Param, const task_options& _TaskOptions = task_options())
5607 #else
5608 explicit task(_Ty _Param, Concurrency::cancellation_token _CancellationToken)
5609 #endif
5610 {
5611 details::_ValidateTaskConstructorArgs<void, _Ty>(_Param);
5612 #if _MSC_VER >= 1800
5613 _M_unitTask._CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());
5614 #else
5615 _M_unitTask._CreateImpl(_CancellationToken._GetImplValue());
5616 #endif
5617 // 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.
5618 #if _MSC_VER >= 1800
5619 _M_unitTask._SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK());
5620 #else
5621 _M_unitTask._SetTaskCreationAddressHint(_ReturnAddress());
5622 #endif
5623 _TaskInitMaybeFunctor(_Param, details::_IsCallable<void>(_Param, 0, 0, 0));
5624 }
5625
5626 /// <summary>
5627 /// Constructs a <c>task</c> object.
5628 /// </summary>
5629 /// <param name="_Other">
5630 /// The source <c>task</c> object.
5631 /// </param>
5632 /// <remarks>
5633 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
5634 /// 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>
5635 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
5636 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
5637 /// completion event is set.</para>
5638 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
5639 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
5640 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
5641 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
5642 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
5643 /// and not when the lamda returns.</para>
5644 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
5645 /// without the need for locks.</para>
5646 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
5647 /// to Windows Store apps.</para>
5648 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
5649 /// </remarks>
5650 /**/
5651 task(const task& _Other) : _M_unitTask(_Other._M_unitTask){}
5652
5653 /// <summary>
5654 /// Constructs a <c>task</c> object.
5655 /// </summary>
5656 /// <param name="_Other">
5657 /// The source <c>task</c> object.
5658 /// </param>
5659 /// <remarks>
5660 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers.
5661 /// 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>
5662 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task.
5663 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task
5664 /// completion event is set.</para>
5665 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the
5666 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para>
5667 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface
5668 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created
5669 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state,
5670 /// and not when the lamda returns.</para>
5671 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads
5672 /// without the need for locks.</para>
5673 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available
5674 /// to Windows Store apps.</para>
5675 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
5676 /// </remarks>
5677 /**/
5678 task(task&& _Other) : _M_unitTask(std::move(_Other._M_unitTask)) {}
5679
5680 /// <summary>
5681 /// Replaces the contents of one <c>task</c> object with another.
5682 /// </summary>
5683 /// <param name="_Other">
5684 /// The source <c>task</c> object.
5685 /// </param>
5686 /// <remarks>
5687 /// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
5688 /// actual task as <paramref name="_Other"/> does.
5689 /// </remarks>
5690 /**/
5691 task& operator=(const task& _Other)
5692 {
5693 if (this != &_Other)
5694 {
5695 _M_unitTask = _Other._M_unitTask;
5696 }
5697 return *this;
5698 }
5699
5700 /// <summary>
5701 /// Replaces the contents of one <c>task</c> object with another.
5702 /// </summary>
5703 /// <param name="_Other">
5704 /// The source <c>task</c> object.
5705 /// </param>
5706 /// <remarks>
5707 /// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same
5708 /// actual task as <paramref name="_Other"/> does.
5709 /// </remarks>
5710 /**/
5711 task& operator=(task&& _Other)
5712 {
5713 if (this != &_Other)
5714 {
5715 _M_unitTask = std::move(_Other._M_unitTask);
5716 }
5717 return *this;
5718 }
5719 #if _MSC_VER < 1800
5720 /// <summary>
5721 /// Adds a continuation task to this task.
5722 /// </summary>
5723 /// <typeparam name="_Function">
5724 /// The type of the function object that will be invoked by this task.
5725 /// </typeparam>
5726 /// <param name="_Func">
5727 /// The continuation function to execute when this task completes. This continuation function must take as input
5728 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
5729 /// of the result this task produces.
5730 /// </param>
5731 /// <returns>
5732 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
5733 /// </returns>
5734 /// <remarks>
5735 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
5736 /// to Windows Store apps.
5737 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
5738 /// </remarks>
5739 /**/
5740 template<typename _Function>
5741 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
5742 auto then(const _Function& _Func) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
5743 {
5744 auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, nullptr, task_continuation_context::use_default());
5745 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
5746 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
5747 return _ContinuationTask;
5748 }
5749 #endif
5750 /// <summary>
5751 /// Adds a continuation task to this task.
5752 /// </summary>
5753 /// <typeparam name="_Function">
5754 /// The type of the function object that will be invoked by this task.
5755 /// </typeparam>
5756 /// <param name="_Func">
5757 /// The continuation function to execute when this task completes. This continuation function must take as input
5758 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
5759 /// of the result this task produces.
5760 /// </param>
5761 /// <param name="_CancellationToken">
5762 /// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
5763 /// the token of its antecedent task.
5764 /// </param>
5765 /// <returns>
5766 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
5767 /// </returns>
5768 /// <remarks>
5769 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
5770 /// to Windows Store apps.
5771 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
5772 /// </remarks>
5773 /**/
5774 template<typename _Function>
5775 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
5776 #if _MSC_VER >= 1800
5777 auto then(const _Function& _Func, task_options _TaskOptions = task_options()) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
5778 {
5779 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
5780 return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);
5781 }
5782 #else
5783 auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
5784 {
5785 auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, _CancellationToken._GetImplValue(), task_continuation_context::use_default());
5786 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
5787 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
5788 return _ContinuationTask;
5789 }
5790 /// <summary>
5791 /// Adds a continuation task to this task.
5792 /// </summary>
5793 /// <typeparam name="_Function">
5794 /// The type of the function object that will be invoked by this task.
5795 /// </typeparam>
5796 /// <param name="_Func">
5797 /// The continuation function to execute when this task completes. This continuation function must take as input
5798 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
5799 /// of the result this task produces.
5800 /// </param>
5801 /// <param name="_ContinuationContext">
5802 /// A variable that specifies where the continuation should execute. This variable is only useful when used in a
5803 /// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
5804 /// </param>
5805 /// <returns>
5806 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
5807 /// </returns>
5808 /// <remarks>
5809 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
5810 /// to Windows Store apps.
5811 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
5812 /// </remarks>
5813 /**/
5814 template<typename _Function>
5815 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
5816 auto then(const _Function& _Func, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
5817 {
5818 auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, nullptr, _ContinuationContext);
5819 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
5820 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
5821 return _ContinuationTask;
5822
5823 }
5824 #endif
5825 /// <summary>
5826 /// Adds a continuation task to this task.
5827 /// </summary>
5828 /// <typeparam name="_Function">
5829 /// The type of the function object that will be invoked by this task.
5830 /// </typeparam>
5831 /// <param name="_Func">
5832 /// The continuation function to execute when this task completes. This continuation function must take as input
5833 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type
5834 /// of the result this task produces.
5835 /// </param>
5836 /// <param name="_CancellationToken">
5837 /// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit
5838 /// the token of its antecedent task.
5839 /// </param>
5840 /// <param name="_ContinuationContext">
5841 /// A variable that specifies where the continuation should execute. This variable is only useful when used in a
5842 /// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see>
5843 /// </param>
5844 /// <returns>
5845 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns.
5846 /// </returns>
5847 /// <remarks>
5848 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available
5849 /// to Windows Store apps.
5850 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para>
5851 /// </remarks>
5852 /**/
5853 template<typename _Function>
5854 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
5855 #if _MSC_VER >= 1800
5856 auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
5857 {
5858 task_options _TaskOptions(_CancellationToken, _ContinuationContext);
5859 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
5860 return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);
5861 }
5862 #else
5863 auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
5864 {
5865 auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, _CancellationToken._GetImplValue(), _ContinuationContext);
5866 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then.
5867 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress());
5868 return _ContinuationTask;
5869 }
5870 #endif
5871
5872 /// <summary>
5873 /// 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
5874 /// dependencies are satisfied, and it has not already been picked up for execution by a background worker.
5875 /// </summary>
5876 /// <returns>
5877 /// A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception
5878 /// during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception.
5879 /// </returns>
5880 /**/
5881 task_status wait() const
5882 {
5883 return _M_unitTask.wait();
5884 }
5885
5886 /// <summary>
5887 /// Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to
5888 /// finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>.
5889 /// </summary>
5890 /// <remarks>
5891 /// If the task is canceled, a call to <c>get</c> will throw a <see cref="task_canceled Class">task_canceled</see> exception. If the task
5892 /// encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception.
5893 /// </remarks>
5894 /**/
5895 void get() const
5896 {
5897 _M_unitTask.get();
5898 }
5899 #if _MSC_VER >= 1800
5900
5901 /// <summary>
5902 /// Determines if the task is completed.
5903 /// </summary>
5904 /// <returns>
5905 /// True if the task has completed, false otherwise.
5906 /// </returns>
5907 /// <remarks>
5908 /// The function returns true if the task is completed or canceled (with or without user exception).
5909 /// </remarks>
5910 bool is_done() const
5911 {
5912 return _M_unitTask.is_done();
5913 }
5914
5915 /// <summary>
5916 /// Returns the scheduler for this task
5917 /// </summary>
5918 /// <returns>
5919 /// A pointer to the scheduler
5920 /// </returns>
5921 Concurrency::scheduler_ptr scheduler() const
5922 {
5923 return _M_unitTask.scheduler();
5924 }
5925 #endif
5926 /// <summary>
5927 /// Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task.
5928 /// </summary>
5929 /// <returns>
5930 /// <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise.
5931 /// </returns>
5932 /**/
5933 bool is_apartment_aware() const
5934 {
5935 return _M_unitTask.is_apartment_aware();
5936 }
5937
5938 /// <summary>
5939 /// Determines whether two <c>task</c> objects represent the same internal task.
5940 /// </summary>
5941 /// <returns>
5942 /// <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise.
5943 /// </returns>
5944 /**/
5945 bool operator==(const task<void>& _Rhs) const
5946 {
5947 return (_M_unitTask == _Rhs._M_unitTask);
5948 }
5949
5950 /// <summary>
5951 /// Determines whether two <c>task</c> objects represent different internal tasks.
5952 /// </summary>
5953 /// <returns>
5954 /// <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise.
5955 /// </returns>
5956 /**/
5957 bool operator!=(const task<void>& _Rhs) const
5958 {
5959 return !operator==(_Rhs);
5960 }
5961
5962 /// <summary>
5963 /// Create an underlying task implementation.
5964 /// </summary>
5965 #if _MSC_VER >= 1800
5966 void _CreateImpl(Concurrency::details::_CancellationTokenState * _Ct, Concurrency::scheduler_ptr _Scheduler)
5967 {
5968 _M_unitTask._CreateImpl(_Ct, _Scheduler);
5969 }
5970 #else
5971 void _CreateImpl(Concurrency::details::_CancellationTokenState * _Ct)
5972 {
5973 _M_unitTask._CreateImpl(_Ct);
5974 }
5975 #endif
5976
5977 /// <summary>
5978 /// Return the underlying implementation for this task.
5979 /// </summary>
5980 const details::_Task_ptr<details::_Unit_type>::_Type & _GetImpl() const
5981 {
5982 return _M_unitTask._M_Impl;
5983 }
5984
5985 /// <summary>
5986 /// Set the implementation of the task to be the supplied implementaion.
5987 /// </summary>
5988 void _SetImpl(const details::_Task_ptr<details::_Unit_type>::_Type & _Impl)
5989 {
5990 _M_unitTask._SetImpl(_Impl);
5991 }
5992
5993 /// <summary>
5994 /// Set the implementation of the task to be the supplied implementaion using a move instead of a copy.
5995 /// </summary>
5996 void _SetImpl(details::_Task_ptr<details::_Unit_type>::_Type && _Impl)
5997 {
5998 _M_unitTask._SetImpl(std::move(_Impl));
5999 }
6000
6001 /// <summary>
6002 /// Sets a property determining whether the task is apartment aware.
6003 /// </summary>
6004 void _SetAsync(bool _Async = true)
6005 {
6006 _M_unitTask._SetAsync(_Async);
6007 }
6008
6009 /// <summary>
6010 /// Sets a field in the task impl to the return address for calls to the task constructors and the then method.
6011 /// </summary>
6012 #if _MSC_VER >= 1800
6013 void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack)
6014 {
6015 _M_unitTask._SetTaskCreationCallstack(_callstack);
6016 }
6017 #else
6018 void _SetTaskCreationAddressHint(void* _Address)
6019 {
6020 _M_unitTask._SetTaskCreationAddressHint(_Address);
6021 }
6022 #endif
6023
6024 /// <summary>
6025 /// An internal version of then that takes additional flags and executes the continuation inline. Used for runtime internal continuations only.
6026 /// </summary>
6027 template<typename _Function>
6028 #if _MSC_VER >= 1800
6029 auto _Then(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState,
6030 details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
6031 {
6032 // inherit from antecedent
6033 auto _Scheduler = _GetImpl()->_GetScheduler();
6034
6035 return _M_unitTask._ThenImpl<void, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);
6036 }
6037 #else
6038 auto _Then(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState,
6039 bool _Aggregating, details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
6040 {
6041 return _M_unitTask._ThenImpl<void, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Aggregating, _InliningMode);
6042 }
6043 #endif
6044
6045 private:
6046 template <typename T> friend class task;
6047 template <typename T> friend class task_completion_event;
6048
6049 /// <summary>
6050 /// Initializes a task using a task completion event.
6051 /// </summary>
6052 void _TaskInitNoFunctor(task_completion_event<void>& _Event)
6053 {
6054 _M_unitTask._TaskInitNoFunctor(_Event._M_unitEvent);
6055 }
6056 /// <summary>
6057 /// Initializes a task using an asynchronous action IAsyncAction*
6058 /// </summary>
6059 void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncAction* _AsyncAction)
6060 {
6061 _M_unitTask._TaskInitAsyncOp<details::_Unit_type>(Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(_AsyncAction).Get());
6062 }
6063
6064 /// <summary>
6065 /// Initializes a task using an asynchronous action with progress IAsyncActionWithProgress<_P>*
6066 /// </summary>
6067 template<typename _P>
6068 void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncActionWithProgress<_P>* _AsyncActionWithProgress)
6069 {
6070 _M_unitTask._TaskInitAsyncOp<details::_Unit_type>(Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_P>>(_AsyncActionWithProgress).Get());
6071 }
6072 /// <summary>
6073 /// Initializes a task using a callable object.
6074 /// </summary>
6075 template<typename _Function>
6076 void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)
6077 {
6078 _M_unitTask._TaskInitWithFunctor<void, _Function>(_Func);
6079 }
6080
6081 /// <summary>
6082 /// Initializes a task using a non-callable object.
6083 /// </summary>
6084 template<typename _T>
6085 void _TaskInitMaybeFunctor(_T & _Param, std::false_type)
6086 {
6087 _TaskInitNoFunctor(_Param);
6088 }
6089
6090 // The void task contains a task of a dummy type so common code can be used for tasks with void and non-void results.
6091 task<details::_Unit_type> _M_unitTask;
6092 };
6093
6094 namespace details
6095 {
6096
6097 /// <summary>
6098 /// The following type traits are used for the create_task function.
6099 /// </summary>
6100
6101 // Unwrap task<T>
6102 template<typename _Ty>
6103 _Ty _GetUnwrappedType(task<_Ty>);
6104
6105 // Unwrap all supported types
6106 template<typename _Ty>
6107 auto _GetUnwrappedReturnType(_Ty _Arg, int) -> decltype(_GetUnwrappedType(_Arg));
6108 // fallback
6109 template<typename _Ty>
6110 _Ty _GetUnwrappedReturnType(_Ty, ...);
6111
6112 /// <summary>
6113 /// <c>_GetTaskType</c> functions will retrieve task type <c>T</c> in <c>task[T](Arg)</c>,
6114 /// for given constructor argument <c>Arg</c> and its property "callable".
6115 /// It will automatically unwrap argument to get the final return type if necessary.
6116 /// </summary>
6117
6118 // Non-Callable
6119 template<typename _Ty>
6120 _Ty _GetTaskType(task_completion_event<_Ty>, std::false_type);
6121
6122 // Non-Callable
6123 template<typename _Ty>
6124 auto _GetTaskType(_Ty _NonFunc, std::false_type) -> decltype(_GetUnwrappedType(_NonFunc));
6125
6126 // Callable
6127 template<typename _Ty>
6128 auto _GetTaskType(_Ty _Func, std::true_type) -> decltype(_GetUnwrappedReturnType(stdx::declval<_FunctionTypeTraits<_Ty, void>::_FuncRetType>(), 0));
6129
6130 // Special callable returns void
6131 void _GetTaskType(std::function<HRESULT()>, std::true_type);
6132 struct _BadArgType{};
6133
6134 template<typename _ReturnType, typename _Ty>
6135 auto _FilterValidTaskType(_Ty _Param, int) -> decltype(_GetTaskType(_Param, _IsCallable<_ReturnType>(_Param, 0, 0, 0)));
6136
6137 template<typename _ReturnType, typename _Ty>
6138 _BadArgType _FilterValidTaskType(_Ty _Param, ...);
6139
6140 template<typename _ReturnType, typename _Ty>
6141 struct _TaskTypeFromParam
6142 {
6143 typedef decltype(_FilterValidTaskType<_ReturnType>(stdx::declval<_Ty>(), 0)) _Type;
6144 };
6145 }
6146
6147
6148 /// <summary>
6149 /// Creates a PPL <see cref="task Class">task</c> object. <c>create_task</c> can be used anywhere you would have used a task constructor.
6150 /// It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks.
6151 /// </summary>
6152 /// <typeparam name="_Ty">
6153 /// The type of the parameter from which the task is to be constructed.
6154 /// </typeparam>
6155 /// <param name="_Param">
6156 /// The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c>
6157 /// object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app.
6158 /// </param>
6159 /// <returns>
6160 /// A new task of type <c>T</c>, that is inferred from <paramref name="_Param"/>.
6161 /// </returns>
6162 /// <remarks>
6163 /// The first overload behaves like a task constructor that takes a single parameter.
6164 /// <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not
6165 /// allowed to pass in a different <c>task</c> object as the first parameter.</para>
6166 /// <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name="_Param"/> is a <c>task_completion_event<T></c>,
6167 /// a <c>task<T></c>, or a functor that returns either type <c>T</c> or <c>task<T></c>, the type of the created task is <c>task<T></c>.
6168 /// <para>In a Windows Store app, if <paramref name="_Param"/> is of type Windows::Foundation::IAsyncOperation<T>^ or
6169 /// Windows::Foundation::IAsyncOperationWithProgress<T,P>^, or a functor that returns either of those types, the created task will be of type <c>task<T></c>.
6170 /// If <paramref name="_Param"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress<P>^, or a functor
6171 /// that returns either of those types, the created task will have type <c>task<void></c>.</para>
6172 /// </remarks>
6173 /// <seealso cref="task Class"/>
6174 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
6175 /**/
6176 template<typename _ReturnType, typename _Ty>
6177 __declspec(noinline)
6178 #if _MSC_VER >= 1800
6179 auto create_task(_Ty _Param, task_options _TaskOptions = task_options()) -> task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type>
6180 #else
6181 auto create_task(_Ty _Param) -> task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type>
6182 #endif
6183 {
6184 static_assert(!std::is_same<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type, details::_BadArgType>::value,
6185 "incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event"
6186 );
6187 #if _MSC_VER >= 1800
6188 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
6189 task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type> _CreatedTask(_Param, _TaskOptions);
6190 #else
6191 task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type> _CreatedTask(_Param);
6192 // Ideally we would like to forceinline create_task, but __forceinline does nothing on debug builds. Therefore, we ask for no inlining
6193 // and overwrite the creation address hint set by the task constructor. DO NOT REMOVE this next line from create_task. It is
6194 // essential that _ReturnAddress() evaluate to the instruction right after the call to create_task in client code.
6195 _CreatedTask._SetTaskCreationAddressHint(_ReturnAddress());
6196 #endif
6197 return _CreatedTask;
6198 }
6199
6200 /// <summary>
6201 /// Creates a PPL <see cref="task Class">task</c> object. <c>create_task</c> can be used anywhere you would have used a task constructor.
6202 /// It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks.
6203 /// </summary>
6204 /// <typeparam name="_Ty">
6205 /// The type of the parameter from which the task is to be constructed.
6206 /// </typeparam>
6207 /// <param name="_Param">
6208 /// The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c>
6209 /// object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app.
6210 /// </param>
6211 /// <param name="_Token">
6212 /// The cancellation token to associate with the task. When the source for this token is canceled, cancellation will be requested on the task.
6213 /// </param>
6214 /// <returns>
6215 /// A new task of type <c>T</c>, that is inferred from <paramref name="_Param"/>.
6216 /// </returns>
6217 /// <remarks>
6218 /// The first overload behaves like a task constructor that takes a single parameter.
6219 /// <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not
6220 /// allowed to pass in a different <c>task</c> object as the first parameter.</para>
6221 /// <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name="_Param"/> is a <c>task_completion_event<T></c>,
6222 /// a <c>task<T></c>, or a functor that returns either type <c>T</c> or <c>task<T></c>, the type of the created task is <c>task<T></c>.
6223 /// <para>In a Windows Store app, if <paramref name="_Param"/> is of type Windows::Foundation::IAsyncOperation<T>^ or
6224 /// Windows::Foundation::IAsyncOperationWithProgress<T,P>^, or a functor that returns either of those types, the created task will be of type <c>task<T></c>.
6225 /// If <paramref name="_Param"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress<P>^, or a functor
6226 /// that returns either of those types, the created task will have type <c>task<void></c>.</para>
6227 /// </remarks>
6228 /// <seealso cref="task Class"/>
6229 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
6230 /**/
6231 #if _MSC_VER >= 1800
6232 template<typename _ReturnType>
6233 __declspec(noinline)
6234 task<_ReturnType> create_task(const task<_ReturnType>& _Task)
6235 {
6236 task<_ReturnType> _CreatedTask(_Task);
6237 return _CreatedTask;
6238 }
6239 #else
6240 template<typename _ReturnType, typename _Ty>
6241 __declspec(noinline)
6242 auto create_task(_Ty _Param, Concurrency::cancellation_token _Token) -> task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type>
6243 {
6244 static_assert(!std::is_same<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type, details::_BadArgType>::value,
6245 "incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event"
6246 );
6247 task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type> _CreatedTask(_Param, _Token);
6248 // Ideally we would like to forceinline create_task, but __forceinline does nothing on debug builds. Therefore, we ask for no inlining
6249 // and overwrite the creation address hint set by the task constructor. DO NOT REMOVE this next line from create_task. It is
6250 // essential that _ReturnAddress() evaluate to the instruction right after the call to create_task in client code.
6251 _CreatedTask._SetTaskCreationAddressHint(_ReturnAddress());
6252 return _CreatedTask;
6253 }
6254 #endif
6255
6256 namespace details
6257 {
6258 template<typename _T>
6259 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)
6260 {
6261 return task<_T>(op);
6262 }
6263
6264 template<typename _T, typename _Progress>
6265 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)
6266 {
6267 return task<_T>(op);
6268 }
6269
6270 inline task<void> _To_task_helper(ABI::Windows::Foundation::IAsyncAction* op)
6271 {
6272 return task<void>(op);
6273 }
6274
6275 template<typename _Progress>
6276 task<void> _To_task_helper(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>* op)
6277 {
6278 return task<void>(op);
6279 }
6280
6281 template<typename _ProgressType>
6282 class _ProgressDispatcherBase
6283 {
6284 public:
6285
6286 virtual ~_ProgressDispatcherBase()
6287 {
6288 }
6289
6290 virtual void _Report(const _ProgressType& _Val) = 0;
6291 };
6292
6293 template<typename _ProgressType, typename _ClassPtrType>
6294 class _ProgressDispatcher : public _ProgressDispatcherBase<_ProgressType>
6295 {
6296 public:
6297
6298 virtual ~_ProgressDispatcher()
6299 {
6300 }
6301
6302 _ProgressDispatcher(_ClassPtrType _Ptr) : _M_ptr(_Ptr)
6303 {
6304 }
6305
6306 virtual void _Report(const _ProgressType& _Val)
6307 {
6308 _M_ptr->_FireProgress(_Val);
6309 }
6310
6311 private:
6312
6313 _ClassPtrType _M_ptr;
6314 };
6315 } // namespace details
6316
6317
6318 /// <summary>
6319 /// The progress reporter class allows reporting progress notifications of a specific type. Each progress_reporter object is bound
6320 /// to a particular asynchronous action or operation.
6321 /// </summary>
6322 /// <typeparam name="_ProgressType">
6323 /// The payload type of each progress notification reported through the progress reporter.
6324 /// </typeparam>
6325 /// <remarks>
6326 /// This type is only available to Windows Store apps.
6327 /// </remarks>
6328 /// <seealso cref="create_async Function"/>
6329 /**/
6330 template<typename _ProgressType>
6331 class progress_reporter
6332 {
6333 typedef std::shared_ptr<details::_ProgressDispatcherBase<_ProgressType>> _PtrType;
6334
6335 public:
6336
6337 /// <summary>
6338 /// Sends a progress report to the asynchronous action or operation to which this progress reporter is bound.
6339 /// </summary>
6340 /// <param name="_Val">
6341 /// The payload to report through a progress notification.
6342 /// </param>
6343 /**/
6344 void report(const _ProgressType& _Val) const
6345 {
6346 _M_dispatcher->_Report(_Val);
6347 }
6348
6349 template<typename _ClassPtrType>
6350 static progress_reporter _CreateReporter(_ClassPtrType _Ptr)
6351 {
6352 progress_reporter _Reporter;
6353 details::_ProgressDispatcherBase<_ProgressType> *_PDispatcher = new details::_ProgressDispatcher<_ProgressType, _ClassPtrType>(_Ptr);
6354 _Reporter._M_dispatcher = _PtrType(_PDispatcher);
6355 return _Reporter;
6356 }
6357 progress_reporter() {}
6358
6359 private:
6360 progress_reporter(details::_ProgressReporterCtorArgType);
6361
6362 _PtrType _M_dispatcher;
6363 };
6364
6365 namespace details
6366 {
6367 //
6368 // maps internal definitions for AsyncStatus and defines states that are not client visible
6369 //
6370 enum _AsyncStatusInternal
6371 {
6372 _AsyncCreated = -1, // externally invisible
6373 // client visible states (must match AsyncStatus exactly)
6374 _AsyncStarted = ABI::Windows::Foundation::AsyncStatus::Started, // 0
6375 _AsyncCompleted = ABI::Windows::Foundation::AsyncStatus::Completed, // 1
6376 _AsyncCanceled = ABI::Windows::Foundation::AsyncStatus::Canceled, // 2
6377 _AsyncError = ABI::Windows::Foundation::AsyncStatus::Error, // 3
6378 // non-client visible internal states
6379 _AsyncCancelPending,
6380 _AsyncClosed,
6381 _AsyncUndefined
6382 };
6383
6384 //
6385 // designates whether the "GetResults" method returns a single result (after complete fires) or multiple results
6386 // (which are progressively consumable between Start state and before Close is called)
6387 //
6388 enum _AsyncResultType
6389 {
6390 SingleResult = 0x0001,
6391 MultipleResults = 0x0002
6392 };
6393
6394 template<typename _T>
6395 struct _ProgressTypeTraits
6396 {
6397 static const bool _TakesProgress = false;
6398 typedef void _ProgressType;
6399 };
6400
6401 template<typename _T>
6402 struct _ProgressTypeTraits<progress_reporter<_T>>
6403 {
6404 static const bool _TakesProgress = true;
6405 typedef typename _T _ProgressType;
6406 };
6407
6408 template<typename _T, bool bTakesToken = std::is_same<_T, Concurrency::cancellation_token>::value, bool bTakesProgress = _ProgressTypeTraits<_T>::_TakesProgress>
6409 struct _TokenTypeTraits
6410 {
6411 static const bool _TakesToken = false;
6412 typedef typename _T _ReturnType;
6413 };
6414
6415 template<typename _T>
6416 struct _TokenTypeTraits<_T, false, true>
6417 {
6418 static const bool _TakesToken = false;
6419 typedef void _ReturnType;
6420 };
6421
6422 template<typename _T>
6423 struct _TokenTypeTraits<_T, true, false>
6424 {
6425 static const bool _TakesToken = true;
6426 typedef void _ReturnType;
6427 };
6428
6429 template<typename _T, size_t count = _FunctorTypeTraits<_T>::_ArgumentCount>
6430 struct _CAFunctorOptions
6431 {
6432 static const bool _TakesProgress = false;
6433 static const bool _TakesToken = false;
6434 typedef void _ProgressType;
6435 typedef void _ReturnType;
6436 };
6437
6438 template<typename _T>
6439 struct _CAFunctorOptions<_T, 1>
6440 {
6441 private:
6442
6443 typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
6444
6445 public:
6446
6447 static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress;
6448 static const bool _TakesToken = _TokenTypeTraits<_Argument1Type>::_TakesToken;
6449 typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
6450 typedef typename _TokenTypeTraits<_Argument1Type>::_ReturnType _ReturnType;
6451 };
6452
6453 template<typename _T>
6454 struct _CAFunctorOptions<_T, 2>
6455 {
6456 private:
6457
6458 typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
6459 typedef typename _FunctorTypeTraits<_T>::_Argument2Type _Argument2Type;
6460
6461 public:
6462
6463 static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress;
6464 static const bool _TakesToken = !_TakesProgress ? true : _TokenTypeTraits<_Argument2Type>::_TakesToken;
6465 typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
6466 typedef typename _TokenTypeTraits<_Argument2Type>::_ReturnType _ReturnType;
6467 };
6468
6469 template<typename _T>
6470 struct _CAFunctorOptions<_T, 3>
6471 {
6472 private:
6473
6474 typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
6475
6476 public:
6477
6478 static const bool _TakesProgress = true;
6479 static const bool _TakesToken = true;
6480 typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
6481 typedef typename _FunctorTypeTraits<_T>::_Argument3Type _ReturnType;
6482 };
6483
6484 class _Zip
6485 {
6486 };
6487
6488 // ***************************************************************************
6489 // Async Operation Task Generators
6490 //
6491
6492 //
6493 // Functor returns an IAsyncInfo - result needs to be wrapped in a task:
6494 //
6495 template<typename _AsyncSelector, typename _ReturnType>
6496 struct _SelectorTaskGenerator
6497 {
6498 #if _MSC_VER >= 1800
6499 template<typename _Function>
6500 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6501 {
6502 task_options _taskOptinos(_Cts.get_token());
6503 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6504 return task<_ReturnType>(_Func(_pRet), _taskOptinos);
6505 }
6506
6507 template<typename _Function>
6508 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6509 {
6510 task_options _taskOptinos(_Cts.get_token());
6511 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6512 return task<_ReturnType>(_Func(_Cts.get_token(), _pRet), _taskOptinos);
6513 }
6514
6515 template<typename _Function, typename _ProgressObject>
6516 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6517 {
6518 task_options _taskOptinos(_Cts.get_token());
6519 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6520 return task<_ReturnType>(_Func(_Progress, _pRet), _taskOptinos);
6521 }
6522
6523 template<typename _Function, typename _ProgressObject>
6524 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6525 {
6526 task_options _taskOptinos(_Cts.get_token());
6527 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6528 return task<_ReturnType>(_Func(_Progress, _Cts.get_token(), _pRet), _taskOptinos);
6529 }
6530 #else
6531 template<typename _Function>
6532 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6533 {
6534 return task<_ReturnType>(_Func(_pRet), _Cts.get_token());
6535 }
6536
6537 template<typename _Function>
6538 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6539 {
6540 return task<_ReturnType>(_Func(_Cts.get_token(), _pRet), _Cts.get_token());
6541 }
6542
6543 template<typename _Function, typename _ProgressObject>
6544 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6545 {
6546 return task<_ReturnType>(_Func(_Progress, _pRet), _Cts.get_token());
6547 }
6548
6549 template<typename _Function, typename _ProgressObject>
6550 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6551 {
6552 return task<_ReturnType>(_Func(_Progress, _Cts.get_token(), _pRet), _Cts.get_token());
6553 }
6554 #endif
6555 };
6556
6557 template<typename _AsyncSelector>
6558 struct _SelectorTaskGenerator<_AsyncSelector, void>
6559 {
6560 #if _MSC_VER >= 1800
6561 template<typename _Function>
6562 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6563 {
6564 task_options _taskOptinos(_Cts.get_token());
6565 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6566 return task<void>(_Func(), _taskOptinos);
6567 }
6568
6569 template<typename _Function>
6570 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6571 {
6572 task_options _taskOptinos(_Cts.get_token());
6573 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6574 return task<void>(_Func(_Cts.get_token()), _taskOptinos);
6575 }
6576
6577 template<typename _Function, typename _ProgressObject>
6578 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6579 {
6580 task_options _taskOptinos(_Cts.get_token());
6581 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6582 return task<void>(_Func(_Progress), _taskOptinos);
6583 }
6584
6585 template<typename _Function, typename _ProgressObject>
6586 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6587 {
6588 task_options _taskOptinos(_Cts.get_token());
6589 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6590 return task<void>(_Func(_Progress, _Cts.get_token()), _taskOptinos);
6591 }
6592 #else
6593 template<typename _Function>
6594 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
6595 {
6596 return task<void>(_Func(), _Cts.get_token());
6597 }
6598
6599 template<typename _Function>
6600 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
6601 {
6602 return task<void>(_Func(_Cts.get_token()), _Cts.get_token());
6603 }
6604
6605 template<typename _Function, typename _ProgressObject>
6606 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
6607 {
6608 return task<void>(_Func(_Progress), _Cts.get_token());
6609 }
6610
6611 template<typename _Function, typename _ProgressObject>
6612 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
6613 {
6614 return task<void>(_Func(_Progress, _Cts.get_token()), _Cts.get_token());
6615 }
6616 #endif
6617 };
6618
6619 #if _MSC_VER < 1800
6620 // For create_async lambdas that return a (non-task) result, we oversubscriber the current task for the duration of the
6621 // lambda.
6622 struct _Task_generator_oversubscriber
6623 {
6624 _Task_generator_oversubscriber()
6625 {
6626 Concurrency::details::_Context::_Oversubscribe(true);
6627 }
6628
6629 ~_Task_generator_oversubscriber()
6630 {
6631 Concurrency::details::_Context::_Oversubscribe(false);
6632 }
6633 };
6634 #endif
6635
6636 //
6637 // Functor returns a result - it needs to be wrapped in a task:
6638 //
6639 template<typename _ReturnType>
6640 struct _SelectorTaskGenerator<details::_TypeSelectorNoAsync, _ReturnType>
6641 {
6642 #if _MSC_VER >= 1800
6643
6644 #pragma warning(push)
6645 #pragma warning(disable: 4702)
6646 template<typename _Function>
6647 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6648 {
6649 task_options _taskOptinos(_Cts.get_token());
6650 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6651 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT {
6652 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber;
6653 (_Oversubscriber);
6654 HRESULT hr = _Func(_pRet);
6655 retVal = _pRet;
6656 return hr;
6657 }, _taskOptinos);
6658 }
6659 #pragma warning(pop)
6660
6661 template<typename _Function>
6662 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6663 {
6664 task_options _taskOptinos(_Cts.get_token());
6665 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6666 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT {
6667 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber;
6668 (_Oversubscriber);
6669 HRESULT hr = _Func(_Cts.get_token(), _pRet);
6670 retVal = _pRet;
6671 return hr;
6672 }, _taskOptinos);
6673 }
6674
6675 template<typename _Function, typename _ProgressObject>
6676 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6677 {
6678 task_options _taskOptinos(_Cts.get_token());
6679 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6680 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT {
6681 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber;
6682 (_Oversubscriber);
6683 HRESULT hr = _Func(_Progress, _pRet);
6684 retVal = _pRet;
6685 return hr;
6686 }, _taskOptinos);
6687 }
6688
6689 template<typename _Function, typename _ProgressObject>
6690 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6691 {
6692 task_options _taskOptinos(_Cts.get_token());
6693 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6694 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT {
6695 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber;
6696 (_Oversubscriber);
6697 HRESULT hr = _Func(_Progress, _Cts.get_token(), _pRet);
6698 retVal = _pRet;
6699 return hr;
6700 }, _taskOptinos);
6701 }
6702 #else
6703 template<typename _Function>
6704 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6705 {
6706 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT {
6707 _Task_generator_oversubscriber _Oversubscriber;
6708 HRESULT hr = _Func(_pRet);
6709 retVal = _pRet;
6710 return hr;
6711 }, _Cts.get_token());
6712 }
6713
6714 template<typename _Function>
6715 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6716 {
6717 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT {
6718 _Task_generator_oversubscriber _Oversubscriber;
6719 HRESULT hr = _Func(_Cts.get_token(), _pRet);
6720 retVal = _pRet;
6721 return hr;
6722 }, _Cts.get_token());
6723 }
6724
6725 template<typename _Function, typename _ProgressObject>
6726 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6727 {
6728 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT {
6729 _Task_generator_oversubscriber _Oversubscriber;
6730 HRESULT hr = _Func(_Progress, _pRet);
6731 retVal = _pRet;
6732 return hr;
6733 }, _Cts.get_token());
6734 }
6735
6736 template<typename _Function, typename _ProgressObject>
6737 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6738 {
6739 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT {
6740 _Task_generator_oversubscriber _Oversubscriber;
6741 HRESULT hr = _Func(_Progress, _Cts.get_token(), _pRet);
6742 retVal = _pRet;
6743 return hr;
6744 }, _Cts.get_token());
6745 }
6746 #endif
6747 };
6748
6749 template<>
6750 struct _SelectorTaskGenerator<details::_TypeSelectorNoAsync, void>
6751 {
6752 #if _MSC_VER >= 1800
6753 template<typename _Function>
6754 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6755 {
6756 task_options _taskOptinos(_Cts.get_token());
6757 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6758 return task<void>([=]() -> HRESULT {
6759 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber;
6760 (_Oversubscriber);
6761 return _Func();
6762 }, _taskOptinos);
6763 }
6764
6765 template<typename _Function>
6766 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6767 {
6768 task_options _taskOptinos(_Cts.get_token());
6769 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6770 return task<void>([=]() -> HRESULT {
6771 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber;
6772 (_Oversubscriber);
6773 return _Func(_Cts.get_token());
6774 }, _taskOptinos);
6775 }
6776
6777 template<typename _Function, typename _ProgressObject>
6778 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6779 {
6780 task_options _taskOptinos(_Cts.get_token());
6781 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6782 return task<void>([=]() -> HRESULT {
6783 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber;
6784 (_Oversubscriber);
6785 return _Func(_Progress);
6786 }, _taskOptinos);
6787 }
6788
6789 template<typename _Function, typename _ProgressObject>
6790 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6791 {
6792 task_options _taskOptinos(_Cts.get_token());
6793 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
6794 return task<void>([=]() -> HRESULT {
6795 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber;
6796 (_Oversubscriber);
6797 return _Func(_Progress, _Cts.get_token());
6798 }, _taskOptinos);
6799 }
6800 #else
6801 template<typename _Function>
6802 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
6803 {
6804 return task<void>([=]() -> HRESULT {
6805 _Task_generator_oversubscriber _Oversubscriber;
6806 return _Func();
6807 }, _Cts.get_token());
6808 }
6809
6810 template<typename _Function>
6811 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
6812 {
6813 return task<void>([=]() -> HRESULT {
6814 _Task_generator_oversubscriber _Oversubscriber;
6815 return _Func(_Cts.get_token());
6816 }, _Cts.get_token());
6817 }
6818
6819 template<typename _Function, typename _ProgressObject>
6820 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
6821 {
6822 return task<void>([=]() -> HRESULT {
6823 _Task_generator_oversubscriber _Oversubscriber;
6824 return _Func(_Progress);
6825 }, _Cts.get_token());
6826 }
6827
6828 template<typename _Function, typename _ProgressObject>
6829 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
6830 {
6831 return task<void>([=]() -> HRESULT {
6832 _Task_generator_oversubscriber _Oversubscriber;
6833 return _Func(_Progress, _Cts.get_token());
6834 }, _Cts.get_token());
6835 }
6836 #endif
6837 };
6838
6839 //
6840 // Functor returns a task - the task can directly be returned:
6841 //
6842 template<typename _ReturnType>
6843 struct _SelectorTaskGenerator<details::_TypeSelectorAsyncTask, _ReturnType>
6844 {
6845 template<typename _Function>
6846 #if _MSC_VER >= 1800
6847 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6848 #else
6849 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6850 #endif
6851 {
6852 task<_ReturnType> _task;
6853 _Func(&_task);
6854 return _task;
6855 }
6856
6857 template<typename _Function>
6858 #if _MSC_VER >= 1800
6859 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6860 #else
6861 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6862 #endif
6863 {
6864 task<_ReturnType> _task;
6865 _Func(_Cts.get_token(), &_task);
6866 return _task;
6867 }
6868
6869 template<typename _Function, typename _ProgressObject>
6870 #if _MSC_VER >= 1800
6871 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6872 #else
6873 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6874 #endif
6875 {
6876 task<_ReturnType> _task;
6877 _Func(_Progress, &_task);
6878 return _task;
6879 }
6880
6881 template<typename _Function, typename _ProgressObject>
6882 #if _MSC_VER >= 1800
6883 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6884 #else
6885 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6886 #endif
6887 {
6888 task<_ReturnType> _task;
6889 _Func(_Progress, _Cts.get_token(), &_task);
6890 return _task;
6891 }
6892 };
6893
6894 template<>
6895 struct _SelectorTaskGenerator<details::_TypeSelectorAsyncTask, void>
6896 {
6897 template<typename _Function>
6898 #if _MSC_VER >= 1800
6899 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6900 #else
6901 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
6902 #endif
6903 {
6904 task<void> _task;
6905 _Func(&_task);
6906 return _task;
6907 }
6908
6909 template<typename _Function>
6910 #if _MSC_VER >= 1800
6911 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6912 #else
6913 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts)
6914 #endif
6915 {
6916 task<void> _task;
6917 _Func(_Cts.get_token(), &_task);
6918 return _task;
6919 }
6920
6921 template<typename _Function, typename _ProgressObject>
6922 #if _MSC_VER >= 1800
6923 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6924 #else
6925 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
6926 #endif
6927 {
6928 task<void> _task;
6929 _Func(_Progress, &_task);
6930 return _task;
6931 }
6932
6933 template<typename _Function, typename _ProgressObject>
6934 #if _MSC_VER >= 1800
6935 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6936 #else
6937 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts)
6938 #endif
6939 {
6940 task<void> _task;
6941 _Func(_Progress, _Cts.get_token(), &_task);
6942 return _task;
6943 }
6944 };
6945
6946 template<typename _Generator, bool _TakesToken, bool TakesProgress>
6947 struct _TaskGenerator
6948 {
6949 };
6950
6951 template<typename _Generator>
6952 struct _TaskGenerator<_Generator, false, false>
6953 {
6954 #if _MSC_VER >= 1800
6955 template<typename _Function, typename _ClassPtr, typename _ProgressType>
6956 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6957 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
6958 {
6959 (void)_Ptr;
6960 return _Generator::_GenerateTask_0(_Func, _Cts, _callstack);
6961 }
6962
6963 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
6964 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
6965 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet, _callstack))
6966 {
6967 return _Generator::_GenerateTask_0(_Func, _Cts, _pRet, _callstack);
6968 }
6969 #else
6970 template<typename _Function, typename _ClassPtr, typename _ProgressType>
6971 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
6972 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts))
6973 {
6974 (void)_Ptr;
6975 return _Generator::_GenerateTask_0(_Func, _Cts);
6976 }
6977
6978 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
6979 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
6980 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet))
6981 {
6982 return _Generator::_GenerateTask_0(_Func, _Cts, _pRet);
6983 }
6984 #endif
6985 };
6986
6987 template<typename _Generator>
6988 struct _TaskGenerator<_Generator, true, false>
6989 {
6990 #if _MSC_VER >= 1800
6991 template<typename _Function, typename _ClassPtr, typename _ProgressType>
6992 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
6993 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
6994 {
6995 return _Generator::_GenerateTask_1C(_Func, _Cts, _callstack);
6996 }
6997
6998 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
6999 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
7000 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet, _callstack))
7001 {
7002 return _Generator::_GenerateTask_1C(_Func, _Cts, _pRet, _callstack);
7003 }
7004 #else
7005 template<typename _Function, typename _ClassPtr, typename _ProgressType>
7006 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
7007 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts))
7008 {
7009 return _Generator::_GenerateTask_1C(_Func, _Cts);
7010 }
7011
7012 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
7013 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
7014 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet))
7015 {
7016 return _Generator::_GenerateTask_1C(_Func, _Cts, _pRet);
7017 }
7018 #endif
7019 };
7020
7021 template<typename _Generator>
7022 struct _TaskGenerator<_Generator, false, true>
7023 {
7024 #if _MSC_VER >= 1800
7025 template<typename _Function, typename _ClassPtr, typename _ProgressType>
7026 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
7027 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
7028 {
7029 return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack);
7030 }
7031
7032 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
7033 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
7034 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet, _callstack))
7035 {
7036 return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _pRet, _callstack);
7037 }
7038 #else
7039 template<typename _Function, typename _ClassPtr, typename _ProgressType>
7040 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
7041 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts))
7042 {
7043 return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts);
7044 }
7045
7046 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
7047 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
7048 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet))
7049 {
7050 return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _pRet);
7051 }
7052 #endif
7053 };
7054
7055 template<typename _Generator>
7056 struct _TaskGenerator<_Generator, true, true>
7057 {
7058 #if _MSC_VER >= 1800
7059 template<typename _Function, typename _ClassPtr, typename _ProgressType>
7060 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
7061 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
7062 {
7063 return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack);
7064 }
7065
7066 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
7067 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
7068 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet, _callstack))
7069 {
7070 return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _pRet, _callstack);
7071 }
7072 #else
7073 template<typename _Function, typename _ClassPtr, typename _ProgressType>
7074 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
7075 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts))
7076 {
7077 return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts);
7078 }
7079
7080 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType>
7081 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
7082 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet))
7083 {
7084 return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _pRet);
7085 }
7086 #endif
7087 };
7088
7089 // ***************************************************************************
7090 // Async Operation Attributes Classes
7091 //
7092 // These classes are passed through the hierarchy of async base classes in order to hold multiple attributes of a given async construct in
7093 // a single container. An attribute class must define:
7094 //
7095 // Mandatory:
7096 // -------------------------
7097 //
7098 // _AsyncBaseType : The Windows Runtime interface which is being implemented.
7099 // _CompletionDelegateType : The Windows Runtime completion delegate type for the interface.
7100 // _ProgressDelegateType : If _TakesProgress is true, the Windows Runtime progress delegate type for the interface. If it is false, an empty Windows Runtime type.
7101 // _ReturnType : The return type of the async construct (void for actions / non-void for operations)
7102 //
7103 // _TakesProgress : An indication as to whether or not
7104 //
7105 // _Generate_Task : A function adapting the user's function into what's necessary to produce the appropriate task
7106 //
7107 // Optional:
7108 // -------------------------
7109 //
7110
7111 template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken, bool _TakesProgress>
7112 struct _AsyncAttributes
7113 {
7114 };
7115
7116 template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>
7117 struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, true>
7118 {
7119 typedef typename ABI::Windows::Foundation::IAsyncOperationWithProgress<_ReturnType, _ProgressType> _AsyncBaseType;
7120 typedef typename ABI::Windows::Foundation::IAsyncOperationProgressHandler<_ReturnType, _ProgressType> _ProgressDelegateType;
7121 typedef typename ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<_ReturnType, _ProgressType> _CompletionDelegateType;
7122 typedef typename _ReturnType _ReturnType;
7123 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationWithProgressSelector(stdx::declval<_AsyncBaseType*>()))>::type _ReturnType_abi;
7124 typedef typename _ProgressType _ProgressType;
7125 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationWithProgressProgressSelector(stdx::declval<_AsyncBaseType*>()))>::type _ProgressType_abi;
7126 typedef typename _TaskTraits::_AsyncKind _AsyncKind;
7127 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
7128 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;
7129
7130 static const bool _TakesProgress = true;
7131 static const bool _TakesToken = _TakesToken;
7132
7133 template<typename _Function, typename _ClassPtr>
7134 #if _MSC_VER >= 1800
7135 static task<typename _TaskTraits::_TaskRetType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
7136 {
7137 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType_abi, _ReturnType>(_Func, _Ptr, _Cts, _pRet, _callstack);
7138 }
7139 #else
7140 static task<typename _TaskTraits::_TaskRetType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
7141 {
7142 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType_abi, _ReturnType>(_Func, _Ptr, _Cts, _pRet);
7143 }
7144 #endif
7145 };
7146
7147 template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>
7148 struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, false>
7149 {
7150 typedef typename ABI::Windows::Foundation::IAsyncOperation<_ReturnType> _AsyncBaseType;
7151 typedef _Zip _ProgressDelegateType;
7152 typedef typename ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_ReturnType> _CompletionDelegateType;
7153 typedef typename _ReturnType _ReturnType;
7154 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationSelector(stdx::declval<_AsyncBaseType*>()))>::type _ReturnType_abi;
7155 typedef typename _TaskTraits::_AsyncKind _AsyncKind;
7156 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
7157 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;
7158
7159 static const bool _TakesProgress = false;
7160 static const bool _TakesToken = _TakesToken;
7161
7162 template<typename _Function, typename _ClassPtr>
7163 #if _MSC_VER >= 1800
7164 static task<typename _TaskTraits::_TaskRetType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
7165 {
7166 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType, _ReturnType>(_Func, _Ptr, _Cts, _pRet, _callstack);
7167 }
7168 #else
7169 static task<typename _TaskTraits::_TaskRetType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
7170 {
7171 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType, _ReturnType>(_Func, _Ptr, _Cts, _pRet);
7172 }
7173 #endif
7174 };
7175
7176 template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>
7177 struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, true>
7178 {
7179 typedef typename ABI::Windows::Foundation::IAsyncActionWithProgress<_ProgressType> _AsyncBaseType;
7180 typedef typename ABI::Windows::Foundation::IAsyncActionProgressHandler<_ProgressType> _ProgressDelegateType;
7181 typedef typename ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler<_ProgressType> _CompletionDelegateType;
7182 typedef void _ReturnType;
7183 typedef void _ReturnType_abi;
7184 typedef typename _ProgressType _ProgressType;
7185 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncActionWithProgressSelector(stdx::declval<_AsyncBaseType*>()))>::type _ProgressType_abi;
7186 typedef typename _TaskTraits::_AsyncKind _AsyncKind;
7187 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
7188 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;
7189
7190 static const bool _TakesProgress = true;
7191 static const bool _TakesToken = _TakesToken;
7192
7193 #if _MSC_VER >= 1800
7194 template<typename _Function, typename _ClassPtr>
7195 static task<void> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
7196 {
7197 return _TaskGenerator::_GenerateTaskNoRet<_Function, _ClassPtr, _ProgressType_abi>(_Func, _Ptr, _Cts, _callstack);
7198 }
7199 template<typename _Function, typename _ClassPtr>
7200 static task<task<void>> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
7201 {
7202 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType_abi>(_Func, _Ptr, _Cts, _pRet, _callstack);
7203 }
7204 #else
7205 template<typename _Function, typename _ClassPtr>
7206 static task<void> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
7207 {
7208 return _TaskGenerator::_GenerateTaskNoRet<_Function, _ClassPtr, _ProgressType_abi>(_Func, _Ptr, _Cts);
7209 }
7210 template<typename _Function, typename _ClassPtr>
7211 static task<task<void>> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
7212 {
7213 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType_abi>(_Func, _Ptr, _Cts, _pRet);
7214 }
7215 #endif
7216 };
7217
7218 template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>
7219 struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, false>
7220 {
7221 typedef typename ABI::Windows::Foundation::IAsyncAction _AsyncBaseType;
7222 typedef _Zip _ProgressDelegateType;
7223 typedef typename ABI::Windows::Foundation::IAsyncActionCompletedHandler _CompletionDelegateType;
7224 typedef void _ReturnType;
7225 typedef void _ReturnType_abi;
7226 typedef typename _TaskTraits::_AsyncKind _AsyncKind;
7227 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
7228 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;
7229
7230 static const bool _TakesProgress = false;
7231 static const bool _TakesToken = _TakesToken;
7232
7233 #if _MSC_VER >= 1800
7234 template<typename _Function, typename _ClassPtr>
7235 static task<void> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
7236 {
7237 return _TaskGenerator::_GenerateTaskNoRet<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);
7238 }
7239 template<typename _Function, typename _ClassPtr>
7240 static task<task<void>> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack)
7241 {
7242 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _pRet, _callstack);
7243 }
7244 #else
7245 template<typename _Function, typename _ClassPtr>
7246 static task<void> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts)
7247 {
7248 return _TaskGenerator::_GenerateTaskNoRet<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts);
7249 }
7250 template<typename _Function, typename _ClassPtr>
7251 static task<task<void>> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet)
7252 {
7253 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _pRet);
7254 }
7255 #endif
7256 };
7257
7258 template<typename _Function>
7259 struct _AsyncLambdaTypeTraits
7260 {
7261 typedef typename _Unhat<typename _CAFunctorOptions<_Function>::_ReturnType>::_Value _ReturnType;
7262 typedef typename _FunctorTypeTraits<_Function>::_Argument1Type _Argument1Type;
7263 typedef typename _CAFunctorOptions<_Function>::_ProgressType _ProgressType;
7264
7265 static const bool _TakesProgress = _CAFunctorOptions<_Function>::_TakesProgress;
7266 static const bool _TakesToken = _CAFunctorOptions<_Function>::_TakesToken;
7267
7268 typedef typename _TaskTypeTraits<_ReturnType> _TaskTraits;
7269 typedef typename _AsyncAttributes<_Function, _ProgressType, typename _TaskTraits::_TaskRetType, _TaskTraits, _TakesToken, _TakesProgress> _AsyncAttributes;
7270 };
7271 // ***************************************************************************
7272 // AsyncInfo (and completion) Layer:
7273 //
7274 #ifndef RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoBase_DEFINED
7275 #define RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoBase_DEFINED
7276 extern const __declspec(selectany) WCHAR RuntimeClass_Concurrency_winrt_details__AsyncInfoBase[] = L"Concurrency_winrt.details._AsyncInfoBase";
7277 #endif
7278
7279 //
7280 // Internal base class implementation for async operations (based on internal Windows representation for ABI level async operations)
7281 //
7282 template < typename _Attributes, _AsyncResultType resultType = SingleResult >
7283 class _AsyncInfoBase abstract : public Microsoft::WRL::RuntimeClass<
7284 Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRt>, Microsoft::WRL::Implements<typename _Attributes::_AsyncBaseType, ABI::Windows::Foundation::IAsyncInfo>>
7285 {
7286 InspectableClass(RuntimeClass_Concurrency_winrt_details__AsyncInfoBase, BaseTrust)
7287 public:
7288 _AsyncInfoBase() :
7289 _M_currentStatus(_AsyncStatusInternal::_AsyncCreated),
7290 _M_errorCode(S_OK),
7291 _M_completeDelegate(nullptr),
7292 _M_CompleteDelegateAssigned(0),
7293 _M_CallbackMade(0)
7294 {
7295 #if _MSC_VER < 1800
7296 _M_id = Concurrency::details::_GetNextAsyncId();
7297 #else
7298 _M_id = Concurrency::details::platform::GetNextAsyncId();
7299 #endif
7300 }
7301 public:
7302 virtual STDMETHODIMP GetResults(typename _Attributes::_ReturnType_abi* results)
7303 {
7304 (void)results;
7305 return E_UNEXPECTED;
7306 }
7307
7308 virtual STDMETHODIMP get_Id(unsigned int* id)
7309 {
7310 HRESULT hr = _CheckValidStateForAsyncInfoCall();
7311 if (FAILED(hr)) return hr;
7312 if (!id) return E_POINTER;
7313 *id = _M_id;
7314 return S_OK;
7315 }
7316
7317 virtual STDMETHODIMP put_Id(unsigned int id)
7318 {
7319 HRESULT hr = _CheckValidStateForAsyncInfoCall();
7320 if (FAILED(hr)) return hr;
7321
7322 if (id == 0)
7323 {
7324 return E_INVALIDARG;
7325 }
7326 else if (_M_currentStatus != _AsyncStatusInternal::_AsyncCreated)
7327 {
7328 return E_ILLEGAL_METHOD_CALL;
7329 }
7330
7331 _M_id = id;
7332 return S_OK;
7333 }
7334 virtual STDMETHODIMP get_Status(ABI::Windows::Foundation::AsyncStatus* status)
7335 {
7336 HRESULT hr = _CheckValidStateForAsyncInfoCall();
7337 if (FAILED(hr)) return hr;
7338 if (!status) return E_POINTER;
7339
7340 _AsyncStatusInternal _Current = _M_currentStatus;
7341 //
7342 // Map our internal cancel pending to cancelled. This way "pending cancelled" looks to the outside as "cancelled" but
7343 // can still transition to "completed" if the operation completes without acknowledging the cancellation request
7344 //
7345 switch (_Current)
7346 {
7347 case _AsyncCancelPending:
7348 _Current = _AsyncCanceled;
7349 break;
7350 case _AsyncCreated:
7351 _Current = _AsyncStarted;
7352 break;
7353 default:
7354 break;
7355 }
7356
7357 *status = static_cast<ABI::Windows::Foundation::AsyncStatus>(_Current);
7358 return S_OK;
7359 }
7360
7361 virtual STDMETHODIMP get_ErrorCode(HRESULT* errorCode)
7362 {
7363 HRESULT hr = _CheckValidStateForAsyncInfoCall();
7364 if (FAILED(hr)) return hr;
7365 if (!hr) return hr;
7366 *errorCode = _M_errorCode;
7367 return S_OK;
7368 }
7369
7370 virtual STDMETHODIMP get_Progress(typename _Attributes::_ProgressDelegateType** _ProgressHandler)
7371 {
7372 return _GetOnProgress(_ProgressHandler);
7373 }
7374
7375 virtual STDMETHODIMP put_Progress(typename _Attributes::_ProgressDelegateType* _ProgressHandler)
7376 {
7377 return _PutOnProgress(_ProgressHandler);
7378 }
7379
7380 virtual STDMETHODIMP Cancel()
7381 {
7382 if (_TransitionToState(_AsyncCancelPending))
7383 {
7384 _OnCancel();
7385 }
7386 return S_OK;
7387 }
7388
7389 virtual STDMETHODIMP Close()
7390 {
7391 if (_TransitionToState(_AsyncClosed))
7392 {
7393 _OnClose();
7394 }
7395 else
7396 {
7397 if (_M_currentStatus != _AsyncClosed) // Closed => Closed transition is just ignored
7398 {
7399 return E_ILLEGAL_STATE_CHANGE;
7400 }
7401 }
7402 return S_OK;
7403 }
7404
7405 virtual STDMETHODIMP get_Completed(typename _Attributes::_CompletionDelegateType** _CompleteHandler)
7406 {
7407 _CheckValidStateForDelegateCall();
7408 if (!_CompleteHandler) return E_POINTER;
7409 *_CompleteHandler = _M_completeDelegate.Get();
7410 return S_OK;
7411 }
7412
7413 virtual STDMETHODIMP put_Completed(typename _Attributes::_CompletionDelegateType* _CompleteHandler)
7414 {
7415 _CheckValidStateForDelegateCall();
7416 // this delegate property is "write once"
7417 if (InterlockedIncrement(&_M_CompleteDelegateAssigned) == 1)
7418 {
7419 _M_completeDelegateContext = _ContextCallback::_CaptureCurrent();
7420 _M_completeDelegate = _CompleteHandler;
7421 // Guarantee that the write of _M_completeDelegate is ordered with respect to the read of state below
7422 // as perceived from _FireCompletion on another thread.
7423 MemoryBarrier();
7424 if (_IsTerminalState())
7425 {
7426 _FireCompletion();
7427 }
7428 }
7429 else
7430 {
7431 return E_ILLEGAL_DELEGATE_ASSIGNMENT;
7432 }
7433 return S_OK;
7434 }
7435
7436 protected:
7437 // _Start - this is not externally visible since async operations "hot start" before returning to the caller
7438 STDMETHODIMP _Start()
7439 {
7440 if (_TransitionToState(_AsyncStarted))
7441 {
7442 _OnStart();
7443 }
7444 else
7445 {
7446 return E_ILLEGAL_STATE_CHANGE;
7447 }
7448 return S_OK;
7449 }
7450
7451 HRESULT _FireCompletion()
7452 {
7453 HRESULT hr = S_OK;
7454 _TryTransitionToCompleted();
7455
7456 // we guarantee that completion can only ever be fired once
7457 if (_M_completeDelegate != nullptr && InterlockedIncrement(&_M_CallbackMade) == 1)
7458 {
7459 hr = _M_completeDelegateContext._CallInContext([=]() -> HRESULT {
7460 ABI::Windows::Foundation::AsyncStatus status;
7461 HRESULT hr;
7462 if (SUCCEEDED(hr = this->get_Status(&status)))
7463 _M_completeDelegate->Invoke((_Attributes::_AsyncBaseType*)this, status);
7464 _M_completeDelegate = nullptr;
7465 return hr;
7466 });
7467 }
7468 return hr;
7469 }
7470
7471 virtual STDMETHODIMP _GetOnProgress(typename _Attributes::_ProgressDelegateType** _ProgressHandler)
7472 {
7473 (void)_ProgressHandler;
7474 return E_UNEXPECTED;
7475 }
7476
7477 virtual STDMETHODIMP _PutOnProgress(typename _Attributes::_ProgressDelegateType* _ProgressHandler)
7478 {
7479 (void)_ProgressHandler;
7480 return E_UNEXPECTED;
7481 }
7482
7483
7484 bool _TryTransitionToCompleted()
7485 {
7486 return _TransitionToState(_AsyncStatusInternal::_AsyncCompleted);
7487 }
7488
7489 bool _TryTransitionToCancelled()
7490 {
7491 return _TransitionToState(_AsyncStatusInternal::_AsyncCanceled);
7492 }
7493
7494 bool _TryTransitionToError(const HRESULT error)
7495 {
7496 _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_errorCode), error, S_OK);
7497 return _TransitionToState(_AsyncStatusInternal::_AsyncError);
7498 }
7499
7500 // This method checks to see if the delegate properties can be
7501 // modified in the current state and generates the appropriate
7502 // error hr in the case of violation.
7503 inline HRESULT _CheckValidStateForDelegateCall()
7504 {
7505 if (_M_currentStatus == _AsyncClosed)
7506 {
7507 return E_ILLEGAL_METHOD_CALL;
7508 }
7509 return S_OK;
7510 }
7511
7512 // This method checks to see if results can be collected in the
7513 // current state and generates the appropriate error hr in
7514 // the case of a violation.
7515 inline HRESULT _CheckValidStateForResultsCall()
7516 {
7517 _AsyncStatusInternal _Current = _M_currentStatus;
7518
7519 if (_Current == _AsyncError)
7520 {
7521 return _M_errorCode;
7522 }
7523 #pragma warning(push)
7524 #pragma warning(disable: 4127) // Conditional expression is constant
7525 // single result illegal before transition to Completed or Cancelled state
7526 if (resultType == SingleResult)
7527 #pragma warning(pop)
7528 {
7529 if (_Current != _AsyncCompleted)
7530 {
7531 return E_ILLEGAL_METHOD_CALL;
7532 }
7533 }
7534 // multiple results can be called after Start has been called and before/after Completed
7535 else if (_Current != _AsyncStarted &&
7536 _Current != _AsyncCancelPending &&
7537 _Current != _AsyncCanceled &&
7538 _Current != _AsyncCompleted)
7539 {
7540 return E_ILLEGAL_METHOD_CALL;
7541 }
7542 return S_OK;
7543 }
7544
7545 // This method can be called by derived classes periodically to determine
7546 // whether the asynchronous operation should continue processing or should
7547 // be halted.
7548 inline bool _ContinueAsyncOperation()
7549 {
7550 return _M_currentStatus == _AsyncStarted;
7551 }
7552
7553 // These two methods are used to allow the async worker implementation do work on
7554 // state transitions. No real "work" should be done in these methods. In other words
7555 // they should not block for a long time on UI timescales.
7556 virtual void _OnStart() = 0;
7557 virtual void _OnClose() = 0;
7558 virtual void _OnCancel() = 0;
7559
7560 private:
7561
7562 // This method is used to check if calls to the AsyncInfo properties
7563 // (id, status, errorcode) are legal in the current state. It also
7564 // generates the appropriate error hr to return in the case of an
7565 // illegal call.
7566 inline HRESULT _CheckValidStateForAsyncInfoCall()
7567 {
7568 _AsyncStatusInternal _Current = _M_currentStatus;
7569 if (_Current == _AsyncClosed)
7570 {
7571 return E_ILLEGAL_METHOD_CALL;
7572 }
7573 else if (_Current == _AsyncCreated)
7574 {
7575 return E_ASYNC_OPERATION_NOT_STARTED;
7576 }
7577 return S_OK;
7578 }
7579
7580 inline bool _TransitionToState(const _AsyncStatusInternal _NewState)
7581 {
7582 _AsyncStatusInternal _Current = _M_currentStatus;
7583
7584 // This enforces the valid state transitions of the asynchronous worker object
7585 // state machine.
7586 switch (_NewState)
7587 {
7588 case _AsyncStatusInternal::_AsyncStarted:
7589 if (_Current != _AsyncCreated)
7590 {
7591 return false;
7592 }
7593 break;
7594 case _AsyncStatusInternal::_AsyncCompleted:
7595 if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
7596 {
7597 return false;
7598 }
7599 break;
7600 case _AsyncStatusInternal::_AsyncCancelPending:
7601 if (_Current != _AsyncStarted)
7602 {
7603 return false;
7604 }
7605 break;
7606 case _AsyncStatusInternal::_AsyncCanceled:
7607 if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
7608 {
7609 return false;
7610 }
7611 break;
7612 case _AsyncStatusInternal::_AsyncError:
7613 if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
7614 {
7615 return false;
7616 }
7617 break;
7618 case _AsyncStatusInternal::_AsyncClosed:
7619 if (!_IsTerminalState(_Current))
7620 {
7621 return false;
7622 }
7623 break;
7624 default:
7625 return false;
7626 break;
7627 }
7628
7629 // attempt the transition to the new state
7630 // Note: if currentStatus_ == _Current, then there was no intervening write
7631 // by the async work object and the swap succeeded.
7632 _AsyncStatusInternal _RetState = static_cast<_AsyncStatusInternal>(
7633 _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_currentStatus),
7634 _NewState,
7635 static_cast<LONG>(_Current)));
7636
7637 // ICE returns the former state, if the returned state and the
7638 // state we captured at the beginning of this method are the same,
7639 // the swap succeeded.
7640 return (_RetState == _Current);
7641 }
7642
7643 inline bool _IsTerminalState()
7644 {
7645 return _IsTerminalState(_M_currentStatus);
7646 }
7647
7648 inline bool _IsTerminalState(_AsyncStatusInternal status)
7649 {
7650 return (status == _AsyncError ||
7651 status == _AsyncCanceled ||
7652 status == _AsyncCompleted ||
7653 status == _AsyncClosed);
7654 }
7655
7656 private:
7657
7658 _ContextCallback _M_completeDelegateContext;
7659 Microsoft::WRL::ComPtr<typename _Attributes::_CompletionDelegateType> _M_completeDelegate; //ComPtr cannot be volatile as it does not have volatile accessors
7660 _AsyncStatusInternal volatile _M_currentStatus;
7661 HRESULT volatile _M_errorCode;
7662 unsigned int _M_id;
7663 long volatile _M_CompleteDelegateAssigned;
7664 long volatile _M_CallbackMade;
7665 };
7666
7667 // ***************************************************************************
7668 // Progress Layer (optional):
7669 //
7670
7671 template< typename _Attributes, bool _HasProgress, _AsyncResultType _ResultType = SingleResult >
7672 class _AsyncProgressBase abstract : public _AsyncInfoBase<_Attributes, _ResultType>
7673 {
7674 };
7675
7676 template< typename _Attributes, _AsyncResultType _ResultType>
7677 class _AsyncProgressBase<_Attributes, true, _ResultType> abstract : public _AsyncInfoBase<_Attributes, _ResultType>
7678 {
7679 public:
7680
7681 _AsyncProgressBase() : _AsyncInfoBase<_Attributes, _ResultType>(),
7682 _M_progressDelegate(nullptr)
7683 {
7684 }
7685
7686 virtual STDMETHODIMP _GetOnProgress(typename _Attributes::_ProgressDelegateType** _ProgressHandler) override
7687 {
7688 HRESULT hr = _CheckValidStateForDelegateCall();
7689 if (FAILED(hr)) return hr;
7690 *_ProgressHandler = _M_progressDelegate;
7691 return S_OK;
7692 }
7693
7694 virtual STDMETHODIMP _PutOnProgress(typename _Attributes::_ProgressDelegateType* _ProgressHandler) override
7695 {
7696 HRESULT hr = _CheckValidStateForDelegateCall();
7697 if (FAILED(hr)) return hr;
7698 _M_progressDelegate = _ProgressHandler;
7699 _M_progressDelegateContext = _ContextCallback::_CaptureCurrent();
7700 return S_OK;
7701 }
7702
7703 public:
7704
7705 void _FireProgress(const typename _Attributes::_ProgressType_abi& _ProgressValue)
7706 {
7707 if (_M_progressDelegate != nullptr)
7708 {
7709 _M_progressDelegateContext._CallInContext([=]() -> HRESULT {
7710 _M_progressDelegate->Invoke((_Attributes::_AsyncBaseType*)this, _ProgressValue);
7711 return S_OK;
7712 });
7713 }
7714 }
7715
7716 private:
7717
7718 _ContextCallback _M_progressDelegateContext;
7719 typename _Attributes::_ProgressDelegateType* _M_progressDelegate;
7720 };
7721
7722 template<typename _Attributes, _AsyncResultType _ResultType = SingleResult>
7723 class _AsyncBaseProgressLayer abstract : public _AsyncProgressBase<_Attributes, _Attributes::_TakesProgress, _ResultType>
7724 {
7725 };
7726
7727 // ***************************************************************************
7728 // Task Adaptation Layer:
7729 //
7730
7731 //
7732 // _AsyncTaskThunkBase provides a bridge between IAsync<Action/Operation> and task.
7733 //
7734 template<typename _Attributes, typename _ReturnType>
7735 class _AsyncTaskThunkBase abstract : public _AsyncBaseProgressLayer<_Attributes>
7736 {
7737 public:
7738
7739 //AsyncAction*
7740 virtual STDMETHODIMP GetResults()
7741 {
7742 HRESULT hr = _CheckValidStateForResultsCall();
7743 if (FAILED(hr)) return hr;
7744 _M_task.get();
7745 return S_OK;
7746 }
7747 public:
7748 typedef task<_ReturnType> _TaskType;
7749
7750 _AsyncTaskThunkBase(const _TaskType& _Task)
7751 : _M_task(_Task)
7752 {
7753 }
7754
7755 _AsyncTaskThunkBase()
7756 {
7757 }
7758 #if _MSC_VER < 1800
7759 void _SetTaskCreationAddressHint(void* _SourceAddressHint)
7760 {
7761 if (!(std::is_same<_Attributes::_AsyncKind, _TypeSelectorAsyncTask>::value))
7762 {
7763 // Overwrite the creation address with the return address of create_async unless the
7764 // lambda returned a task. If the create async lambda returns a task, that task is reused and
7765 // we want to preserve its creation address hint.
7766 _M_task._SetTaskCreationAddressHint(_SourceAddressHint);
7767 }
7768 }
7769 #endif
7770 protected:
7771 virtual void _OnStart() override
7772 {
7773 _M_task.then([=](_TaskType _Antecedent) -> HRESULT {
7774 try
7775 {
7776 _Antecedent.get();
7777 }
7778 catch (Concurrency::task_canceled&)
7779 {
7780 _TryTransitionToCancelled();
7781 }
7782 catch (IRestrictedErrorInfo*& _Ex)
7783 {
7784 HRESULT hr;
7785 HRESULT _hr;
7786 hr = _Ex->GetErrorDetails(NULL, &_hr, NULL, NULL);
7787 if (SUCCEEDED(hr)) hr = _hr;
7788 _TryTransitionToError(hr);
7789 }
7790 catch (...)
7791 {
7792 _TryTransitionToError(E_FAIL);
7793 }
7794 return _FireCompletion();
7795 });
7796 }
7797
7798 protected:
7799 _TaskType _M_task;
7800 Concurrency::cancellation_token_source _M_cts;
7801 };
7802
7803 template<typename _Attributes, typename _ReturnType, typename _Return>
7804 class _AsyncTaskReturn abstract : public _AsyncTaskThunkBase<_Attributes, _Return>
7805 {
7806 public:
7807 //AsyncOperation*
7808 virtual STDMETHODIMP GetResults(_ReturnType* results)
7809 {
7810 HRESULT hr = _CheckValidStateForResultsCall();
7811 if (FAILED(hr)) return hr;
7812 _M_task.get();
7813 *results = _M_results;
7814 return S_OK;
7815 }
7816 template <typename _Function>
7817 #if _MSC_VER >= 1800
7818 void DoCreateTask(_Function _func, const _TaskCreationCallstack & _callstack)
7819 {
7820 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results, _callstack);
7821 }
7822 #else
7823 void DoCreateTask(_Function _func)
7824 {
7825 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results);
7826 }
7827 #endif
7828 protected:
7829 _ReturnType _M_results;
7830 };
7831
7832 template<typename _Attributes, typename _ReturnType>
7833 class _AsyncTaskReturn<_Attributes, _ReturnType, void> abstract : public _AsyncTaskThunkBase<_Attributes, void>
7834 {
7835 public:
7836 template <typename _Function>
7837 #if _MSC_VER >= 1800
7838 void DoCreateTask(_Function _func, const _TaskCreationCallstack & _callstack)
7839 {
7840 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, _callstack);
7841 }
7842 #else
7843 void DoCreateTask(_Function _func)
7844 {
7845 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts);
7846 }
7847 #endif
7848 };
7849
7850 template<typename _Attributes>
7851 class _AsyncTaskReturn<_Attributes, void, task<void>> abstract : public _AsyncTaskThunkBase<_Attributes, task<void>>
7852 {
7853 public:
7854 template <typename _Function>
7855 #if _MSC_VER >= 1800
7856 void DoCreateTask(_Function _func, const _TaskCreationCallstack & _callstack)
7857 {
7858 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results, _callstack);
7859 }
7860 #else
7861 void DoCreateTask(_Function _func)
7862 {
7863 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results);
7864 }
7865 #endif
7866 protected:
7867 task<void> _M_results;
7868 };
7869
7870 template<typename _Attributes>
7871 class _AsyncTaskThunk : public _AsyncTaskReturn<_Attributes, typename _Attributes::_ReturnType_abi, typename _Attributes::_ReturnType>
7872 {
7873 public:
7874
7875 _AsyncTaskThunk(const _TaskType& _Task) :
7876 _AsyncTaskThunkBase(_Task)
7877 {
7878 }
7879
7880 _AsyncTaskThunk()
7881 {
7882 }
7883
7884 protected:
7885
7886 virtual void _OnClose() override
7887 {
7888 }
7889
7890 virtual void _OnCancel() override
7891 {
7892 _M_cts.cancel();
7893 }
7894 };
7895
7896 // ***************************************************************************
7897 // Async Creation Layer:
7898 //
7899 template<typename _Function>
7900 class _AsyncTaskGeneratorThunk : public _AsyncTaskThunk<typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes>
7901 {
7902 public:
7903
7904 typedef typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes _Attributes;
7905 typedef typename _AsyncTaskThunk<_Attributes> _Base;
7906 typedef typename _Attributes::_AsyncBaseType _AsyncBaseType;
7907
7908 #if _MSC_VER >= 1800
7909 _AsyncTaskGeneratorThunk(const _Function& _Func, const _TaskCreationCallstack &_callstack) : _M_func(_Func), _M_creationCallstack(_callstack)
7910 #else
7911 _AsyncTaskGeneratorThunk(const _Function& _Func) : _M_func(_Func)
7912 #endif
7913 {
7914 // Virtual call here is safe as the class is declared 'sealed'
7915 _Start();
7916 }
7917
7918 protected:
7919
7920 //
7921 // The only thing we must do different from the base class is we must spin the hot task on transition from Created->Started. Otherwise,
7922 // let the base thunk handle everything.
7923 //
7924
7925 virtual void _OnStart() override
7926 {
7927 //
7928 // Call the appropriate task generator to actually produce a task of the expected type. This might adapt the user lambda for progress reports,
7929 // wrap the return result in a task, or allow for direct return of a task depending on the form of the lambda.
7930 //
7931 #if _MSC_VER >= 1800
7932 DoCreateTask<_Function>(_M_func, _M_creationCallstack);
7933 #else
7934 DoCreateTask<_Function>(_M_func);
7935 #endif
7936 _Base::_OnStart();
7937 }
7938
7939 virtual void _OnCancel() override
7940 {
7941 _Base::_OnCancel();
7942 }
7943
7944 private:
7945 #if _MSC_VER >= 1800
7946 _TaskCreationCallstack _M_creationCallstack;
7947 #endif
7948 _Function _M_func;
7949 };
7950 } // namespace details
7951
7952 /// <summary>
7953 /// Creates a Windows Runtime asynchronous construct based on a user supplied lambda or function object. The return type of <c>create_async</c> is
7954 /// one of either <c>IAsyncAction^</c>, <c>IAsyncActionWithProgress<TProgress>^</c>, <c>IAsyncOperation<TResult>^</c>, or
7955 /// <c>IAsyncOperationWithProgress<TResult, TProgress>^</c> based on the signature of the lambda passed to the method.
7956 /// </summary>
7957 /// <param name="_Func">
7958 /// The lambda or function object from which to create a Windows Runtime asynchronous construct.
7959 /// </param>
7960 /// <returns>
7961 /// An asynchronous construct represented by an IAsyncAction^, IAsyncActionWithProgress<TProgress>^, IAsyncOperation<TResult>^, or an
7962 /// IAsyncOperationWithProgress<TResult, TProgress>^. The interface returned depends on the signature of the lambda passed into the function.
7963 /// </returns>
7964 /// <remarks>
7965 /// The return type of the lambda determines whether the construct is an action or an operation.
7966 /// <para>Lambdas that return void cause the creation of actions. Lambdas that return a result of type <c>TResult</c> cause the creation of
7967 /// operations of TResult.</para>
7968 /// <para>The lambda may also return a <c>task<TResult></c> which encapsulates the aysnchronous work within itself or is the continuation of
7969 /// 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
7970 /// execute asynchronously, and the return type of the lambda is unwrapped to produce the asynchronous construct returned by <c>create_async</c>.
7971 /// 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
7972 /// cause the creation of operations of TResult.</para>
7973 /// <para>The lambda may take either zero, one or two arguments. The valid arguments are <c>progress_reporter<TProgress></c> and
7974 /// <c>cancellation_token</c>, in that order if both are used. A lambda without arguments causes the creation of an asynchronous construct without
7975 /// the capability for progress reporting. A lambda that takes a progress_reporter<TProgress> will cause <c>create_async</c> to return an asynchronous
7976 /// construct which reports progress of type TProgress each time the <c>report</c> method of the progress_reporter object is called. A lambda that
7977 /// 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
7978 /// asynchronous construct causes cancellation of those tasks.</para>
7979 /// <para>If the body of the lambda or function object returns a result (and not a task<TResult>), the lamdba will be executed
7980 /// asynchronously within the process MTA in the context of a task the Runtime implicitly creates for it. The <c>IAsyncInfo::Cancel</c> method will
7981 /// cause cancellation of the implicit task.</para>
7982 /// <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
7983 /// <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.
7984 /// 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
7985 /// the async operation or action produced..</para>
7986 /// <para>This function is only available to Windows Store apps.</para>
7987 /// </remarks>
7988 /// <seealso cref="task Class"/>
7989 /// <seealso cref="progress_reporter Class"/>
7990 /// <seealso cref="cancelation_token Class"/>
7991 /**/
7992 template<typename _ReturnType, typename _Function>
7993 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
7994 details::_AsyncTaskGeneratorThunk<_Function>* create_async(const _Function& _Func)
7995 {
7996 static_assert(std::is_same<decltype(details::_IsValidCreateAsync<_ReturnType>(_Func, 0, 0, 0, 0, 0, 0, 0, 0)), std::true_type>::value,
7997 "argument to create_async must be a callable object taking zero, one, two or three arguments");
7998 #if _MSC_VER >= 1800
7999 Microsoft::WRL::ComPtr<details::_AsyncTaskGeneratorThunk<_Function>> _AsyncInfo = Microsoft::WRL::Make<details::_AsyncTaskGeneratorThunk<_Function>>(_Func, _CAPTURE_CALLSTACK());
8000 #else
8001 Microsoft::WRL::ComPtr<details::_AsyncTaskGeneratorThunk<_Function>> _AsyncInfo = Microsoft::WRL::Make<details::_AsyncTaskGeneratorThunk<_Function>>(_Func);
8002 _AsyncInfo->_SetTaskCreationAddressHint(_ReturnAddress());
8003 #endif
8004 return _AsyncInfo.Detach();
8005 }
8006
8007 namespace details
8008 {
8009 #if _MSC_VER < 1800
8010 // Internal API which retrieves the next async id.
8011 _CRTIMP2 unsigned int __cdecl _GetNextAsyncId();
8012 #endif
8013 // Helper struct for when_all operators to know when tasks have completed
8014 template<typename _Type>
8015 struct _RunAllParam
8016 {
8017 _RunAllParam() : _M_completeCount(0), _M_numTasks(0)
8018 {
8019 }
8020
8021 void _Resize(size_t _Len, bool _SkipVector = false)
8022 {
8023 _M_numTasks = _Len;
8024 if (!_SkipVector)
8025 #if _MSC_VER >= 1800
8026 {
8027 _M_vector._Result.resize(_Len);
8028 }
8029 #else
8030 _M_vector.resize(_Len);
8031 _M_contexts.resize(_Len);
8032 #endif
8033 }
8034
8035 task_completion_event<_Unit_type> _M_completed;
8036 atomic_size_t _M_completeCount;
8037 #if _MSC_VER >= 1800
8038 _ResultHolder<std::vector<_Type> > _M_vector;
8039 _ResultHolder<_Type> _M_mergeVal;
8040 #else
8041 std::vector<_Type> _M_vector;
8042 std::vector<_ContextCallback> _M_contexts;
8043 _Type _M_mergeVal;
8044 #endif
8045 size_t _M_numTasks;
8046 };
8047
8048 #if _MSC_VER >= 1800
8049 template<typename _Type>
8050 struct _RunAllParam<std::vector<_Type> >
8051 {
8052 _RunAllParam() : _M_completeCount(0), _M_numTasks(0)
8053 {
8054 }
8055
8056 void _Resize(size_t _Len, bool _SkipVector = false)
8057 {
8058 _M_numTasks = _Len;
8059
8060 if (!_SkipVector)
8061 {
8062 _M_vector.resize(_Len);
8063 }
8064 }
8065
8066 task_completion_event<_Unit_type> _M_completed;
8067 std::vector<_ResultHolder<std::vector<_Type> > > _M_vector;
8068 atomic_size_t _M_completeCount;
8069 size_t _M_numTasks;
8070 };
8071 #endif
8072
8073 // Helper struct specialization for void
8074 template<>
8075 #if _MSC_VER >= 1800
8076 struct _RunAllParam<_Unit_type>
8077 #else
8078 struct _RunAllParam<void>
8079 #endif
8080 {
8081 _RunAllParam() : _M_completeCount(0), _M_numTasks(0)
8082 {
8083 }
8084
8085 void _Resize(size_t _Len)
8086 {
8087 _M_numTasks = _Len;
8088 }
8089
8090 task_completion_event<_Unit_type> _M_completed;
8091 atomic_size_t _M_completeCount;
8092 size_t _M_numTasks;
8093 };
8094
8095 inline void _JoinAllTokens_Add(const Concurrency::cancellation_token_source& _MergedSrc, Concurrency::details::_CancellationTokenState *_PJoinedTokenState)
8096 {
8097 if (_PJoinedTokenState != nullptr && _PJoinedTokenState != Concurrency::details::_CancellationTokenState::_None())
8098 {
8099 Concurrency::cancellation_token _T = Concurrency::cancellation_token::_FromImpl(_PJoinedTokenState);
8100 _T.register_callback([=](){
8101 _MergedSrc.cancel();
8102 });
8103 }
8104 }
8105
8106 template<typename _ElementType, typename _Function, typename _TaskType>
8107 void _WhenAllContinuationWrapper(_RunAllParam<_ElementType>* _PParam, _Function _Func, task<_TaskType>& _Task)
8108 {
8109 if (_Task._GetImpl()->_IsCompleted())
8110 {
8111 _Func();
8112 #if _MSC_VER >= 1800
8113 if (Concurrency::details::atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
8114 #else
8115 if (_InterlockedIncrementSizeT(&_PParam->_M_completeCount) == _PParam->_M_numTasks)
8116 #endif
8117 {
8118 // Inline execute its direct continuation, the _ReturnTask
8119 _PParam->_M_completed.set(_Unit_type());
8120 // It's safe to delete it since all usage of _PParam in _ReturnTask has been finished.
8121 delete _PParam;
8122 }
8123 }
8124 else
8125 {
8126 _CONCRT_ASSERT(_Task._GetImpl()->_IsCanceled());
8127 if (_Task._GetImpl()->_HasUserException())
8128 {
8129 // _Cancel will return false if the TCE is already canceled with or without exception
8130 _PParam->_M_completed._Cancel(_Task._GetImpl()->_GetExceptionHolder());
8131 }
8132 else
8133 {
8134 _PParam->_M_completed._Cancel();
8135 }
8136 #if _MSC_VER >= 1800
8137 if (Concurrency::details::atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
8138 #else
8139 if (_InterlockedIncrementSizeT(&_PParam->_M_completeCount) == _PParam->_M_numTasks)
8140 #endif
8141 {
8142 delete _PParam;
8143 }
8144 }
8145 }
8146
8147 template<typename _ElementType, typename _Iterator>
8148 struct _WhenAllImpl
8149 {
8150 #if _MSC_VER >= 1800
8151 static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
8152 #else
8153 static task<std::vector<_ElementType>> _Perform(Concurrency::details::_CancellationTokenState *_PTokenState, _Iterator _Begin, _Iterator _End)
8154 #endif
8155 {
8156 #if _MSC_VER >= 1800
8157 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
8158 #endif
8159 auto _PParam = new _RunAllParam<_ElementType>();
8160 Concurrency::cancellation_token_source _MergedSource;
8161
8162 // Step1: Create task completion event.
8163 #if _MSC_VER >= 1800
8164 task_options _Options(_TaskOptions);
8165 _Options.set_cancellation_token(_MergedSource.get_token());
8166 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);
8167 #else
8168 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token());
8169 #endif
8170 // The return task must be created before step 3 to enforce inline execution.
8171 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type, std::vector<_ElementType>* retVal) -> HRESULT {
8172 #if _MSC_VER >= 1800
8173 * retVal = _PParam->_M_vector.Get();
8174 #else
8175 auto _Result = _PParam->_M_vector; // copy by value
8176
8177 size_t _Index = 0;
8178 for (auto _It = _Result.begin(); _It != _Result.end(); ++_It)
8179 {
8180 *_It = _ResultContext<_ElementType>::_GetValue(*_It, _PParam->_M_contexts[_Index++], false);
8181 }
8182 *retVal = _Result;
8183 #endif
8184 return S_OK;
8185 #if _MSC_VER >= 1800
8186 }, nullptr);
8187 #else
8188 }, nullptr, true);
8189 #endif
8190 // Step2: Combine and check tokens, and count elements in range.
8191 if (_PTokenState)
8192 {
8193 details::_JoinAllTokens_Add(_MergedSource, _PTokenState);
8194 _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));
8195 }
8196 else
8197 {
8198 size_t _TaskNum = 0;
8199 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
8200 {
8201 _TaskNum++;
8202 details::_JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);
8203 }
8204 _PParam->_Resize(_TaskNum);
8205 }
8206
8207 // Step3: Check states of previous tasks.
8208 if (_Begin == _End)
8209 {
8210 _PParam->_M_completed.set(_Unit_type());
8211 delete _PParam;
8212 }
8213 else
8214 {
8215 size_t _Index = 0;
8216 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
8217 {
8218 if (_PTask->is_apartment_aware())
8219 {
8220 _ReturnTask._SetAsync();
8221 }
8222
8223 _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) -> HRESULT {
8224
8225 #if _MSC_VER >= 1800
8226 // Dev10 compiler bug
8227 typedef _ElementType _ElementTypeDev10;
8228 auto _PParamCopy = _PParam;
8229 auto _IndexCopy = _Index;
8230 auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask](){
8231 _PParamCopy->_M_vector._Result[_IndexCopy] = _ResultTask._GetImpl()->_GetResult();
8232 };
8233 #else
8234 auto _Func = [_PParam, _Index, &_ResultTask](){
8235 _PParam->_M_vector[_Index] = _ResultTask._GetImpl()->_GetResult();
8236 _PParam->_M_contexts[_Index] = _ResultContext<_ElementType>::_GetContext(false);
8237 };
8238 #endif
8239 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
8240 return S_OK;
8241 #if _MSC_VER >= 1800
8242 }, Concurrency::details::_CancellationTokenState::_None());
8243 #else
8244 }, Concurrency::details::_CancellationTokenState::_None(), false);
8245 #endif
8246
8247 _Index++;
8248 }
8249 }
8250
8251 return _ReturnTask;
8252 }
8253 };
8254
8255 template<typename _ElementType, typename _Iterator>
8256 struct _WhenAllImpl<std::vector<_ElementType>, _Iterator>
8257 {
8258 #if _MSC_VER >= 1800
8259 static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
8260 #else
8261 static task<std::vector<_ElementType>> _Perform(Concurrency::details::_CancellationTokenState *_PTokenState, _Iterator _Begin, _Iterator _End)
8262 #endif
8263 {
8264 #if _MSC_VER >= 1800
8265 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
8266 #endif
8267 auto _PParam = new _RunAllParam<std::vector<_ElementType>>();
8268 Concurrency::cancellation_token_source _MergedSource;
8269
8270 // Step1: Create task completion event.
8271 #if _MSC_VER >= 1800
8272 task_options _Options(_TaskOptions);
8273 _Options.set_cancellation_token(_MergedSource.get_token());
8274 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);
8275 #else
8276 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token());
8277 #endif
8278 // The return task must be created before step 3 to enforce inline execution.
8279 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type, std::vector<_ElementType>* retVal) -> HRESULT {
8280 _CONCRT_ASSERT(_PParam->_M_completeCount == _PParam->_M_numTasks);
8281 std::vector<_ElementType> _Result;
8282 for (size_t _I = 0; _I < _PParam->_M_numTasks; _I++)
8283 {
8284 #if _MSC_VER >= 1800
8285 const std::vector<_ElementType>& _Vec = _PParam->_M_vector[_I].Get();
8286 #else
8287 std::vector<_ElementType>& _Vec = _PParam->_M_vector[_I];
8288
8289 for (auto _It = _Vec.begin(); _It != _Vec.end(); ++_It)
8290 {
8291 *_It = _ResultContext<_ElementType>::_GetValue(*_It, _PParam->_M_contexts[_I], false);
8292 }
8293 #endif
8294 _Result.insert(_Result.end(), _Vec.begin(), _Vec.end());
8295 }
8296 *retVal = _Result;
8297 return S_OK;
8298 #if _MSC_VER >= 1800
8299 }, nullptr);
8300 #else
8301 }, nullptr, true);
8302 #endif
8303
8304 // Step2: Combine and check tokens, and count elements in range.
8305 if (_PTokenState)
8306 {
8307 details::_JoinAllTokens_Add(_MergedSource, _PTokenState);
8308 _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));
8309 }
8310 else
8311 {
8312 size_t _TaskNum = 0;
8313 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
8314 {
8315 _TaskNum++;
8316 details::_JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);
8317 }
8318 _PParam->_Resize(_TaskNum);
8319 }
8320
8321 // Step3: Check states of previous tasks.
8322 if (_Begin == _End)
8323 {
8324 _PParam->_M_completed.set(_Unit_type());
8325 delete _PParam;
8326 }
8327 else
8328 {
8329 size_t _Index = 0;
8330 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
8331 {
8332 if (_PTask->is_apartment_aware())
8333 {
8334 _ReturnTask._SetAsync();
8335 }
8336
8337 _PTask->_Then([_PParam, _Index](task<std::vector<_ElementType>> _ResultTask) -> HRESULT {
8338 #if _MSC_VER >= 1800
8339 // Dev10 compiler bug
8340 typedef _ElementType _ElementTypeDev10;
8341 auto _PParamCopy = _PParam;
8342 auto _IndexCopy = _Index;
8343 auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask]() {
8344 _PParamCopy->_M_vector[_IndexCopy].Set(_ResultTask._GetImpl()->_GetResult());
8345 };
8346 #else
8347 auto _Func = [_PParam, _Index, &_ResultTask]() {
8348 _PParam->_M_vector[_Index] = _ResultTask._GetImpl()->_GetResult();
8349 _PParam->_M_contexts[_Index] = _ResultContext<_ElementType>::_GetContext(false);
8350 };
8351 #endif
8352 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
8353 return S_OK;
8354 #if _MSC_VER >= 1800
8355 }, Concurrency::details::_CancellationTokenState::_None());
8356 #else
8357 }, Concurrency::details::_CancellationTokenState::_None(), false);
8358 #endif
8359
8360 _Index++;
8361 }
8362 }
8363
8364 return _ReturnTask;
8365 }
8366 };
8367
8368 template<typename _Iterator>
8369 struct _WhenAllImpl<void, _Iterator>
8370 {
8371 #if _MSC_VER >= 1800
8372 static task<void> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
8373 #else
8374 static task<void> _Perform(Concurrency::details::_CancellationTokenState *_PTokenState, _Iterator _Begin, _Iterator _End)
8375 #endif
8376 {
8377 #if _MSC_VER >= 1800
8378 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
8379 #endif
8380 auto _PParam = new _RunAllParam<_Unit_type>();
8381 Concurrency::cancellation_token_source _MergedSource;
8382
8383 // Step1: Create task completion event.
8384 #if _MSC_VER >= 1800
8385 task_options _Options(_TaskOptions);
8386 _Options.set_cancellation_token(_MergedSource.get_token());
8387 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);
8388 #else
8389 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token());
8390 #endif
8391 // The return task must be created before step 3 to enforce inline execution.
8392 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> HRESULT { return S_OK;
8393 #if _MSC_VER >= 1800
8394 }, nullptr);
8395 #else
8396 }, nullptr, false);
8397 #endif
8398
8399 // Step2: Combine and check tokens, and count elements in range.
8400 if (_PTokenState)
8401 {
8402 details::_JoinAllTokens_Add(_MergedSource, _PTokenState);
8403 _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));
8404 }
8405 else
8406 {
8407 size_t _TaskNum = 0;
8408 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
8409 {
8410 _TaskNum++;
8411 details::_JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);
8412 }
8413 _PParam->_Resize(_TaskNum);
8414 }
8415
8416 // Step3: Check states of previous tasks.
8417 if (_Begin == _End)
8418 {
8419 _PParam->_M_completed.set(_Unit_type());
8420 delete _PParam;
8421 }
8422 else
8423 {
8424 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
8425 {
8426 if (_PTask->is_apartment_aware())
8427 {
8428 _ReturnTask._SetAsync();
8429 }
8430
8431 _PTask->_Then([_PParam](task<void> _ResultTask) -> HRESULT {
8432
8433 auto _Func = []() -> HRESULT { return S_OK; };
8434 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
8435 return S_OK;
8436 #if _MSC_VER >= 1800
8437 }, Concurrency::details::_CancellationTokenState::_None());
8438 #else
8439 }, Concurrency::details::_CancellationTokenState::_None(), false);
8440 #endif
8441 }
8442 }
8443
8444 return _ReturnTask;
8445 }
8446 };
8447
8448 template<typename _ReturnType>
8449 task<std::vector<_ReturnType>> _WhenAllVectorAndValue(const task<std::vector<_ReturnType>>& _VectorTask, const task<_ReturnType>& _ValueTask,
8450 bool _OutputVectorFirst)
8451 {
8452 auto _PParam = new _RunAllParam<_ReturnType>();
8453 Concurrency::cancellation_token_source _MergedSource;
8454
8455 // Step1: Create task completion event.
8456 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token());
8457 // The return task must be created before step 3 to enforce inline execution.
8458 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type, std::vector<_ReturnType>* retVal) -> HRESULT {
8459 _CONCRT_ASSERT(_PParam->_M_completeCount == 2);
8460 #if _MSC_VER >= 1800
8461 auto _Result = _PParam->_M_vector.Get(); // copy by value
8462 auto _mergeVal = _PParam->_M_mergeVal.Get();
8463 #else
8464 auto _Result = _PParam->_M_vector; // copy by value
8465 for (auto _It = _Result.begin(); _It != _Result.end(); ++_It)
8466 {
8467 *_It = _ResultContext<_ReturnType>::_GetValue(*_It, _PParam->_M_contexts[0], false);
8468 }
8469 #endif
8470
8471 if (_OutputVectorFirst == true)
8472 {
8473 #if _MSC_VER >= 1800
8474 _Result.push_back(_mergeVal);
8475 #else
8476 _Result.push_back(_ResultContext<_ReturnType>::_GetValue(_PParam->_M_mergeVal, _PParam->_M_contexts[1], false));
8477 #endif
8478 }
8479 else
8480 {
8481 #if _MSC_VER >= 1800
8482 _Result.insert(_Result.begin(), _mergeVal);
8483 #else
8484 _Result.insert(_Result.begin(), _ResultContext<_ReturnType>::_GetValue(_PParam->_M_mergeVal, _PParam->_M_contexts[1], false));
8485 #endif
8486 }
8487 *retVal = _Result;
8488 return S_OK;
8489 }, nullptr, true);
8490
8491 // Step2: Combine and check tokens.
8492 _JoinAllTokens_Add(_MergedSource, _VectorTask._GetImpl()->_M_pTokenState);
8493 _JoinAllTokens_Add(_MergedSource, _ValueTask._GetImpl()->_M_pTokenState);
8494
8495 // Step3: Check states of previous tasks.
8496 _PParam->_Resize(2, true);
8497
8498 if (_VectorTask.is_apartment_aware() || _ValueTask.is_apartment_aware())
8499 {
8500 _ReturnTask._SetAsync();
8501 }
8502 _VectorTask._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) -> HRESULT {
8503 #if _MSC_VER >= 1800
8504 // Dev10 compiler bug
8505 typedef _ReturnType _ReturnTypeDev10;
8506 auto _PParamCopy = _PParam;
8507 auto _Func = [_PParamCopy, &_ResultTask]() {
8508 auto _ResultLocal = _ResultTask._GetImpl()->_GetResult();
8509 _PParamCopy->_M_vector.Set(_ResultLocal);
8510 };
8511 #else
8512 auto _Func = [_PParam, &_ResultTask]() {
8513 _PParam->_M_vector = _ResultTask._GetImpl()->_GetResult();
8514 _PParam->_M_contexts[0] = _ResultContext<_ReturnType>::_GetContext(false);
8515 };
8516 #endif
8517
8518 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
8519 return S_OK;
8520 #if _MSC_VER >= 1800
8521 }, _CancellationTokenState::_None());
8522 #else
8523 }, _CancellationTokenState::_None(), false);
8524 #endif
8525 _ValueTask._Then([_PParam](task<_ReturnType> _ResultTask) -> HRESULT {
8526 #if _MSC_VER >= 1800
8527 // Dev10 compiler bug
8528 typedef _ReturnType _ReturnTypeDev10;
8529 auto _PParamCopy = _PParam;
8530 auto _Func = [_PParamCopy, &_ResultTask]() {
8531 auto _ResultLocal = _ResultTask._GetImpl()->_GetResult();
8532 _PParamCopy->_M_mergeVal.Set(_ResultLocal);
8533 };
8534 #else
8535 auto _Func = [_PParam, &_ResultTask]() {
8536 _PParam->_M_mergeVal = _ResultTask._GetImpl()->_GetResult();
8537 _PParam->_M_contexts[1] = _ResultContext<_ReturnType>::_GetContext(false);
8538 };
8539 #endif
8540 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
8541 return S_OK;
8542 #if _MSC_VER >= 1800
8543 }, _CancellationTokenState::_None());
8544 #else
8545 }, _CancellationTokenState::_None(), false);
8546 #endif
8547
8548 return _ReturnTask;
8549 }
8550 } // namespace details
8551
8552 #if _MSC_VER < 1800
8553 /// <summary>
8554 /// Creates a task that will complete successfully when all of the tasks supplied as arguments complete successfully.
8555 /// </summary>
8556 /// <typeparam name="_Iterator">
8557 /// The type of the input iterator.
8558 /// </typeparam>
8559 /// <param name="_Begin">
8560 /// The position of the first element in the range of elements to be combined into the resulting task.
8561 /// </param>
8562 /// <param name="_End">
8563 /// The position of the first element beyond the range of elements to be combined into the resulting task.
8564 /// </param>
8565 /// <returns>
8566 /// A task that completes sucessfully when all of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
8567 /// 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
8568 /// task will also be a <c>task<void></c>.
8569 /// </returns>
8570 /// <remarks>
8571 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
8572 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
8573 /// </remarks>
8574 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
8575 /**/
8576 template <typename _Iterator>
8577 auto when_all(_Iterator _Begin, _Iterator _End)
8578 -> decltype (details::_WhenAllImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(nullptr, _Begin, _End))
8579 {
8580 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
8581 return details::_WhenAllImpl<_ElementType, _Iterator>::_Perform(nullptr, _Begin, _End);
8582 }
8583 #endif
8584
8585 /// <summary>
8586 /// Creates a task that will complete successfully when all of the tasks supplied as arguments complete successfully.
8587 /// </summary>
8588 /// <typeparam name="_Iterator">
8589 /// The type of the input iterator.
8590 /// </typeparam>
8591 /// <param name="_Begin">
8592 /// The position of the first element in the range of elements to be combined into the resulting task.
8593 /// </param>
8594 /// <param name="_End">
8595 /// The position of the first element beyond the range of elements to be combined into the resulting task.
8596 /// </param>
8597 /// <param name="_CancellationToken">
8598 /// The cancellation token which controls cancellation of the returned task. If you do not provide a cancellation token, the resulting
8599 /// task will be created with a token that is a combination of all the cancelable tokens (tokens created by methods other than
8600 /// <c>cancellation_token::none()</c>of the tasks supplied.
8601 /// </param>
8602 /// <returns>
8603 /// A task that completes sucessfully when all of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
8604 /// 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
8605 /// task will also be a <c>task<void></c>.
8606 /// </returns>
8607 /// <remarks>
8608 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
8609 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
8610 /// </remarks>
8611 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
8612 /**/
8613 template <typename _Iterator>
8614 #if _MSC_VER >= 1800
8615 auto when_all(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options())
8616 -> decltype (details::_WhenAllImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End))
8617 {
8618 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
8619 return details::_WhenAllImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End);
8620 }
8621 #else
8622 auto when_all(_Iterator _Begin, _Iterator _End, Concurrency::cancellation_token _CancellationToken)
8623 -> decltype (details::_WhenAllImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End))
8624 {
8625 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
8626 return details::_WhenAllImpl<_ElementType, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End);
8627 }
8628 #endif
8629
8630 /// <summary>
8631 /// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully.
8632 /// </summary>
8633 /// <typeparam name="_ReturnType">
8634 /// The type of the returned task.
8635 /// </typeparam>
8636 /// <param name="_Lhs">
8637 /// The first task to combine into the resulting task.
8638 /// </param>
8639 /// <param name="_Rhs">
8640 /// The second task to combine into the resulting task.
8641 /// </param>
8642 /// <returns>
8643 /// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
8644 /// 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
8645 /// task will also be a <c>task<void></c>.
8646 /// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator
8647 /// 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>
8648 /// </returns>
8649 /// <remarks>
8650 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
8651 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
8652 /// </remarks>
8653 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
8654 /**/
8655 template<typename _ReturnType>
8656 task<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs)
8657 {
8658 task<_ReturnType> _PTasks[2] = { _Lhs, _Rhs };
8659 return when_all(_PTasks, _PTasks + 2);
8660 }
8661
8662 /// <summary>
8663 /// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully.
8664 /// </summary>
8665 /// <typeparam name="_ReturnType">
8666 /// The type of the returned task.
8667 /// </typeparam>
8668 /// <param name="_Lhs">
8669 /// The first task to combine into the resulting task.
8670 /// </param>
8671 /// <param name="_Rhs">
8672 /// The second task to combine into the resulting task.
8673 /// </param>
8674 /// <returns>
8675 /// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
8676 /// 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
8677 /// task will also be a <c>task<void></c>.
8678 /// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator
8679 /// 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>
8680 /// </returns>
8681 /// <remarks>
8682 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
8683 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
8684 /// </remarks>
8685 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
8686 /**/
8687 template<typename _ReturnType>
8688 task<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs)
8689 {
8690 return details::_WhenAllVectorAndValue(_Lhs, _Rhs, true);
8691 }
8692
8693 /// <summary>
8694 /// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully.
8695 /// </summary>
8696 /// <typeparam name="_ReturnType">
8697 /// The type of the returned task.
8698 /// </typeparam>
8699 /// <param name="_Lhs">
8700 /// The first task to combine into the resulting task.
8701 /// </param>
8702 /// <param name="_Rhs">
8703 /// The second task to combine into the resulting task.
8704 /// </param>
8705 /// <returns>
8706 /// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
8707 /// 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
8708 /// task will also be a <c>task<void></c>.
8709 /// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator
8710 /// 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>
8711 /// </returns>
8712 /// <remarks>
8713 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
8714 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
8715 /// </remarks>
8716 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
8717 /**/
8718 template<typename _ReturnType>
8719 task<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)
8720 {
8721 return details::_WhenAllVectorAndValue(_Rhs, _Lhs, false);
8722 }
8723
8724 /// <summary>
8725 /// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully.
8726 /// </summary>
8727 /// <typeparam name="_ReturnType">
8728 /// The type of the returned task.
8729 /// </typeparam>
8730 /// <param name="_Lhs">
8731 /// The first task to combine into the resulting task.
8732 /// </param>
8733 /// <param name="_Rhs">
8734 /// The second task to combine into the resulting task.
8735 /// </param>
8736 /// <returns>
8737 /// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
8738 /// 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
8739 /// task will also be a <c>task<void></c>.
8740 /// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator
8741 /// 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>
8742 /// </returns>
8743 /// <remarks>
8744 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
8745 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
8746 /// </remarks>
8747 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
8748 /**/
8749 template<typename _ReturnType>
8750 task<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)
8751 {
8752 task<std::vector<_ReturnType>> _PTasks[2] = { _Lhs, _Rhs };
8753 return when_all(_PTasks, _PTasks + 2);
8754 }
8755
8756 /// <summary>
8757 /// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully.
8758 /// </summary>
8759 /// <typeparam name="_ReturnType">
8760 /// The type of the returned task.
8761 /// </typeparam>
8762 /// <param name="_Lhs">
8763 /// The first task to combine into the resulting task.
8764 /// </param>
8765 /// <param name="_Rhs">
8766 /// The second task to combine into the resulting task.
8767 /// </param>
8768 /// <returns>
8769 /// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>,
8770 /// 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
8771 /// task will also be a <c>task<void></c>.
8772 /// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator
8773 /// 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>
8774 /// </returns>
8775 /// <remarks>
8776 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception,
8777 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task.
8778 /// </remarks>
8779 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
8780 /**/
8781 inline task<void> operator&&(const task<void> & _Lhs, const task<void> & _Rhs)
8782 {
8783 task<void> _PTasks[2] = { _Lhs, _Rhs };
8784 return when_all(_PTasks, _PTasks + 2);
8785 }
8786
8787 namespace details
8788 {
8789 // Helper struct for when_any operators to know when tasks have completed
8790 template <typename _CompletionType>
8791 struct _RunAnyParam
8792 {
8793 _RunAnyParam() : _M_completeCount(0), _M_numTasks(0), _M_exceptionRelatedToken(nullptr), _M_fHasExplicitToken(false)
8794 {
8795 }
8796 ~_RunAnyParam()
8797 {
8798 if (Concurrency::details::_CancellationTokenState::_IsValid(_M_exceptionRelatedToken))
8799 _M_exceptionRelatedToken->_Release();
8800 }
8801 task_completion_event<_CompletionType> _M_Completed;
8802 Concurrency::cancellation_token_source _M_cancellationSource;
8803 Concurrency::details::_CancellationTokenState* _M_exceptionRelatedToken;
8804 atomic_size_t _M_completeCount;
8805 size_t _M_numTasks;
8806 bool _M_fHasExplicitToken;
8807 };
8808
8809 template<typename _CompletionType, typename _Function, typename _TaskType>
8810 void _WhenAnyContinuationWrapper(_RunAnyParam<_CompletionType> * _PParam, const _Function & _Func, task<_TaskType>& _Task)
8811 {
8812 bool _IsTokenCancled = !_PParam->_M_fHasExplicitToken && _Task._GetImpl()->_M_pTokenState != Concurrency::details::_CancellationTokenState::_None() && _Task._GetImpl()->_M_pTokenState->_IsCanceled();
8813 if (_Task._GetImpl()->_IsCompleted() && !_IsTokenCancled)
8814 {
8815 _Func();
8816 #if _MSC_VER >= 1800
8817 if (Concurrency::details::atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
8818 #else
8819 if (_InterlockedIncrementSizeT(&_PParam->_M_completeCount) == _PParam->_M_numTasks)
8820 #endif
8821 {
8822 delete _PParam;
8823 }
8824 }
8825 else
8826 {
8827 _CONCRT_ASSERT(_Task._GetImpl()->_IsCanceled() || _IsTokenCancled);
8828 if (_Task._GetImpl()->_HasUserException() && !_IsTokenCancled)
8829 {
8830 if (_PParam->_M_Completed._StoreException(_Task._GetImpl()->_GetExceptionHolder()))
8831 {
8832 // This can only enter once.
8833 _PParam->_M_exceptionRelatedToken = _Task._GetImpl()->_M_pTokenState;
8834 _CONCRT_ASSERT(_PParam->_M_exceptionRelatedToken);
8835 // Deref token will be done in the _PParam destructor.
8836 if (_PParam->_M_exceptionRelatedToken != Concurrency::details::_CancellationTokenState::_None())
8837 {
8838 _PParam->_M_exceptionRelatedToken->_Reference();
8839 }
8840 }
8841 }
8842
8843 #if _MSC_VER >= 1800
8844 if (Concurrency::details::atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
8845 #else
8846 if (_InterlockedIncrementSizeT(&_PParam->_M_completeCount) == _PParam->_M_numTasks)
8847 #endif
8848 {
8849 // If no one has be completed so far, we need to make some final cancellation decision.
8850 if (!_PParam->_M_Completed._IsTriggered())
8851 {
8852 // If we already explicit token, we can skip the token join part.
8853 if (!_PParam->_M_fHasExplicitToken)
8854 {
8855 if (_PParam->_M_exceptionRelatedToken)
8856 {
8857 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _PParam->_M_exceptionRelatedToken);
8858 }
8859 else
8860 {
8861 // If haven't captured any exception token yet, there was no exception for all those tasks,
8862 // so just pick a random token (current one) for normal cancellation.
8863 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Task._GetImpl()->_M_pTokenState);
8864 }
8865 }
8866 // Do exception cancellation or normal cancellation based on whether it has stored exception.
8867 _PParam->_M_Completed._Cancel();
8868 }
8869 delete _PParam;
8870 }
8871 }
8872 }
8873
8874 template<typename _ElementType, typename _Iterator>
8875 struct _WhenAnyImpl
8876 {
8877 #if _MSC_VER >= 1800
8878 static task<std::pair<_ElementType, size_t>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
8879 #else
8880 static task<std::pair<_ElementType, size_t>> _Perform(Concurrency::details::_CancellationTokenState *_PTokenState, _Iterator _Begin, _Iterator _End)
8881 #endif
8882 {
8883 if (_Begin == _End)
8884 {
8885 throw Concurrency::invalid_operation("when_any(begin, end) cannot be called on an empty container.");
8886 }
8887 #if _MSC_VER >= 1800
8888 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
8889 #endif
8890 auto _PParam = new _RunAnyParam<std::pair<std::pair<_ElementType, size_t>, Concurrency::details::_CancellationTokenState *>>();
8891
8892 if (_PTokenState)
8893 {
8894 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState);
8895 _PParam->_M_fHasExplicitToken = true;
8896 }
8897 #if _MSC_VER >= 1800
8898 task_options _Options(_TaskOptions);
8899 _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token());
8900 task<std::pair<std::pair<_ElementType, size_t>, Concurrency::details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options);
8901 #else
8902 task<std::pair<std::pair<_ElementType, size_t>, Concurrency::details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
8903 _Any_tasks_completed._GetImpl()->_M_fRuntimeAggregate = true;
8904 #endif
8905 // Keep a copy ref to the token source
8906 auto _CancellationSource = _PParam->_M_cancellationSource;
8907
8908 _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End));
8909 size_t index = 0;
8910 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
8911 {
8912 if (_PTask->is_apartment_aware())
8913 {
8914 _Any_tasks_completed._SetAsync();
8915 }
8916
8917 _PTask->_Then([_PParam, index](task<_ElementType> _ResultTask) -> HRESULT {
8918 #if _MSC_VER >= 1800
8919 auto _PParamCopy = _PParam; // Dev10
8920 auto _IndexCopy = index; // Dev10
8921 auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() {
8922 _PParamCopy->_M_Completed.set(std::make_pair(std::make_pair(_ResultTask._GetImpl()->_GetResult(), _IndexCopy), _ResultTask._GetImpl()->_M_pTokenState));
8923 };
8924 #else
8925 auto _Func = [&_ResultTask, _PParam, index]() {
8926 _PParam->_M_Completed.set(std::make_pair(std::make_pair(_ResultTask._GetImpl()->_GetResult(), index), _ResultTask._GetImpl()->_M_pTokenState));
8927 };
8928 #endif
8929 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
8930 return S_OK;
8931 #if _MSC_VER >= 1800
8932 }, Concurrency::details::_CancellationTokenState::_None());
8933 #else
8934 }, Concurrency::details::_CancellationTokenState::_None(), false);
8935 #endif
8936 index++;
8937 }
8938
8939 // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.
8940 return _Any_tasks_completed._Then([=](std::pair<std::pair<_ElementType, size_t>, Concurrency::details::_CancellationTokenState *> _Result, std::pair<_ElementType, size_t>* retVal) -> HRESULT {
8941 _CONCRT_ASSERT(_Result.second);
8942 if (!_PTokenState)
8943 {
8944 details::_JoinAllTokens_Add(_CancellationSource, _Result.second);
8945 }
8946 *retVal = _Result.first;
8947 return S_OK;
8948 #if _MSC_VER >= 1800
8949 }, nullptr);
8950 #else
8951 }, nullptr, true);
8952 #endif
8953 }
8954 };
8955
8956 template<typename _Iterator>
8957 struct _WhenAnyImpl<void, _Iterator>
8958 {
8959 #if _MSC_VER >= 1800
8960 static task<size_t> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
8961 #else
8962 static task<size_t> _Perform(Concurrency::details::_CancellationTokenState *_PTokenState, _Iterator _Begin, _Iterator _End)
8963 #endif
8964 {
8965 if (_Begin == _End)
8966 {
8967 throw Concurrency::invalid_operation("when_any(begin, end) cannot be called on an empty container.");
8968 }
8969 #if _MSC_VER >= 1800
8970 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
8971 #endif
8972 auto _PParam = new _RunAnyParam<std::pair<size_t, Concurrency::details::_CancellationTokenState *>>();
8973
8974 if (_PTokenState)
8975 {
8976 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState);
8977 _PParam->_M_fHasExplicitToken = true;
8978 }
8979
8980 #if _MSC_VER >= 1800
8981 task_options _Options(_TaskOptions);
8982 _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token());
8983 task<std::pair<size_t, _CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options);
8984 #else
8985 task<std::pair<size_t, Concurrency::details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
8986 #endif
8987 // Keep a copy ref to the token source
8988 auto _CancellationSource = _PParam->_M_cancellationSource;
8989
8990 _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End));
8991 size_t index = 0;
8992 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
8993 {
8994 if (_PTask->is_apartment_aware())
8995 {
8996 _Any_tasks_completed._SetAsync();
8997 }
8998
8999 _PTask->_Then([_PParam, index](task<void> _ResultTask) -> HRESULT {
9000 #if _MSC_VER >= 1800
9001 auto _PParamCopy = _PParam; // Dev10
9002 auto _IndexCopy = index; // Dev10
9003 auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() {
9004 _PParamCopy->_M_Completed.set(std::make_pair(_IndexCopy, _ResultTask._GetImpl()->_M_pTokenState));
9005 };
9006 #else
9007 auto _Func = [&_ResultTask, _PParam, index]() {
9008 _PParam->_M_Completed.set(std::make_pair(index, _ResultTask._GetImpl()->_M_pTokenState));
9009 };
9010 #endif
9011 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
9012 return S_OK;
9013 #if _MSC_VER >= 1800
9014 }, Concurrency::details::_CancellationTokenState::_None());
9015 #else
9016 }, Concurrency::details::_CancellationTokenState::_None(), false);
9017 #endif
9018
9019 index++;
9020 }
9021
9022 // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.
9023 return _Any_tasks_completed._Then([=](std::pair<size_t, Concurrency::details::_CancellationTokenState *> _Result, size_t* retVal) -> HRESULT {
9024 _CONCRT_ASSERT(_Result.second);
9025 if (!_PTokenState)
9026 {
9027 details::_JoinAllTokens_Add(_CancellationSource, _Result.second);
9028 }
9029 *retVal = _Result.first;
9030 return S_OK;
9031 #if _MSC_VER >= 1800
9032 }, nullptr);
9033 #else
9034 }, nullptr, false);
9035 #endif
9036 }
9037 };
9038 } // namespace details
9039
9040 /// <summary>
9041 /// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.
9042 /// </summary>
9043 /// <typeparam name="_Iterator">
9044 /// The type of the input iterator.
9045 /// </typeparam>
9046 /// <param name="_Begin">
9047 /// The position of the first element in the range of elements to be combined into the resulting task.
9048 /// </param>
9049 /// <param name="_End">
9050 /// The position of the first element beyond the range of elements to be combined into the resulting task.
9051 /// </param>
9052 /// <returns>
9053 /// 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>,
9054 /// 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
9055 /// 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>
9056 /// the output is a <c>task<size_t></c>, where the result is the index of the completing task.
9057 /// </returns>
9058 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
9059 /**/
9060 template<typename _Iterator>
9061 #if _MSC_VER >= 1800
9062 auto when_any(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options())
9063 -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End))
9064 {
9065 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
9066 return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End);
9067 }
9068 #else
9069 auto when_any(_Iterator _Begin, _Iterator _End)
9070 -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(nullptr, _Begin, _End))
9071 {
9072 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
9073 return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(nullptr, _Begin, _End);
9074 }
9075 #endif
9076
9077 /// <summary>
9078 /// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.
9079 /// </summary>
9080 /// <typeparam name="_Iterator">
9081 /// The type of the input iterator.
9082 /// </typeparam>
9083 /// <param name="_Begin">
9084 /// The position of the first element in the range of elements to be combined into the resulting task.
9085 /// </param>
9086 /// <param name="_End">
9087 /// The position of the first element beyond the range of elements to be combined into the resulting task.
9088 /// </param>
9089 /// <param name="_CancellationToken">
9090 /// The cancellation token which controls cancellation of the returned task. If you do not provide a cancellation token, the resulting
9091 /// task will receive the cancellation token of the task that causes it to complete.
9092 /// </param>
9093 /// <returns>
9094 /// 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>,
9095 /// 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
9096 /// 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>
9097 /// the output is a <c>task<size_t></c>, where the result is the index of the completing task.
9098 /// </returns>
9099 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
9100 /**/
9101 template<typename _Iterator>
9102 auto when_any(_Iterator _Begin, _Iterator _End, Concurrency::cancellation_token _CancellationToken)
9103 -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End))
9104 {
9105 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
9106 return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End);
9107 }
9108
9109 /// <summary>
9110 /// Creates a task that will complete successfully when either of the tasks supplied as arguments completes successfully.
9111 /// </summary>
9112 /// <typeparam name="_ReturnType">
9113 /// The type of the returned task.
9114 /// </typeparam>
9115 /// <param name="_Lhs">
9116 /// The first task to combine into the resulting task.
9117 /// </param>
9118 /// <param name="_Rhs">
9119 /// The second task to combine into the resulting task.
9120 /// </param>
9121 /// <returns>
9122 /// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,
9123 /// 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
9124 /// will also be a <c>task<void></c>.
9125 /// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence
9126 /// 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>
9127 /// and the other one is of type <c>task<T>.</para>
9128 /// </returns>
9129 /// <remarks>
9130 /// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,
9131 /// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.
9132 /// </remarks>
9133 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
9134 /**/
9135 template<typename _ReturnType>
9136 task<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs)
9137 {
9138 #if _MSC_VER >= 1800
9139 auto _PParam = new details::_RunAnyParam<std::pair<_ReturnType, size_t>>();
9140
9141 task<std::pair<_ReturnType, size_t>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
9142 // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
9143 // So that _PParam can be used before it getting deleted.
9144 auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<_ReturnType, size_t> _Ret, _ReturnType* retVal) -> HRESULT {
9145 _CONCRT_ASSERT(_Ret.second);
9146 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, reinterpret_cast<Concurrency::details::_CancellationTokenState *>(_Ret.second));
9147 *retVal = _Ret.first;
9148 return S_OK;
9149 }, nullptr);
9150 #else
9151 auto _PParam = new details::_RunAnyParam<std::pair<_ReturnType, Concurrency::details::_CancellationTokenState *>>();
9152
9153 task<std::pair<_ReturnType, Concurrency::details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
9154 // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
9155 // So that _PParam can be used before it getting deleted.
9156 auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<_ReturnType, Concurrency::details::_CancellationTokenState *> _Ret, _ReturnType* retVal) -> HRESULT {
9157 _CONCRT_ASSERT(_Ret.second);
9158 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second);
9159 *retVal = _Ret.first;
9160 return S_OK;
9161 }, nullptr, false);
9162 #endif
9163 if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())
9164 {
9165 _ReturnTask._SetAsync();
9166 }
9167
9168 _PParam->_M_numTasks = 2;
9169 auto _Continuation = [_PParam](task<_ReturnType> _ResultTask) -> HRESULT {
9170 #if _MSC_VER >= 1800
9171 // Dev10 compiler bug
9172 auto _PParamCopy = _PParam;
9173 auto _Func = [&_ResultTask, _PParamCopy]() {
9174 _PParamCopy->_M_Completed.set(std::make_pair(_ResultTask._GetImpl()->_GetResult(), reinterpret_cast<size_t>(_ResultTask._GetImpl()->_M_pTokenState)));
9175 };
9176 #else
9177 auto _Func = [&_ResultTask, _PParam]() {
9178 _PParam->_M_Completed.set(std::make_pair(_ResultTask._GetImpl()->_GetResult(), _ResultTask._GetImpl()->_M_pTokenState));
9179 };
9180 #endif
9181 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
9182 return S_OK;
9183 };
9184
9185 #if _MSC_VER >= 1800
9186 _Lhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None());
9187 _Rhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None());
9188 #else
9189 _Lhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None(), false);
9190 _Rhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None(), false);
9191 #endif
9192 return _ReturnTask;
9193 }
9194
9195 /// <summary>
9196 /// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.
9197 /// </summary>
9198 /// <typeparam name="_ReturnType">
9199 /// The type of the returned task.
9200 /// </typeparam>
9201 /// <param name="_Lhs">
9202 /// The first task to combine into the resulting task.
9203 /// </param>
9204 /// <param name="_Rhs">
9205 /// The second task to combine into the resulting task.
9206 /// </param>
9207 /// <returns>
9208 /// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,
9209 /// 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
9210 /// will also be a <c>task<void></c>.
9211 /// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence
9212 /// 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>
9213 /// and the other one is of type <c>task<T>.</para>
9214 /// </returns>
9215 /// <remarks>
9216 /// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,
9217 /// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.
9218 /// </remarks>
9219 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
9220 /**/
9221 template<typename _ReturnType>
9222 task<std::vector<_ReturnType>> operator||(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs)
9223 {
9224 auto _PParam = new details::_RunAnyParam<std::pair<std::vector<_ReturnType>, Concurrency::details::_CancellationTokenState *>>();
9225
9226 task<std::pair<std::vector<_ReturnType>, Concurrency::details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
9227 #if _MSC_VER < 1800
9228 _Any_tasks_completed._GetImpl()->_M_fRuntimeAggregate = true;
9229 #endif
9230 // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
9231 // So that _PParam can be used before it getting deleted.
9232 auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<std::vector<_ReturnType>, Concurrency::details::_CancellationTokenState *> _Ret, std::vector<_ReturnType>* retVal) -> HRESULT {
9233 _CONCRT_ASSERT(_Ret.second);
9234 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second);
9235 *retVal = _Ret.first;
9236 return S_OK;
9237 }, nullptr, true);
9238
9239 if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())
9240 {
9241 _ReturnTask._SetAsync();
9242 }
9243
9244 _PParam->_M_numTasks = 2;
9245 _Lhs._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) -> HRESULT {
9246 #if _MSC_VER >= 1800
9247 // Dev10 compiler bug
9248 auto _PParamCopy = _PParam;
9249 auto _Func = [&_ResultTask, _PParamCopy]() {
9250 auto _Result = _ResultTask._GetImpl()->_GetResult();
9251 _PParamCopy->_M_Completed.set(std::make_pair(_Result, _ResultTask._GetImpl()->_M_pTokenState));
9252 };
9253 #else
9254 auto _Func = [&_ResultTask, _PParam]() {
9255 std::vector<_ReturnType> _Result = _ResultTask._GetImpl()->_GetResult();
9256 _PParam->_M_Completed.set(std::make_pair(_Result, _ResultTask._GetImpl()->_M_pTokenState));
9257 };
9258 #endif
9259 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
9260 return S_OK;
9261 #if _MSC_VER >= 1800
9262 }, Concurrency::details::_CancellationTokenState::_None());
9263 #else
9264 }, Concurrency::details::_CancellationTokenState::_None(), false);
9265 #endif
9266 _Rhs._Then([_PParam](task<_ReturnType> _ResultTask) -> HRESULT {
9267 #if _MSC_VER >= 1800
9268 // Dev10 compiler bug
9269 typedef _ReturnType _ReturnTypeDev10;
9270 auto _PParamCopy = _PParam;
9271 auto _Func = [&_ResultTask, _PParamCopy]() {
9272 auto _Result = _ResultTask._GetImpl()->_GetResult();
9273
9274 std::vector<_ReturnTypeDev10> _Vec;
9275 _Vec.push_back(_Result);
9276 _PParamCopy->_M_Completed.set(std::make_pair(_Vec, _ResultTask._GetImpl()->_M_pTokenState));
9277 };
9278 #else
9279 auto _Func = [&_ResultTask, _PParam]() {
9280 _ReturnType _Result = _ResultTask._GetImpl()->_GetResult();
9281
9282 std::vector<_ReturnType> _Vec;
9283 _Vec.push_back(_Result);
9284 _PParam->_M_Completed.set(std::make_pair(_Vec, _ResultTask._GetImpl()->_M_pTokenState));
9285 };
9286 #endif
9287 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
9288 return S_OK;
9289 #if _MSC_VER >= 1800
9290 }, Concurrency::details::_CancellationTokenState::_None());
9291 #else
9292 }, Concurrency::details::_CancellationTokenState::_None(), false);
9293 #endif
9294 return _ReturnTask;
9295 }
9296
9297 /// <summary>
9298 /// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.
9299 /// </summary>
9300 /// <typeparam name="_ReturnType">
9301 /// The type of the returned task.
9302 /// </typeparam>
9303 /// <param name="_Lhs">
9304 /// The first task to combine into the resulting task.
9305 /// </param>
9306 /// <param name="_Rhs">
9307 /// The second task to combine into the resulting task.
9308 /// </param>
9309 /// <returns>
9310 /// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,
9311 /// 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
9312 /// will also be a <c>task<void></c>.
9313 /// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence
9314 /// 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>
9315 /// and the other one is of type <c>task<T>.</para>
9316 /// </returns>
9317 /// <remarks>
9318 /// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,
9319 /// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.
9320 /// </remarks>
9321 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
9322 /**/
9323 template<typename _ReturnType>
9324 task<std::vector<_ReturnType>> operator||(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)
9325 {
9326 return _Rhs || _Lhs;
9327 }
9328
9329 /// <summary>
9330 /// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully.
9331 /// </summary>
9332 /// <typeparam name="_ReturnType">
9333 /// The type of the returned task.
9334 /// </typeparam>
9335 /// <param name="_Lhs">
9336 /// The first task to combine into the resulting task.
9337 /// </param>
9338 /// <param name="_Rhs">
9339 /// The second task to combine into the resulting task.
9340 /// </param>
9341 /// <returns>
9342 /// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>,
9343 /// 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
9344 /// will also be a <c>task<void></c>.
9345 /// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence
9346 /// 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>
9347 /// and the other one is of type <c>task<T>.</para>
9348 /// </returns>
9349 /// <remarks>
9350 /// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions,
9351 /// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task.
9352 /// </remarks>
9353 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/>
9354 /**/
9355 inline task<void> operator||(const task<void> & _Lhs, const task<void> & _Rhs)
9356 {
9357 auto _PParam = new details::_RunAnyParam<std::pair<details::_Unit_type, Concurrency::details::_CancellationTokenState *>>();
9358
9359 task<std::pair<details::_Unit_type, Concurrency::details::_CancellationTokenState *>> _Any_task_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
9360 // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
9361 // So that _PParam can be used before it getting deleted.
9362 auto _ReturnTask = _Any_task_completed._Then([=](std::pair<details::_Unit_type, Concurrency::details::_CancellationTokenState *> _Ret) -> HRESULT {
9363 _CONCRT_ASSERT(_Ret.second);
9364 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second);
9365 return S_OK;
9366 #if _MSC_VER >= 1800
9367 }, nullptr);
9368 #else
9369 }, nullptr, false);
9370 #endif
9371
9372 if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())
9373 {
9374 _ReturnTask._SetAsync();
9375 }
9376
9377 _PParam->_M_numTasks = 2;
9378 auto _Continuation = [_PParam](task<void> _ResultTask) mutable -> HRESULT {
9379 // Dev10 compiler needs this.
9380 auto _PParam1 = _PParam;
9381 auto _Func = [&_ResultTask, _PParam1]() {
9382 _PParam1->_M_Completed.set(std::make_pair(details::_Unit_type(), _ResultTask._GetImpl()->_M_pTokenState));
9383 };
9384 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
9385 return S_OK;
9386 };
9387
9388 #if _MSC_VER >= 1800
9389 _Lhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None());
9390 _Rhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None());
9391 #else
9392 _Lhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None(), false);
9393 _Rhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None(), false);
9394 #endif
9395
9396 return _ReturnTask;
9397 }
9398
9399 #if _MSC_VER >= 1800
9400 template<typename _Ty>
9401 task<_Ty> task_from_result(_Ty _Param, const task_options& _TaskOptions = task_options())
9402 {
9403 task_completion_event<_Ty> _Tce;
9404 _Tce.set(_Param);
9405 return create_task<_Ty>(_Tce, _TaskOptions);
9406 }
9407
9408 // Work around VS 2010 compiler bug
9409 #if _MSC_VER == 1600
9410 inline task<bool> task_from_result(bool _Param)
9411 {
9412 task_completion_event<bool> _Tce;
9413 _Tce.set(_Param);
9414 return create_task<bool>(_Tce, task_options());
9415 }
9416 #endif
9417 inline task<void> task_from_result(const task_options& _TaskOptions = task_options())
9418 {
9419 task_completion_event<void> _Tce;
9420 _Tce.set();
9421 return create_task<void>(_Tce, _TaskOptions);
9422 }
9423
9424 template<typename _TaskType, typename _ExType>
9425 task<_TaskType> task_from_exception(_ExType _Exception, const task_options& _TaskOptions = task_options())
9426 {
9427 task_completion_event<_TaskType> _Tce;
9428 _Tce.set_exception(_Exception);
9429 return create_task<_TaskType>(_Tce, _TaskOptions);
9430 }
9431
9432 namespace details
9433 {
9434 /// <summary>
9435 /// A convenient extension to Concurrency: loop until a condition is no longer met
9436 /// </summary>
9437 /// <param name="func">
9438 /// A function representing the body of the loop. It will be invoked at least once and
9439 /// then repetitively as long as it returns true.
9440 /// </param>
9441 inline
9442 task<bool> do_while(std::function<task<bool>(void)> func)
9443 {
9444 task<bool> first = func();
9445 return first.then([=](bool guard, task<bool>* retVal) -> HRESULT {
9446 if (guard)
9447 *retVal = do_while(func);
9448 else
9449 *retVal = first;
9450 return S_OK;
9451 });
9452 }
9453
9454 } // namespace details
9455 #endif
9456
9457 } // namespace Concurrency_winrt
9458
9459 namespace concurrency_winrt = Concurrency_winrt;
9460
9461 #pragma pop_macro("new")
9462 #pragma warning(pop)
9463 #pragma pack(pop)
9464 #endif
9465
9466 #endif
9467