Skip to content

Commit 5f75ec9

Browse files
committed
Merge pull request #47 from anton/fixing#418
2 parents 9052811 + 2e23b2a commit 5f75ec9

File tree

2 files changed

+90
-21
lines changed

2 files changed

+90
-21
lines changed

Release/include/pplx/pplxtasks.h

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3093,6 +3093,47 @@ namespace details
30933093
template<typename _Ty>
30943094
static std::false_type _IsValidCreateAsync(_Ty _Param, ...);
30953095
#endif /* defined (__cplusplus_winrt) */
3096+
3097+
/// <summary>
3098+
/// A helper class template that makes only movable functions be able to be passed to std::function
3099+
/// </summary>
3100+
template<typename _Ty>
3101+
struct _NonCopyableFunctorWrapper
3102+
{
3103+
template<typename _Tx, typename =
3104+
typename std::enable_if<!std::is_base_of<_NonCopyableFunctorWrapper<_Ty>,
3105+
typename std::decay<_Tx>::type>::value>::type>
3106+
explicit _NonCopyableFunctorWrapper(_Tx&& f)
3107+
: _M_functor{std::make_shared<_Ty>(std::forward<_Tx>(f))}
3108+
{}
3109+
3110+
template <class... _Args>
3111+
auto operator()(_Args&&... args) -> decltype(std::declval<_Ty>()(std::forward<_Args>(args)...))
3112+
{
3113+
return _M_functor->operator()(std::forward<_Args>(args)...);
3114+
}
3115+
3116+
template <class... _Args>
3117+
auto operator()(_Args&&... args) const -> decltype(std::declval<_Ty>()(std::forward<_Args>(args)...))
3118+
{
3119+
return _M_functor->operator()(std::forward<_Args>(args)...);
3120+
}
3121+
3122+
std::shared_ptr<_Ty> _M_functor;
3123+
};
3124+
3125+
template<typename _Ty, typename Enable = void>
3126+
struct _CopyableFunctor
3127+
{
3128+
typedef _Ty _Type;
3129+
};
3130+
3131+
template<typename _Ty>
3132+
struct _CopyableFunctor<_Ty, typename std::enable_if<
3133+
std::is_move_constructible<_Ty>::value && !std::is_copy_constructible<_Ty>::value>::type>
3134+
{
3135+
typedef _NonCopyableFunctorWrapper<_Ty> _Type;
3136+
};
30963137
}
30973138
/// <summary>
30983139
/// A helper class template that transforms a continuation lambda that either takes or returns void, or both, into a lambda that takes and returns a
@@ -3424,11 +3465,11 @@ class task
34243465
/**/
34253466
template<typename _Function>
34263467
__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
3468+
auto then(_Function&& _Func) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
34283469
{
34293470
task_options _TaskOptions;
34303471
details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
3431-
return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
3472+
return _ThenImpl<_ReturnType, _Function>(std::forward<_Function>(_Func), _TaskOptions);
34323473
}
34333474

34343475
/// <summary>
@@ -3457,10 +3498,10 @@ class task
34573498
/**/
34583499
template<typename _Function>
34593500
__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
3501+
auto then(_Function&& _Func, task_options _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
34613502
{
34623503
details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
3463-
return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
3504+
return _ThenImpl<_ReturnType, _Function>(std::forward<_Function>(_Func), _TaskOptions);
34643505
}
34653506

34663507
/// <summary>
@@ -3493,11 +3534,11 @@ class task
34933534
/**/
34943535
template<typename _Function>
34953536
__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
3537+
auto then(_Function&& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
34973538
{
34983539
task_options _TaskOptions(_CancellationToken, _ContinuationContext);
34993540
details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
3500-
return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
3541+
return _ThenImpl<_ReturnType, _Function>(std::forward<_Function>(_Func), _TaskOptions);
35013542
}
35023543

35033544
/// <summary>
@@ -3682,13 +3723,13 @@ class task
36823723
/// This function is Used for runtime internal continuations only.
36833724
/// </summary>
36843725
template<typename _Function>
3685-
auto _Then(const _Function& _Func, details::_CancellationTokenState *_PTokenState,
3726+
auto _Then(_Function&& _Func, details::_CancellationTokenState *_PTokenState,
36863727
details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
36873728
{
36883729
// inherit from antecedent
36893730
auto _Scheduler = _GetImpl()->_GetScheduler();
36903731

3691-
return _ThenImpl<_ReturnType, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);
3732+
return _ThenImpl<_ReturnType, _Function>(std::forward<_Function>(_Func), _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);
36923733
}
36933734

36943735
private:
@@ -3801,16 +3842,17 @@ class task
38013842
typedef typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type _NormalizedContinuationReturnType;
38023843

38033844
typename details::_Task_ptr<_ReturnType>::_Type _M_ancestorTaskImpl;
3804-
_Function _M_function;
3845+
typename details::_CopyableFunctor<typename std::decay<_Function>::type >::_Type _M_function;
38053846

3847+
template <class _ForwardedFunction>
38063848
_ContinuationTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _AncestorImpl,
38073849
const typename details::_Task_ptr<_NormalizedContinuationReturnType>::_Type & _ContinuationImpl,
3808-
const _Function & _Func, const task_continuation_context & _Context, details::_TaskInliningMode_t _InliningMode)
3850+
_ForwardedFunction&& _Func, const task_continuation_context & _Context, details::_TaskInliningMode_t _InliningMode)
38093851
: details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,
38103852
_ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>
38113853
::_PPLTaskHandle(_ContinuationImpl)
38123854
, _M_ancestorTaskImpl(_AncestorImpl)
3813-
, _M_function(_Func)
3855+
, _M_function(std::forward<_ForwardedFunction>(_Func))
38143856
{
38153857
this->_M_isTaskBasedContinuation = _IsTaskBased::value;
38163858
this->_M_continuationContext = _Context;
@@ -4095,7 +4137,7 @@ class task
40954137
}
40964138

40974139
template<typename _InternalReturnType, typename _Function>
4098-
auto _ThenImpl(const _Function& _Func, const task_options& _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
4140+
auto _ThenImpl(_Function&& _Func, const task_options& _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
40994141
{
41004142
if (!_M_Impl)
41014143
{
@@ -4105,14 +4147,14 @@ class task
41054147
details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
41064148
auto _Scheduler = _TaskOptions.has_scheduler() ? _TaskOptions.get_scheduler() : _GetImpl()->_GetScheduler();
41074149
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);
4150+
return _ThenImpl<_InternalReturnType, _Function>(std::forward<_Function>(_Func), _PTokenState, _TaskOptions.get_continuation_context(), _Scheduler, _CreationStack);
41094151
}
41104152

41114153
/// <summary>
41124154
/// The one and only implementation of then for void and non-void tasks.
41134155
/// </summary>
41144156
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,
4157+
auto _ThenImpl(_Function&& _Func, details::_CancellationTokenState *_PTokenState, const task_continuation_context& _ContinuationContext, scheduler_ptr _Scheduler, details::_TaskCreationCallstack _CreationStack,
41164158
details::_TaskInliningMode_t _InliningMode = details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
41174159
{
41184160
if (!_M_Impl)
@@ -4149,7 +4191,7 @@ class task
41494191
_ContinuationTask._SetTaskCreationCallstack(_CreationStack);
41504192

41514193
_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));
4194+
_GetImpl(), _ContinuationTask._GetImpl(), std::forward<_Function>(_Func), _ContinuationContext, _InliningMode));
41534195

41544196
return _ContinuationTask;
41554197
}
@@ -4371,10 +4413,10 @@ class task<void>
43714413
/**/
43724414
template<typename _Function>
43734415
__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
4416+
auto then(_Function&& _Func, task_options _TaskOptions = task_options()) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
43754417
{
43764418
details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
4377-
return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);
4419+
return _M_unitTask._ThenImpl<void, _Function>(std::forward<_Function>(_Func), _TaskOptions);
43784420
}
43794421

43804422
/// <summary>
@@ -4407,11 +4449,11 @@ class task<void>
44074449
/**/
44084450
template<typename _Function>
44094451
__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
4452+
auto then(_Function&& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
44114453
{
44124454
task_options _TaskOptions(_CancellationToken, _ContinuationContext);
44134455
details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
4414-
return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);
4456+
return _M_unitTask._ThenImpl<void, _Function>(std::forward<_Function>(_Func), _TaskOptions);
44154457
}
44164458

44174459
/// <summary>
@@ -4555,13 +4597,13 @@ class task<void>
45554597
/// An internal version of then that takes additional flags and executes the continuation inline. Used for runtime internal continuations only.
45564598
/// </summary>
45574599
template<typename _Function>
4558-
auto _Then(const _Function& _Func, details::_CancellationTokenState *_PTokenState,
4600+
auto _Then(_Function&& _Func, details::_CancellationTokenState *_PTokenState,
45594601
details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
45604602
{
45614603
// inherit from antecedent
45624604
auto _Scheduler = _GetImpl()->_GetScheduler();
45634605

4564-
return _M_unitTask._ThenImpl<void, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);
4606+
return _M_unitTask._ThenImpl<void, _Function>(std::forward<_Function>(_Func), _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode);
45654607
}
45664608

45674609
private:

Release/tests/functional/pplx/pplx_test/pplxtask_tests.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,33 @@ TEST(TestTasks_void_tasks_default_construction)
304304
}
305305
}
306306

307+
TEST(TestTasks_movable_then)
308+
{
309+
#ifndef _MSC_VER
310+
// create movable only type
311+
struct A
312+
{
313+
A() = default;
314+
A(A&&) = default;
315+
A& operator=(A&&) = default;
316+
317+
// explicitly delete copy functions
318+
A(const A&) = delete;
319+
A& operator=(const A&) = delete;
320+
321+
char operator()(int)
322+
{
323+
return 'c';
324+
}
325+
} a;
326+
327+
task<int> task = create_task([]{ return 2; });
328+
auto f = task.then(std::move(a));
329+
330+
IsTrue(f.get() == 'c', L".then should be able to work with movable functors");
331+
#endif // _MSC_VER
332+
}
333+
307334
TEST(TestTasks_constant_this)
308335
{
309336
#ifdef _MSC_VER

0 commit comments

Comments
 (0)