C++ Rest SDK
The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.
pplxtasks.h
1 /***
2 * ==++==
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * ==--==
17 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
18 *
19 * Parallel Patterns Library - PPLx Tasks
20 *
21 * For the latest on this and related APIs, please see http://casablanca.codeplex.com.
22 *
23 * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
24 ****/
25 
26 #pragma once
27 
28 #ifndef _PPLXTASKS_H
29 #define _PPLXTASKS_H
30 
31 #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX
32 #include <ppltasks.h>
33 namespace pplx = Concurrency;
34 #if (_MSC_VER >= 1900)
35 #include <concrt.h>
36 namespace Concurrency {
37  namespace extensibility {
38  typedef ::std::condition_variable condition_variable_t;
39  typedef ::std::mutex critical_section_t;
40  typedef ::std::unique_lock< ::std::mutex> scoped_critical_section_t;
41 
42  typedef ::Concurrency::event event_t;
43  typedef ::Concurrency::reader_writer_lock reader_writer_lock_t;
44  typedef ::Concurrency::reader_writer_lock::scoped_lock scoped_rw_lock_t;
45  typedef ::Concurrency::reader_writer_lock::scoped_lock_read scoped_read_lock_t;
46 
47  typedef ::Concurrency::details::_ReentrantBlockingLock recursive_lock_t;
48  typedef recursive_lock_t::_Scoped_lock scoped_recursive_lock_t;
49  }
50 }
51 #endif // _MSC_VER >= 1900
52 #else
53 
54 #include "pplx/pplx.h"
55 
56 #if defined(__ANDROID__)
57 #include <jni.h>
58 void cpprest_init(JavaVM*);
59 #endif
60 
61 // Cannot build using a compiler that is older than dev10 SP1
62 #if defined(_MSC_VER)
63 #if _MSC_FULL_VER < 160040219 /*IFSTRIP=IGN*/
64 #error ERROR: Visual Studio 2010 SP1 or later is required to build ppltasks
65 #endif /*IFSTRIP=IGN*/
66 #endif /* defined(_MSC_VER) */
67 
68 #include <functional>
69 #include <vector>
70 #include <utility>
71 #include <exception>
72 #include <algorithm>
73 
74 #if defined(_MSC_VER)
75 #if defined(__cplusplus_winrt)
76 #include <windows.h>
77 #include <ctxtcall.h>
78 #include <agile.h>
79 #include <winapifamily.h>
80 #ifndef _UITHREADCTXT_SUPPORT
81 
82 #ifdef WINAPI_FAMILY /*IFSTRIP=IGN*/
83 
84 // It is safe to include winapifamily as WINAPI_FAMILY was defined by the user
85 #include <winapifamily.h>
86 
87 #if WINAPI_FAMILY == WINAPI_FAMILY_APP
88  // UI thread context support is not required for desktop and Windows Store apps
89  #define _UITHREADCTXT_SUPPORT 0
90 #elif WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
91  // UI thread context support is not required for desktop and Windows Store apps
92  #define _UITHREADCTXT_SUPPORT 0
93 #else /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */
94  #define _UITHREADCTXT_SUPPORT 1
95 #endif /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */
96 
97 #else /* WINAPI_FAMILY */
98  // Not supported without a WINAPI_FAMILY setting.
99  #define _UITHREADCTXT_SUPPORT 0
100 #endif /* WINAPI_FAMILY */
101 
102 #endif /* _UITHREADCTXT_SUPPORT */
103 
104 #if _UITHREADCTXT_SUPPORT
105  #include <uithreadctxt.h>
106 #endif /* _UITHREADCTXT_SUPPORT */
107 
108  #pragma detect_mismatch("_PPLTASKS_WITH_WINRT", "1")
109 #else /* defined(__cplusplus_winrt) */
110  #pragma detect_mismatch("_PPLTASKS_WITH_WINRT", "0")
111 #endif /* defined(__cplusplus_winrt) */
112 #endif /* defined(_MSC_VER) */
113 
114 #ifdef _DEBUG
115  #define _DBG_ONLY(X) X
116 #else
117  #define _DBG_ONLY(X)
118 #endif // #ifdef _DEBUG
119 
120 // std::copy_exception changed to std::make_exception_ptr from VS 2010 to VS 11.
121 #ifdef _MSC_VER
122 #if _MSC_VER < 1700 /*IFSTRIP=IGN*/
123 namespace std
124 {
125  template<class _E> exception_ptr make_exception_ptr(_E _Except)
126  {
127  return copy_exception(_Except);
128  }
129 }
130 #endif /* _MSC_VER < 1700 */
131 #ifndef _PPLTASK_ASYNC_LOGGING
132  #if _MSC_VER >= 1800 && defined(__cplusplus_winrt)
133  #define _PPLTASK_ASYNC_LOGGING 1 // Only enable async logging under dev12 winrt
134  #else
135  #define _PPLTASK_ASYNC_LOGGING 0
136  #endif
137 #endif /* !_PPLTASK_ASYNC_LOGGING */
138 #endif /* _MSC_VER */
139 
140 #pragma pack(push,_CRT_PACKING)
141 
142 #if defined(_MSC_VER)
143 #pragma warning(push)
144 #pragma warning(disable: 28197)
145 #pragma warning(disable: 4100) // Unreferenced formal parameter - needed for document generation
146 #pragma warning(disable: 4127) // constant express in if condition - we use it for meta programming
147 #endif /* defined(_MSC_VER) */
148 
149 // All CRT public header files are required to be protected from the macro new
150 #pragma push_macro("new")
151 #undef new
152 
153 // stuff ported from Dev11 CRT
154 // NOTE: this doesn't actually match std::declval. it behaves differently for void!
155 // so don't blindly change it to std::declval.
156 namespace stdx
157 {
158  template<class _T>
159  _T&& declval();
160 }
161 
166 
167 namespace pplx
168 {
173 
175 
176 template <typename _Type> class task;
177 template <> class task<void>;
178 
179 // 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.
180 #ifndef PPL_TASK_SAVE_FRAME_COUNT
181 #ifdef _DEBUG
182 #define PPL_TASK_SAVE_FRAME_COUNT 10
183 #else
184 #define PPL_TASK_SAVE_FRAME_COUNT 1
185 #endif
186 #endif
187 
196 #if PPL_TASK_SAVE_FRAME_COUNT > 1
197 #if defined(__cplusplus_winrt) && !defined(_DEBUG)
198 #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!")
199 #define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())
200 #else
201 #define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureMultiFramesCallstack(PPL_TASK_SAVE_FRAME_COUNT)
202 #endif
203 #else
204 #define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())
205 #endif
206 
207 
229 
230 inline bool _pplx_cdecl is_task_cancellation_requested()
231 {
232  return ::pplx::details::_TaskCollection_t::_Is_cancellation_requested();
233 }
234 
244 
245 inline __declspec(noreturn) void _pplx_cdecl cancel_current_task()
246 {
247  throw task_canceled();
248 }
249 
250 namespace details
251 {
258  {
259  private:
260  // If _M_SingleFrame != nullptr, there will be only one frame of callstacks, which is stored in _M_SingleFrame;
261  // otherwise, _M_Frame will store all the callstack frames.
262  void* _M_SingleFrame;
263  std::vector<void *> _M_frames;
264  public:
266  {
267  _M_SingleFrame = nullptr;
268  }
269 
270  // Store one frame of callstack. This function works for both Debug / Release CRT.
271  static _TaskCreationCallstack _CaptureSingleFrameCallstack(void *_SingleFrame)
272  {
274  _csc._M_SingleFrame = _SingleFrame;
275  return _csc;
276  }
277 
278  // Capture _CaptureFrames number of callstack frames. This function only work properly for Desktop or Debug CRT.
279  __declspec(noinline)
280  static _TaskCreationCallstack _CaptureMultiFramesCallstack(size_t _CaptureFrames)
281  {
283  _csc._M_frames.resize(_CaptureFrames);
284  // skip 2 frames to make sure callstack starts from user code
285  _csc._M_frames.resize(::pplx::details::platform::CaptureCallstack(&_csc._M_frames[0], 2, _CaptureFrames));
286  return _csc;
287  }
288  };
289  typedef unsigned char _Unit_type;
290 
298 
299  template<typename _Ty>
301  {
302  typedef _Ty _Type;
303  };
304 
305  template<>
307  {
308  typedef _Unit_type _Type;
309  };
310 
311  template<typename _T>
313  {
314  static const bool _Value = true;
315  };
316 
317  template<>
319  {
320  static const bool _Value = false;
321  };
322 
323  template <typename _Ty>
325  {
326  typedef _Ty _Type;
327  };
328 
329  template <typename _Ty>
330  struct _UnwrapTaskType<task<_Ty>>
331  {
332  typedef _Ty _Type;
333  };
334 
335  template <typename _T>
336  _TypeSelectorAsyncTask _AsyncOperationKindSelector(task<_T>);
337 
338  _TypeSelectorNoAsync _AsyncOperationKindSelector(...);
339 
340 #if defined(__cplusplus_winrt)
341  template <typename _Type>
342  struct _Unhat
343  {
344  typedef _Type _Value;
345  };
346 
347  template <typename _Type>
348  struct _Unhat<_Type^>
349  {
350  typedef _Type _Value;
351  };
352 
353  value struct _NonUserType { public: int _Dummy; };
354 
355  template <typename _Type, bool _IsValueTypeOrRefType = __is_valid_winrt_type(_Type)>
356  struct _ValueTypeOrRefType
357  {
358  typedef _NonUserType _Value;
359  };
360 
361  template <typename _Type>
362  struct _ValueTypeOrRefType<_Type, true>
363  {
364  typedef _Type _Value;
365  };
366 
367  template <typename _T1, typename _T2>
368  _T2 _ProgressTypeSelector(Windows::Foundation::IAsyncOperationWithProgress<_T1,_T2>^);
369 
370  template <typename _T1>
371  _T1 _ProgressTypeSelector(Windows::Foundation::IAsyncActionWithProgress<_T1>^);
372 
373  template <typename _Type>
374  struct _GetProgressType
375  {
376  typedef decltype(_ProgressTypeSelector(stdx::declval<_Type>())) _Value;
377  };
378 
379  template <typename _Type>
380  struct _IsIAsyncInfo
381  {
382  static const bool _Value = __is_base_of(Windows::Foundation::IAsyncInfo, typename _Unhat<_Type>::_Value);
383  };
384 
385  template <typename _T>
386  _TypeSelectorAsyncOperation _AsyncOperationKindSelector(Windows::Foundation::IAsyncOperation<_T>^);
387 
388  _TypeSelectorAsyncAction _AsyncOperationKindSelector(Windows::Foundation::IAsyncAction^);
389 
390  template <typename _T1, typename _T2>
391  _TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector(Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>^);
392 
393  template <typename _T>
394  _TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector(Windows::Foundation::IAsyncActionWithProgress<_T>^);
395 
396  template <typename _Type, bool _IsAsync = _IsIAsyncInfo<_Type>::_Value>
397  struct _TaskTypeTraits
398  {
399  typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType;
400  typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;
401  typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType;
402 
403  static const bool _IsAsyncTask = _IsAsync;
404  static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value;
405  };
406 
407  template<typename _Type>
408  struct _TaskTypeTraits<_Type, true >
409  {
410  typedef decltype(((_Type)nullptr)->GetResults()) _TaskRetType;
411  typedef _TaskRetType _NormalizedTaskRetType;
412  typedef decltype(_AsyncOperationKindSelector((_Type)nullptr)) _AsyncKind;
413 
414  static const bool _IsAsyncTask = true;
415  static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value;
416  };
417 
418 #else /* defined (__cplusplus_winrt) */
419  template <typename _Type>
421  {
422  static const bool _Value = false;
423  };
424 
425  template <typename _Type, bool _IsAsync = false>
427  {
428  typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType;
429  typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;
430  typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType;
431 
432  static const bool _IsAsyncTask = false;
433  static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value;
434  };
435 #endif /* defined (__cplusplus_winrt) */
436 
437  template <typename _Function> auto _IsCallable(_Function _Func, int) -> decltype(_Func(), std::true_type()) { (void)(_Func); return std::true_type(); }
438  template <typename _Function> std::false_type _IsCallable(_Function, ...) { return std::false_type(); }
439 
440  template <>
441  struct _TaskTypeTraits<void>
442  {
443  typedef void _TaskRetType;
444  typedef _TypeSelectorNoAsync _AsyncKind;
445  typedef _Unit_type _NormalizedTaskRetType;
446 
447  static const bool _IsAsyncTask = false;
448  static const bool _IsUnwrappedTaskOrAsync = false;
449  };
450 
451  template<typename _Type>
452  task<_Type> _To_task(_Type t);
453 
454  template<typename _Func>
455  task<void> _To_task_void(_Func f);
456 
458 
459  template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)));
460  template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, ...) -> decltype(_Func(t));
461  template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, ...) -> _BadContinuationParamType;
462 
463  template <typename _Function, typename _Type> auto _IsTaskHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)), std::true_type());
464  template <typename _Function, typename _Type> std::false_type _IsTaskHelper(_Type t, _Function _Func, int, ...);
465 
466  template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func)));
467  template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, ...) -> decltype(_Func());
468 
469  template <typename _Function> auto _VoidIsTaskHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func)), std::true_type());
470  template <typename _Function> std::false_type _VoidIsTaskHelper(_Function _Func, int, ...);
471 
472  template<typename _Function, typename _ExpectedParameterType>
474  {
475  typedef decltype(_ReturnTypeHelper(stdx::declval<_ExpectedParameterType>(),stdx::declval<_Function>(), 0, 0)) _FuncRetType;
476  static_assert(!std::is_same<_FuncRetType,_BadContinuationParamType>::value, "incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below)");
477 
478  typedef decltype(_IsTaskHelper(stdx::declval<_ExpectedParameterType>(),stdx::declval<_Function>(), 0, 0)) _Takes_task;
479  };
480 
481  template<typename _Function>
482  struct _FunctionTypeTraits<_Function, void>
483  {
484  typedef decltype(_VoidReturnTypeHelper(stdx::declval<_Function>(), 0, 0)) _FuncRetType;
485  typedef decltype(_VoidIsTaskHelper(stdx::declval<_Function>(), 0, 0)) _Takes_task;
486  };
487 
488  template<typename _Function, typename _ReturnType>
490  {
492  };
493 
494  // _InitFunctorTypeTraits is used to decide whether a task constructed with a lambda should be unwrapped. Depending on how the variable is
495  // declared, the constructor may or may not perform unwrapping. For eg.
496  //
497  // This declaration SHOULD NOT cause unwrapping
498  // task<task<void>> t1([]() -> task<void> {
499  // task<void> t2([]() {});
500  // return t2;
501  // });
502  //
503  // This declaration SHOULD cause unwrapping
504  // task<void>> t1([]() -> task<void> {
505  // task<void> t2([]() {});
506  // return t2;
507  // });
508  // 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.
509  template <typename _TaskType, typename _FuncRetType>
511  {
512  typedef typename _TaskTypeTraits<_FuncRetType>::_AsyncKind _AsyncKind;
513  static const bool _IsAsyncTask = _TaskTypeTraits<_FuncRetType>::_IsAsyncTask;
514  static const bool _IsUnwrappedTaskOrAsync = _TaskTypeTraits<_FuncRetType>::_IsUnwrappedTaskOrAsync;
515  };
516 
517  template<typename T>
519  {
520  typedef _TypeSelectorNoAsync _AsyncKind;
521  static const bool _IsAsyncTask = false;
522  static const bool _IsUnwrappedTaskOrAsync = false;
523  };
524 
529  {
530  _TaskProcThunk(const std::function<void ()> & _Callback) :
531  _M_func(_Callback)
532  {
533  }
534 
535  static void _pplx_cdecl _Bridge(void *_PData)
536  {
537  _TaskProcThunk *_PThunk = reinterpret_cast<_TaskProcThunk *>(_PData);
538  _Holder _ThunkHolder(_PThunk);
539  _PThunk->_M_func();
540  }
541  private:
542 
543  // RAII holder
544  struct _Holder
545  {
546  _Holder(_TaskProcThunk * _PThunk) : _M_pThunk(_PThunk)
547  {
548  }
549 
550  ~_Holder()
551  {
552  delete _M_pThunk;
553  }
554 
555  _TaskProcThunk * _M_pThunk;
556 
557  private:
558  _Holder& operator=(const _Holder&);
559  };
560 
561  std::function<void()> _M_func;
562  _TaskProcThunk& operator=(const _TaskProcThunk&);
563  };
564 
576  static void _ScheduleFuncWithAutoInline(const std::function<void ()> & _Func, _TaskInliningMode_t _InliningMode)
577  {
578  _TaskCollection_t::_RunTask(&_TaskProcThunk::_Bridge, new _TaskProcThunk(_Func), _InliningMode);
579  }
580 
582  {
583  typedef std::function<void(void)> _CallbackFunction;
584 
585 #if defined (__cplusplus_winrt)
586 
587  public:
588 
589  static _ContextCallback _CaptureCurrent()
590  {
591  _ContextCallback _Context;
592  _Context._Capture();
593  return _Context;
594  }
595 
597  {
598  _Reset();
599  }
600 
601  _ContextCallback(bool _DeferCapture = false)
602  {
603  if (_DeferCapture)
604  {
605  _M_context._M_captureMethod = _S_captureDeferred;
606  }
607  else
608  {
609  _M_context._M_pContextCallback = nullptr;
610  }
611  }
612 
613  // Resolves a context that was created as _S_captureDeferred based on the environment (ancestor, current context).
614  void _Resolve(bool _CaptureCurrent)
615  {
616  if(_M_context._M_captureMethod == _S_captureDeferred)
617  {
618  _M_context._M_pContextCallback = nullptr;
619 
620  if (_CaptureCurrent)
621  {
622  if (_IsCurrentOriginSTA())
623  {
624  _Capture();
625  }
626 #if _UITHREADCTXT_SUPPORT
627  else
628  {
629  // This method will fail if not called from the UI thread.
630  HRESULT _Hr = CaptureUiThreadContext(&_M_context._M_pContextCallback);
631  if (FAILED(_Hr))
632  {
633  _M_context._M_pContextCallback = nullptr;
634  }
635  }
636 #endif /* _UITHREADCTXT_SUPPORT */
637  }
638  }
639  }
640 
641  void _Capture()
642  {
643  HRESULT _Hr = CoGetObjectContext(IID_IContextCallback, reinterpret_cast<void **>(&_M_context._M_pContextCallback));
644  if (FAILED(_Hr))
645  {
646  _M_context._M_pContextCallback = nullptr;
647  }
648  }
649 
651  {
652  _Assign(_Src._M_context._M_pContextCallback);
653  }
654 
656  {
657  _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;
658  _Src._M_context._M_pContextCallback = nullptr;
659  }
660 
661  _ContextCallback& operator=(const _ContextCallback& _Src)
662  {
663  if (this != &_Src)
664  {
665  _Reset();
666  _Assign(_Src._M_context._M_pContextCallback);
667  }
668  return *this;
669  }
670 
671  _ContextCallback& operator=(_ContextCallback&& _Src)
672  {
673  if (this != &_Src)
674  {
675  _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;
676  _Src._M_context._M_pContextCallback = nullptr;
677  }
678  return *this;
679  }
680 
681  bool _HasCapturedContext() const
682  {
683  _ASSERTE(_M_context._M_captureMethod != _S_captureDeferred);
684  return (_M_context._M_pContextCallback != nullptr);
685  }
686 
687  void _CallInContext(_CallbackFunction _Func) const
688  {
689  if (!_HasCapturedContext())
690  {
691  _Func();
692  }
693  else
694  {
695  ComCallData callData;
696  ZeroMemory(&callData, sizeof(callData));
697  callData.pUserDefined = reinterpret_cast<void *>(&_Func);
698 
699  HRESULT _Hr = _M_context._M_pContextCallback->ContextCallback(&_Bridge, &callData, IID_ICallbackWithNoReentrancyToApplicationSTA, 5, nullptr);
700  if (FAILED(_Hr))
701  {
702  throw ::Platform::Exception::CreateException(_Hr);
703  }
704  }
705  }
706 
707  bool operator==(const _ContextCallback& _Rhs) const
708  {
709  return (_M_context._M_pContextCallback == _Rhs._M_context._M_pContextCallback);
710  }
711 
712  bool operator!=(const _ContextCallback& _Rhs) const
713  {
714  return !(operator==(_Rhs));
715  }
716 
717  private:
718  void _Reset()
719  {
720  if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)
721  {
722  _M_context._M_pContextCallback->Release();
723  }
724  }
725 
726  void _Assign(IContextCallback *_PContextCallback)
727  {
728  _M_context._M_pContextCallback = _PContextCallback;
729  if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)
730  {
731  _M_context._M_pContextCallback->AddRef();
732  }
733  }
734 
735  static HRESULT __stdcall _Bridge(ComCallData *_PParam)
736  {
737  _CallbackFunction *pFunc = reinterpret_cast<_CallbackFunction *>(_PParam->pUserDefined);
738  (*pFunc)();
739  return S_OK;
740  }
741 
742  // Returns the origin information for the caller (runtime / Windows Runtime apartment as far as task continuations need know)
743  static bool _IsCurrentOriginSTA()
744  {
745  APTTYPE _AptType;
746  APTTYPEQUALIFIER _AptTypeQualifier;
747 
748  HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);
749  if (SUCCEEDED(hr))
750  {
751  // We determine the origin of a task continuation by looking at where .then is called, so we can tell whether
752  // to need to marshal the continuation back to the originating apartment. If an STA thread is in executing in
753  // a neutral aparment when it schedules a continuation, we will not marshal continuations back to the STA,
754  // since variables used within a neutral apartment are expected to be apartment neutral.
755  switch(_AptType)
756  {
757  case APTTYPE_MAINSTA:
758  case APTTYPE_STA:
759  return true;
760  default:
761  break;
762  }
763  }
764  return false;
765  }
766 
767  union
768  {
769  IContextCallback *_M_pContextCallback;
770  size_t _M_captureMethod;
771  } _M_context;
772 
773  static const size_t _S_captureDeferred = 1;
774 #else /* defined (__cplusplus_winrt) */
775  public:
776 
777  static _ContextCallback _CaptureCurrent()
778  {
779  return _ContextCallback();
780  }
781 
782  _ContextCallback(bool = false)
783  {
784  }
785 
787  {
788  }
789 
791  {
792  }
793 
794  _ContextCallback& operator=(const _ContextCallback&)
795  {
796  return *this;
797  }
798 
799  _ContextCallback& operator=(_ContextCallback&&)
800  {
801  return *this;
802  }
803 
804  bool _HasCapturedContext() const
805  {
806  return false;
807  }
808 
809  void _Resolve(bool) const
810  {
811  }
812 
813  void _CallInContext(_CallbackFunction _Func) const
814  {
815  _Func();
816  }
817 
818  bool operator==(const _ContextCallback&) const
819  {
820  return true;
821  }
822 
823  bool operator!=(const _ContextCallback&) const
824  {
825  return false;
826  }
827 
828 #endif /* defined (__cplusplus_winrt) */
829  };
830 
831  template<typename _Type>
833  {
834  void Set(const _Type& _type)
835  {
836  _Result = _type;
837  }
838 
839  _Type Get()
840  {
841  return _Result;
842  }
843 
844  _Type _Result;
845  };
846 
847 #if defined (__cplusplus_winrt)
848 
849  template<typename _Type>
850  struct _ResultHolder<_Type^>
851  {
852  void Set(_Type^ const & _type)
853  {
854  _M_Result = _type;
855  }
856 
857  _Type^ Get()
858  {
859  return _M_Result.Get();
860  }
861  private:
862  // ::Platform::Agile handle specialization of all hats
863  // including ::Platform::String and ::Platform::Array
864  ::Platform::Agile<_Type^> _M_Result;
865  };
866 
867  //
868  // The below are for composability with tasks auto-created from when_any / when_all / && / || constructs.
869  //
870  template<typename _Type>
871  struct _ResultHolder<std::vector<_Type^>>
872  {
873  void Set(const std::vector<_Type^>& _type)
874  {
875  _Result.reserve(_type.size());
876 
877  for (auto _PTask = _type.begin(); _PTask != _type.end(); ++_PTask)
878  {
879  _Result.emplace_back(*_PTask);
880  }
881  }
882 
883  std::vector<_Type^> Get()
884  {
885  // Return vectory<T^> with the objects that are marshaled in the proper appartment
886  std::vector<_Type^> _Return;
887  _Return.reserve(_Result.size());
888 
889  for (auto _PTask = _Result.begin(); _PTask != _Result.end(); ++_PTask)
890  {
891  _Return.push_back(_PTask->Get()); // Platform::Agile will marshal the object to appropriate appartment if neccessary
892  }
893 
894  return _Return;
895  }
896 
897  std::vector< ::Platform::Agile<_Type^> > _Result;
898  };
899 
900  template<typename _Type>
901  struct _ResultHolder<std::pair<_Type^, void*> >
902  {
903  void Set(const std::pair<_Type^, size_t>& _type)
904  {
905  _M_Result = _type;
906  }
907 
908  std::pair<_Type^, size_t> Get()
909  {
910  return std::make_pair(_M_Result.first.Get(), _M_Result.second);
911  }
912  private:
913  std::pair< ::Platform::Agile<_Type^>, size_t> _M_Result;
914  };
915 
916 #endif /* defined (__cplusplus_winrt) */
917 
918  // 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.
919  // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception
920  // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.
922  {
923  private:
924  void ReportUnhandledError()
925  {
926 #if _MSC_VER >= 1800 && defined(__cplusplus_winrt)
927  if (_M_winRTException != nullptr)
928  {
929  ::Platform::Details::ReportUnhandledError(_M_winRTException);
930  }
931 #endif /* defined (__cplusplus_winrt) */
932  }
933  public:
934  explicit _ExceptionHolder(const std::exception_ptr& _E, const _TaskCreationCallstack &_stackTrace) :
935  _M_exceptionObserved(0), _M_stdException(_E), _M_stackTrace(_stackTrace)
936 #if defined (__cplusplus_winrt)
937  , _M_winRTException(nullptr)
938 #endif /* defined (__cplusplus_winrt) */
939  {
940  }
941 
942 #if defined (__cplusplus_winrt)
943  explicit _ExceptionHolder(::Platform::Exception^ _E, const _TaskCreationCallstack &_stackTrace) :
944  _M_exceptionObserved(0), _M_winRTException(_E), _M_stackTrace(_stackTrace)
945  {
946  }
947 #endif /* defined (__cplusplus_winrt) */
948 
949  __declspec(noinline)
951  {
952  if (_M_exceptionObserved == 0)
953  {
954  // If you are trapped here, it means an exception thrown in task chain didn't get handled.
955  // Please add task-based continuation to handle all exceptions coming from tasks.
956  // this->_M_stackTrace keeps the creation callstack of the task generates this exception.
957  _REPORT_PPLTASK_UNOBSERVED_EXCEPTION();
958  }
959  }
960 
961  void _RethrowUserException()
962  {
963  if (_M_exceptionObserved == 0)
964  {
965  atomic_exchange(_M_exceptionObserved, 1l);
966  }
967 
968 #if defined (__cplusplus_winrt)
969  if (_M_winRTException != nullptr)
970  {
971  throw _M_winRTException;
972  }
973 #endif /* defined (__cplusplus_winrt) */
974  std::rethrow_exception(_M_stdException);
975  }
976 
977  // A variable that remembers if this exception was every rethrown into user code (and hence handled by the user). Exceptions that
978  // are unobserved when the exception holder is destructed will terminate the process.
979  atomic_long _M_exceptionObserved;
980 
981  // Either _M_stdException or _M_winRTException is populated based on the type of exception encountered.
982  std::exception_ptr _M_stdException;
983 #if defined (__cplusplus_winrt)
984  ::Platform::Exception^ _M_winRTException;
985 #endif /* defined (__cplusplus_winrt) */
986 
987  // Disassembling this value will point to a source instruction right after a call instruction. If the call is to create_task,
988  // a task constructor or the then method, the task created by that method is the one that encountered this exception. If the call
989  // is to task_completion_event::set_exception, the set_exception method was the source of the exception.
990  // DO NOT REMOVE THIS VARIABLE. It is extremely helpful for debugging.
991  _TaskCreationCallstack _M_stackTrace;
992 
993  };
994 
995 #if defined (__cplusplus_winrt)
996  template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Result>
1000  ref struct _AsyncInfoImpl abstract : Windows::Foundation::IAsyncOperation<_Result>
1001  {
1002  internal:
1003  // The async action, action with progress or operation with progress that this stub forwards to.
1004  ::Platform::Agile<_AsyncOperationType> _M_asyncInfo;
1005 
1006  Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ _M_CompletedHandler;
1007 
1008  _AsyncInfoImpl( _AsyncOperationType _AsyncInfo ) : _M_asyncInfo(_AsyncInfo) {}
1009 
1010  public:
1011  virtual void Cancel() { _M_asyncInfo.Get()->Cancel(); }
1012  virtual void Close() { _M_asyncInfo.Get()->Close(); }
1013 
1014  virtual property Windows::Foundation::HResult ErrorCode
1015  {
1016  Windows::Foundation::HResult get()
1017  {
1018  return _M_asyncInfo.Get()->ErrorCode;
1019  }
1020  }
1021 
1022  virtual property UINT Id
1023  {
1024  UINT get()
1025  {
1026  return _M_asyncInfo.Get()->Id;
1027  }
1028  }
1029 
1030  virtual property Windows::Foundation::AsyncStatus Status
1031  {
1032  Windows::Foundation::AsyncStatus get()
1033  {
1034  return _M_asyncInfo.Get()->Status;
1035  }
1036  }
1037 
1038  virtual _Result GetResults() { throw std::runtime_error("derived class must implement"); }
1039 
1040  virtual property Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ Completed
1041  {
1042  Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ get()
1043  {
1044  return _M_CompletedHandler;
1045  }
1046 
1047  void set(Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ value)
1048  {
1049  _M_CompletedHandler = value;
1050  _M_asyncInfo.Get()->Completed = ref new _CompletionHandlerType([&](_AsyncOperationType, Windows::Foundation::AsyncStatus status) {
1051  _M_CompletedHandler->Invoke(this, status);
1052  });
1053  }
1054  }
1055  };
1056 
1060  template<typename _Result, typename _Progress>
1061  ref struct _IAsyncOperationWithProgressToAsyncOperationConverter sealed :
1062  _AsyncInfoImpl<Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^,
1063  Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result,_Progress>,
1064  _Result>
1065  {
1066  internal:
1067  _IAsyncOperationWithProgressToAsyncOperationConverter(Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^ _Operation) :
1068  _AsyncInfoImpl<Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^,
1069  Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result,_Progress>,
1070  _Result>(_Operation) {}
1071 
1072  public:
1073  virtual _Result GetResults() override { return _M_asyncInfo.Get()->GetResults(); }
1074  };
1075 
1079  ref struct _IAsyncActionToAsyncOperationConverter sealed :
1080  _AsyncInfoImpl<Windows::Foundation::IAsyncAction^,
1081  Windows::Foundation::AsyncActionCompletedHandler,
1082  details::_Unit_type>
1083  {
1084  internal:
1085  _IAsyncActionToAsyncOperationConverter(Windows::Foundation::IAsyncAction^ _Operation) :
1086  _AsyncInfoImpl<Windows::Foundation::IAsyncAction^,
1087  Windows::Foundation::AsyncActionCompletedHandler,
1088  details::_Unit_type>(_Operation) {}
1089 
1090  public:
1091  virtual details::_Unit_type GetResults() override
1092  {
1093  // Invoke GetResults on the IAsyncAction to allow exceptions to be thrown to higher layers before returning a dummy value.
1094  _M_asyncInfo.Get()->GetResults();
1095  return details::_Unit_type();
1096  }
1097  };
1098 
1102  template<typename _Progress>
1103  ref struct _IAsyncActionWithProgressToAsyncOperationConverter sealed :
1104  _AsyncInfoImpl<Windows::Foundation::IAsyncActionWithProgress<_Progress>^,
1105  Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>,
1106  details::_Unit_type>
1107  {
1108  internal:
1109  _IAsyncActionWithProgressToAsyncOperationConverter(Windows::Foundation::IAsyncActionWithProgress<_Progress>^ _Action) :
1110  _AsyncInfoImpl<Windows::Foundation::IAsyncActionWithProgress<_Progress>^,
1111  Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>,
1112  details::_Unit_type>(_Action) {}
1113  public:
1114  virtual details::_Unit_type GetResults() override
1115  {
1116  // Invoke GetResults on the IAsyncActionWithProgress to allow exceptions to be thrown before returning a dummy value.
1117  _M_asyncInfo.Get()->GetResults();
1118  return details::_Unit_type();
1119  }
1120  };
1121 #endif /* defined (__cplusplus_winrt) */
1122 } // namespace details
1123 
1130 
1132 {
1133 public:
1134 
1151 
1153  {
1154 #if defined (__cplusplus_winrt)
1155  // The callback context is created with the context set to CaptureDeferred and resolved when it is used in .then()
1156  return task_continuation_context(true); // sets it to deferred, is resolved in the constructor of _ContinuationTaskHandle
1157 #else /* defined (__cplusplus_winrt) */
1158  return task_continuation_context();
1159 #endif /* defined (__cplusplus_winrt) */
1160  }
1161 
1162 #if defined (__cplusplus_winrt)
1163 
1177  static task_continuation_context use_arbitrary()
1178  {
1179  task_continuation_context _Arbitrary(true);
1180  _Arbitrary._Resolve(false);
1181  return _Arbitrary;
1182  }
1183 
1197 
1198  static task_continuation_context use_current()
1199  {
1200  task_continuation_context _Current(true);
1201  _Current._Resolve(true);
1202  return _Current;
1203  }
1204 #endif /* defined (__cplusplus_winrt) */
1205 
1206 private:
1207 
1208  task_continuation_context(bool _DeferCapture = false) : details::_ContextCallback(_DeferCapture)
1209  {
1210  }
1211 };
1212 
1213 class task_options;
1214 namespace details
1215 {
1217  {
1218  bool _M_hasPresetCreationCallstack;
1219  _TaskCreationCallstack _M_presetCreationCallstack;
1220 
1221  void _set_creation_callstack(const _TaskCreationCallstack &_callstack)
1222  {
1223  _M_hasPresetCreationCallstack = true;
1224  _M_presetCreationCallstack = _callstack;
1225  }
1227  {
1228  _M_hasPresetCreationCallstack = false;
1229  }
1230  };
1231 
1232  inline _Internal_task_options &_get_internal_task_options(task_options &options);
1233  inline const _Internal_task_options &_get_internal_task_options(const task_options &options);
1234 }
1239 {
1240 public:
1241 
1242 
1247  : _M_Scheduler(get_ambient_scheduler()),
1248  _M_CancellationToken(cancellation_token::none()),
1249  _M_ContinuationContext(task_continuation_context::use_default()),
1250  _M_HasCancellationToken(false),
1251  _M_HasScheduler(false)
1252  {
1253  }
1254 
1259  : _M_Scheduler(get_ambient_scheduler()),
1260  _M_CancellationToken(_Token),
1261  _M_ContinuationContext(task_continuation_context::use_default()),
1262  _M_HasCancellationToken(true),
1263  _M_HasScheduler(false)
1264  {
1265  }
1266 
1271  : _M_Scheduler(get_ambient_scheduler()),
1272  _M_CancellationToken(cancellation_token::none()),
1273  _M_ContinuationContext(_ContinuationContext),
1274  _M_HasCancellationToken(false),
1275  _M_HasScheduler(false)
1276  {
1277  }
1278 
1283  : _M_Scheduler(get_ambient_scheduler()),
1284  _M_CancellationToken(_Token),
1285  _M_ContinuationContext(_ContinuationContext),
1286  _M_HasCancellationToken(false),
1287  _M_HasScheduler(false)
1288  {
1289  }
1290 
1294  template<typename _SchedType>
1295  task_options(std::shared_ptr<_SchedType> _Scheduler)
1296  : _M_Scheduler(std::move(_Scheduler)),
1297  _M_CancellationToken(cancellation_token::none()),
1298  _M_ContinuationContext(task_continuation_context::use_default()),
1299  _M_HasCancellationToken(false),
1300  _M_HasScheduler(true)
1301  {
1302  }
1303 
1307  task_options(scheduler_interface& _Scheduler)
1308  : _M_Scheduler(&_Scheduler),
1309  _M_CancellationToken(cancellation_token::none()),
1310  _M_ContinuationContext(task_continuation_context::use_default()),
1311  _M_HasCancellationToken(false),
1312  _M_HasScheduler(true)
1313  {
1314  }
1315 
1320  : _M_Scheduler(std::move(_Scheduler)),
1321  _M_CancellationToken(cancellation_token::none()),
1322  _M_ContinuationContext(task_continuation_context::use_default()),
1323  _M_HasCancellationToken(false),
1324  _M_HasScheduler(true)
1325  {
1326  }
1327 
1331  task_options(const task_options& _TaskOptions)
1332  : _M_Scheduler(_TaskOptions.get_scheduler()),
1333  _M_CancellationToken(_TaskOptions.get_cancellation_token()),
1334  _M_ContinuationContext(_TaskOptions.get_continuation_context()),
1335  _M_HasCancellationToken(_TaskOptions.has_cancellation_token()),
1336  _M_HasScheduler(_TaskOptions.has_scheduler())
1337  {
1338  }
1339 
1344  {
1345  _M_CancellationToken = _Token;
1346  _M_HasCancellationToken = true;
1347  }
1348 
1353  {
1354  _M_ContinuationContext = _ContinuationContext;
1355  }
1356 
1361  {
1362  return _M_HasCancellationToken;
1363  }
1364 
1369  {
1370  return _M_CancellationToken;
1371  }
1372 
1377  {
1378  return _M_ContinuationContext;
1379  }
1380 
1384  bool has_scheduler() const
1385  {
1386  return _M_HasScheduler;
1387  }
1388 
1393  {
1394  return _M_Scheduler;
1395  }
1396 
1397 private:
1398 
1399  task_options const& operator=(task_options const& _Right);
1400  friend details::_Internal_task_options &details::_get_internal_task_options(task_options &);
1401  friend const details::_Internal_task_options &details::_get_internal_task_options(const task_options &);
1402 
1403  scheduler_ptr _M_Scheduler;
1404  cancellation_token _M_CancellationToken;
1405  task_continuation_context _M_ContinuationContext;
1406  details::_Internal_task_options _M_InternalTaskOptions;
1407  bool _M_HasCancellationToken;
1408  bool _M_HasScheduler;
1409 };
1410 
1411 namespace details
1412 {
1413  inline _Internal_task_options & _get_internal_task_options(task_options &options)
1414  {
1415  return options._M_InternalTaskOptions;
1416  }
1417  inline const _Internal_task_options & _get_internal_task_options(const task_options &options)
1418  {
1419  return options._M_InternalTaskOptions;
1420  }
1421 
1422  struct _Task_impl_base;
1423  template<typename _ReturnType> struct _Task_impl;
1424 
1425  template<typename _ReturnType>
1426  struct _Task_ptr
1427  {
1428  typedef std::shared_ptr<_Task_impl<_ReturnType>> _Type;
1429  static _Type _Make(_CancellationTokenState * _Ct, scheduler_ptr _Scheduler_arg) { return std::make_shared<_Task_impl<_ReturnType>>(_Ct, _Scheduler_arg); }
1430  };
1431 
1433  typedef std::shared_ptr<_Task_impl_base> _Task_ptr_base;
1434 
1435  // The weak-typed base task handler for continuation tasks.
1436  struct _ContinuationTaskHandleBase : _UnrealizedChore_t
1437  {
1438  _ContinuationTaskHandleBase * _M_next;
1439  task_continuation_context _M_continuationContext;
1440  bool _M_isTaskBasedContinuation;
1441 
1442  // This field gives inlining scheduling policy for current chore.
1443  _TaskInliningMode_t _M_inliningMode;
1444 
1445  virtual _Task_ptr_base _GetTaskImplBase() const = 0;
1446 
1448  _M_next(nullptr), _M_continuationContext(task_continuation_context::use_default()), _M_isTaskBasedContinuation(false), _M_inliningMode(details::_NoInline)
1449  {
1450  }
1451 
1452  virtual ~_ContinuationTaskHandleBase() {}
1453  };
1454 
1455 #if _PPLTASK_ASYNC_LOGGING
1456  // GUID used for identifying causality logs from PPLTask
1457  const ::Platform::Guid _PPLTaskCausalityPlatformID(0x7A76B220, 0xA758, 0x4E6E, 0xB0, 0xE0, 0xD7, 0xC6, 0xD7, 0x4A, 0x88, 0xFE);
1458 
1459  __declspec(selectany) volatile long _isCausalitySupported = 0;
1460 
1461  inline bool _IsCausalitySupported()
1462  {
1463 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
1464  if (_isCausalitySupported == 0)
1465  {
1466  long _causality = 1;
1467  OSVERSIONINFOEX _osvi = {};
1468  _osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
1469 
1470  // The Causality is supported on Windows version higher than Windows 8
1471  _osvi.dwMajorVersion = 6;
1472  _osvi.dwMinorVersion = 3;
1473 
1474  DWORDLONG _conditionMask = 0;
1475  VER_SET_CONDITION( _conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL );
1476  VER_SET_CONDITION( _conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL );
1477 
1478  if ( ::VerifyVersionInfo(&_osvi, VER_MAJORVERSION | VER_MINORVERSION, _conditionMask))
1479  {
1480  _causality = 2;
1481  }
1482 
1483  _isCausalitySupported = _causality;
1484  return _causality == 2;
1485  }
1486 
1487  return _isCausalitySupported == 2 ? true : false;
1488 #else
1489  return true;
1490 #endif
1491  }
1492 
1493  // Stateful logger rests inside task_impl_base.
1494  struct _TaskEventLogger
1495  {
1496  _Task_impl_base *_M_task;
1497  bool _M_scheduled;
1498  bool _M_taskPostEventStarted;
1499 
1500  // Log before scheduling task
1501  void _LogScheduleTask(bool _isContinuation)
1502  {
1503  if (details::_IsCausalitySupported())
1504  {
1505  ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCreation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1506  _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task),
1507  _isContinuation ? "pplx::PPLTask::ScheduleContinuationTask" : "pplx::PPLTask::ScheduleTask", 0);
1508  _M_scheduled = true;
1509  }
1510  }
1511 
1512  // It will log the cancel event but not canceled state. _LogTaskCompleted will log the terminal state, which includes cancel state.
1513  void _LogCancelTask()
1514  {
1515  if (details::_IsCausalitySupported())
1516  {
1517  ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationRelation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Important, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1518  _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalityRelation::Cancel);
1519 
1520  }
1521  }
1522 
1523  // Log when task reaches terminal state. Note: the task can reach a terminal state (by cancellation or exception) without having run
1524  void _LogTaskCompleted();
1525 
1526  // Log when task body (which includes user lambda and other scheduling code) begin to run
1527  void _LogTaskExecutionStarted() { }
1528 
1529  // Log when task body finish executing
1530  void _LogTaskExecutionCompleted()
1531  {
1532  if (_M_taskPostEventStarted && details::_IsCausalitySupported())
1533  {
1534  ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1535  ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification);
1536  }
1537  }
1538 
1539  // Log right before user lambda being invoked
1540  void _LogWorkItemStarted()
1541  {
1542  if (details::_IsCausalitySupported())
1543  {
1544  ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1545  _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution);
1546  }
1547  }
1548 
1549  // Log right after user lambda being invoked
1550  void _LogWorkItemCompleted()
1551  {
1552  if (details::_IsCausalitySupported())
1553  {
1554  ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1555  ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution);
1556 
1557  ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1558  _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification);
1559  _M_taskPostEventStarted = true;
1560  }
1561  }
1562 
1563  _TaskEventLogger(_Task_impl_base *_task): _M_task(_task)
1564  {
1565  _M_scheduled = false;
1566  _M_taskPostEventStarted = false;
1567  }
1568  };
1569 
1570  // Exception safe logger for user lambda
1571  struct _TaskWorkItemRAIILogger
1572  {
1573  _TaskEventLogger &_M_logger;
1574  _TaskWorkItemRAIILogger(_TaskEventLogger &_taskHandleLogger): _M_logger(_taskHandleLogger)
1575  {
1576  _M_logger._LogWorkItemStarted();
1577  }
1578 
1579  ~_TaskWorkItemRAIILogger()
1580  {
1581  _M_logger._LogWorkItemCompleted();
1582  }
1583  _TaskWorkItemRAIILogger &operator =(const _TaskWorkItemRAIILogger &); // cannot be assigned
1584  };
1585 
1586 #else
1587  inline void _LogCancelTask(_Task_impl_base *) {}
1589  {
1590  void _LogScheduleTask(bool) {}
1591  void _LogCancelTask() {}
1592  void _LogWorkItemStarted() {}
1593  void _LogWorkItemCompleted() {}
1594  void _LogTaskExecutionStarted() {}
1595  void _LogTaskExecutionCompleted() {}
1596  void _LogTaskCompleted() {}
1598  };
1600  {
1602  };
1603 #endif
1604 
1620  template<typename _ReturnType, typename _DerivedTaskHandle, typename _BaseTaskHandle>
1621  struct _PPLTaskHandle : _BaseTaskHandle
1622  {
1623  _PPLTaskHandle(const typename _Task_ptr<_ReturnType>::_Type & _PTask) : _M_pTask(_PTask)
1624  {
1625  }
1626 
1627  virtual ~_PPLTaskHandle()
1628  {
1629  // Here is the sink of all task completion code paths
1630  _M_pTask->_M_taskEventLogger._LogTaskCompleted();
1631  }
1632 
1633  virtual void invoke() const
1634  {
1635  // All exceptions should be rethrown to finish cleanup of the task collection. They will be caught and handled
1636  // by the runtime.
1637  _ASSERTE((bool)_M_pTask);
1638  if (!_M_pTask->_TransitionedToStarted())
1639  {
1640  static_cast<const _DerivedTaskHandle *>(this)->_SyncCancelAndPropagateException();
1641  return;
1642  }
1643 
1644  _M_pTask->_M_taskEventLogger._LogTaskExecutionStarted();
1645  try
1646  {
1647  // All derived task handle must implement this contract function.
1648  static_cast<const _DerivedTaskHandle *>(this)->_Perform();
1649  }
1650  catch(const task_canceled &)
1651  {
1652  _M_pTask->_Cancel(true);
1653  }
1654  catch(const _Interruption_exception &)
1655  {
1656  _M_pTask->_Cancel(true);
1657  }
1658 #if defined (__cplusplus_winrt)
1659  catch(::Platform::Exception^ _E)
1660  {
1661  _M_pTask->_CancelWithException(_E);
1662  }
1663 #endif /* defined (__cplusplus_winrt) */
1664  catch(...)
1665  {
1666  _M_pTask->_CancelWithException(std::current_exception());
1667  }
1668  _M_pTask->_M_taskEventLogger._LogTaskExecutionCompleted();
1669  }
1670 
1671  // Cast _M_pTask pointer to "type-less" _Task_impl_base pointer, which can be used in _ContinuationTaskHandleBase.
1672  // The return value should be automatically optimized by R-value ref.
1673  _Task_ptr_base _GetTaskImplBase() const
1674  {
1675  return _M_pTask;
1676  }
1677 
1678  typename _Task_ptr<_ReturnType>::_Type _M_pTask;
1679  private:
1680  _PPLTaskHandle const & operator=(_PPLTaskHandle const&); // no assignment operator
1681  };
1682 
1687 
1689  {
1690  enum _TaskInternalState
1691  {
1692  // Tracks the state of the task, rather than the task collection on which the task is scheduled
1693  _Created,
1694  _Started,
1695  _PendingCancel,
1696  _Completed,
1697  _Canceled
1698  };
1699 // _M_taskEventLogger - 'this' : used in base member initializer list
1700 #if defined(_MSC_VER)
1701 #pragma warning(push)
1702 #pragma warning(disable: 4355)
1703 #endif
1704  _Task_impl_base(_CancellationTokenState * _PTokenState, scheduler_ptr _Scheduler_arg)
1705  : _M_TaskState(_Created),
1706  _M_fFromAsync(false), _M_fUnwrappedTask(false),
1707  _M_pRegistration(nullptr), _M_Continuations(nullptr), _M_TaskCollection(_Scheduler_arg),
1708  _M_taskEventLogger(this)
1709  {
1710  // Set cancelation token
1711  _M_pTokenState = _PTokenState;
1712  _ASSERTE(_M_pTokenState != nullptr);
1713  if (_M_pTokenState != _CancellationTokenState::_None())
1714  _M_pTokenState->_Reference();
1715  }
1716 #if defined(_MSC_VER)
1717 #pragma warning(pop)
1718 #endif
1719 
1720  virtual ~_Task_impl_base()
1721  {
1722  _ASSERTE(_M_pTokenState != nullptr);
1723  if (_M_pTokenState != _CancellationTokenState::_None())
1724  {
1725  _M_pTokenState->_Release();
1726  }
1727  }
1728 
1729  task_status _Wait()
1730  {
1731  bool _DoWait = true;
1732 
1733 #if defined (__cplusplus_winrt)
1734  if (_IsNonBlockingThread())
1735  {
1736  // In order to prevent Windows Runtime STA threads from blocking the UI, calling task.wait() task.get() is illegal
1737  // if task has not been completed.
1738  if (!_IsCompleted() && !_IsCanceled())
1739  {
1740  throw invalid_operation("Illegal to wait on a task in a Windows Runtime STA");
1741  }
1742  else
1743  {
1744  // Task Continuations are 'scheduled' *inside* the chore that is executing on the ancestors's task group. If a continuation
1745  // needs to be marshalled to a different apartment, instead of scheduling, we make a synchronous cross apartment COM
1746  // call to execute the continuation. If it then happens to do something which waits on the ancestor (say it calls .get(), which
1747  // task based continuations are wont to do), waiting on the task group results in on the chore that is making this
1748  // synchronous callback, which causes a deadlock. To avoid this, we test the state ancestor's event , and we will NOT wait on
1749  // if it has finished execution (which means now we are on the inline synchronous callback).
1750  _DoWait = false;
1751  }
1752  }
1753 #endif /* defined (__cplusplus_winrt) */
1754  if (_DoWait)
1755  {
1756  // If this task was created from a Windows Runtime async operation, do not attempt to inline it. The
1757  // async operation will take place on a thread in the appropriate apartment Simply wait for the completed
1758  // event to be set.
1759  if (_M_fFromAsync)
1760  {
1761  _M_TaskCollection._Wait();
1762  }
1763  else
1764  {
1765  // Wait on the task collection to complete. The task collection is guaranteed to still be
1766  // valid since the task must be still within scope so that the _Task_impl_base destructor
1767  // has not yet been called. This call to _Wait potentially inlines execution of work.
1768  try
1769  {
1770  // Invoking wait on a task collection resets the state of the task collection. This means that
1771  // if the task collection itself were canceled, or had encountered an exception, only the first
1772  // call to wait will receive this status. However, both cancellation and exceptions flowing through
1773  // tasks set state in the task impl itself.
1774 
1775  // When it returns cancelled, either work chore or the cancel thread should already have set task's state
1776  // properly -- cancelled state or completed state (because there was no interruption point).
1777  // For tasks with unwrapped tasks, we should not change the state of current task, since the unwrapped task are still running.
1778  _M_TaskCollection._RunAndWait();
1779  }
1781  {
1782  // The _TaskCollection will never be an interruption point since it has a none token.
1783  _ASSERTE(false);
1784  }
1785  catch(task_canceled&)
1786  {
1787  // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task
1788  // must be called from code that is executed within the task (throwing it from parallel work created by and waited
1789  // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen
1790  // the exception and canceled the task. Swallow the exception here.
1791  _ASSERTE(_IsCanceled());
1792  }
1793 #if defined (__cplusplus_winrt)
1794  catch(::Platform::Exception^ _E)
1795  {
1796  // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.
1797  if(!_HasUserException())
1798  {
1799  _CancelWithException(_E);
1800  }
1801  // Rethrow will mark the exception as observed.
1802  _M_exceptionHolder->_RethrowUserException();
1803  }
1804 #endif /* defined (__cplusplus_winrt) */
1805  catch(...)
1806  {
1807  // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.
1808  if(!_HasUserException())
1809  {
1810  _CancelWithException(std::current_exception());
1811  }
1812  // Rethrow will mark the exception as observed.
1813  _M_exceptionHolder->_RethrowUserException();
1814  }
1815 
1816  // If the lambda body for this task (executed or waited upon in _RunAndWait above) happened to return a task
1817  // which is to be unwrapped and plumbed to the output of this task, we must not only wait on the lambda body, we must
1818  // wait on the **INNER** body. It is in theory possible that we could inline such if we plumb a series of things through;
1819  // however, this takes the tact of simply waiting upon the completion signal.
1820  if (_M_fUnwrappedTask)
1821  {
1822  _M_TaskCollection._Wait();
1823  }
1824  }
1825  }
1826 
1827  if (_HasUserException())
1828  {
1829  _M_exceptionHolder->_RethrowUserException();
1830  }
1831  else if (_IsCanceled())
1832  {
1833  return canceled;
1834  }
1835  _ASSERTE(_IsCompleted());
1836  return completed;
1837  }
1838 
1858  virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder>& _ExHolder) = 0;
1859 
1860  bool _Cancel(bool _SynchronousCancel)
1861  {
1862  // Send in a dummy value for exception. It is not used when the first parameter is false.
1863  return _CancelAndRunContinuations(_SynchronousCancel, false, false, _M_exceptionHolder);
1864  }
1865 
1866  bool _CancelWithExceptionHolder(const std::shared_ptr<_ExceptionHolder>& _ExHolder, bool _PropagatedFromAncestor)
1867  {
1868  // This task was canceled because an ancestor task encountered an exception.
1869  return _CancelAndRunContinuations(true, true, _PropagatedFromAncestor, _ExHolder);
1870  }
1871 
1872 #if defined (__cplusplus_winrt)
1873  bool _CancelWithException(::Platform::Exception^ _Exception)
1874  {
1875  // This task was canceled because the task body encountered an exception.
1876  _ASSERTE(!_HasUserException());
1877  return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack()));
1878  }
1879 #endif /* defined (__cplusplus_winrt) */
1880 
1881  bool _CancelWithException(const std::exception_ptr& _Exception)
1882  {
1883  // This task was canceled because the task body encountered an exception.
1884  _ASSERTE(!_HasUserException());
1885  return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack()));
1886  }
1887 
1888  void _RegisterCancellation(std::weak_ptr<_Task_impl_base> _WeakPtr)
1889  {
1890  _ASSERTE(details::_CancellationTokenState::_IsValid(_M_pTokenState));
1891 
1892  auto _CancellationCallback = [_WeakPtr](){
1893  // Taking ownership of the task prevents dead lock during destruction
1894  // if the destructor waits for the cancellations to be finished
1895  auto _task = _WeakPtr.lock();
1896  if (_task != nullptr)
1897  _task->_Cancel(false);
1898  };
1899 
1900  _M_pRegistration = new details::_CancellationTokenCallback<decltype(_CancellationCallback)>(_CancellationCallback);
1901  _M_pTokenState->_RegisterCallback(_M_pRegistration);
1902  }
1903 
1904  void _DeregisterCancellation()
1905  {
1906  if (_M_pRegistration != nullptr)
1907  {
1908  _M_pTokenState->_DeregisterCallback(_M_pRegistration);
1909  _M_pRegistration->_Release();
1910  _M_pRegistration = nullptr;
1911  }
1912  }
1913 
1914  bool _IsCreated()
1915  {
1916  return (_M_TaskState == _Created);
1917  }
1918 
1919  bool _IsStarted()
1920  {
1921  return (_M_TaskState == _Started);
1922  }
1923 
1924  bool _IsPendingCancel()
1925  {
1926  return (_M_TaskState == _PendingCancel);
1927  }
1928 
1929  bool _IsCompleted()
1930  {
1931  return (_M_TaskState == _Completed);
1932  }
1933 
1934  bool _IsCanceled()
1935  {
1936  return (_M_TaskState == _Canceled);
1937  }
1938 
1939  bool _HasUserException()
1940  {
1941  return static_cast<bool>(_M_exceptionHolder);
1942  }
1943 
1944  const std::shared_ptr<_ExceptionHolder>& _GetExceptionHolder()
1945  {
1946  _ASSERTE(_HasUserException());
1947  return _M_exceptionHolder;
1948  }
1949 
1950  bool _IsApartmentAware()
1951  {
1952  return _M_fFromAsync;
1953  }
1954 
1955  void _SetAsync(bool _Async = true)
1956  {
1957  _M_fFromAsync = _Async;
1958  }
1959 
1960  _TaskCreationCallstack _GetTaskCreationCallstack()
1961  {
1962  return _M_pTaskCreationCallstack;
1963  }
1964 
1965  void _SetTaskCreationCallstack(const _TaskCreationCallstack &_Callstack)
1966  {
1967  _M_pTaskCreationCallstack = _Callstack;
1968  }
1969 
1979  void _ScheduleTask(_UnrealizedChore_t * _PTaskHandle, _TaskInliningMode_t _InliningMode)
1980  {
1981  try
1982  {
1983  _M_TaskCollection._ScheduleTask(_PTaskHandle, _InliningMode);
1984  }
1985  catch(const task_canceled &)
1986  {
1987  // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task
1988  // must be called from code that is executed within the task (throwing it from parallel work created by and waited
1989  // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen
1990  // the exception and canceled the task. Swallow the exception here.
1991  _ASSERTE(_IsCanceled());
1992  }
1993  catch(const _Interruption_exception &)
1994  {
1995  // The _TaskCollection will never be an interruption point since it has a none token.
1996  _ASSERTE(false);
1997  }
1998  catch(...)
1999  {
2000  // The exception could have come from two places:
2001  // 1. From the chore body, so it already should have been caught and canceled.
2002  // In this case swallow the exception.
2003  // 2. From trying to actually schedule the task on the scheduler.
2004  // In this case cancel the task with the current exception, otherwise the
2005  // task will never be signaled leading to deadlock when waiting on the task.
2006  if (!_HasUserException())
2007  {
2008  _CancelWithException(std::current_exception());
2009  }
2010  }
2011  }
2012 
2020 
2022  {
2023  _Task_ptr_base _ImplBase = _PTaskHandle->_GetTaskImplBase();
2024  if (_IsCanceled() && !_PTaskHandle->_M_isTaskBasedContinuation)
2025  {
2026  if (_HasUserException())
2027  {
2028  // If the ancestor encountered an exception, transfer the exception to the continuation
2029  // This traverses down the tree to propagate the exception.
2030  _ImplBase->_CancelWithExceptionHolder(_GetExceptionHolder(), true);
2031  }
2032  else
2033  {
2034  // If the ancestor was canceled, then your own execution should be canceled.
2035  // This traverses down the tree to cancel it.
2036  _ImplBase->_Cancel(true);
2037  }
2038  }
2039  else
2040  {
2041  // This can only run when the ancestor has completed or it's a task based continuation that fires when a task is canceled
2042  // (with or without a user exception).
2043  _ASSERTE(_IsCompleted() || _PTaskHandle->_M_isTaskBasedContinuation);
2044  _ASSERTE(!_ImplBase->_IsCanceled());
2045  return _ImplBase->_ScheduleContinuationTask(_PTaskHandle);
2046  }
2047 
2048  // If the handle is not scheduled, we need to manually delete it.
2049  delete _PTaskHandle;
2050  }
2051 
2052  // Schedule a continuation to run
2053  void _ScheduleContinuationTask(_ContinuationTaskHandleBase * _PTaskHandle)
2054  {
2055 
2056  _M_taskEventLogger._LogScheduleTask(true);
2057  // Ensure that the continuation runs in proper context (this might be on a Concurrency Runtime thread or in a different Windows Runtime apartment)
2058  if (_PTaskHandle->_M_continuationContext._HasCapturedContext())
2059  {
2060  // For those continuations need to be scheduled inside captured context, we will try to apply automatic inlining to their inline modes,
2061  // if they haven't been specified as _ForceInline yet. This change will encourage those continuations to be executed inline so that reduce
2062  // the cost of marshaling.
2063  // For normal continuations we won't do any change here, and their inline policies are completely decided by ._ThenImpl method.
2064  if (_PTaskHandle->_M_inliningMode != details::_ForceInline)
2065  {
2066  _PTaskHandle->_M_inliningMode = details::_DefaultAutoInline;
2067  }
2068  _ScheduleFuncWithAutoInline([_PTaskHandle]() {
2069  // Note that we cannot directly capture "this" pointer, instead, we should use _TaskImplPtr, a shared_ptr to the _Task_impl_base.
2070  // Because "this" pointer will be invalid as soon as _PTaskHandle get deleted. _PTaskHandle will be deleted after being scheduled.
2071  auto _TaskImplPtr = _PTaskHandle->_GetTaskImplBase();
2072  if (details::_ContextCallback::_CaptureCurrent() == _PTaskHandle->_M_continuationContext)
2073  {
2074  _TaskImplPtr->_ScheduleTask(_PTaskHandle, details::_ForceInline);
2075  }
2076  else
2077  {
2078  //
2079  // It's entirely possible that the attempt to marshal the call into a differing context will fail. In this case, we need to handle
2080  // the exception and mark the continuation as canceled with the appropriate exception. There is one slight hitch to this:
2081  //
2082  // NOTE: COM's legacy behavior is to swallow SEH exceptions and marshal them back as HRESULTS. This will in effect turn an SEH into
2083  // a C++ exception that gets tagged on the task. One unfortunate result of this is that various pieces of the task infrastructure will
2084  // not be in a valid state after this in /EHsc (due to the lack of destructors running, etc...).
2085  //
2086  try
2087  {
2088  // Dev10 compiler needs this!
2089  auto _PTaskHandle1 = _PTaskHandle;
2090  _PTaskHandle->_M_continuationContext._CallInContext( [_PTaskHandle1, _TaskImplPtr](){
2091  _TaskImplPtr->_ScheduleTask(_PTaskHandle1, details::_ForceInline);
2092  });
2093  }
2094 #if defined (__cplusplus_winrt)
2095  catch(::Platform::Exception^ _E)
2096  {
2097  _TaskImplPtr->_CancelWithException(_E);
2098  }
2099 #endif /* defined (__cplusplus_winrt) */
2100  catch(...)
2101  {
2102  _TaskImplPtr->_CancelWithException(std::current_exception());
2103  }
2104  }
2105  }, _PTaskHandle->_M_inliningMode);
2106  }
2107  else
2108  {
2109  _ScheduleTask(_PTaskHandle, _PTaskHandle->_M_inliningMode);
2110  }
2111  }
2112 
2123 
2125  {
2126  enum { _Nothing, _Schedule, _Cancel, _CancelWithException } _Do = _Nothing;
2127 
2128  // If the task has canceled, cancel the continuation. If the task has completed, execute the continuation right away.
2129  // Otherwise, add it to the list of pending continuations
2130  {
2131  ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);
2132  if (_IsCompleted() || (_IsCanceled() && _PTaskHandle->_M_isTaskBasedContinuation))
2133  {
2134  _Do = _Schedule;
2135  }
2136  else if (_IsCanceled())
2137  {
2138  if (_HasUserException())
2139  {
2140  _Do = _CancelWithException;
2141  }
2142  else
2143  {
2144  _Do = _Cancel;
2145  }
2146  }
2147  else
2148  {
2149  // chain itself on the continuation chain.
2150  _PTaskHandle->_M_next = _M_Continuations;
2151  _M_Continuations = _PTaskHandle;
2152  }
2153  }
2154 
2155  // Cancellation and execution of continuations should be performed after releasing the lock. Continuations off of
2156  // async tasks may execute inline.
2157  switch (_Do)
2158  {
2159  case _Schedule:
2160  {
2161  _PTaskHandle->_GetTaskImplBase()->_ScheduleContinuationTask(_PTaskHandle);
2162  break;
2163  }
2164  case _Cancel:
2165  {
2166  // If the ancestor was canceled, then your own execution should be canceled.
2167  // This traverses down the tree to cancel it.
2168  _PTaskHandle->_GetTaskImplBase()->_Cancel(true);
2169 
2170  delete _PTaskHandle;
2171  break;
2172  }
2173  case _CancelWithException:
2174  {
2175  // If the ancestor encountered an exception, transfer the exception to the continuation
2176  // This traverses down the tree to propagate the exception.
2177  _PTaskHandle->_GetTaskImplBase()->_CancelWithExceptionHolder(_GetExceptionHolder(), true);
2178 
2179  delete _PTaskHandle;
2180  break;
2181  }
2182  case _Nothing:
2183  default:
2184  // In this case, we have inserted continuation to continuation chain,
2185  // nothing more need to be done, just leave.
2186  break;
2187  }
2188  }
2189 
2190  void _RunTaskContinuations()
2191  {
2192  // The link list can no longer be modified at this point,
2193  // since all following up continuations will be scheduled by themselves.
2194  _ContinuationList _Cur = _M_Continuations, _Next;
2195  _M_Continuations = nullptr;
2196  while (_Cur)
2197  {
2198  // Current node might be deleted after running,
2199  // so we must fetch the next first.
2200  _Next = _Cur->_M_next;
2201  _RunContinuation(_Cur);
2202  _Cur = _Next;
2203  }
2204  }
2205 
2206 #if defined (__cplusplus_winrt)
2207  static bool _IsNonBlockingThread()
2208  {
2209  APTTYPE _AptType;
2210  APTTYPEQUALIFIER _AptTypeQualifier;
2211 
2212  HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);
2213  //
2214  // If it failed, it's not a Windows Runtime/COM initialized thread. This is not a failure.
2215  //
2216  if (SUCCEEDED(hr))
2217  {
2218  switch(_AptType)
2219  {
2220  case APTTYPE_STA:
2221  case APTTYPE_MAINSTA:
2222  return true;
2223  break;
2224  case APTTYPE_NA:
2225  switch(_AptTypeQualifier)
2226  {
2227  // A thread executing in a neutral apartment is either STA or MTA. To find out if this thread is allowed
2228  // to wait, we check the app qualifier. If it is an STA thread executing in a neutral apartment, waiting
2229  // is illegal, because the thread is responsible for pumping messages and waiting on a task could take the
2230  // thread out of circulation for a while.
2231  case APTTYPEQUALIFIER_NA_ON_STA:
2232  case APTTYPEQUALIFIER_NA_ON_MAINSTA:
2233  return true;
2234  break;
2235  }
2236  break;
2237  }
2238  }
2239 
2240 #if _UITHREADCTXT_SUPPORT
2241  // This method is used to throw an exepection in _Wait() if called within STA. We
2242  // want the same behavior if _Wait is called on the UI thread.
2243  if (SUCCEEDED(CaptureUiThreadContext(nullptr)))
2244  {
2245  return true;
2246  }
2247 #endif /* _UITHREADCTXT_SUPPORT */
2248 
2249  return false;
2250  }
2251 
2252  template<typename _ReturnType, typename>
2253  static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type & _OuterTask,
2254  Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)
2255  {
2256  // This method is invoked either when a task is created from an existing async operation or
2257  // when a lambda that creates an async operation executes.
2258 
2259  // If the outer task is pending cancel, cancel the async operation before setting the completed handler. The COM reference on
2260  // the IAsyncInfo object will be released when all ^references to the operation go out of scope.
2261 
2262  // This assertion uses the existence of taskcollection to determine if the task was created from an event.
2263  // That is no longer valid as even tasks created from a user lambda could have no underlying taskcollection
2264  // when a custom scheduler is used.
2265  // _ASSERTE((!_OuterTask->_M_TaskCollection._IsCreated() || _OuterTask->_M_fUnwrappedTask) && !_OuterTask->_IsCanceled());
2266 
2267  // Pass the shared_ptr by value into the lambda instead of using 'this'.
2268  _AsyncOp->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType>(
2269  [_OuterTask](Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _Operation, Windows::Foundation::AsyncStatus _Status) mutable
2270  {
2271  if (_Status == Windows::Foundation::AsyncStatus::Canceled)
2272  {
2273  _OuterTask->_Cancel(true);
2274  }
2275  else if (_Status == Windows::Foundation::AsyncStatus::Error)
2276  {
2277  _OuterTask->_CancelWithException(::Platform::Exception::ReCreateException(static_cast<int>(_Operation->ErrorCode.Value)));
2278  }
2279  else
2280  {
2281  _ASSERTE(_Status == Windows::Foundation::AsyncStatus::Completed);
2282  _OuterTask->_FinalizeAndRunContinuations(_Operation->GetResults());
2283  }
2284 
2285  // Take away this shared pointers reference on the task instead of waiting for the delegate to be released. It could
2286  // be released on a different thread after a delay, and not releasing the reference here could cause the tasks to hold
2287  // on to resources longer than they should. As an example, without this reset, writing to a file followed by reading from
2288  // it using the Windows Runtime Async APIs causes a sharing violation.
2289  // Using const_cast is the workaround for failed mutable keywords
2290  const_cast<_Task_ptr<_ReturnType>::_Type &>(_OuterTask).reset();
2291  });
2292  _OuterTask->_SetUnwrappedAsyncOp(_AsyncOp);
2293  }
2294 #endif /* defined (__cplusplus_winrt) */
2295 
2296  template<typename _ReturnType, typename _InternalReturnType>
2297  static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type& _OuterTask, const task<_InternalReturnType> & _UnwrappedTask)
2298  {
2299  _ASSERTE(_OuterTask->_M_fUnwrappedTask && !_OuterTask->_IsCanceled());
2300 
2301  //
2302  // We must ensure that continuations off _OuterTask (especially exception handling ones) continue to function in the
2303  // presence of an exception flowing out of the inner task _UnwrappedTask. This requires an exception handling continuation
2304  // off the inner task which does the appropriate funnelling to the outer one. We use _Then instead of then to prevent
2305  // the exception from being marked as observed by our internal continuation. This continuation must be scheduled regardless
2306  // of whether or not the _OuterTask task is canceled.
2307  //
2308  _UnwrappedTask._Then([_OuterTask] (task<_InternalReturnType> _AncestorTask) {
2309 
2310  if (_AncestorTask._GetImpl()->_IsCompleted())
2311  {
2312  _OuterTask->_FinalizeAndRunContinuations(_AncestorTask._GetImpl()->_GetResult());
2313  }
2314  else
2315  {
2316  _ASSERTE(_AncestorTask._GetImpl()->_IsCanceled());
2317  if (_AncestorTask._GetImpl()->_HasUserException())
2318  {
2319  // Set _PropagatedFromAncestor to false, since _AncestorTask is not an ancestor of _UnwrappedTask.
2320  // Instead, it is the enclosing task.
2321  _OuterTask->_CancelWithExceptionHolder(_AncestorTask._GetImpl()->_GetExceptionHolder(), false);
2322  }
2323  else
2324  {
2325  _OuterTask->_Cancel(true);
2326  }
2327  }
2328  }, nullptr, details::_DefaultAutoInline);
2329 
2330  }
2331 
2332  scheduler_ptr _GetScheduler() const
2333  {
2334  return _M_TaskCollection._GetScheduler();
2335  }
2336 
2337  // Tracks the internal state of the task
2338  volatile _TaskInternalState _M_TaskState;
2339  // 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
2340  // async operation or async action that is unwrapped by the runtime.
2341  bool _M_fFromAsync;
2342  // Set to true when a continuation unwraps a task or async operation.
2343  bool _M_fUnwrappedTask;
2344 
2345  // 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.
2346  // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception
2347  // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.
2348  std::shared_ptr<_ExceptionHolder> _M_exceptionHolder;
2349 
2350  ::pplx::extensibility::critical_section_t _M_ContinuationsCritSec;
2351 
2352  // The cancellation token state.
2353  _CancellationTokenState * _M_pTokenState;
2354 
2355  // The registration on the token.
2356  _CancellationTokenRegistration * _M_pRegistration;
2357 
2358  typedef _ContinuationTaskHandleBase * _ContinuationList;
2359  _ContinuationList _M_Continuations;
2360 
2361  // The async task collection wrapper
2362  ::pplx::details::_TaskCollection_t _M_TaskCollection;
2363 
2364  // Callstack for function call (constructor or .then) that created this task impl.
2365  _TaskCreationCallstack _M_pTaskCreationCallstack;
2366 
2367  _TaskEventLogger _M_taskEventLogger;
2368  private:
2369  // Must not be copied by value:
2370  _Task_impl_base(const _Task_impl_base&);
2371  _Task_impl_base const & operator=(_Task_impl_base const&);
2372  };
2373 
2374 #if _PPLTASK_ASYNC_LOGGING
2375  inline void _TaskEventLogger::_LogTaskCompleted()
2376  {
2377  if (_M_scheduled)
2378  {
2379  ::Windows::Foundation::AsyncStatus _State;
2380  if (_M_task->_IsCompleted())
2381  _State = ::Windows::Foundation::AsyncStatus::Completed;
2382  else if (_M_task->_HasUserException())
2383  _State = ::Windows::Foundation::AsyncStatus::Error;
2384  else
2385  _State = ::Windows::Foundation::AsyncStatus::Canceled;
2386 
2387  if (details::_IsCausalitySupported())
2388  {
2389  ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
2390  _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), _State);
2391  }
2392  }
2393  }
2394 #endif
2395 
2404 
2405  template<typename _ReturnType>
2406  struct _Task_impl : public _Task_impl_base
2407  {
2408 #if defined (__cplusplus_winrt)
2409  typedef Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value> _AsyncOperationType;
2410 #endif // defined(__cplusplus_winrt)
2411  _Task_impl(_CancellationTokenState * _Ct, scheduler_ptr _Scheduler_arg)
2412  : _Task_impl_base(_Ct, _Scheduler_arg)
2413  {
2414 #if defined (__cplusplus_winrt)
2415  _M_unwrapped_async_op = nullptr;
2416 #endif /* defined (__cplusplus_winrt) */
2417  }
2418 
2419  virtual ~_Task_impl()
2420  {
2421  // We must invoke _DeregisterCancellation in the derived class destructor. Calling it in the base class destructor could cause
2422  // a partially initialized _Task_impl to be in the list of registrations for a cancellation token.
2423  _DeregisterCancellation();
2424  }
2425 
2426  virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder> & _ExceptionHolder_arg)
2427  {
2428  bool _RunContinuations = false;
2429  {
2430  ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);
2431  if (_UserException)
2432  {
2433  _ASSERTE(_SynchronousCancel && !_IsCompleted());
2434  // If the state is _Canceled, the exception has to be coming from an ancestor.
2435  _ASSERTE(!_IsCanceled() || _PropagatedFromAncestor);
2436 
2437  // We should not be canceled with an exception more than once.
2438  _ASSERTE(!_HasUserException());
2439 
2440  // Mark _PropagatedFromAncestor as used.
2441  (void)_PropagatedFromAncestor;
2442 
2443  if (_M_TaskState == _Canceled)
2444  {
2445  // If the task has finished cancelling there should not be any continuation records in the array.
2446  return false;
2447  }
2448  else
2449  {
2450  _ASSERTE(_M_TaskState != _Completed);
2451  _M_exceptionHolder = _ExceptionHolder_arg;
2452  }
2453  }
2454  else
2455  {
2456  // Completed is a non-cancellable state, and if this is an asynchronous cancel, we're unable to do better than the last async cancel
2457  // which is to say, cancellation is already initiated, so return early.
2458  if (_IsCompleted() || _IsCanceled() || (_IsPendingCancel() && !_SynchronousCancel))
2459  {
2460  _ASSERTE(!_IsCompleted() || !_HasUserException());
2461  return false;
2462  }
2463  _ASSERTE(!_SynchronousCancel || !_HasUserException());
2464  }
2465 
2466  if (_SynchronousCancel)
2467  {
2468  // Be aware that this set must be done BEFORE _M_Scheduled being set, or race will happen between this and wait()
2469  _M_TaskState = _Canceled;
2470  // Cancellation completes the task, so all dependent tasks must be run to cancel them
2471  // They are canceled when they begin running (see _RunContinuation) and see that their
2472  // ancestor has been canceled.
2473  _RunContinuations = true;
2474  }
2475  else
2476  {
2477  _ASSERTE(!_UserException);
2478 
2479  if (_IsStarted())
2480  {
2481 #if defined (__cplusplus_winrt)
2482  if (_M_unwrapped_async_op != nullptr)
2483  {
2484  // We will only try to cancel async operation but not unwrapped tasks, since unwrapped tasks cannot be canceled without its token.
2485  _M_unwrapped_async_op->Cancel();
2486  }
2487 #endif /* defined (__cplusplus_winrt) */
2488  _M_TaskCollection._Cancel();
2489  }
2490 
2491  // The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore).
2492  // In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from
2493  // _Started to _PendingCancel before it can move to _Canceled when it is finished executing.
2494  _M_TaskState = _PendingCancel;
2495 
2496  _M_taskEventLogger._LogCancelTask();
2497  }
2498 
2499 
2500  }
2501 
2502  // Only execute continuations and mark the task as completed if we were able to move the task to the _Canceled state.
2503  if (_RunContinuations)
2504  {
2505  _M_TaskCollection._Complete();
2506 
2507  if (_M_Continuations)
2508  {
2509  // Scheduling cancellation with automatic inlining.
2510  _ScheduleFuncWithAutoInline([=](){ _RunTaskContinuations(); }, details::_DefaultAutoInline);
2511  }
2512  }
2513  return true;
2514  }
2515 
2516  void _FinalizeAndRunContinuations(_ReturnType _Result)
2517  {
2518  _M_Result.Set(_Result);
2519 
2520  {
2521  //
2522  // Hold this lock to ensure continuations being concurrently either get added
2523  // to the _M_Continuations vector or wait for the result
2524  //
2525  ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);
2526 
2527  // A task could still be in the _Created state if it was created with a task_completion_event.
2528  // It could also be in the _Canceled state for the same reason.
2529  _ASSERTE(!_HasUserException() && !_IsCompleted());
2530  if (_IsCanceled())
2531  {
2532  return;
2533  }
2534 
2535  // Always transition to "completed" state, even in the face of unacknowledged pending cancellation
2536  _M_TaskState = _Completed;
2537  }
2538  _M_TaskCollection._Complete();
2539  _RunTaskContinuations();
2540  }
2541 
2542  //
2543  // This method is invoked when the starts executing. The task returns early if this method returns true.
2544  //
2545  bool _TransitionedToStarted()
2546  {
2547  ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);
2548  // Canceled state could only result from antecedent task's canceled state, but that code path will not reach here.
2549  _ASSERTE(!_IsCanceled());
2550  if (_IsPendingCancel())
2551  return false;
2552 
2553  _ASSERTE(_IsCreated());
2554  _M_TaskState = _Started;
2555  return true;
2556  }
2557 
2558 #if defined (__cplusplus_winrt)
2559  void _SetUnwrappedAsyncOp(_AsyncOperationType^ _AsyncOp)
2560  {
2561  ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_ContinuationsCritSec);
2562  // Cancel the async operation if the task itself is canceled, since the thread that canceled the task missed it.
2563  if (_IsPendingCancel())
2564  {
2565  _ASSERTE(!_IsCanceled());
2566  _AsyncOp->Cancel();
2567  }
2568  else
2569  {
2570  _M_unwrapped_async_op = _AsyncOp;
2571  }
2572  }
2573 #endif /* defined (__cplusplus_winrt) */
2574 
2575  // Return true if the task has reached a terminal state
2576  bool _IsDone()
2577  {
2578  return _IsCompleted() || _IsCanceled();
2579  }
2580 
2581  _ReturnType _GetResult()
2582  {
2583  return _M_Result.Get();
2584  }
2585 
2586  _ResultHolder<_ReturnType> _M_Result; // this means that the result type must have a public default ctor.
2587 #if defined (__cplusplus_winrt)
2588  _AsyncOperationType^ _M_unwrapped_async_op;
2589 #endif /* defined (__cplusplus_winrt) */
2590  };
2591 
2592  template<typename _ResultType>
2594  {
2595  private:
2598 
2599  public:
2600 
2601  typedef std::vector<typename _Task_ptr<_ResultType>::_Type> _TaskList;
2602 
2604  _M_fHasValue(false), _M_fIsCanceled(false)
2605  {
2606  }
2607 
2608  bool _HasUserException()
2609  {
2610  return _M_exceptionHolder != nullptr;
2611  }
2612 
2614  {
2615  for( auto _TaskIt = _M_tasks.begin(); _TaskIt != _M_tasks.end(); ++_TaskIt )
2616  {
2617  _ASSERTE(!_M_fHasValue && !_M_fIsCanceled);
2618  // Cancel the tasks since the event was never signaled or canceled.
2619  (*_TaskIt)->_Cancel(true);
2620  }
2621  }
2622 
2623  // We need to protect the loop over the array, so concurrent_vector would not have helped
2624  _TaskList _M_tasks;
2625  ::pplx::extensibility::critical_section_t _M_taskListCritSec;
2626  _ResultHolder<_ResultType> _M_value;
2627  std::shared_ptr<_ExceptionHolder> _M_exceptionHolder;
2628  bool _M_fHasValue;
2629  bool _M_fIsCanceled;
2630  };
2631 
2632  // Utility method for dealing with void functions
2633  inline std::function<_Unit_type(void)> _MakeVoidToUnitFunc(const std::function<void(void)>& _Func)
2634  {
2635  return [=]() -> _Unit_type { _Func(); return _Unit_type(); };
2636  }
2637 
2638  template <typename _Type>
2639  std::function<_Type(_Unit_type)> _MakeUnitToTFunc(const std::function<_Type(void)>& _Func)
2640  {
2641  return [=](_Unit_type) -> _Type { return _Func(); };
2642  }
2643 
2644  template <typename _Type>
2645  std::function<_Unit_type(_Type)> _MakeTToUnitFunc(const std::function<void(_Type)>& _Func)
2646  {
2647  return [=](_Type t) -> _Unit_type { _Func(t); return _Unit_type(); };
2648  }
2649 
2650  inline std::function<_Unit_type(_Unit_type)> _MakeUnitToUnitFunc(const std::function<void(void)>& _Func)
2651  {
2652  return [=](_Unit_type) -> _Unit_type { _Func(); return _Unit_type(); };
2653  }
2654 } // namespace details
2655 
2672 
2673 template<typename _ResultType>
2675 {
2676 public:
2680 
2682  : _M_Impl(std::make_shared<details::_Task_completion_event_impl<_ResultType>>())
2683  {
2684  }
2685 
2701 
2702  bool set(_ResultType _Result) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2703  {
2704  // Subsequent sets are ignored. This makes races to set benign: the first setter wins and all others are ignored.
2705  if (_IsTriggered())
2706  {
2707  return false;
2708  }
2709 
2710  _TaskList _Tasks;
2711  bool _RunContinuations = false;
2712  {
2713  ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);
2714 
2715  if (!_IsTriggered())
2716  {
2717  _M_Impl->_M_value.Set(_Result);
2718  _M_Impl->_M_fHasValue = true;
2719 
2720  _Tasks.swap(_M_Impl->_M_tasks);
2721  _RunContinuations = true;
2722  }
2723  }
2724 
2725  if (_RunContinuations)
2726  {
2727  for( auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt )
2728  {
2729  // If current task was cancelled by a cancellation_token, it would be in cancel pending state.
2730  if ((*_TaskIt)->_IsPendingCancel())
2731  (*_TaskIt)->_Cancel(true);
2732  else
2733  {
2734  // Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all
2735  // if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we
2736  // need to run continuations after the lock is released.
2737  (*_TaskIt)->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get());
2738  }
2739  }
2740  if (_M_Impl->_HasUserException())
2741  {
2742  _M_Impl->_M_exceptionHolder.reset();
2743  }
2744  return true;
2745  }
2746 
2747  return false;
2748  }
2749 
2750  template<typename _E>
2751  __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
2752  bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2753  {
2754  // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.
2755  return _Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK());
2756  }
2757 
2764 
2765  __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
2766  bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2767  {
2768  // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.
2769  return _Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK());
2770  }
2771 
2776  bool _Cancel() const
2777  {
2778  // Cancel with the stored exception if one exists.
2779  return _CancelInternal();
2780  }
2781 
2786  template<typename _ExHolderType>
2787  bool _Cancel(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack ()) const
2788  {
2789  bool _Canceled;
2790  if(_StoreException(_ExHolder, _SetExceptionAddressHint))
2791  {
2792  _Canceled = _CancelInternal();
2793  _ASSERTE(_Canceled);
2794  }
2795  else
2796  {
2797  _Canceled = false;
2798  }
2799  return _Canceled;
2800  }
2801 
2807  template<typename _ExHolderType>
2808  bool _StoreException(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack ()) const
2809  {
2810  ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);
2811  if (!_IsTriggered() && !_M_Impl->_HasUserException())
2812  {
2813  // Create the exception holder only if we have ensured there we will be successful in setting it onto the
2814  // task completion event. Failing to do so will result in an unobserved task exception.
2815  _M_Impl->_M_exceptionHolder = _ToExceptionHolder(_ExHolder, _SetExceptionAddressHint);
2816  return true;
2817  }
2818  return false;
2819  }
2820 
2824  bool _IsTriggered() const
2825  {
2826  return _M_Impl->_M_fHasValue || _M_Impl->_M_fIsCanceled;
2827  }
2828 
2829 private:
2830 
2831  static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder, const details::_TaskCreationCallstack&)
2832  {
2833  return _ExHolder;
2834  }
2835 
2836  static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(std::exception_ptr _ExceptionPtr, const details::_TaskCreationCallstack &_SetExceptionAddressHint)
2837  {
2838  return std::make_shared<details::_ExceptionHolder>(_ExceptionPtr, _SetExceptionAddressHint);
2839  }
2840 
2841 
2842  template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask
2843  template <typename T> friend class task_completion_event;
2844 
2845  typedef typename details::_Task_completion_event_impl<_ResultType>::_TaskList _TaskList;
2846 
2850  bool _CancelInternal() const
2851  {
2852  // Cancellation of task completion events is an internal only utility. Our usage is such that _CancelInternal
2853  // will never be invoked if the task completion event has been set.
2854  _ASSERTE(!_M_Impl->_M_fHasValue);
2855  if (_M_Impl->_M_fIsCanceled)
2856  {
2857  return false;
2858  }
2859 
2860  _TaskList _Tasks;
2861  bool _Cancel = false;
2862  {
2863  ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);
2864  _ASSERTE(!_M_Impl->_M_fHasValue);
2865  if (!_M_Impl->_M_fIsCanceled)
2866  {
2867  _M_Impl->_M_fIsCanceled = true;
2868  _Tasks.swap(_M_Impl->_M_tasks);
2869  _Cancel = true;
2870  }
2871  }
2872 
2873  bool _UserException = _M_Impl->_HasUserException();
2874 
2875  if (_Cancel)
2876  {
2877  for( auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt )
2878  {
2879  // Need to call this after the lock is released. See comments in set().
2880  if (_UserException)
2881  {
2882  (*_TaskIt)->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);
2883  }
2884  else
2885  {
2886  (*_TaskIt)->_Cancel(true);
2887  }
2888  }
2889  }
2890  return _Cancel;
2891  }
2892 
2897  void _RegisterTask(const typename details::_Task_ptr<_ResultType>::_Type & _TaskParam)
2898  {
2899  ::pplx::extensibility::scoped_critical_section_t _LockHolder(_M_Impl->_M_taskListCritSec);
2900 
2901  //If an exception was already set on this event, then cancel the task with the stored exception.
2902  if(_M_Impl->_HasUserException())
2903  {
2904  _TaskParam->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);
2905  }
2906  else if (_M_Impl->_M_fHasValue)
2907  {
2908  _TaskParam->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get());
2909  }
2910  else
2911  {
2912  _M_Impl->_M_tasks.push_back(_TaskParam);
2913  }
2914  }
2915 
2916  std::shared_ptr<details::_Task_completion_event_impl<_ResultType>> _M_Impl;
2917 };
2918 
2932 
2933 template<>
2935 {
2936 public:
2949 
2950  bool set() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2951  {
2952  return _M_unitEvent.set(details::_Unit_type());
2953  }
2954 
2955  template<typename _E>
2956  __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
2957  bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2958  {
2959  return _M_unitEvent._Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK());
2960  }
2961 
2968 
2969  __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK intrinsic gives us the expected result
2970  bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2971  {
2972  // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.
2973  return _M_unitEvent._Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK());
2974  }
2975 
2980  void _Cancel() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2981  {
2982  _M_unitEvent._Cancel();
2983  }
2984 
2989  void _Cancel(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const
2990  {
2991  _M_unitEvent._Cancel(_ExHolder);
2992  }
2993 
2999  bool _StoreException(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const
3000  {
3001  return _M_unitEvent._StoreException(_ExHolder);
3002  }
3003 
3007  bool _IsTriggered() const
3008  {
3009  return _M_unitEvent._IsTriggered();
3010  }
3011 
3012 private:
3013  template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask
3014 
3019  void _RegisterTask(details::_Task_ptr<details::_Unit_type>::_Type _TaskParam)
3020  {
3021  _M_unitEvent._RegisterTask(_TaskParam);
3022  }
3023 
3024  // The void event contains an event a dummy type so common code can be used for events with void and non-void results.
3025  task_completion_event<details::_Unit_type> _M_unitEvent;
3026 };
3027 
3028 namespace details
3029 {
3030  //
3031  // Compile-time validation helpers
3032  //
3033 
3034  // Task constructor validation: issue helpful diagnostics for common user errors. Do not attempt full validation here.
3035  //
3036  // Anything callable is fine
3037  template<typename _ReturnType, typename _Ty>
3038  auto _IsValidTaskCtor(_Ty _Param, int,int,int,int) -> decltype(_Param(), std::true_type());
3039 
3040 #if defined (__cplusplus_winrt)
3041  // Anything that has GetResults is fine: this covers all async operations
3042  template<typename _ReturnType, typename _Ty>
3043  auto _IsValidTaskCtor(_Ty _Param, int, int, int,...) -> decltype(_Param->GetResults(), std::true_type());
3044 #endif
3045 
3046  // Allow parameters with set: this covers task_completion_event
3047  template<typename _ReturnType, typename _Ty>
3048  auto _IsValidTaskCtor(_Ty _Param, int, int, ...) -> decltype(_Param.set(stdx::declval<_ReturnType>()), std::true_type());
3049 
3050  template<typename _ReturnType, typename _Ty>
3051  auto _IsValidTaskCtor(_Ty _Param, int, ...) -> decltype(_Param.set(), std::true_type());
3052 
3053  // All else is invalid
3054  template<typename _ReturnType, typename _Ty>
3055  std::false_type _IsValidTaskCtor(_Ty _Param, ...);
3056 
3057  template<typename _ReturnType, typename _Ty>
3058  void _ValidateTaskConstructorArgs(_Ty _Param)
3059  {
3060  static_assert(std::is_same<decltype(_IsValidTaskCtor<_ReturnType>(_Param,0,0,0,0)),std::true_type>::value,
3061 #if defined (__cplusplus_winrt)
3062  "incorrect argument for task constructor; can be a callable object, an asynchronous operation, or a task_completion_event"
3063 #else /* defined (__cplusplus_winrt) */
3064  "incorrect argument for task constructor; can be a callable object or a task_completion_event"
3065 #endif /* defined (__cplusplus_winrt) */
3066  );
3067 #if defined (__cplusplus_winrt)
3068  static_assert(!(std::is_same<_Ty,_ReturnType>::value && details::_IsIAsyncInfo<_Ty>::_Value),
3069  "incorrect template argument for task; consider using the return type of the async operation");
3070 #endif /* defined (__cplusplus_winrt) */
3071  }
3072 
3073 #if defined (__cplusplus_winrt)
3074  // Helpers for create_async validation
3075  //
3076  // A parameter lambda taking no arguments is valid
3077  template<typename _Ty>
3078  static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int) -> decltype(_Param(), std::true_type());
3079 
3080  // A parameter lambda taking an cancellation_token argument is valid
3081  template<typename _Ty>
3082  static auto _IsValidCreateAsync(_Ty _Param, int, int, int, ...) -> decltype(_Param(cancellation_token::none()), std::true_type());
3083 
3084  // A parameter lambda taking a progress report argument is valid
3085  template<typename _Ty>
3086  static auto _IsValidCreateAsync(_Ty _Param, int, int, ...) -> decltype(_Param(details::_ProgressReporterCtorArgType()), std::true_type());
3087 
3088  // A parameter lambda taking a progress report and a cancellation_token argument is valid
3089  template<typename _Ty>
3090  static auto _IsValidCreateAsync(_Ty _Param, int, ...) -> decltype(_Param(details::_ProgressReporterCtorArgType(), cancellation_token::none()), std::true_type());
3091 
3092  // All else is invalid
3093  template<typename _Ty>
3094  static std::false_type _IsValidCreateAsync(_Ty _Param, ...);
3095 #endif /* defined (__cplusplus_winrt) */
3096 }
3101 template<typename _InpType, typename _OutType>
3103 {
3104 public:
3105  static auto _Perform(std::function<_OutType(_InpType)> _Func) -> decltype(_Func)
3106  {
3107  return _Func;
3108  }
3109 };
3110 
3111 template<typename _OutType>
3112 class _Continuation_func_transformer<void, _OutType>
3113 {
3114 public:
3115  static auto _Perform(std::function<_OutType(void)> _Func) -> decltype(details::_MakeUnitToTFunc<_OutType>(_Func))
3116  {
3117  return details::_MakeUnitToTFunc<_OutType>(_Func);
3118  }
3119 };
3120 
3121 template<typename _InType>
3123 {
3124 public:
3125  static auto _Perform(std::function<void(_InType)> _Func) -> decltype(details::_MakeTToUnitFunc<_InType>(_Func))
3126  {
3127  return details::_MakeTToUnitFunc<_InType>(_Func);
3128  }
3129 };
3130 
3131 template<>
3133 {
3134 public:
3135  static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeUnitToUnitFunc(_Func))
3136  {
3137  return details::_MakeUnitToUnitFunc(_Func);
3138  }
3139 };
3140 
3141 // 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
3142 // to substitute for void). This is to minimize the special handling required for 'void'.
3143 template<typename _RetType>
3145 {
3146 public:
3147  static auto _Perform(std::function<_RetType(void)> _Func) -> decltype(_Func)
3148  {
3149  return _Func;
3150  }
3151 };
3152 
3153 template<>
3155 {
3156 public:
3157  static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeVoidToUnitFunc(_Func))
3158  {
3159  return details::_MakeVoidToUnitFunc(_Func);
3160  }
3161 };
3162 
3176 
3177 template<typename _ReturnType>
3178 class task
3179 {
3180 public:
3184 
3185  typedef _ReturnType result_type;
3186 
3208 
3209  task() : _M_Impl(nullptr)
3210  {
3211  // The default constructor should create a task with a nullptr impl. This is a signal that the
3212  // task is not usable and should throw if any wait(), get() or then() APIs are used.
3213  }
3214 
3249 
3250  template<typename _Ty>
3251  __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
3252  explicit task(_Ty _Param)
3253  {
3254  task_options _TaskOptions;
3255  details::_ValidateTaskConstructorArgs<_ReturnType,_Ty>(_Param);
3256 
3257  _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());
3258  // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.
3259  _SetTaskCreationCallstack(_CAPTURE_CALLSTACK());
3260 
3261  _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));
3262  }
3263 
3297 
3298  template<typename _Ty>
3299  __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
3300  explicit task(_Ty _Param, const task_options &_TaskOptions)
3301  {
3302  details::_ValidateTaskConstructorArgs<_ReturnType,_Ty>(_Param);
3303 
3304  _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());
3305  // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.
3306  _SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK());
3307 
3308  _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));
3309  }
3310 
3335 
3336  task(const task& _Other): _M_Impl(_Other._M_Impl) {}
3337 
3362 
3363  task(task&& _Other): _M_Impl(std::move(_Other._M_Impl)) {}
3364 
3375 
3376  task& operator=(const task& _Other)
3377  {
3378  if (this != &_Other)
3379  {
3380  _M_Impl = _Other._M_Impl;
3381  }
3382  return *this;
3383  }
3384 
3395 
3396  task& operator=(task&& _Other)
3397  {
3398  if (this != &_Other)
3399  {
3400  _M_Impl = std::move(_Other._M_Impl);
3401  }
3402  return *this;
3403  }
3404 
3424 
3425  template<typename _Function>
3426  __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
3427  auto then(const _Function& _Func) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
3428  {
3429  task_options _TaskOptions;
3430  details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
3431  return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
3432  }
3433 
3457 
3458  template<typename _Function>
3459  __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
3460  auto then(const _Function& _Func, task_options _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
3461  {
3462  details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
3463  return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
3464  }
3465 
3493 
3494  template<typename _Function>
3495  __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
3496  auto then(const _Function& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
3497  {
3498  task_options _TaskOptions(_CancellationToken, _ContinuationContext);
3499  details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
3500  return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
3501  }
3502 
3511 
3512  task_status wait() const
3513  {
3514  if (!_M_Impl)
3515  {
3516  throw invalid_operation("wait() cannot be called on a default constructed task.");
3517  }
3518 
3519  return _M_Impl->_Wait();
3520  }
3521 
3533 
3534  _ReturnType get() const
3535  {
3536  if (!_M_Impl)
3537  {
3538  throw invalid_operation("get() cannot be called on a default constructed task.");
3539  }
3540 
3541  if (_M_Impl->_Wait() == canceled)
3542  {
3543  throw task_canceled();
3544  }
3545 
3546  return _M_Impl->_GetResult();
3547  }
3548 
3558  bool is_done() const
3559  {
3560  if (!_M_Impl)
3561  {
3562  throw invalid_operation("is_done() cannot be called on a default constructed task.");
3563  }
3564 
3565  return _M_Impl->_IsDone();
3566  }
3567 
3575  {
3576  if (!_M_Impl)
3577  {
3578  throw invalid_operation("scheduler() cannot be called on a default constructed task.");
3579  }
3580 
3581  return _M_Impl->_GetScheduler();
3582  }
3583 
3590 
3591  bool is_apartment_aware() const
3592  {
3593  if (!_M_Impl)
3594  {
3595  throw invalid_operation("is_apartment_aware() cannot be called on a default constructed task.");
3596  }
3597  return _M_Impl->_IsApartmentAware();
3598  }
3599 
3606 
3607  bool operator==(const task<_ReturnType>& _Rhs) const
3608  {
3609  return (_M_Impl == _Rhs._M_Impl);
3610  }
3611 
3618 
3619  bool operator!=(const task<_ReturnType>& _Rhs) const
3620  {
3621  return !operator==(_Rhs);
3622  }
3623 
3628  {
3629  _ASSERTE(_Ct != nullptr);
3630  _M_Impl = details::_Task_ptr<_ReturnType>::_Make(_Ct, _Scheduler);
3631  if (_Ct != details::_CancellationTokenState::_None())
3632  {
3633  _M_Impl->_RegisterCancellation(_M_Impl);
3634  }
3635  }
3636 
3640  const typename details::_Task_ptr<_ReturnType>::_Type & _GetImpl() const
3641  {
3642  return _M_Impl;
3643  }
3644 
3648  void _SetImpl(const typename details::_Task_ptr<_ReturnType>::_Type & _Impl)
3649  {
3650  _ASSERTE(!_M_Impl);
3651  _M_Impl = _Impl;
3652  }
3653 
3657  void _SetImpl(typename details::_Task_ptr<_ReturnType>::_Type && _Impl)
3658  {
3659  _ASSERTE(!_M_Impl);
3660  _M_Impl = std::move(_Impl);
3661  }
3662 
3666  void _SetAsync(bool _Async = true)
3667  {
3668  _GetImpl()->_SetAsync(_Async);
3669  }
3670 
3675  {
3676  _GetImpl()->_SetTaskCreationCallstack(_callstack);
3677  }
3678 
3684  template<typename _Function>
3685  auto _Then(const _Function& _Func, details::_CancellationTokenState *_PTokenState,
3686  details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
3687  {
3688  // inherit from antecedent
3689  auto _Scheduler = _GetImpl()->_GetScheduler();
3690 
3691  return _ThenImpl<_ReturnType, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);
3692  }
3693 
3694 private:
3695  template <typename T> friend class task;
3696 
3697 
3698  // The task handle type used to construct an 'initial task' - a task with no dependents.
3699  template <typename _InternalReturnType, typename _Function, typename _TypeSelection>
3700  struct _InitialTaskHandle :
3701  details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore_t>
3702  {
3703  _Function _M_function;
3704  _InitialTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _TaskImpl, const _Function & _func)
3705  : details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore_t>::_PPLTaskHandle(_TaskImpl)
3706  , _M_function(_func)
3707  {
3708  }
3709 
3710  virtual ~_InitialTaskHandle() {}
3711 
3712  template <typename _Func>
3713  auto _LogWorkItemAndInvokeUserLambda(_Func && _func) const -> decltype(_func())
3714  {
3715  details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger);
3716  CASABLANCA_UNREFERENCED_PARAMETER(_LogWorkItem);
3717  return _func();
3718  }
3719 
3720  void _Perform() const
3721  {
3722  _Init(_TypeSelection());
3723  }
3724 
3725  void _SyncCancelAndPropagateException() const
3726  {
3727  this->_M_pTask->_Cancel(true);
3728  }
3729 
3730  //
3731  // Overload 0: returns _InternalReturnType
3732  //
3733  // This is the most basic task with no unwrapping
3734  //
3735  void _Init(details::_TypeSelectorNoAsync) const
3736  {
3737  this->_M_pTask->_FinalizeAndRunContinuations(_LogWorkItemAndInvokeUserLambda(_Init_func_transformer<_InternalReturnType>::_Perform(_M_function)));
3738  }
3739 
3740  //
3741  // Overload 1: returns IAsyncOperation<_InternalReturnType>^ (only uder /ZW)
3742  // or
3743  // returns task<_InternalReturnType>
3744  //
3745  // This is task whose functor returns an async operation or a task which will be unwrapped for continuation
3746  // Depending on the output type, the right _AsyncInit gets invoked
3747  //
3748  void _Init(details::_TypeSelectorAsyncOperationOrTask) const
3749  {
3750  details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, _LogWorkItemAndInvokeUserLambda(_M_function));
3751  }
3752 
3753 #if defined (__cplusplus_winrt)
3754  //
3755  // Overload 2: returns IAsyncAction^
3756  //
3757  // This is task whose functor returns an async action which will be unwrapped for continuation
3758  //
3759  void _Init(details::_TypeSelectorAsyncAction) const
3760  {
3761  details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda(_M_function)));
3762  }
3763 
3764  //
3765  // Overload 3: returns IAsyncOperationWithProgress<_InternalReturnType, _ProgressType>^
3766  //
3767  // This is task whose functor returns an async operation with progress which will be unwrapped for continuation
3768  //
3769  void _Init(details::_TypeSelectorAsyncOperationWithProgress) const
3770  {
3771  typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;
3772 
3773  details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask,
3774  ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_InternalReturnType,_ProgressType>(_LogWorkItemAndInvokeUserLambda(_M_function)));
3775  }
3776 
3777  //
3778  // Overload 4: returns IAsyncActionWithProgress<_ProgressType>^
3779  //
3780  // This is task whose functor returns an async action with progress which will be unwrapped for continuation
3781  //
3782  void _Init(details::_TypeSelectorAsyncActionWithProgress) const
3783  {
3784  typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;
3785 
3786  details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask,
3787  ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(_LogWorkItemAndInvokeUserLambda(_M_function)));
3788  }
3789 #endif /* defined (__cplusplus_winrt) */
3790  };
3791 
3792 
3796  template <typename _InternalReturnType, typename _ContinuationReturnType, typename _Function, typename _IsTaskBased, typename _TypeSelection>
3797  struct _ContinuationTaskHandle :
3798  details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,
3799  _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>
3800  {
3801  typedef typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type _NormalizedContinuationReturnType;
3802 
3803  typename details::_Task_ptr<_ReturnType>::_Type _M_ancestorTaskImpl;
3804  _Function _M_function;
3805 
3806  _ContinuationTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _AncestorImpl,
3807  const typename details::_Task_ptr<_NormalizedContinuationReturnType>::_Type & _ContinuationImpl,
3808  const _Function & _Func, const task_continuation_context & _Context, details::_TaskInliningMode_t _InliningMode)
3809  : details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,
3810  _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>
3811  ::_PPLTaskHandle(_ContinuationImpl)
3812  , _M_ancestorTaskImpl(_AncestorImpl)
3813  , _M_function(_Func)
3814  {
3815  this->_M_isTaskBasedContinuation = _IsTaskBased::value;
3816  this->_M_continuationContext = _Context;
3817  this->_M_continuationContext._Resolve(_AncestorImpl->_IsApartmentAware());
3818  this->_M_inliningMode = _InliningMode;
3819  }
3820 
3821  virtual ~_ContinuationTaskHandle() {}
3822 
3823  template <typename _Func, typename _Arg>
3824  auto _LogWorkItemAndInvokeUserLambda(_Func && _func, _Arg && _value) const -> decltype(_func(std::forward<_Arg>(_value)))
3825  {
3826  details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger);
3827  CASABLANCA_UNREFERENCED_PARAMETER(_LogWorkItem);
3828  return _func(std::forward<_Arg>(_value));
3829  }
3830 
3831  void _Perform() const
3832  {
3833  _Continue(_IsTaskBased(), _TypeSelection());
3834  }
3835 
3836  void _SyncCancelAndPropagateException() const
3837  {
3838  if (_M_ancestorTaskImpl->_HasUserException())
3839  {
3840  // If the ancestor encountered an exception, transfer the exception to the continuation
3841  // This traverses down the tree to propagate the exception.
3842  this->_M_pTask->_CancelWithExceptionHolder(_M_ancestorTaskImpl->_GetExceptionHolder(), true);
3843  }
3844  else
3845  {
3846  // If the ancestor was canceled, then your own execution should be canceled.
3847  // This traverses down the tree to cancel it.
3848  this->_M_pTask->_Cancel(true);
3849  }
3850  }
3851 
3852  //
3853  // Overload 0-0: _InternalReturnType -> _TaskType
3854  //
3855  // This is a straight task continuation which simply invokes its target with the ancestor's completion argument
3856  //
3857  void _Continue(std::false_type, details::_TypeSelectorNoAsync) const
3858  {
3859  this->_M_pTask->_FinalizeAndRunContinuations(
3860  _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult()));
3861  }
3862 
3863  //
3864  // Overload 0-1: _InternalReturnType -> IAsyncOperation<_TaskType>^ (only uder /ZW)
3865  // or
3866  // _InternalReturnType -> task<_TaskType>
3867  //
3868  // This is a straight task continuation which returns an async operation or a task which will be unwrapped for continuation
3869  // Depending on the output type, the right _AsyncInit gets invoked
3870  //
3871  void _Continue(std::false_type, details::_TypeSelectorAsyncOperationOrTask) const
3872  {
3873  typedef typename details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
3874 
3875  details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
3876  this->_M_pTask,
3877  _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult())
3878  );
3879  }
3880 
3881 #if defined (__cplusplus_winrt)
3882  //
3883  // Overload 0-2: _InternalReturnType -> IAsyncAction^
3884  //
3885  // This is a straight task continuation which returns an async action which will be unwrapped for continuation
3886  //
3887  void _Continue(std::false_type, details::_TypeSelectorAsyncAction) const
3888  {
3889  typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
3890 
3891  details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
3892  this->_M_pTask,
3893  ref new details::_IAsyncActionToAsyncOperationConverter(
3894  _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult())));
3895  }
3896 
3897  //
3898  // Overload 0-3: _InternalReturnType -> IAsyncOperationWithProgress<_TaskType, _ProgressType>^
3899  //
3900  // This is a straight task continuation which returns an async operation with progress which will be unwrapped for continuation
3901  //
3902  void _Continue(std::false_type, details::_TypeSelectorAsyncOperationWithProgress) const
3903  {
3904  typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
3905 
3906  auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult());
3907  typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;
3908 
3909  details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
3910  this->_M_pTask,
3911  ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>(_OpWithProgress));
3912  }
3913 
3914  //
3915  // Overload 0-4: _InternalReturnType -> IAsyncActionWithProgress<_ProgressType>^
3916  //
3917  // This is a straight task continuation which returns an async action with progress which will be unwrapped for continuation
3918  //
3919  void _Continue(std::false_type, details::_TypeSelectorAsyncActionWithProgress) const
3920  {
3921  typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
3922 
3923  auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult());
3924  typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;
3925 
3926  details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
3927  this->_M_pTask,
3928  ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(_OpWithProgress));
3929  }
3930 
3931 #endif /* defined (__cplusplus_winrt) */
3932 
3933  //
3934  // Overload 1-0: task<_InternalReturnType> -> _TaskType
3935  //
3936  // This is an exception handling type of continuation which takes the task rather than the task's result.
3937  //
3938  void _Continue(std::true_type, details::_TypeSelectorNoAsync) const
3939  {
3940  typedef task<_InternalReturnType> _FuncInputType;
3941  task<_InternalReturnType> _ResultTask;
3942  _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
3943  this->_M_pTask->_FinalizeAndRunContinuations(
3944  _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function), std::move(_ResultTask)));
3945  }
3946 
3947  //
3948  // Overload 1-1: task<_InternalReturnType> -> IAsyncOperation<_TaskType>^
3949  // or
3950  // task<_TaskType>
3951  //
3952  // This is an exception handling type of continuation which takes the task rather than
3953  // the task's result. It also returns an async operation or a task which will be unwrapped
3954  // for continuation
3955  //
3956  void _Continue(std::true_type, details::_TypeSelectorAsyncOperationOrTask) const
3957  {
3958  // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
3959  task<_InternalReturnType> _ResultTask;
3960  _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
3961  details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,
3962  _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask)));
3963  }
3964 
3965 #if defined (__cplusplus_winrt)
3966 
3967  //
3968  // Overload 1-2: task<_InternalReturnType> -> IAsyncAction^
3969  //
3970  // This is an exception handling type of continuation which takes the task rather than
3971  // the task's result. It also returns an async action which will be unwrapped for continuation
3972  //
3973  void _Continue(std::true_type, details::_TypeSelectorAsyncAction) const
3974  {
3975  // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
3976  task<_InternalReturnType> _ResultTask;
3977  _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
3978  details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,
3979  ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));
3980  }
3981 
3982  //
3983  // Overload 1-3: task<_InternalReturnType> -> IAsyncOperationWithProgress<_TaskType, _ProgressType>^
3984  //
3985  // This is an exception handling type of continuation which takes the task rather than
3986  // the task's result. It also returns an async operation with progress which will be unwrapped
3987  // for continuation
3988  //
3989  void _Continue(std::true_type, details::_TypeSelectorAsyncOperationWithProgress) const
3990  {
3991  // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
3992  task<_InternalReturnType> _ResultTask;
3993  _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
3994 
3995  typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;
3996 
3997  details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,
3998  ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>(
3999  _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));
4000  }
4001 
4002  //
4003  // Overload 1-4: task<_InternalReturnType> -> IAsyncActionWithProgress<_ProgressType>^
4004  //
4005  // This is an exception handling type of continuation which takes the task rather than
4006  // the task's result. It also returns an async operation with progress which will be unwrapped
4007  // for continuation
4008  //
4009  void _Continue(std::true_type, details::_TypeSelectorAsyncActionWithProgress) const
4010  {
4011  // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
4012  task<_InternalReturnType> _ResultTask;
4013  _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
4014 
4015  typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;
4016 
4017  details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,
4018  ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(
4019  _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));
4020  }
4021 #endif /* defined (__cplusplus_winrt) */
4022  };
4023 
4027  template<typename _InternalReturnType, typename _Function>
4028  void _TaskInitWithFunctor(const _Function& _Func)
4029  {
4030  typedef typename details::_InitFunctorTypeTraits<_InternalReturnType, decltype(_Func())> _Async_type_traits;
4031 
4032  _M_Impl->_M_fFromAsync = _Async_type_traits::_IsAsyncTask;
4033  _M_Impl->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;
4034  _M_Impl->_M_taskEventLogger._LogScheduleTask(false);
4035  _M_Impl->_ScheduleTask(new _InitialTaskHandle<_InternalReturnType, _Function, typename _Async_type_traits::_AsyncKind>(_GetImpl(), _Func), details::_NoInline);
4036  }
4037 
4041  void _TaskInitNoFunctor(task_completion_event<_ReturnType>& _Event)
4042  {
4043  _Event._RegisterTask(_M_Impl);
4044  }
4045 
4046 #if defined (__cplusplus_winrt)
4047  void _TaskInitAsyncOp(Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)
4051  {
4052  _M_Impl->_M_fFromAsync = true;
4053 
4054  // Mark this task as started here since we can set the state in the constructor without acquiring a lock. Once _AsyncInit
4055  // returns a completion could execute concurrently and the task must be fully initialized before that happens.
4056  _M_Impl->_M_TaskState = details::_Task_impl_base::_Started;
4057  // Pass the shared pointer into _AsyncInit for storage in the Async Callback.
4058  details::_Task_impl_base::_AsyncInit<_ReturnType, _ReturnType>(_M_Impl, _AsyncOp);
4059  }
4060 
4064  void _TaskInitNoFunctor(Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)
4065  {
4066  _TaskInitAsyncOp(_AsyncOp);
4067  }
4068 
4072  template<typename _Progress>
4073  void _TaskInitNoFunctor(Windows::Foundation::IAsyncOperationWithProgress<typename details::_ValueTypeOrRefType<_ReturnType>::_Value, _Progress>^ _AsyncOp)
4074  {
4075  _TaskInitAsyncOp(ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<typename details::_ValueTypeOrRefType<_ReturnType>::_Value, _Progress>(_AsyncOp));
4076  }
4077 #endif /* defined (__cplusplus_winrt) */
4078 
4082  template<typename _Function>
4083  void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)
4084  {
4085  _TaskInitWithFunctor<_ReturnType, _Function>(_Func);
4086  }
4087 
4091  template<typename _Ty>
4092  void _TaskInitMaybeFunctor(_Ty & _Param, std::false_type)
4093  {
4094  _TaskInitNoFunctor(_Param);
4095  }
4096 
4097  template<typename _InternalReturnType, typename _Function>
4098  auto _ThenImpl(const _Function& _Func, const task_options& _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
4099  {
4100  if (!_M_Impl)
4101  {
4102  throw invalid_operation("then() cannot be called on a default constructed task.");
4103  }
4104 
4105  details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
4106  auto _Scheduler = _TaskOptions.has_scheduler() ? _TaskOptions.get_scheduler() : _GetImpl()->_GetScheduler();
4107  auto _CreationStack = details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : details::_TaskCreationCallstack();
4108  return _ThenImpl<_InternalReturnType, _Function>(_Func, _PTokenState, _TaskOptions.get_continuation_context(), _Scheduler, _CreationStack);
4109  }
4110 
4114  template<typename _InternalReturnType, typename _Function>
4115  auto _ThenImpl(const _Function& _Func, details::_CancellationTokenState *_PTokenState, const task_continuation_context& _ContinuationContext, scheduler_ptr _Scheduler, details::_TaskCreationCallstack _CreationStack,
4116  details::_TaskInliningMode_t _InliningMode = details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
4117  {
4118  if (!_M_Impl)
4119  {
4120  throw invalid_operation("then() cannot be called on a default constructed task.");
4121  }
4122 
4123  typedef details::_FunctionTypeTraits<_Function, _InternalReturnType> _Function_type_traits;
4124  typedef details::_TaskTypeTraits<typename _Function_type_traits::_FuncRetType> _Async_type_traits;
4125  typedef typename _Async_type_traits::_TaskRetType _TaskType;
4126 
4127  //
4128  // 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
4129  // an exception handling continuation. In that case, we break the chain with a _None. That continuation is never canceled unless the user
4130  // explicitly passes the same token.
4131  //
4132  if (_PTokenState == nullptr)
4133  {
4134  if (_Function_type_traits::_Takes_task::value)
4135  {
4136  _PTokenState = details::_CancellationTokenState::_None();
4137  }
4138  else
4139  {
4140  _PTokenState = _GetImpl()->_M_pTokenState;
4141  }
4142  }
4143 
4144  task<_TaskType> _ContinuationTask;
4145  _ContinuationTask._CreateImpl(_PTokenState, _Scheduler);
4146 
4147  _ContinuationTask._GetImpl()->_M_fFromAsync = (_GetImpl()->_M_fFromAsync || _Async_type_traits::_IsAsyncTask);
4148  _ContinuationTask._GetImpl()->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;
4149  _ContinuationTask._SetTaskCreationCallstack(_CreationStack);
4150 
4151  _GetImpl()->_ScheduleContinuation(new _ContinuationTaskHandle<_InternalReturnType, _TaskType, _Function, typename _Function_type_traits::_Takes_task, typename _Async_type_traits::_AsyncKind>(
4152  _GetImpl(), _ContinuationTask._GetImpl(), _Func, _ContinuationContext, _InliningMode));
4153 
4154  return _ContinuationTask;
4155  }
4156 
4157  // The underlying implementation for this task
4158  typename details::_Task_ptr<_ReturnType>::_Type _M_Impl;
4159 };
4160 
4171 
4172 template<>
4173 class task<void>
4174 {
4175 public:
4179 
4180  typedef void result_type;
4181 
4203 
4204  task() : _M_unitTask()
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 
4240 
4241  template<typename _Ty>
4242  __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
4243  explicit task(_Ty _Param, const task_options& _TaskOptions = task_options())
4244  {
4245  details::_ValidateTaskConstructorArgs<void,_Ty>(_Param);
4246 
4247  _M_unitTask._CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());
4248  // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.
4249  _M_unitTask._SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK());
4250 
4251  _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));
4252  }
4253 
4278 
4279  task(const task& _Other): _M_unitTask(_Other._M_unitTask){}
4280 
4305 
4306  task(task&& _Other) : _M_unitTask(std::move(_Other._M_unitTask)) {}
4307 
4318 
4319  task& operator=(const task& _Other)
4320  {
4321  if (this != &_Other)
4322  {
4323  _M_unitTask = _Other._M_unitTask;
4324  }
4325  return *this;
4326  }
4327 
4338 
4339  task& operator=(task&& _Other)
4340  {
4341  if (this != &_Other)
4342  {
4343  _M_unitTask = std::move(_Other._M_unitTask);
4344  }
4345  return *this;
4346  }
4347 
4371 
4372  template<typename _Function>
4373  __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
4374  auto then(const _Function& _Func, task_options _TaskOptions = task_options()) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
4375  {
4376  details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
4377  return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);
4378  }
4379 
4407 
4408  template<typename _Function>
4409  __declspec(noinline) // Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
4410  auto then(const _Function& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
4411  {
4412  task_options _TaskOptions(_CancellationToken, _ContinuationContext);
4413  details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
4414  return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);
4415  }
4416 
4425 
4426  task_status wait() const
4427  {
4428  return _M_unitTask.wait();
4429  }
4430 
4439 
4440  void get() const
4441  {
4442  _M_unitTask.get();
4443  }
4444 
4454  bool is_done() const
4455  {
4456  return _M_unitTask.is_done();
4457  }
4458 
4466  {
4467  return _M_unitTask.scheduler();
4468  }
4469 
4476 
4477  bool is_apartment_aware() const
4478  {
4479  return _M_unitTask.is_apartment_aware();
4480  }
4481 
4488 
4489  bool operator==(const task<void>& _Rhs) const
4490  {
4491  return (_M_unitTask == _Rhs._M_unitTask);
4492  }
4493 
4500 
4501  bool operator!=(const task<void>& _Rhs) const
4502  {
4503  return !operator==(_Rhs);
4504  }
4505 
4510  {
4511  _M_unitTask._CreateImpl(_Ct, _Scheduler);
4512  }
4513 
4517  const details::_Task_ptr<details::_Unit_type>::_Type & _GetImpl() const
4518  {
4519  return _M_unitTask._M_Impl;
4520  }
4521 
4525  void _SetImpl(const details::_Task_ptr<details::_Unit_type>::_Type & _Impl)
4526  {
4527  _M_unitTask._SetImpl(_Impl);
4528  }
4529 
4533  void _SetImpl(details::_Task_ptr<details::_Unit_type>::_Type && _Impl)
4534  {
4535  _M_unitTask._SetImpl(std::move(_Impl));
4536  }
4537 
4541  void _SetAsync(bool _Async = true)
4542  {
4543  _M_unitTask._SetAsync(_Async);
4544  }
4545 
4550  {
4551  _M_unitTask._SetTaskCreationCallstack(_callstack);
4552  }
4553 
4557  template<typename _Function>
4558  auto _Then(const _Function& _Func, details::_CancellationTokenState *_PTokenState,
4559  details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
4560  {
4561  // inherit from antecedent
4562  auto _Scheduler = _GetImpl()->_GetScheduler();
4563 
4564  return _M_unitTask._ThenImpl<void, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);
4565  }
4566 
4567 private:
4568  template <typename T> friend class task;
4569  template <typename T> friend class task_completion_event;
4570 
4574  void _TaskInitNoFunctor(task_completion_event<void>& _Event)
4575  {
4576  _M_unitTask._TaskInitNoFunctor(_Event._M_unitEvent);
4577  }
4578 
4579 #if defined (__cplusplus_winrt)
4580  void _TaskInitNoFunctor(Windows::Foundation::IAsyncAction^ _AsyncAction)
4584  {
4585  _M_unitTask._TaskInitAsyncOp(ref new details::_IAsyncActionToAsyncOperationConverter(_AsyncAction));
4586  }
4587 
4591  template<typename _P>
4592  void _TaskInitNoFunctor(Windows::Foundation::IAsyncActionWithProgress<_P>^ _AsyncActionWithProgress)
4593  {
4594  _M_unitTask._TaskInitAsyncOp(ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_P>(_AsyncActionWithProgress));
4595  }
4596 #endif /* defined (__cplusplus_winrt) */
4597 
4601  template<typename _Function>
4602  void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)
4603  {
4604  _M_unitTask._TaskInitWithFunctor<void, _Function>(_Func);
4605  }
4606 
4610  template<typename _T>
4611  void _TaskInitMaybeFunctor(_T & _Param, std::false_type)
4612  {
4613  _TaskInitNoFunctor(_Param);
4614  }
4615 
4616  // The void task contains a task of a dummy type so common code can be used for tasks with void and non-void results.
4617  task<details::_Unit_type> _M_unitTask;
4618 };
4619 
4620 namespace details
4621 {
4625 
4626 #if defined (__cplusplus_winrt)
4627  // Unwrap functions for asyncOperations
4628  template<typename _Ty>
4629  _Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperation<_Ty>^);
4630 
4631  void _GetUnwrappedType(Windows::Foundation::IAsyncAction^);
4632 
4633  template<typename _Ty, typename _Progress>
4634  _Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperationWithProgress<_Ty, _Progress>^);
4635 
4636  template<typename _Progress>
4637  void _GetUnwrappedType(Windows::Foundation::IAsyncActionWithProgress<_Progress>^);
4638 #endif /* defined (__cplusplus_winrt) */
4639 
4640  // Unwrap task<T>
4641  template<typename _Ty>
4642  _Ty _GetUnwrappedType(task<_Ty>);
4643 
4644  // Unwrap all supportted types
4645  template<typename _Ty>
4646  auto _GetUnwrappedReturnType(_Ty _Arg, int) -> decltype(_GetUnwrappedType(_Arg));
4647  // fallback
4648  template<typename _Ty>
4649  _Ty _GetUnwrappedReturnType(_Ty, ...);
4650 
4656 
4657  // Non-Callable
4658  template<typename _Ty>
4659  _Ty _GetTaskType(task_completion_event<_Ty>, std::false_type);
4660 
4661  // Non-Callable
4662  template<typename _Ty>
4663  auto _GetTaskType(_Ty _NonFunc, std::false_type) -> decltype(_GetUnwrappedType(_NonFunc));
4664 
4665  // Callable
4666  template<typename _Ty>
4667  auto _GetTaskType(_Ty _Func, std::true_type) -> decltype(_GetUnwrappedReturnType(_Func(), 0));
4668 
4669  // Special callable returns void
4670  void _GetTaskType(std::function<void()>, std::true_type);
4671  struct _BadArgType{};
4672 
4673  template<typename _Ty>
4674  auto _FilterValidTaskType(_Ty _Param, int) -> decltype(_GetTaskType(_Param, _IsCallable(_Param, 0)));
4675 
4676  template<typename _Ty>
4677  _BadArgType _FilterValidTaskType(_Ty _Param, ...);
4678 
4679  template<typename _Ty>
4681  {
4682  typedef decltype(_FilterValidTaskType(stdx::declval<_Ty>(), 0)) _Type;
4683  };
4684 } // namespace details
4685 
4713 
4714 template<typename _Ty>
4715 __declspec(noinline)
4716 auto create_task(_Ty _Param, task_options _TaskOptions = task_options()) -> task<typename details::_TaskTypeFromParam<_Ty>::_Type>
4717 {
4718  static_assert(!std::is_same<typename details::_TaskTypeFromParam<_Ty>::_Type,details::_BadArgType>::value,
4719 #if defined (__cplusplus_winrt)
4720  "incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event"
4721 #else /* defined (__cplusplus_winrt) */
4722  "incorrect argument for create_task; can be a callable object or a task_completion_event"
4723 #endif /* defined (__cplusplus_winrt) */
4724  );
4725  details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
4726  task<typename details::_TaskTypeFromParam<_Ty>::_Type> _CreatedTask(_Param, _TaskOptions);
4727  return _CreatedTask;
4728 }
4729 
4760 
4761 template<typename _ReturnType>
4762 __declspec(noinline)
4763 task<_ReturnType> create_task(const task<_ReturnType>& _Task)
4764 {
4765  task<_ReturnType> _CreatedTask(_Task);
4766  return _CreatedTask;
4767 }
4768 
4769 #if defined (__cplusplus_winrt)
4770 namespace details
4771 {
4772  template<typename _T>
4773  task<_T> _To_task_helper(Windows::Foundation::IAsyncOperation<_T>^ op)
4774  {
4775  return task<_T>(op);
4776  }
4777 
4778  template<typename _T, typename _Progress>
4779  task<_T> _To_task_helper(Windows::Foundation::IAsyncOperationWithProgress<_T, _Progress>^ op)
4780  {
4781  return task<_T>(op);
4782  }
4783 
4784  inline task<void> _To_task_helper(Windows::Foundation::IAsyncAction^ op)
4785  {
4786  return task<void>(op);
4787  }
4788 
4789  template<typename _Progress>
4790  task<void> _To_task_helper(Windows::Foundation::IAsyncActionWithProgress<_Progress>^ op)
4791  {
4792  return task<void>(op);
4793  }
4794 
4795  template<typename _ProgressType>
4796  class _ProgressDispatcherBase
4797  {
4798  public:
4799 
4800  virtual ~_ProgressDispatcherBase()
4801  {
4802  }
4803 
4804  virtual void _Report(const _ProgressType& _Val) = 0;
4805  };
4806 
4807  template<typename _ProgressType, typename _ClassPtrType>
4808  class _ProgressDispatcher : public _ProgressDispatcherBase<_ProgressType>
4809  {
4810  public:
4811 
4812  virtual ~_ProgressDispatcher()
4813  {
4814  }
4815 
4816  _ProgressDispatcher(_ClassPtrType _Ptr) : _M_ptr(_Ptr)
4817  {
4818  }
4819 
4820  virtual void _Report(const _ProgressType& _Val)
4821  {
4822  _M_ptr->_FireProgress(_Val);
4823  }
4824 
4825  private:
4826 
4827  _ClassPtrType _M_ptr;
4828  };
4829  class _ProgressReporterCtorArgType{};
4830 } // namespace details
4831 
4843 
4844 template<typename _ProgressType>
4845 class progress_reporter
4846 {
4847  typedef std::shared_ptr<details::_ProgressDispatcherBase<_ProgressType>> _PtrType;
4848 
4849 public:
4850 
4857 
4858  void report(const _ProgressType& _Val) const
4859  {
4860  _M_dispatcher->_Report(_Val);
4861  }
4862 
4863  template<typename _ClassPtrType>
4864  static progress_reporter _CreateReporter(_ClassPtrType _Ptr)
4865  {
4866  progress_reporter _Reporter;
4867  details::_ProgressDispatcherBase<_ProgressType> *_PDispatcher = new details::_ProgressDispatcher<_ProgressType, _ClassPtrType>(_Ptr);
4868  _Reporter._M_dispatcher = _PtrType(_PDispatcher);
4869  return _Reporter;
4870  }
4871  progress_reporter() {}
4872 
4873 private:
4874  progress_reporter(details::_ProgressReporterCtorArgType);
4875 
4876  _PtrType _M_dispatcher;
4877 };
4878 
4879 namespace details
4880 {
4881  //
4882  // maps internal definitions for AsyncStatus and defines states that are not client visible
4883  //
4884  enum _AsyncStatusInternal
4885  {
4886  _AsyncCreated = -1, // externally invisible
4887  // client visible states (must match AsyncStatus exactly)
4888  _AsyncStarted = 0, // Windows::Foundation::AsyncStatus::Started,
4889  _AsyncCompleted = 1, // Windows::Foundation::AsyncStatus::Completed,
4890  _AsyncCanceled = 2, // Windows::Foundation::AsyncStatus::Canceled,
4891  _AsyncError = 3, // Windows::Foundation::AsyncStatus::Error,
4892  // non-client visible internal states
4893  _AsyncCancelPending,
4894  _AsyncClosed,
4895  _AsyncUndefined
4896  };
4897 
4898  //
4899  // designates whether the "GetResults" method returns a single result (after complete fires) or multiple results
4900  // (which are progressively consumable between Start state and before Close is called)
4901  //
4902  enum _AsyncResultType
4903  {
4904  SingleResult = 0x0001,
4905  MultipleResults = 0x0002
4906  };
4907 
4908  // ***************************************************************************
4909  // Template type traits and helpers for async production APIs:
4910  //
4911 
4912  struct _ZeroArgumentFunctor { };
4913  struct _OneArgumentFunctor { };
4914  struct _TwoArgumentFunctor { };
4915 
4916  // ****************************************
4917  // CLASS TYPES:
4918 
4919  // ********************
4920  // TWO ARGUMENTS:
4921 
4922  // non-void arg:
4923  template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
4924  _Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);
4925 
4926  // non-void arg:
4927  template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
4928  _Arg2 _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);
4929 
4930  template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
4931  _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);
4932 
4933  template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
4934  _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1, _Arg2) const);
4935 
4936  // ********************
4937  // ONE ARGUMENT:
4938 
4939  // non-void arg:
4940  template<typename _Class, typename _ReturnType, typename _Arg1>
4941  _Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);
4942 
4943  // non-void arg:
4944  template<typename _Class, typename _ReturnType, typename _Arg1>
4945  void _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);
4946 
4947  template<typename _Class, typename _ReturnType, typename _Arg1>
4948  _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);
4949 
4950  template<typename _Class, typename _ReturnType, typename _Arg1>
4951  _OneArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1) const);
4952 
4953  // ********************
4954  // ZERO ARGUMENT:
4955 
4956  // void arg:
4957  template<typename _Class, typename _ReturnType>
4958  void _Arg1ClassHelperThunk(_ReturnType (_Class::*)() const);
4959 
4960  // void arg:
4961  template<typename _Class, typename _ReturnType>
4962  void _Arg2ClassHelperThunk(_ReturnType (_Class::*)() const);
4963 
4964  // void arg:
4965  template<typename _Class, typename _ReturnType>
4966  _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)() const);
4967 
4968  template<typename _Class, typename _ReturnType>
4969  _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)() const);
4970 
4971  // ****************************************
4972  // POINTER TYPES:
4973 
4974  // ********************
4975  // TWO ARGUMENTS:
4976 
4977  template<typename _ReturnType, typename _Arg1, typename _Arg2>
4978  _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
4979 
4980  template<typename _ReturnType, typename _Arg1, typename _Arg2>
4981  _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
4982 
4983  template<typename _ReturnType, typename _Arg1, typename _Arg2>
4984  _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
4985 
4986  template<typename _ReturnType, typename _Arg1, typename _Arg2>
4987  _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2));
4988 
4989  template<typename _ReturnType, typename _Arg1, typename _Arg2>
4990  _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
4991 
4992  template<typename _ReturnType, typename _Arg1, typename _Arg2>
4993  _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
4994 
4995  template<typename _ReturnType, typename _Arg1, typename _Arg2>
4996  _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
4997 
4998  template<typename _ReturnType, typename _Arg1, typename _Arg2>
4999  _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2));
5000 
5001  template<typename _ReturnType, typename _Arg1, typename _Arg2>
5002  _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
5003 
5004  template<typename _ReturnType, typename _Arg1, typename _Arg2>
5005  _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
5006 
5007  template<typename _ReturnType, typename _Arg1, typename _Arg2>
5008  _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
5009 
5010  template<typename _ReturnType, typename _Arg1, typename _Arg2>
5011  _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2));
5012 
5013  // ********************
5014  // ONE ARGUMENT:
5015 
5016  template<typename _ReturnType, typename _Arg1>
5017  _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
5018 
5019  template<typename _ReturnType, typename _Arg1>
5020  void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
5021 
5022  template<typename _ReturnType, typename _Arg1>
5023  _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
5024 
5025  template<typename _ReturnType, typename _Arg1>
5026  _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1));
5027 
5028  template<typename _ReturnType, typename _Arg1>
5029  _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
5030 
5031  template<typename _ReturnType, typename _Arg1>
5032  void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
5033 
5034  template<typename _ReturnType, typename _Arg1>
5035  _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
5036 
5037  template<typename _ReturnType, typename _Arg1>
5038  _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1));
5039 
5040  template<typename _ReturnType, typename _Arg1>
5041  _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
5042 
5043  template<typename _ReturnType, typename _Arg1>
5044  void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
5045 
5046  template<typename _ReturnType, typename _Arg1>
5047  _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
5048 
5049  template<typename _ReturnType, typename _Arg1>
5050  _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1));
5051 
5052  // ********************
5053  // ZERO ARGUMENT:
5054 
5055  template<typename _ReturnType>
5056  void _Arg1PFNHelperThunk(_ReturnType(__cdecl *)());
5057 
5058  template<typename _ReturnType>
5059  void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)());
5060 
5061  template<typename _ReturnType>
5062  _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)());
5063 
5064  template<typename _ReturnType>
5065  _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)());
5066 
5067  template<typename _ReturnType>
5068  void _Arg1PFNHelperThunk(_ReturnType(__stdcall *)());
5069 
5070  template<typename _ReturnType>
5071  void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)());
5072 
5073  template<typename _ReturnType>
5074  _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)());
5075 
5076  template<typename _ReturnType>
5077  _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)());
5078 
5079  template<typename _ReturnType>
5080  void _Arg1PFNHelperThunk(_ReturnType(__fastcall *)());
5081 
5082  template<typename _ReturnType>
5083  void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)());
5084 
5085  template<typename _ReturnType>
5086  _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)());
5087 
5088  template<typename _ReturnType>
5089  _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)());
5090 
5091  template<typename _T>
5092  struct _FunctorArguments
5093  {
5094  static const size_t _Count = 0;
5095  };
5096 
5097  template<>
5098  struct _FunctorArguments<_OneArgumentFunctor>
5099  {
5100  static const size_t _Count = 1;
5101  };
5102 
5103  template<>
5104  struct _FunctorArguments<_TwoArgumentFunctor>
5105  {
5106  static const size_t _Count = 2;
5107  };
5108 
5109  template<typename _T>
5110  struct _FunctorTypeTraits
5111  {
5112  typedef decltype(_ArgumentCountHelper(&(_T::operator()))) _ArgumentCountType;
5113  static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;
5114 
5115  typedef decltype(_ReturnTypeClassHelperThunk(&(_T::operator()))) _ReturnType;
5116  typedef decltype(_Arg1ClassHelperThunk(&(_T::operator()))) _Argument1Type;
5117  typedef decltype(_Arg2ClassHelperThunk(&(_T::operator()))) _Argument2Type;
5118  };
5119 
5120  template<typename _T>
5121  struct _FunctorTypeTraits<_T *>
5122  {
5123  typedef decltype(_ArgumentCountHelper(stdx::declval<_T*>())) _ArgumentCountType;
5124  static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;
5125 
5126  typedef decltype(_ReturnTypePFNHelperThunk(stdx::declval<_T*>())) _ReturnType;
5127  typedef decltype(_Arg1PFNHelperThunk(stdx::declval<_T*>())) _Argument1Type;
5128  typedef decltype(_Arg2PFNHelperThunk(stdx::declval<_T*>())) _Argument2Type;
5129  };
5130 
5131  template<typename _T>
5132  struct _ProgressTypeTraits
5133  {
5134  static const bool _TakesProgress = false;
5135  typedef void _ProgressType;
5136  };
5137 
5138  template<typename _T>
5139  struct _ProgressTypeTraits<progress_reporter<_T>>
5140  {
5141  static const bool _TakesProgress = true;
5142  typedef typename _T _ProgressType;
5143  };
5144 
5145 
5146  template<typename _T, size_t count = _FunctorTypeTraits<_T>::_ArgumentCount>
5147  struct _CAFunctorOptions
5148  {
5149  static const bool _TakesProgress = false;
5150  static const bool _TakesToken = false;
5151  typedef void _ProgressType;
5152  };
5153 
5154  template<typename _T>
5155  struct _CAFunctorOptions<_T, 1>
5156  {
5157  private:
5158 
5159  typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
5160 
5161  public:
5162 
5163  static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress;
5164  static const bool _TakesToken = !_TakesProgress;
5165  typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
5166  };
5167 
5168  template<typename _T>
5169  struct _CAFunctorOptions<_T, 2>
5170  {
5171  private:
5172 
5173  typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
5174 
5175  public:
5176 
5177  static const bool _TakesProgress = true;
5178  static const bool _TakesToken = true;
5179  typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
5180  };
5181 
5182  ref class _Zip
5183  {
5184  };
5185 
5186  // ***************************************************************************
5187  // Async Operation Task Generators
5188  //
5189 
5190  //
5191  // Functor returns an IAsyncInfo - result needs to be wrapped in a task:
5192  //
5193  template<typename _AsyncSelector, typename _ReturnType>
5194  struct _SelectorTaskGenerator
5195  {
5196  template<typename _Function>
5197  static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5198  {
5199  task_options _taskOptinos(_Cts.get_token());
5200  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5201  return task<_ReturnType>(_Func(), _taskOptinos);
5202  }
5203 
5204  template<typename _Function>
5205  static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5206  {
5207  task_options _taskOptinos(_Cts.get_token());
5208  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5209  return task<_ReturnType>(_Func(_Cts.get_token()), _taskOptinos);
5210  }
5211 
5212  template<typename _Function, typename _ProgressObject>
5213  static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5214  {
5215  task_options _taskOptinos(_Cts.get_token());
5216  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5217  return task<_ReturnType>(_Func(_Progress), _taskOptinos);
5218  }
5219 
5220  template<typename _Function, typename _ProgressObject>
5221  static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5222  {
5223  task_options _taskOptinos(_Cts.get_token());
5224  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5225  return task<_ReturnType>(_Func(_Progress, _Cts.get_token()), _taskOptinos);
5226  }
5227  };
5228 
5229  template<typename _AsyncSelector>
5230  struct _SelectorTaskGenerator<_AsyncSelector, void>
5231  {
5232  template<typename _Function>
5233  static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5234  {
5235  task_options _taskOptinos(_Cts.get_token());
5236  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5237  return task<void>(_Func(), _taskOptinos);
5238  }
5239 
5240  template<typename _Function>
5241  static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5242  {
5243  task_options _taskOptinos(_Cts.get_token());
5244  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5245  return task<void>(_Func(_Cts.get_token()), _taskOptinos);
5246  }
5247 
5248  template<typename _Function, typename _ProgressObject>
5249  static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5250  {
5251  task_options _taskOptinos(_Cts.get_token());
5252  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5253  return task<void>(_Func(_Progress), _taskOptinos);
5254  }
5255 
5256  template<typename _Function, typename _ProgressObject>
5257  static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5258  {
5259  task_options _taskOptinos(_Cts.get_token());
5260  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5261  return task<void>(_Func(_Progress, _Cts.get_token()), _taskOptinos);
5262  }
5263  };
5264 
5265  //
5266  // Functor returns a result - it needs to be wrapped in a task:
5267  //
5268  template<typename _ReturnType>
5269  struct _SelectorTaskGenerator<_TypeSelectorNoAsync, _ReturnType>
5270  {
5271 
5272 #pragma warning(push)
5273 #pragma warning(disable: 4702)
5274  template<typename _Function>
5275  static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5276  {
5277  task_options _taskOptinos(_Cts.get_token());
5278  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5279  return task<_ReturnType>( [=]() -> _ReturnType {
5280  _Task_generator_oversubscriber_t _Oversubscriber;
5281  (_Oversubscriber);
5282  return _Func();
5283  }, _taskOptinos);
5284  }
5285 #pragma warning(pop)
5286 
5287  template<typename _Function>
5288  static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5289  {
5290  task_options _taskOptinos(_Cts.get_token());
5291  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5292  return task<_ReturnType>( [=]() -> _ReturnType {
5293  _Task_generator_oversubscriber_t _Oversubscriber;
5294  (_Oversubscriber);
5295  return _Func(_Cts.get_token());
5296  }, _taskOptinos);
5297  }
5298 
5299  template<typename _Function, typename _ProgressObject>
5300  static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5301  {
5302  task_options _taskOptinos(_Cts.get_token());
5303  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5304  return task<_ReturnType>( [=]() -> _ReturnType {
5305  _Task_generator_oversubscriber_t _Oversubscriber;
5306  (_Oversubscriber);
5307  return _Func(_Progress);
5308  }, _taskOptinos);
5309  }
5310 
5311  template<typename _Function, typename _ProgressObject>
5312  static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5313  {
5314  task_options _taskOptinos(_Cts.get_token());
5315  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5316  return task<_ReturnType>( [=]() -> _ReturnType {
5317  _Task_generator_oversubscriber_t _Oversubscriber;
5318  (_Oversubscriber);
5319  return _Func(_Progress, _Cts.get_token());
5320  }, _taskOptinos);
5321  }
5322  };
5323 
5324  template<>
5325  struct _SelectorTaskGenerator<_TypeSelectorNoAsync, void>
5326  {
5327  template<typename _Function>
5328  static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5329  {
5330  task_options _taskOptinos(_Cts.get_token());
5331  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5332  return task<void>( [=]() {
5333  _Task_generator_oversubscriber_t _Oversubscriber;
5334  (_Oversubscriber);
5335  _Func();
5336  }, _taskOptinos);
5337  }
5338 
5339  template<typename _Function>
5340  static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5341  {
5342  task_options _taskOptinos(_Cts.get_token());
5343  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5344  return task<void>( [=]() {
5345  _Task_generator_oversubscriber_t _Oversubscriber;
5346  (_Oversubscriber);
5347  _Func(_Cts.get_token());
5348  }, _taskOptinos);
5349  }
5350 
5351  template<typename _Function, typename _ProgressObject>
5352  static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5353  {
5354  task_options _taskOptinos(_Cts.get_token());
5355  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5356  return task<void>( [=]() {
5357  _Task_generator_oversubscriber_t _Oversubscriber;
5358  (_Oversubscriber);
5359  _Func(_Progress);
5360  }, _taskOptinos);
5361  }
5362 
5363  template<typename _Function, typename _ProgressObject>
5364  static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5365  {
5366  task_options _taskOptinos(_Cts.get_token());
5367  details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5368  return task<void>( [=]() {
5369  _Task_generator_oversubscriber_t _Oversubscriber;
5370  (_Oversubscriber);
5371  _Func(_Progress, _Cts.get_token());
5372  }, _taskOptinos);
5373  }
5374  };
5375 
5376  //
5377  // Functor returns a task - the task can directly be returned:
5378  //
5379  template<typename _ReturnType>
5380  struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, _ReturnType>
5381  {
5382  template<typename _Function>
5383  static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5384  {
5385  return _Func();
5386  }
5387 
5388  template<typename _Function>
5389  static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5390  {
5391  return _Func(_Cts.get_token());
5392  }
5393 
5394  template<typename _Function, typename _ProgressObject>
5395  static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5396  {
5397  return _Func(_Progress);
5398  }
5399 
5400  template<typename _Function, typename _ProgressObject>
5401  static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5402  {
5403  return _Func(_Progress, _Cts.get_token());
5404  }
5405  };
5406 
5407  template<>
5408  struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, void>
5409  {
5410  template<typename _Function>
5411  static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5412  {
5413  return _Func();
5414  }
5415 
5416  template<typename _Function>
5417  static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5418  {
5419  return _Func(_Cts.get_token());
5420  }
5421 
5422  template<typename _Function, typename _ProgressObject>
5423  static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5424  {
5425  return _Func(_Progress);
5426  }
5427 
5428  template<typename _Function, typename _ProgressObject>
5429  static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5430  {
5431  return _Func(_Progress, _Cts.get_token());
5432  }
5433  };
5434 
5435  template<typename _Generator, bool _TakesToken, bool TakesProgress>
5436  struct _TaskGenerator
5437  {
5438  };
5439 
5440  template<typename _Generator>
5441  struct _TaskGenerator<_Generator, false, false>
5442  {
5443  template<typename _Function, typename _ClassPtr, typename _ProgressType>
5444  static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5445  -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
5446  {
5447  return _Generator::_GenerateTask_0(_Func, _Cts, _callstack);
5448  }
5449  };
5450 
5451  template<typename _Generator>
5452  struct _TaskGenerator<_Generator, true, false>
5453  {
5454  template<typename _Function, typename _ClassPtr, typename _ProgressType>
5455  static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5456  -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
5457  {
5458  return _Generator::_GenerateTask_1C(_Func, _Cts, _callstack);
5459  }
5460  };
5461 
5462  template<typename _Generator>
5463  struct _TaskGenerator<_Generator, false, true>
5464  {
5465  template<typename _Function, typename _ClassPtr, typename _ProgressType>
5466  static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5467  -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
5468  {
5469  return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack);
5470  }
5471  };
5472 
5473  template<typename _Generator>
5474  struct _TaskGenerator<_Generator, true, true>
5475  {
5476  template<typename _Function, typename _ClassPtr, typename _ProgressType>
5477  static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5478  -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
5479  {
5480  return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack);
5481  }
5482  };
5483 
5484  // ***************************************************************************
5485  // Async Operation Attributes Classes
5486  //
5487  // These classes are passed through the hierarchy of async base classes in order to hold multiple attributes of a given async construct in
5488  // a single container. An attribute class must define:
5489  //
5490  // Mandatory:
5491  // -------------------------
5492  //
5493  // _AsyncBaseType : The Windows Runtime interface which is being implemented.
5494  // _CompletionDelegateType : The Windows Runtime completion delegate type for the interface.
5495  // _ProgressDelegateType : If _TakesProgress is true, the Windows Runtime progress delegate type for the interface. If it is false, an empty Windows Runtime type.
5496  // _ReturnType : The return type of the async construct (void for actions / non-void for operations)
5497  //
5498  // _TakesProgress : An indication as to whether or not
5499  //
5500  // _Generate_Task : A function adapting the user's function into what's necessary to produce the appropriate task
5501  //
5502  // Optional:
5503  // -------------------------
5504  //
5505 
5506  template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken, bool _TakesProgress>
5507  struct _AsyncAttributes
5508  {
5509  };
5510 
5511  template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>
5512  struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, true>
5513  {
5514  typedef typename Windows::Foundation::IAsyncOperationWithProgress<_ReturnType, _ProgressType> _AsyncBaseType;
5515  typedef typename Windows::Foundation::AsyncOperationProgressHandler<_ReturnType, _ProgressType> _ProgressDelegateType;
5516  typedef typename Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_ReturnType, _ProgressType> _CompletionDelegateType;
5517  typedef typename _ReturnType _ReturnType;
5518  typedef typename _ProgressType _ProgressType;
5519  typedef typename _TaskTraits::_AsyncKind _AsyncKind;
5520  typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
5521  typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;
5522 
5523  static const bool _TakesProgress = true;
5524  static const bool _TakesToken = _TakesToken;
5525 
5526  template<typename _Function, typename _ClassPtr>
5527  static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5528  {
5529  return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);
5530  }
5531  };
5532 
5533  template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>
5534  struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, false>
5535  {
5536  typedef typename Windows::Foundation::IAsyncOperation<_ReturnType> _AsyncBaseType;
5537  typedef _Zip _ProgressDelegateType;
5538  typedef typename Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType> _CompletionDelegateType;
5539  typedef typename _ReturnType _ReturnType;
5540  typedef typename _TaskTraits::_AsyncKind _AsyncKind;
5541  typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
5542  typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;
5543 
5544  static const bool _TakesProgress = false;
5545  static const bool _TakesToken = _TakesToken;
5546 
5547  template<typename _Function, typename _ClassPtr>
5548  static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5549  {
5550  return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);
5551  }
5552  };
5553 
5554  template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>
5555  struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, true>
5556  {
5557  typedef typename Windows::Foundation::IAsyncActionWithProgress<_ProgressType> _AsyncBaseType;
5558  typedef typename Windows::Foundation::AsyncActionProgressHandler<_ProgressType> _ProgressDelegateType;
5559  typedef typename Windows::Foundation::AsyncActionWithProgressCompletedHandler<_ProgressType> _CompletionDelegateType;
5560  typedef void _ReturnType;
5561  typedef typename _ProgressType _ProgressType;
5562  typedef typename _TaskTraits::_AsyncKind _AsyncKind;
5563  typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
5564  typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;
5565 
5566  static const bool _TakesProgress = true;
5567  static const bool _TakesToken = _TakesToken;
5568 
5569  template<typename _Function, typename _ClassPtr>
5570  static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5571  {
5572  return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);
5573  }
5574  };
5575 
5576  template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>
5577  struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, false>
5578  {
5579  typedef typename Windows::Foundation::IAsyncAction _AsyncBaseType;
5580  typedef _Zip _ProgressDelegateType;
5581  typedef typename Windows::Foundation::AsyncActionCompletedHandler _CompletionDelegateType;
5582  typedef void _ReturnType;
5583  typedef typename _TaskTraits::_AsyncKind _AsyncKind;
5584  typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
5585  typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;
5586 
5587  static const bool _TakesProgress = false;
5588  static const bool _TakesToken = _TakesToken;
5589 
5590  template<typename _Function, typename _ClassPtr>
5591  static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5592  {
5593  return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);
5594  }
5595  };
5596 
5597  template<typename _Function>
5598  struct _AsyncLambdaTypeTraits
5599  {
5600  typedef typename _FunctorTypeTraits<_Function>::_ReturnType _ReturnType;
5601  typedef typename _FunctorTypeTraits<_Function>::_Argument1Type _Argument1Type;
5602  typedef typename _CAFunctorOptions<_Function>::_ProgressType _ProgressType;
5603 
5604  static const bool _TakesProgress = _CAFunctorOptions<_Function>::_TakesProgress;
5605  static const bool _TakesToken = _CAFunctorOptions<_Function>::_TakesToken;
5606 
5607  typedef typename _TaskTypeTraits<_ReturnType> _TaskTraits;
5608  typedef typename _AsyncAttributes<_Function, _ProgressType, typename _TaskTraits::_TaskRetType, _TaskTraits, _TakesToken, _TakesProgress> _AsyncAttributes;
5609  };
5610 
5611  // ***************************************************************************
5612  // AsyncInfo (and completion) Layer:
5613  //
5614 
5615  //
5616  // Internal base class implementation for async operations (based on internal Windows representation for ABI level async operations)
5617  //
5618  template < typename _Attributes, _AsyncResultType resultType = SingleResult >
5619  ref class _AsyncInfoBase abstract : _Attributes::_AsyncBaseType
5620  {
5621  internal:
5622 
5623  _AsyncInfoBase() :
5624  _M_currentStatus(_AsyncStatusInternal::_AsyncCreated),
5625  _M_errorCode(S_OK),
5626  _M_completeDelegate(nullptr),
5627  _M_CompleteDelegateAssigned(0),
5628  _M_CallbackMade(0)
5629  {
5630  _M_id = ::pplx::details::platform::GetNextAsyncId();
5631  }
5632 
5633  public:
5634  virtual typename _Attributes::_ReturnType GetResults()
5635  {
5636  throw ::Platform::Exception::CreateException(E_UNEXPECTED);
5637  }
5638 
5639  virtual property unsigned int Id
5640  {
5641  unsigned int get()
5642  {
5643  _CheckValidStateForAsyncInfoCall();
5644 
5645  return _M_id;
5646  }
5647 
5648  void set(unsigned int id)
5649  {
5650  _CheckValidStateForAsyncInfoCall();
5651 
5652  if (id == 0)
5653  {
5654  throw ::Platform::Exception::CreateException(E_INVALIDARG);
5655  }
5656  else if (_M_currentStatus != _AsyncStatusInternal::_AsyncCreated)
5657  {
5658  throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);
5659  }
5660 
5661  _M_id = id;
5662  }
5663  }
5664 
5665  virtual property Windows::Foundation::AsyncStatus Status
5666  {
5667  Windows::Foundation::AsyncStatus get()
5668  {
5669  _CheckValidStateForAsyncInfoCall();
5670 
5671  _AsyncStatusInternal _Current = _M_currentStatus;
5672 
5673  //
5674  // Map our internal cancel pending to cancelled. This way "pending cancelled" looks to the outside as "cancelled" but
5675  // can still transition to "completed" if the operation completes without acknowledging the cancellation request
5676  //
5677  switch(_Current)
5678  {
5679  case _AsyncCancelPending:
5680  _Current = _AsyncCanceled;
5681  break;
5682  case _AsyncCreated:
5683  _Current = _AsyncStarted;
5684  break;
5685  default:
5686  break;
5687  }
5688 
5689  return static_cast<Windows::Foundation::AsyncStatus>(_Current);
5690  }
5691  }
5692 
5693  virtual property Windows::Foundation::HResult ErrorCode
5694  {
5695  Windows::Foundation::HResult get()
5696  {
5697  _CheckValidStateForAsyncInfoCall();
5698 
5699  Windows::Foundation::HResult _Hr;
5700  _Hr.Value = _M_errorCode;
5701  return _Hr;
5702  }
5703  }
5704 
5705  virtual property typename _Attributes::_ProgressDelegateType^ Progress
5706  {
5707  typename typename _Attributes::_ProgressDelegateType^ get()
5708  {
5709  return _GetOnProgress();
5710  }
5711 
5712  void set(typename _Attributes::_ProgressDelegateType^ _ProgressHandler)
5713  {
5714  _PutOnProgress(_ProgressHandler);
5715  }
5716  }
5717 
5718  virtual void Cancel()
5719  {
5720  if (_TransitionToState(_AsyncCancelPending))
5721  {
5722  _OnCancel();
5723  }
5724  }
5725 
5726  virtual void Close()
5727  {
5728  if (_TransitionToState(_AsyncClosed))
5729  {
5730  _OnClose();
5731  }
5732  else
5733  {
5734  if (_M_currentStatus != _AsyncClosed) // Closed => Closed transition is just ignored
5735  {
5736  throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE);
5737  }
5738  }
5739  }
5740 
5741  virtual property typename _Attributes::_CompletionDelegateType^ Completed
5742  {
5743  typename _Attributes::_CompletionDelegateType^ get()
5744  {
5745  _CheckValidStateForDelegateCall();
5746  return _M_completeDelegate;
5747  }
5748 
5749  void set(typename _Attributes::_CompletionDelegateType^ _CompleteHandler)
5750  {
5751  _CheckValidStateForDelegateCall();
5752  // this delegate property is "write once"
5753  if (InterlockedIncrement(&_M_CompleteDelegateAssigned) == 1)
5754  {
5755  _M_completeDelegateContext = _ContextCallback::_CaptureCurrent();
5756  _M_completeDelegate = _CompleteHandler;
5757  // Guarantee that the write of _M_completeDelegate is ordered with respect to the read of state below
5758  // as perceived from _FireCompletion on another thread.
5759  MemoryBarrier();
5760  if (_IsTerminalState())
5761  {
5762  _FireCompletion();
5763  }
5764  }
5765  else
5766  {
5767  throw ::Platform::Exception::CreateException(E_ILLEGAL_DELEGATE_ASSIGNMENT);
5768  }
5769  }
5770  }
5771 
5772 
5773  protected private:
5774 
5775  // _Start - this is not externally visible since async operations "hot start" before returning to the caller
5776  void _Start()
5777  {
5778  if (_TransitionToState(_AsyncStarted))
5779  {
5780  _OnStart();
5781  }
5782  else
5783  {
5784  throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE);
5785  }
5786  }
5787 
5788 
5789  void _FireCompletion()
5790  {
5791  _TryTransitionToCompleted();
5792 
5793  // we guarantee that completion can only ever be fired once
5794  if (_M_completeDelegate != nullptr && InterlockedIncrement(&_M_CallbackMade) == 1)
5795  {
5796  _M_completeDelegateContext._CallInContext([=] {
5797  _M_completeDelegate((_Attributes::_AsyncBaseType^)this, this->Status);
5798  _M_completeDelegate = nullptr;
5799  });
5800  }
5801  }
5802 
5803  virtual typename _Attributes::_ProgressDelegateType^ _GetOnProgress()
5804  {
5805  throw ::Platform::Exception::CreateException(E_UNEXPECTED);
5806  }
5807 
5808  virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType^ _ProgressHandler)
5809  {
5810  throw ::Platform::Exception::CreateException(E_UNEXPECTED);
5811  }
5812 
5813  bool _TryTransitionToCompleted()
5814  {
5815  return _TransitionToState(_AsyncStatusInternal::_AsyncCompleted);
5816  }
5817 
5818  bool _TryTransitionToCancelled()
5819  {
5820  return _TransitionToState(_AsyncStatusInternal::_AsyncCanceled);
5821  }
5822 
5823  bool _TryTransitionToError(const HRESULT error)
5824  {
5825  _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_errorCode), error, S_OK);
5826  return _TransitionToState(_AsyncStatusInternal::_AsyncError);
5827  }
5828 
5829  // This method checks to see if the delegate properties can be
5830  // modified in the current state and generates the appropriate
5831  // error hr in the case of violation.
5832  inline void _CheckValidStateForDelegateCall()
5833  {
5834  if (_M_currentStatus == _AsyncClosed)
5835  {
5836  throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);
5837  }
5838  }
5839 
5840  // This method checks to see if results can be collected in the
5841  // current state and generates the appropriate error hr in
5842  // the case of a violation.
5843  inline void _CheckValidStateForResultsCall()
5844  {
5845  _AsyncStatusInternal _Current = _M_currentStatus;
5846 
5847  if (_Current == _AsyncError)
5848  {
5849  throw ::Platform::Exception::CreateException(_M_errorCode);
5850  }
5851 #pragma warning(push)
5852 #pragma warning(disable: 4127) // Conditional expression is constant
5853  // single result illegal before transition to Completed or Cancelled state
5854  if (resultType == SingleResult)
5855 #pragma warning(pop)
5856  {
5857  if (_Current != _AsyncCompleted)
5858  {
5859  throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);
5860  }
5861  }
5862  // multiple results can be called after Start has been called and before/after Completed
5863  else if (_Current != _AsyncStarted &&
5864  _Current != _AsyncCancelPending &&
5865  _Current != _AsyncCanceled &&
5866  _Current != _AsyncCompleted)
5867  {
5868  throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);
5869  }
5870  }
5871 
5872  // This method can be called by derived classes periodically to determine
5873  // whether the asynchronous operation should continue processing or should
5874  // be halted.
5875  inline bool _ContinueAsyncOperation()
5876  {
5877  return (_M_currentStatus == _AsyncStarted);
5878  }
5879 
5880  // These two methods are used to allow the async worker implementation do work on
5881  // state transitions. No real "work" should be done in these methods. In other words
5882  // they should not block for a long time on UI timescales.
5883  virtual void _OnStart() = 0;
5884  virtual void _OnClose() = 0;
5885  virtual void _OnCancel() = 0;
5886 
5887  private:
5888 
5889  // This method is used to check if calls to the AsyncInfo properties
5890  // (id, status, errorcode) are legal in the current state. It also
5891  // generates the appropriate error hr to return in the case of an
5892  // illegal call.
5893  inline void _CheckValidStateForAsyncInfoCall()
5894  {
5895  _AsyncStatusInternal _Current = _M_currentStatus;
5896  if (_Current == _AsyncClosed)
5897  {
5898  throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);
5899  }
5900  else if (_Current == _AsyncCreated)
5901  {
5902  throw ::Platform::Exception::CreateException(E_ASYNC_OPERATION_NOT_STARTED);
5903  }
5904 
5905  }
5906 
5907  inline bool _TransitionToState(const _AsyncStatusInternal _NewState)
5908  {
5909  _AsyncStatusInternal _Current = _M_currentStatus;
5910 
5911  // This enforces the valid state transitions of the asynchronous worker object
5912  // state machine.
5913  switch(_NewState)
5914  {
5915  case _AsyncStatusInternal::_AsyncStarted:
5916  if (_Current != _AsyncCreated)
5917  {
5918  return false;
5919  }
5920  break;
5921  case _AsyncStatusInternal::_AsyncCompleted:
5922  if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
5923  {
5924  return false;
5925  }
5926  break;
5927  case _AsyncStatusInternal::_AsyncCancelPending:
5928  if (_Current != _AsyncStarted)
5929  {
5930  return false;
5931  }
5932  break;
5933  case _AsyncStatusInternal::_AsyncCanceled:
5934  if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
5935  {
5936  return false;
5937  }
5938  break;
5939  case _AsyncStatusInternal::_AsyncError:
5940  if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
5941  {
5942  return false;
5943  }
5944  break;
5945  case _AsyncStatusInternal::_AsyncClosed:
5946  if (!_IsTerminalState(_Current))
5947  {
5948  return false;
5949  }
5950  break;
5951  default:
5952  return false;
5953  break;
5954  }
5955 
5956  // attempt the transition to the new state
5957  // Note: if currentStatus_ == _Current, then there was no intervening write
5958  // by the async work object and the swap succeeded.
5959  _AsyncStatusInternal _RetState = static_cast<_AsyncStatusInternal>(
5960  _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_currentStatus),
5961  _NewState,
5962  static_cast<LONG>(_Current)));
5963 
5964  // ICE returns the former state, if the returned state and the
5965  // state we captured at the beginning of this method are the same,
5966  // the swap succeeded.
5967  return (_RetState == _Current);
5968  }
5969 
5970  inline bool _IsTerminalState()
5971  {
5972  return _IsTerminalState(_M_currentStatus);
5973  }
5974 
5975  inline bool _IsTerminalState(_AsyncStatusInternal status)
5976  {
5977  return (status == _AsyncError ||
5978  status == _AsyncCanceled ||
5979  status == _AsyncCompleted ||
5980  status == _AsyncClosed);
5981  }
5982 
5983  private:
5984 
5985  _ContextCallback _M_completeDelegateContext;
5986  typename _Attributes::_CompletionDelegateType^ volatile _M_completeDelegate;
5987  _AsyncStatusInternal volatile _M_currentStatus;
5988  HRESULT volatile _M_errorCode;
5989  unsigned int _M_id;
5990  long volatile _M_CompleteDelegateAssigned;
5991  long volatile _M_CallbackMade;
5992  };
5993 
5994  // ***************************************************************************
5995  // Progress Layer (optional):
5996  //
5997 
5998  template< typename _Attributes, bool _HasProgress, _AsyncResultType _ResultType = SingleResult >
5999  ref class _AsyncProgressBase abstract : _AsyncInfoBase<_Attributes, _ResultType>
6000  {
6001  };
6002 
6003  template< typename _Attributes, _AsyncResultType _ResultType>
6004  ref class _AsyncProgressBase<_Attributes, true, _ResultType> abstract : _AsyncInfoBase<_Attributes, _ResultType>
6005  {
6006  internal:
6007 
6008  _AsyncProgressBase() : _AsyncInfoBase<_Attributes, _ResultType>(),
6009  _M_progressDelegate(nullptr)
6010  {
6011  }
6012 
6013  virtual typename _Attributes::_ProgressDelegateType^ _GetOnProgress() override
6014  {
6015  _CheckValidStateForDelegateCall();
6016  return _M_progressDelegate;
6017  }
6018 
6019  virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType^ _ProgressHandler) override
6020  {
6021  _CheckValidStateForDelegateCall();
6022  _M_progressDelegate = _ProgressHandler;
6023  _M_progressDelegateContext = _ContextCallback::_CaptureCurrent();
6024  }
6025 
6026  void _FireProgress(const typename _Attributes::_ProgressType& _ProgressValue)
6027  {
6028  if (_M_progressDelegate != nullptr)
6029  {
6030  _M_progressDelegateContext._CallInContext([=] {
6031  _M_progressDelegate((_Attributes::_AsyncBaseType^)this, _ProgressValue);
6032  });
6033  }
6034  }
6035 
6036  private:
6037 
6038  _ContextCallback _M_progressDelegateContext;
6039  typename _Attributes::_ProgressDelegateType^ _M_progressDelegate;
6040  };
6041 
6042  template<typename _Attributes, _AsyncResultType _ResultType = SingleResult>
6043  ref class _AsyncBaseProgressLayer abstract : _AsyncProgressBase<_Attributes, _Attributes::_TakesProgress, _ResultType>
6044  {
6045  };
6046 
6047  // ***************************************************************************
6048  // Task Adaptation Layer:
6049  //
6050 
6051  //
6052  // _AsyncTaskThunkBase provides a bridge between IAsync<Action/Operation> and task.
6053  //
6054  template<typename _Attributes, typename _ReturnType>
6055  ref class _AsyncTaskThunkBase abstract : _AsyncBaseProgressLayer<_Attributes>
6056  {
6057  public:
6058 
6059  virtual _ReturnType GetResults() override
6060  {
6061  _CheckValidStateForResultsCall();
6062  return _M_task.get();
6063  }
6064 
6065  internal:
6066 
6067  typedef task<_ReturnType> _TaskType;
6068 
6069  _AsyncTaskThunkBase(const _TaskType& _Task)
6070  : _M_task(_Task)
6071  {
6072  }
6073 
6074  _AsyncTaskThunkBase()
6075  {
6076  }
6077 
6078  protected:
6079 
6080  virtual void _OnStart() override
6081  {
6082  _M_task.then( [=](_TaskType _Antecedent) {
6083  try
6084  {
6085  _Antecedent.get();
6086  }
6087  catch(task_canceled&)
6088  {
6089  _TryTransitionToCancelled();
6090  }
6091  catch(::Platform::Exception^ _Ex)
6092  {
6093  _TryTransitionToError(_Ex->HResult);
6094  }
6095  catch(...)
6096  {
6097  _TryTransitionToError(E_FAIL);
6098  }
6099  _FireCompletion();
6100  });
6101  }
6102 
6103  internal:
6104 
6105  _TaskType _M_task;
6106  cancellation_token_source _M_cts;
6107  };
6108 
6109  template<typename _Attributes>
6110  ref class _AsyncTaskThunk : _AsyncTaskThunkBase<_Attributes, typename _Attributes::_ReturnType>
6111  {
6112  internal:
6113 
6114  _AsyncTaskThunk(const _TaskType& _Task) :
6115  _AsyncTaskThunkBase(_Task)
6116  {
6117  }
6118 
6119  _AsyncTaskThunk()
6120  {
6121  }
6122 
6123  protected:
6124 
6125  virtual void _OnClose() override
6126  {
6127  }
6128 
6129  virtual void _OnCancel() override
6130  {
6131  _M_cts.cancel();
6132  }
6133  };
6134 
6135  // ***************************************************************************
6136  // Async Creation Layer:
6137  //
6138  template<typename _Function>
6139  ref class _AsyncTaskGeneratorThunk sealed : _AsyncTaskThunk<typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes>
6140  {
6141  internal:
6142 
6143  typedef typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes _Attributes;
6144  typedef typename _AsyncTaskThunk<_Attributes> _Base;
6145  typedef typename _Attributes::_AsyncBaseType _AsyncBaseType;
6146 
6147  _AsyncTaskGeneratorThunk(const _Function& _Func, const _TaskCreationCallstack &_callstack) : _M_func(_Func), _M_creationCallstack(_callstack)
6148  {
6149  // Virtual call here is safe as the class is declared 'sealed'
6150  _Start();
6151  }
6152 
6153  protected:
6154 
6155  //
6156  // The only thing we must do different from the base class is we must spin the hot task on transition from Created->Started. Otherwise,
6157  // let the base thunk handle everything.
6158  //
6159 
6160  virtual void _OnStart() override
6161  {
6162  //
6163  // Call the appropriate task generator to actually produce a task of the expected type. This might adapt the user lambda for progress reports,
6164  // wrap the return result in a task, or allow for direct return of a task depending on the form of the lambda.
6165  //
6166  _M_task = _Attributes::_Generate_Task(_M_func, this, _M_cts, _M_creationCallstack);
6167  _Base::_OnStart();
6168  }
6169 
6170  virtual void _OnCancel() override
6171  {
6172  _Base::_OnCancel();
6173  }
6174 
6175  private:
6176  _TaskCreationCallstack _M_creationCallstack;
6177  _Function _M_func;
6178  };
6179 } // namespace details
6180 
6220 
6221 template<typename _Function>
6222 __declspec(noinline)
6223 details::_AsyncTaskGeneratorThunk<_Function> ^create_async(const _Function& _Func)
6224 {
6225  static_assert(std::is_same<decltype(details::_IsValidCreateAsync(_Func,0,0,0,0)),std::true_type>::value,
6226  "argument to create_async must be a callable object taking zero, one or two arguments");
6227  return ref new details::_AsyncTaskGeneratorThunk<_Function>(_Func, _CAPTURE_CALLSTACK());
6228 }
6229 
6230 #endif /* defined (__cplusplus_winrt) */
6231 
6232 namespace details
6233 {
6234  // Helper struct for when_all operators to know when tasks have completed
6235  template<typename _Type>
6236  struct _RunAllParam
6237  {
6238  _RunAllParam() : _M_completeCount(0), _M_numTasks(0)
6239  {
6240  }
6241 
6242  void _Resize(size_t _Len, bool _SkipVector = false)
6243  {
6244  _M_numTasks = _Len;
6245  if (!_SkipVector)
6246  {
6247  _M_vector._Result.resize(_Len);
6248  }
6249  }
6250 
6251  task_completion_event<_Unit_type> _M_completed;
6252  _ResultHolder<std::vector<_Type> > _M_vector;
6253  _ResultHolder<_Type> _M_mergeVal;
6254  atomic_size_t _M_completeCount;
6255  size_t _M_numTasks;
6256  };
6257 
6258  template<typename _Type>
6259  struct _RunAllParam<std::vector<_Type> >
6260  {
6261  _RunAllParam() : _M_completeCount(0), _M_numTasks(0)
6262  {
6263  }
6264 
6265  void _Resize(size_t _Len, bool _SkipVector = false)
6266  {
6267  _M_numTasks = _Len;
6268 
6269  if (!_SkipVector)
6270  {
6271  _M_vector.resize(_Len);
6272  }
6273  }
6274 
6275  task_completion_event<_Unit_type> _M_completed;
6276  std::vector<_ResultHolder<std::vector<_Type> > > _M_vector;
6277  atomic_size_t _M_completeCount;
6278  size_t _M_numTasks;
6279  };
6280 
6281  // Helper struct specialization for void
6282  template<>
6283  struct _RunAllParam<_Unit_type>
6284  {
6285  _RunAllParam() : _M_completeCount(0), _M_numTasks(0)
6286  {
6287  }
6288 
6289  void _Resize(size_t _Len)
6290  {
6291  _M_numTasks = _Len;
6292  }
6293 
6294  task_completion_event<_Unit_type> _M_completed;
6295  atomic_size_t _M_completeCount;
6296  size_t _M_numTasks;
6297  };
6298 
6299  inline void _JoinAllTokens_Add(const cancellation_token_source& _MergedSrc, _CancellationTokenState *_PJoinedTokenState)
6300  {
6301  if (_PJoinedTokenState != nullptr && _PJoinedTokenState != _CancellationTokenState::_None())
6302  {
6303  cancellation_token _T = cancellation_token::_FromImpl(_PJoinedTokenState);
6304  _T.register_callback( [=](){
6305  _MergedSrc.cancel();
6306  });
6307  }
6308  }
6309 
6310  template<typename _ElementType, typename _Function, typename _TaskType>
6311  void _WhenAllContinuationWrapper(_RunAllParam<_ElementType>* _PParam, _Function _Func, task<_TaskType>& _Task)
6312  {
6313  if (_Task._GetImpl()->_IsCompleted())
6314  {
6315  _Func();
6316  if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
6317  {
6318  // Inline execute its direct continuation, the _ReturnTask
6319  _PParam->_M_completed.set(_Unit_type());
6320  // It's safe to delete it since all usage of _PParam in _ReturnTask has been finished.
6321  delete _PParam;
6322  }
6323  }
6324  else
6325  {
6326  _ASSERTE(_Task._GetImpl()->_IsCanceled());
6327  if (_Task._GetImpl()->_HasUserException())
6328  {
6329  // _Cancel will return false if the TCE is already canceled with or without exception
6330  _PParam->_M_completed._Cancel(_Task._GetImpl()->_GetExceptionHolder());
6331  }
6332  else
6333  {
6334  _PParam->_M_completed._Cancel();
6335  }
6336 
6337  if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
6338  {
6339  delete _PParam;
6340  }
6341  }
6342  }
6343 
6344  template<typename _ElementType, typename _Iterator>
6345  struct _WhenAllImpl
6346  {
6347  static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
6348  {
6349  _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
6350 
6351  auto _PParam = new _RunAllParam<_ElementType>();
6352  cancellation_token_source _MergedSource;
6353 
6354  // Step1: Create task completion event.
6355  task_options _Options(_TaskOptions);
6356  _Options.set_cancellation_token(_MergedSource.get_token());
6357  task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);
6358  // The return task must be created before step 3 to enforce inline execution.
6359  auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ElementType> {
6360  return _PParam->_M_vector.Get();
6361  }, nullptr);
6362 
6363  // Step2: Combine and check tokens, and count elements in range.
6364  if (_PTokenState)
6365  {
6366  _JoinAllTokens_Add(_MergedSource, _PTokenState);
6367  _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));
6368  }
6369  else
6370  {
6371  size_t _TaskNum = 0;
6372  for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6373  {
6374  _TaskNum++;
6375  _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);
6376  }
6377  _PParam->_Resize(_TaskNum);
6378  }
6379 
6380  // Step3: Check states of previous tasks.
6381  if( _Begin == _End )
6382  {
6383  _PParam->_M_completed.set(_Unit_type());
6384  delete _PParam;
6385  }
6386  else
6387  {
6388  size_t _Index = 0;
6389  for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6390  {
6391  if (_PTask->is_apartment_aware())
6392  {
6393  _ReturnTask._SetAsync();
6394  }
6395 
6396  _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) {
6397 
6398  auto _PParamCopy = _PParam;
6399  auto _IndexCopy = _Index;
6400  auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask](){
6401  _PParamCopy->_M_vector._Result[_IndexCopy] = _ResultTask._GetImpl()->_GetResult();
6402  };
6403 
6404  _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
6405  }, _CancellationTokenState::_None());
6406 
6407  _Index++;
6408  }
6409  }
6410 
6411  return _ReturnTask;
6412  }
6413  };
6414 
6415  template<typename _ElementType, typename _Iterator>
6416  struct _WhenAllImpl<std::vector<_ElementType>, _Iterator>
6417  {
6418  static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
6419  {
6420  _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
6421 
6422  auto _PParam = new _RunAllParam<std::vector<_ElementType>>();
6423  cancellation_token_source _MergedSource;
6424 
6425  // Step1: Create task completion event.
6426  task_options _Options(_TaskOptions);
6427  _Options.set_cancellation_token(_MergedSource.get_token());
6428  task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);
6429  // The return task must be created before step 3 to enforce inline execution.
6430  auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ElementType> {
6431  _ASSERTE(_PParam->_M_completeCount == _PParam->_M_numTasks);
6432  std::vector<_ElementType> _Result;
6433  for(size_t _I = 0; _I < _PParam->_M_numTasks; _I++)
6434  {
6435  const std::vector<_ElementType>& _Vec = _PParam->_M_vector[_I].Get();
6436  _Result.insert(_Result.end(), _Vec.begin(), _Vec.end());
6437  }
6438  return _Result;
6439  }, nullptr);
6440 
6441  // Step2: Combine and check tokens, and count elements in range.
6442  if (_PTokenState)
6443  {
6444  _JoinAllTokens_Add(_MergedSource, _PTokenState);
6445  _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));
6446  }
6447  else
6448  {
6449  size_t _TaskNum = 0;
6450  for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6451  {
6452  _TaskNum++;
6453  _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);
6454  }
6455  _PParam->_Resize(_TaskNum);
6456  }
6457 
6458  // Step3: Check states of previous tasks.
6459  if( _Begin == _End )
6460  {
6461  _PParam->_M_completed.set(_Unit_type());
6462  delete _PParam;
6463  }
6464  else
6465  {
6466  size_t _Index = 0;
6467  for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6468  {
6469  if (_PTask->is_apartment_aware())
6470  {
6471  _ReturnTask._SetAsync();
6472  }
6473 
6474  _PTask->_Then([_PParam, _Index](task<std::vector<_ElementType>> _ResultTask) {
6475 
6476  auto _PParamCopy = _PParam;
6477  auto _IndexCopy = _Index;
6478  auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask]() {
6479  _PParamCopy->_M_vector[_IndexCopy].Set(_ResultTask._GetImpl()->_GetResult());
6480  };
6481 
6482  _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
6483  }, _CancellationTokenState::_None());
6484 
6485  _Index++;
6486  }
6487  }
6488 
6489  return _ReturnTask;
6490  }
6491  };
6492 
6493  template<typename _Iterator>
6494  struct _WhenAllImpl<void, _Iterator>
6495  {
6496  static task<void> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
6497  {
6498  _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
6499 
6500  auto _PParam = new _RunAllParam<_Unit_type>();
6501  cancellation_token_source _MergedSource;
6502 
6503  // Step1: Create task completion event.
6504  task_options _Options(_TaskOptions);
6505  _Options.set_cancellation_token(_MergedSource.get_token());
6506  task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);
6507  // The return task must be created before step 3 to enforce inline execution.
6508  auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) {
6509  }, nullptr);
6510 
6511  // Step2: Combine and check tokens, and count elements in range.
6512  if (_PTokenState)
6513  {
6514  _JoinAllTokens_Add(_MergedSource, _PTokenState);
6515  _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));
6516  }
6517  else
6518  {
6519  size_t _TaskNum = 0;
6520  for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6521  {
6522  _TaskNum++;
6523  _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);
6524  }
6525  _PParam->_Resize(_TaskNum);
6526  }
6527 
6528  // Step3: Check states of previous tasks.
6529  if( _Begin == _End )
6530  {
6531  _PParam->_M_completed.set(_Unit_type());
6532  delete _PParam;
6533  }
6534  else
6535  {
6536  for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6537  {
6538  if (_PTask->is_apartment_aware())
6539  {
6540  _ReturnTask._SetAsync();
6541  }
6542 
6543  _PTask->_Then([_PParam](task<void> _ResultTask) {
6544  auto _Func = [](){};
6545  _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
6546  }, _CancellationTokenState::_None());
6547  }
6548  }
6549 
6550  return _ReturnTask;
6551  }
6552  };
6553 
6554  template<typename _ReturnType>
6555  task<std::vector<_ReturnType>> _WhenAllVectorAndValue(const task<std::vector<_ReturnType>>& _VectorTask, const task<_ReturnType>& _ValueTask,
6556  bool _OutputVectorFirst)
6557  {
6558  auto _PParam = new _RunAllParam<_ReturnType>();
6559  cancellation_token_source _MergedSource;
6560 
6561  // Step1: Create task completion event.
6562  task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token());
6563  // The return task must be created before step 3 to enforce inline execution.
6564  auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ReturnType> {
6565  _ASSERTE(_PParam->_M_completeCount == 2);
6566  auto _Result = _PParam->_M_vector.Get(); // copy by value
6567  auto _mergeVal = _PParam->_M_mergeVal.Get();
6568 
6569  if (_OutputVectorFirst == true)
6570  {
6571  _Result.push_back(_mergeVal);
6572  }
6573  else
6574  {
6575  _Result.insert(_Result.begin(), _mergeVal);
6576  }
6577  return _Result;
6578  }, nullptr);
6579 
6580  // Step2: Combine and check tokens.
6581  _JoinAllTokens_Add(_MergedSource, _VectorTask._GetImpl()->_M_pTokenState);
6582  _JoinAllTokens_Add(_MergedSource, _ValueTask._GetImpl()->_M_pTokenState);
6583 
6584  // Step3: Check states of previous tasks.
6585  _PParam->_Resize(2, true);
6586 
6587  if (_VectorTask.is_apartment_aware() || _ValueTask.is_apartment_aware())
6588  {
6589  _ReturnTask._SetAsync();
6590  }
6591  _VectorTask._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) {
6592  auto _PParamCopy = _PParam;
6593  auto _Func = [_PParamCopy, &_ResultTask]() {
6594  auto _ResultLocal = _ResultTask._GetImpl()->_GetResult();
6595  _PParamCopy->_M_vector.Set(_ResultLocal);
6596  };
6597 
6598  _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
6599  }, _CancellationTokenState::_None());
6600  _ValueTask._Then([_PParam](task<_ReturnType> _ResultTask) {
6601  auto _PParamCopy = _PParam;
6602  auto _Func = [_PParamCopy, &_ResultTask]() {
6603  auto _ResultLocal = _ResultTask._GetImpl()->_GetResult();
6604  _PParamCopy->_M_mergeVal.Set(_ResultLocal);
6605  };
6606 
6607  _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
6608  }, _CancellationTokenState::_None());
6609 
6610  return _ReturnTask;
6611  }
6612 } // namespace details
6613 
6636 
6637 template <typename _Iterator>
6638 auto when_all(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options())
6639  -> decltype (details::_WhenAllImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End))
6640 {
6641  typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
6642  return details::_WhenAllImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End);
6643 }
6644 
6669 
6670 template<typename _ReturnType>
6671 task<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs)
6672 {
6673  task<_ReturnType> _PTasks[2] = {_Lhs, _Rhs};
6674  return when_all(_PTasks, _PTasks+2);
6675 }
6676 
6701 
6702 template<typename _ReturnType>
6703 task<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs)
6704 {
6705  return details::_WhenAllVectorAndValue(_Lhs, _Rhs, true);
6706 }
6707 
6732 
6733 template<typename _ReturnType>
6734 task<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)
6735 {
6736  return details::_WhenAllVectorAndValue(_Rhs, _Lhs, false);
6737 }
6738 
6763 
6764 template<typename _ReturnType>
6765 task<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)
6766 {
6767  task<std::vector<_ReturnType>> _PTasks[2] = {_Lhs, _Rhs};
6768  return when_all(_PTasks, _PTasks+2);
6769 }
6770 
6795 
6796 inline task<void> operator&&(const task<void> & _Lhs, const task<void> & _Rhs)
6797 {
6798  task<void> _PTasks[2] = {_Lhs, _Rhs};
6799  return when_all(_PTasks, _PTasks+2);
6800 }
6801 
6802 namespace details
6803 {
6804  // Helper struct for when_any operators to know when tasks have completed
6805  template <typename _CompletionType>
6806  struct _RunAnyParam
6807  {
6808  _RunAnyParam() : _M_exceptionRelatedToken(nullptr), _M_completeCount(0), _M_numTasks(0), _M_fHasExplicitToken(false)
6809  {
6810  }
6811  ~_RunAnyParam()
6812  {
6813  if (_CancellationTokenState::_IsValid(_M_exceptionRelatedToken))
6814  _M_exceptionRelatedToken->_Release();
6815  }
6816  task_completion_event<_CompletionType> _M_Completed;
6817  cancellation_token_source _M_cancellationSource;
6818  _CancellationTokenState * _M_exceptionRelatedToken;
6819  atomic_size_t _M_completeCount;
6820  size_t _M_numTasks;
6821  bool _M_fHasExplicitToken;
6822  };
6823 
6824  template<typename _CompletionType, typename _Function, typename _TaskType>
6825  void _WhenAnyContinuationWrapper(_RunAnyParam<_CompletionType> * _PParam, const _Function & _Func, task<_TaskType>& _Task)
6826  {
6827  bool _IsTokenCancled = !_PParam->_M_fHasExplicitToken && _Task._GetImpl()->_M_pTokenState != _CancellationTokenState::_None() && _Task._GetImpl()->_M_pTokenState->_IsCanceled();
6828  if (_Task._GetImpl()->_IsCompleted() && !_IsTokenCancled)
6829  {
6830  _Func();
6831  if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
6832  {
6833  delete _PParam;
6834  }
6835  }
6836  else
6837  {
6838  _ASSERTE(_Task._GetImpl()->_IsCanceled() || _IsTokenCancled);
6839  if (_Task._GetImpl()->_HasUserException() && !_IsTokenCancled)
6840  {
6841  if (_PParam->_M_Completed._StoreException(_Task._GetImpl()->_GetExceptionHolder()))
6842  {
6843  // This can only enter once.
6844  _PParam->_M_exceptionRelatedToken = _Task._GetImpl()->_M_pTokenState;
6845  _ASSERTE(_PParam->_M_exceptionRelatedToken);
6846  // Deref token will be done in the _PParam destructor.
6847  if (_PParam->_M_exceptionRelatedToken != _CancellationTokenState::_None())
6848  {
6849  _PParam->_M_exceptionRelatedToken->_Reference();
6850  }
6851  }
6852  }
6853 
6854  if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
6855  {
6856  // If no one has be completed so far, we need to make some final cancellation decision.
6857  if (!_PParam->_M_Completed._IsTriggered())
6858  {
6859  // If we already explicit token, we can skip the token join part.
6860  if (!_PParam->_M_fHasExplicitToken)
6861  {
6862  if (_PParam->_M_exceptionRelatedToken)
6863  {
6864  _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PParam->_M_exceptionRelatedToken);
6865  }
6866  else
6867  {
6868  // If haven't captured any exception token yet, there was no exception for all those tasks,
6869  // so just pick a random token (current one) for normal cancellation.
6870  _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Task._GetImpl()->_M_pTokenState);
6871  }
6872  }
6873  // Do exception cancellation or normal cancellation based on whether it has stored exception.
6874  _PParam->_M_Completed._Cancel();
6875  }
6876  delete _PParam;
6877  }
6878  }
6879  }
6880 
6881  template<typename _ElementType, typename _Iterator>
6882  struct _WhenAnyImpl
6883  {
6884  static task<std::pair<_ElementType, size_t>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
6885  {
6886  if( _Begin == _End )
6887  {
6888  throw invalid_operation("when_any(begin, end) cannot be called on an empty container.");
6889  }
6890  _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
6891  auto _PParam = new _RunAnyParam<std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *>>();
6892 
6893  if (_PTokenState)
6894  {
6895  _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState);
6896  _PParam->_M_fHasExplicitToken = true;
6897  }
6898 
6899  task_options _Options(_TaskOptions);
6900  _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token());
6901  task<std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options);
6902 
6903  // Keep a copy ref to the token source
6904  auto _CancellationSource = _PParam->_M_cancellationSource;
6905 
6906  _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End));
6907  size_t _Index = 0;
6908  for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6909  {
6910  if (_PTask->is_apartment_aware())
6911  {
6912  _Any_tasks_completed._SetAsync();
6913  }
6914 
6915  _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) {
6916  auto _PParamCopy = _PParam; // Dev10
6917  auto _IndexCopy = _Index; // Dev10
6918  auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() {
6919  _PParamCopy->_M_Completed.set(std::make_pair(std::make_pair(_ResultTask._GetImpl()->_GetResult(), _IndexCopy), _ResultTask._GetImpl()->_M_pTokenState));
6920  };
6921 
6922  _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
6923  }, _CancellationTokenState::_None());
6924 
6925  _Index++;
6926  }
6927 
6928  // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.
6929  return _Any_tasks_completed._Then([=](std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *> _Result) -> std::pair<_ElementType, size_t> {
6930  _ASSERTE(_Result.second);
6931  if (!_PTokenState)
6932  {
6933  _JoinAllTokens_Add(_CancellationSource, _Result.second);
6934  }
6935  return _Result.first;
6936  }, nullptr);
6937  }
6938  };
6939 
6940  template<typename _Iterator>
6941  struct _WhenAnyImpl<void, _Iterator>
6942  {
6943  static task<size_t> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
6944  {
6945  if( _Begin == _End )
6946  {
6947  throw invalid_operation("when_any(begin, end) cannot be called on an empty container.");
6948  }
6949 
6950  _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
6951  auto _PParam = new _RunAnyParam<std::pair<size_t, _CancellationTokenState *>>();
6952 
6953  if (_PTokenState)
6954  {
6955  _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState);
6956  _PParam->_M_fHasExplicitToken = true;
6957  }
6958 
6959  task_options _Options(_TaskOptions);
6960  _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token());
6961  task<std::pair<size_t, _CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options);
6962 
6963  // Keep a copy ref to the token source
6964  auto _CancellationSource = _PParam->_M_cancellationSource;
6965 
6966  _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End));
6967  size_t _Index = 0;
6968  for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6969  {
6970  if (_PTask->is_apartment_aware())
6971  {
6972  _Any_tasks_completed._SetAsync();
6973  }
6974 
6975  _PTask->_Then([_PParam, _Index](task<void> _ResultTask) {
6976  auto _PParamCopy = _PParam; // Dev10
6977  auto _IndexCopy = _Index; // Dev10
6978  auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() {
6979  _PParamCopy->_M_Completed.set(std::make_pair(_IndexCopy, _ResultTask._GetImpl()->_M_pTokenState));
6980  };
6981  _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
6982  }, _CancellationTokenState::_None());
6983 
6984  _Index++;
6985  }
6986 
6987  // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.
6988  return _Any_tasks_completed._Then([=](std::pair<size_t, _CancellationTokenState *> _Result) -> size_t {
6989  _ASSERTE(_Result.second);
6990  if (!_PTokenState)
6991  {
6992  _JoinAllTokens_Add(_CancellationSource, _Result.second);
6993  }
6994  return _Result.first;
6995  }, nullptr);
6996  }
6997  };
6998 } // namespace details
6999 
7019 
7020 template<typename _Iterator>
7021 auto when_any(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options())
7022  -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End))
7023 {
7024  typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
7025  return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End);
7026 }
7027 
7051 
7052 template<typename _Iterator>
7053 auto when_any(_Iterator _Begin, _Iterator _End, cancellation_token _CancellationToken)
7054  -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End))
7055 {
7056  typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
7057  return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End);
7058 }
7059 
7085 
7086 template<typename _ReturnType>
7087 task<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs)
7088 {
7089  auto _PParam = new details::_RunAnyParam<std::pair<_ReturnType, size_t>>();
7090 
7091  task<std::pair<_ReturnType, size_t>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
7092  // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
7093  // So that _PParam can be used before it getting deleted.
7094  auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<_ReturnType, size_t> _Ret) -> _ReturnType {
7095  _ASSERTE(_Ret.second);
7096  _JoinAllTokens_Add(_PParam->_M_cancellationSource, reinterpret_cast<details::_CancellationTokenState *>(_Ret.second));
7097  return _Ret.first;
7098  }, nullptr);
7099 
7100  if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())
7101  {
7102  _ReturnTask._SetAsync();
7103  }
7104 
7105  _PParam->_M_numTasks = 2;
7106  auto _Continuation = [_PParam](task<_ReturnType> _ResultTask) {
7107  // Dev10 compiler bug
7108  auto _PParamCopy = _PParam;
7109  auto _Func = [&_ResultTask, _PParamCopy]() {
7110  _PParamCopy->_M_Completed.set(std::make_pair(_ResultTask._GetImpl()->_GetResult(), reinterpret_cast<size_t>(_ResultTask._GetImpl()->_M_pTokenState)));
7111  };
7112  _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
7113  };
7114 
7115  _Lhs._Then(_Continuation, details::_CancellationTokenState::_None());
7116  _Rhs._Then(_Continuation, details::_CancellationTokenState::_None());
7117 
7118  return _ReturnTask;
7119 }
7120 
7146 
7147 template<typename _ReturnType>
7148 task<std::vector<_ReturnType>> operator||(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs)
7149 {
7150  auto _PParam = new details::_RunAnyParam<std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *>>();
7151 
7152  task<std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
7153 
7154  // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
7155  // So that _PParam can be used before it getting deleted.
7156  auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *> _Ret) -> std::vector<_ReturnType> {
7157  _ASSERTE(_Ret.second);
7158  _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second);
7159  return _Ret.first;
7160  }, nullptr);
7161 
7162  if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())
7163  {
7164  _ReturnTask._SetAsync();
7165  }
7166 
7167  _PParam->_M_numTasks = 2;
7168  _Lhs._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) {
7169  // Dev10 compiler bug
7170  auto _PParamCopy = _PParam;
7171  auto _Func = [&_ResultTask, _PParamCopy]() {
7172  auto _Result = _ResultTask._GetImpl()->_GetResult();
7173  _PParamCopy->_M_Completed.set(std::make_pair(_Result, _ResultTask._GetImpl()->_M_pTokenState));
7174  };
7175  _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
7176  }, details::_CancellationTokenState::_None());
7177 
7178 
7179  _Rhs._Then([_PParam](task<_ReturnType> _ResultTask)
7180  {
7181  auto _PParamCopy = _PParam;
7182  auto _Func = [&_ResultTask, _PParamCopy]() {
7183  auto _Result = _ResultTask._GetImpl()->_GetResult();
7184 
7185  std::vector<_ReturnType> _Vec;
7186  _Vec.push_back(_Result);
7187  _PParamCopy->_M_Completed.set(std::make_pair(_Vec, _ResultTask._GetImpl()->_M_pTokenState));
7188  };
7189  _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
7190  }, details::_CancellationTokenState::_None());
7191 
7192  return _ReturnTask;
7193 }
7194 
7220 
7221 template<typename _ReturnType>
7222 task<std::vector<_ReturnType>> operator||(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)
7223 {
7224  return _Rhs || _Lhs;
7225 }
7226 
7252 
7253 inline task<void> operator||(const task<void> & _Lhs, const task<void> & _Rhs)
7254 {
7255  auto _PParam = new details::_RunAnyParam<std::pair<details::_Unit_type, details::_CancellationTokenState *>>();
7256 
7257  task<std::pair<details::_Unit_type, details::_CancellationTokenState *>> _Any_task_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
7258  // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
7259  // So that _PParam can be used before it getting deleted.
7260  auto _ReturnTask = _Any_task_completed._Then([=](std::pair<details::_Unit_type, details::_CancellationTokenState *> _Ret) {
7261  _ASSERTE(_Ret.second);
7262  details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second);
7263  }, nullptr);
7264 
7265  if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())
7266  {
7267  _ReturnTask._SetAsync();
7268  }
7269 
7270  _PParam->_M_numTasks = 2;
7271  auto _Continuation = [_PParam](task<void> _ResultTask) mutable {
7272  // Dev10 compiler needs this.
7273  auto _PParam1 = _PParam;
7274  auto _Func = [&_ResultTask, _PParam1]() {
7275  _PParam1->_M_Completed.set(std::make_pair(details::_Unit_type(), _ResultTask._GetImpl()->_M_pTokenState));
7276  };
7277  _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
7278  };
7279 
7280  _Lhs._Then(_Continuation, details::_CancellationTokenState::_None());
7281  _Rhs._Then(_Continuation, details::_CancellationTokenState::_None());
7282 
7283  return _ReturnTask;
7284 }
7285 
7286 template<typename _Ty>
7287 task<_Ty> task_from_result(_Ty _Param, const task_options& _TaskOptions = task_options())
7288 {
7289  task_completion_event<_Ty> _Tce;
7290  _Tce.set(_Param);
7291  return create_task(_Tce, _TaskOptions);
7292 }
7293 
7294 // Work around VS 2010 compiler bug
7295 #if _MSC_VER == 1600
7296 inline task<bool> task_from_result(bool _Param)
7297 {
7298  task_completion_event<bool> _Tce;
7299  _Tce.set(_Param);
7300  return create_task(_Tce, task_options());
7301 }
7302 #endif
7303 inline task<void> task_from_result(const task_options& _TaskOptions = task_options())
7304 {
7305  task_completion_event<void> _Tce;
7306  _Tce.set();
7307  return create_task(_Tce, _TaskOptions);
7308 }
7309 
7310 template<typename _TaskType, typename _ExType>
7311 task<_TaskType> task_from_exception(_ExType _Exception, const task_options& _TaskOptions = task_options())
7312 {
7313  task_completion_event<_TaskType> _Tce;
7314  _Tce.set_exception(_Exception);
7315  return create_task(_Tce, _TaskOptions);
7316 }
7317 
7318 namespace details
7319 {
7327  inline
7328  task<bool> do_while(std::function<task<bool>(void)> func)
7329  {
7330  task<bool> first = func();
7331  return first.then([=](bool guard) -> task<bool> {
7332  if (guard)
7333  return do_while(func);
7334  else
7335  return first;
7336  });
7337  }
7338 
7339 } // namespace details
7340 
7341 } // namespace Concurrency
7342 
7343 #pragma pop_macro("new")
7344 
7345 #if defined(_MSC_VER)
7346 #pragma warning(pop)
7347 #endif
7348 #pragma pack(pop)
7349 
7350 #endif // (defined(_MSC_VER) && (_MSC_VER >= 1800))
7351 
7352 #ifndef _CONCRT_H
7353 #ifndef _LWRCASE_CNCRRNCY
7354 #define _LWRCASE_CNCRRNCY
7355 // Note to reader: we're using lower-case namespace names everywhere, but the 'Concurrency' namespace
7356 // is capitalized for historical reasons. The alias let's us pretend that style issue doesn't exist.
7357 namespace Concurrency {}
7358 namespace concurrency = Concurrency;
7359 #endif
7360 #endif
7361 
7362 #endif // _PPLXTASKS_H
bool _Cancel() const
Internal method to cancel the task_completion_event. Any task created using this event will be marked...
Definition: pplxtasks.h:2776
A generic RAII wrapper for locks that implements the critical_section interface cpprest_synchronizati...
Definition: pplxlinux.h:264
task_options(std::shared_ptr< _SchedType > _Scheduler)
Task option that specify a scheduler with shared lifetime
Definition: pplxtasks.h:1295
bool _StoreException(const std::shared_ptr< details::_ExceptionHolder > &_ExHolder) const
Method that stores an exception in the task completion event. This is used internally by when_any...
Definition: pplxtasks.h:2999
task_options(const task_options &_TaskOptions)
Task option copy constructor
Definition: pplxtasks.h:1331
void _SetAsync(bool _Async=true)
Sets a property determining whether the task is apartment aware.
Definition: pplxtasks.h:3666
Definition: pplxtasks.h:1436
The task_completion_event class allows you to delay the execution of a task until a condition is sati...
Definition: pplxtasks.h:2934
bool has_scheduler() const
Indicates whether a scheduler n was specified by the user
Definition: pplxtasks.h:1384
task()
Constructs a task object.
Definition: pplxtasks.h:4204
void _ScheduleTask(_UnrealizedChore_t *_PTaskHandle, _TaskInliningMode_t _InliningMode)
Helper function to schedule the task on the Task Collection.
Definition: pplxtasks.h:1979
The pplx namespace provides classes and functions that give you access to the Concurrency Runtime...
Definition: pplx.h:81
void result_type
The type of the result an object of this class produces.
Definition: pplxtasks.h:4180
task_status wait() const
Waits for this task to reach a terminal state. It is possible for wait to execute the task inline...
Definition: pplxtasks.h:3512
Definition: pplxtasks.h:1588
task & operator=(task &&_Other)
Replaces the contents of one task object with another.
Definition: pplxtasks.h:3396
Callstack container, which is used to capture and preserve callstacks in ppltasks. Members of this class is examined by vc debugger, thus there will be no public access methods. Please note that names of this class should be kept stable for debugger examining.
Definition: pplxtasks.h:257
void _SetImpl(const typename details::_Task_ptr< _ReturnType >::_Type &_Impl)
Set the implementation of the task to be the supplied implementaion.
Definition: pplxtasks.h:3648
__declspec(noinline) auto then(const _Function &_Func) const -> typename details::_ContinuationTypeTraits< _Function, _ReturnType >::_TaskOfType
Adds a continuation task to this task.
Definition: pplxtasks.h:3426
task(const task &_Other)
Constructs a task object.
Definition: pplxtasks.h:3336
bool _Cancel(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint=details::_TaskCreationCallstack()) const
Internal method to cancel the task_completion_event with the exception provided. Any task created usi...
Definition: pplxtasks.h:2787
Definition: pplxtasks.h:832
_PPLXIMP std::shared_ptr< pplx::scheduler_interface > _pplx_cdecl get_ambient_scheduler()
Gets the ambient scheduler to be used by the PPL constructs
Definition: pplxtasks.h:2593
struct __declspec(novtable) scheduler_interface
Scheduler Interface
Definition: pplxinterface.h:64
void _CreateImpl(details::_CancellationTokenState *_Ct, scheduler_ptr _Scheduler)
Create an underlying task implementation.
Definition: pplxtasks.h:4509
static task_continuation_context use_default()
Creates the default task continuation context.
Definition: pplxtasks.h:1152
Definition: pplxtasks.h:324
auto _Then(const _Function &_Func, details::_CancellationTokenState *_PTokenState, details::_TaskInliningMode_t _InliningMode=details::_ForceInline) const -> typename details::_ContinuationTypeTraits< _Function, void >::_TaskOfType
An internal version of then that takes additional flags and executes the continuation inline...
Definition: pplxtasks.h:4558
bool _pplx_cdecl is_task_cancellation_requested()
Returns an indication of whether the task that is currently executing has received a request to cance...
Definition: pplxtasks.h:230
const details::_Task_ptr< _ReturnType >::_Type & _GetImpl() const
Return the underlying implementation for this task.
Definition: pplxtasks.h:3640
Definition: pplxtasks.h:581
The _PPLTaskHandle is the strong-typed task handle base. All user task functions need to be wrapped i...
Definition: pplxtasks.h:1621
virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr< _ExceptionHolder > &_ExceptionHolder_arg)
Requests cancellation on the task and schedules continuations if the task can be transitioned to a te...
Definition: pplxtasks.h:2426
void set_cancellation_token(cancellation_token _Token)
Sets the given token in the options
Definition: pplxtasks.h:1343
bool operator!=(const task< void > &_Rhs) const
Determines whether two task objects represent different internal tasks.
Definition: pplxtasks.h:4501
void _Cancel() const
Cancel the task_completion_event. Any task created using this event will be marked as canceled if it ...
Definition: pplxtasks.h:2980
__declspec(noinline) bool set_exception(std
Propagates an exception to all tasks associated with this event.
Definition: pplxtasks.h:2969
bool is_done() const
Determines if the task is completed.
Definition: pplxtasks.h:3558
Definition: pplxtasks.h:1599
Represents a pointer to a scheduler. This class exists to allow the the specification of a shared lif...
Definition: pplxinterface.h:74
void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack)
Sets a field in the task impl to the return callstack for calls to the task constructors and the then...
Definition: pplxtasks.h:4549
This class describes an exception thrown by the PPL tasks layer in order to force the current task to...
Definition: pplxcancellation_token.h:56
void _RunContinuation(_ContinuationTaskHandleBase *_PTaskHandle)
Function executes a continuation. This function is recorded by a parent task implementation when a co...
Definition: pplxtasks.h:2021
task_options(cancellation_token _Token)
Task option that specify a cancellation token
Definition: pplxtasks.h:1258
task & operator=(const task &_Other)
Replaces the contents of one task object with another.
Definition: pplxtasks.h:3376
void _SetImpl(const details::_Task_ptr< details::_Unit_type >::_Type &_Impl)
Set the implementation of the task to be the supplied implementaion.
Definition: pplxtasks.h:4525
Definition: pplxtasks.h:420
bool has_cancellation_token() const
Indicates whether a cancellation token was specified by the user
Definition: pplxtasks.h:1360
task_options(scheduler_ptr _Scheduler)
Task option that specify a scheduler
Definition: pplxtasks.h:1319
Definition: pplxtasks.h:457
scheduler_ptr scheduler() const
Returns the scheduler for this task
Definition: pplxtasks.h:3574
Definition: pplxtasks.h:291
task_completion_event()
Constructs a task_completion_event object.
Definition: pplxtasks.h:2681
cancellation_token get_cancellation_token() const
Returns the cancellation token
Definition: pplxtasks.h:1368
task_options()
Default list of task creation options
Definition: pplxtasks.h:1246
Definition: pplxtasks.h:489
Definition: pplxtasks.h:426
The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed as...
Definition: pplxtasks.h:176
bool set(_ResultType _Result) const
Sets the task completion event.
Definition: pplxtasks.h:2702
The tasks queued to the task_group or structured_task_group object completed successfully.
Definition: pplxinterface.h:143
Definition: pplxtasks.h:1426
Definition: pplxcancellation_token.h:256
The cancellation_token class represents the ability to determine whether some operation has been requ...
Definition: pplxcancellation_token.h:712
task_status wait() const
Waits for this task to reach a terminal state. It is possible for wait to execute the task inline...
Definition: pplxtasks.h:4426
bool is_apartment_aware() const
Determines whether the task unwraps a Windows Runtime IAsyncInfo interface or is descended from such ...
Definition: pplxtasks.h:3591
Definition: pplxtasks.h:473
bool operator==(const task< void > &_Rhs) const
Determines whether two task objects represent the same internal task.
Definition: pplxtasks.h:4489
Definition: pplxtasks.h:510
Represents the allowed options for creating a task
Definition: pplxtasks.h:1238
task_options(scheduler_interface &_Scheduler)
Task option that specify a scheduler reference
Definition: pplxtasks.h:1307
bool operator!=(const task< _ReturnType > &_Rhs) const
Determines whether two task objects represent different internal tasks.
Definition: pplxtasks.h:3619
scheduler_ptr scheduler() const
Returns the scheduler for this task
Definition: pplxtasks.h:4465
Definition: pplxtasks.h:4671
Definition: pplx.h:115
The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed as...
Definition: pplxtasks.h:4173
bool is_apartment_aware() const
Determines whether the task unwraps a Windows Runtime IAsyncInfo interface or is descended from such ...
Definition: pplxtasks.h:4477
bool _StoreException(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint=details::_TaskCreationCallstack()) const
Internal method that stores an exception in the task completion event. This is used internally by whe...
Definition: pplxtasks.h:2808
Definition: pplxtasks.h:300
bool operator==(const task< _ReturnType > &_Rhs) const
Determines whether two task objects represent the same internal task.
Definition: pplxtasks.h:3607
const details::_Task_ptr< details::_Unit_type >::_Type & _GetImpl() const
Return the underlying implementation for this task.
Definition: pplxtasks.h:4517
_ReturnType result_type
The type of the result an object of this class produces.
Definition: pplxtasks.h:3185
static cancellation_token none()
Returns a cancellation token which can never be subject to cancellation.
Definition: pplxcancellation_token.h:724
Definition: astreambuf.h:37
task_continuation_context get_continuation_context() const
Returns the continuation context
Definition: pplxtasks.h:1376
bool _IsTriggered() const
Tests whether current event has been either Set, or Canceled.
Definition: pplxtasks.h:2824
void _SetImpl(typename details::_Task_ptr< _ReturnType >::_Type &&_Impl)
Set the implementation of the task to be the supplied implementaion using a move instead of a copy...
Definition: pplxtasks.h:3657
Definition: pplxtasks.h:4680
__declspec(noinline) bool set_exception(std
Propagates an exception to all tasks associated with this event.
Definition: pplxtasks.h:2765
Definition: pplxtasks.h:312
Definition: pplxtasks.h:3144
Definition: pplxtasks.h:156
void _Cancel(const std::shared_ptr< details::_ExceptionHolder > &_ExHolder) const
Cancel the task_completion_event with the exception holder provided. Any task created using this even...
Definition: pplxtasks.h:2989
auto _Then(const _Function &_Func, details::_CancellationTokenState *_PTokenState, details::_TaskInliningMode_t _InliningMode=details::_ForceInline) const -> typename details::_ContinuationTypeTraits< _Function, _ReturnType >::_TaskOfType
An internal version of then that takes additional flags and always execute the continuation inline by...
Definition: pplxtasks.h:3685
task_options(cancellation_token _Token, task_continuation_context _ContinuationContext)
Task option that specify a cancellation token and a continuation context. This is valid only for cont...
Definition: pplxtasks.h:1282
Definition: pplxtasks.h:1216
bool _IsTriggered() const
Test whether current event has been either Set, or Canceled.
Definition: pplxtasks.h:3007
task()
Constructs a task object.
Definition: pplxtasks.h:3209
A helper class template that transforms a continuation lambda that either takes or returns void...
Definition: pplxtasks.h:3102
void _SetAsync(bool _Async=true)
Sets a property determining whether the task is apartment aware.
Definition: pplxtasks.h:4541
bool set() const
Sets the task completion event.
Definition: pplxtasks.h:2950
void _SetImpl(details::_Task_ptr< details::_Unit_type >::_Type &&_Impl)
Set the implementation of the task to be the supplied implementaion using a move instead of a copy...
Definition: pplxtasks.h:4533
Definition: pplxtasks.h:921
Definition: pplxtasks.h:295
task_group_status
Describes the execution status of a task_group or structured_task_group object. A value of this type ...
Definition: pplxinterface.h:130
__declspec(noinline) explicit task(_Ty _Param)
Constructs a task object.
Definition: pplxtasks.h:3251
scheduler_ptr get_scheduler() const
Returns the scheduler
Definition: pplxtasks.h:1392
void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack)
Sets a field in the task impl to the return callstack for calls to the task constructors and the then...
Definition: pplxtasks.h:3674
task(task &&_Other)
Constructs a task object.
Definition: pplxtasks.h:3363
The implementation of a first-class task. This structure contains the task group used to execute the ...
Definition: pplxtasks.h:1423
void _ScheduleContinuation(_ContinuationTaskHandleBase *_PTaskHandle)
Schedule the actual continuation. This will either schedule the function on the continuation task's i...
Definition: pplxtasks.h:2124
Helper object used for LWT invocation.
Definition: pplxtasks.h:528
Definition: pplxcancellation_token.h:301
void _CreateImpl(details::_CancellationTokenState *_Ct, scheduler_ptr _Scheduler)
Create an underlying task implementation.
Definition: pplxtasks.h:3627
The task_group or structured_task_group object was canceled. One or more tasks may not have executed...
Definition: pplxinterface.h:149
The base implementation of a first-class task. This class contains all the non-type specific implemen...
Definition: pplxtasks.h:1688
The task_continuation_context class allows you to specify where you would like a continuation to be e...
Definition: pplxtasks.h:1131
The task_completion_event class allows you to delay the execution of a task until a condition is sati...
Definition: pplxtasks.h:2674
task_group_status task_status
A type that represents the terminal state of a task. Valid values are completed and canceled...
Definition: pplxtasks.h:174
task_options(task_continuation_context _ContinuationContext)
Task option that specify a continuation context. This is valid only for continuations (then) ...
Definition: pplxtasks.h:1270
This class describes an exception thrown when an invalid operation is performed that is not more accu...
Definition: pplxcancellation_token.h:99
void set_continuation_context(task_continuation_context _ContinuationContext)
Sets the given continuation context in the options
Definition: pplxtasks.h:1352
Definition: pplxtasks.h:294
bool is_done() const
Determines if the task is completed.
Definition: pplxtasks.h:4454