18 #ifndef viskores_worklet_internal_DispatcherBase_h
19 #define viskores_worklet_internal_DispatcherBase_h
42 #include <viskoresstd/integer_sequence.h>
43 #include <viskoresstd/is_trivial.h>
54 template <
typename Domain>
55 inline auto SchedulingRange(
const Domain& inputDomain) -> decltype(inputDomain.GetNumberOfValues())
57 return inputDomain.GetNumberOfValues();
60 template <
typename Domain>
61 inline auto SchedulingRange(
const Domain*
const inputDomain)
62 -> decltype(inputDomain->GetNumberOfValues())
64 return inputDomain->GetNumberOfValues();
67 template <
typename Domain,
typename SchedulingRangeType>
68 inline auto SchedulingRange(
const Domain& inputDomain, SchedulingRangeType type)
69 -> decltype(inputDomain.GetSchedulingRange(type))
71 return inputDomain.GetSchedulingRange(type);
74 template <
typename Domain,
typename SchedulingRangeType>
75 inline auto SchedulingRange(
const Domain*
const inputDomain, SchedulingRangeType type)
76 -> decltype(inputDomain->GetSchedulingRange(type))
78 return inputDomain->GetSchedulingRange(type);
92 inline void PrintFailureMessage(
int index)
94 std::stringstream message;
95 message <<
"Encountered bad type for parameter " << index
96 <<
" when calling Invoke on a dispatcher.";
100 inline void PrintNullPtrMessage(
int index,
int mode)
102 std::stringstream message;
105 message <<
"Encountered nullptr for parameter " << index;
109 message <<
"Encountered nullptr for " << index <<
" from last parameter ";
111 message <<
" when calling Invoke on a dispatcher.";
115 template <
typename T>
116 inline void not_nullptr(T* ptr,
int index,
int mode = 0)
120 PrintNullPtrMessage(index, mode);
123 template <
typename T>
124 inline void not_nullptr(T&&,
int,
int mode = 0)
129 template <
typename T>
130 inline T& as_ref(T* ptr)
134 template <
typename T>
135 inline T&& as_ref(T&& t)
137 return std::forward<T>(t);
141 template <
typename T,
bool noError>
142 struct ReportTypeOnError : std::integral_constant<bool, noError>
146 template <
int Value,
bool noError>
147 struct ReportValueOnError : std::integral_constant<bool, noError>
151 template <
typename Type>
152 struct IsDynamicTypeImpl
154 using T = viskores::internal::remove_pointer_and_decay<Type>;
155 using DynamicTag =
typename viskores::cont::internal::DynamicTransformTraits<T>::DynamicTag;
157 typename std::is_same<DynamicTag,
158 viskores::cont::internal::DynamicTransformTagCastAndCall>::type;
160 template <
typename T>
161 using IsDynamicType =
typename IsDynamicTypeImpl<T>::type;
163 template <
typename SigTagList,
typename ParamList,
typename IndexSequence>
164 struct ZipControlParamImpl;
166 struct ZipControlParamImpl<
viskores::List<SigTags...>,
168 viskoresstd::integer_sequence<viskores::IdComponent, Indices...>>
178 template <
typename SigTagList,
typename ParamList,
typename IndexSequence>
179 using ZipControlParam =
typename ZipControlParamImpl<SigTagList, ParamList, IndexSequence>::type;
181 template <
typename WorkletType>
182 struct ControlArgumentValidator
184 template <
typename SigTag,
typename Param, viskores::IdComponent Index>
186 viskores::List<SigTag, Param, std::integral_constant<viskores::IdComponent, Index>>)
const
188 using T = std::remove_pointer_t<Param>;
189 using TypeCheckTag =
typename SigTag::TypeCheckTag;
194 "If you get an error here, that means that your code has invoked a worklet,"
195 " and one of the arguments of the Invoke is the wrong type. Each argument of the invoke"
196 " corresponds to a tag in the arguments of the ControlSignature of the worklet. If there"
197 " is a mismatch, then you get an error here (instead of where you called invoke). For"
198 " example, if the worklet has a control signature as ControlSignature(CellSetIn, ...) and"
199 " the first argument passed to the invoke is an ArrayHandle, you will get an error here"
200 " because you cannot use an ArrayHandle in place of a CellSetIn argument. (You need to use"
201 " a CellSet.) If the compiler supports it, the next few errors on the following lines of"
202 " code will give information about where the error actually occurred.");
212 static_assert(ReportTypeOnError<WorkletType, isCorrect>::value,
213 "The first template argument to ReportTypeOnError is the worklet being invoked");
214 static_assert(ReportValueOnError<Index, isCorrect>::value,
215 "The first template argument to ReportTypeOnError is the index of Invoke "
216 "parameter (starting at index 1)");
217 static_assert(ReportTypeOnError<T, isCorrect>::value,
218 "The first template argument to ReportTypeOnError is the type passed to Invoke");
219 static_assert(ReportTypeOnError<TypeCheckTag, isCorrect>::value,
220 "The first template argument to ReportTypeOnError is the type check tag used");
226 struct DispatcherBaseControlSignatureTagCheck
228 template <
typename ControlSignatureTag, viskores::IdComponent Index>
234 using type = ControlSignatureTag;
240 struct DispatcherBaseExecutionSignatureTagCheck
242 template <
typename ExecutionSignatureTag, viskores::IdComponent Index>
248 using type = ExecutionSignatureTag;
252 struct DispatcherBaseTryExecuteFunctor
254 template <
typename Device,
typename DispatcherBaseType,
typename Invocation,
typename RangeType>
256 const DispatcherBaseType*
self,
257 Invocation& invocation,
258 const RangeType& dimensions)
260 auto outputRange =
self->Scatter.GetOutputRange(dimensions);
261 self->InvokeTransportParameters(
262 invocation, dimensions, outputRange, self->Mask.GetThreadRange(outputRange), device);
269 template <
typename ControlInterface, viskores::IdComponent Index>
270 struct DispatcherBaseTransportInvokeTypes
273 using ControlSignatureTag =
typename ControlInterface::template ParameterType<Index>::type;
274 using TransportTag =
typename ControlSignatureTag::TransportTag;
286 return range[0] * range[1] * range[2];
291 template <
typename ControlInterface,
typename InputDomainType,
typename Device>
292 struct DispatcherBaseTransportFunctor
294 const InputDomainType& InputDomain;
303 template <
typename InputRangeType,
typename OutputRangeType>
304 VISKORES_CONT DispatcherBaseTransportFunctor(
const InputDomainType& inputDomain,
305 const InputRangeType& inputRange,
306 const OutputRangeType& outputRange,
308 : InputDomain(inputDomain)
309 , InputRange(FlatRange(inputRange))
310 , OutputRange(FlatRange(outputRange))
316 template <
typename ControlParameter, viskores::IdComponent Index>
320 typename DispatcherBaseTransportInvokeTypes<ControlInterface, Index>::TransportTag;
321 using T = viskores::internal::remove_pointer_and_decay<ControlParameter>;
323 using type =
typename std::decay<typename TransportType::ExecObjectType>::type;
331 VISKORES_IS_TRIVIALLY_COPYABLE(type);
334 template <
typename ControlParameter, viskores::IdComponent Index>
335 VISKORES_CONT typename ReturnType<ControlParameter, Index>::type operator()(
336 ControlParameter&& invokeData,
337 viskores::internal::IndexTag<Index>)
const
340 typename DispatcherBaseTransportInvokeTypes<ControlInterface, Index>::TransportTag;
341 using T = viskores::internal::remove_pointer_and_decay<ControlParameter>;
344 not_nullptr(invokeData,
Index);
345 return transport(as_ref(invokeData),
346 as_ref(this->InputDomain),
355 void operator=(
const DispatcherBaseTransportFunctor&) =
delete;
360 template <
typename L>
361 struct ListRemoveFirstImpl;
362 template <
typename T,
typename... Ts>
363 struct ListRemoveFirstImpl<
viskores::List<T, Ts...>>
367 template <
typename L>
368 using ListRemoveFirst =
typename ListRemoveFirstImpl<L>::type;
371 template <std::
size_t LeftToProcess>
372 struct for_each_dynamic_arg;
374 template <std::
size_t LeftToProcess,
typename TypeCheckTag>
375 struct convert_arg_wrapper
377 template <
typename T,
typename... Args>
378 void operator()(T&& t, Args&&... args)
const
380 using Type =
typename std::decay<T>::type;
382 std::integral_constant<bool, viskores::cont::arg::TypeCheck<TypeCheckTag, Type>::value>;
383 this->WillContinue(valid(), std::forward<T>(t), std::forward<Args>(args)...);
385 template <
typename T,
typename... Args>
386 void WillContinue(std::true_type, T&& t, Args&&... args)
const
388 for_each_dynamic_arg<LeftToProcess - 1>()(std::forward<Args>(args)..., std::forward<T>(t));
390 template <
typename... Args>
391 void WillContinue(std::false_type, Args&&...)
const
393 viskores::worklet::internal::detail::PrintFailureMessage(LeftToProcess);
397 template <std::size_t LeftToProcess,
402 inline void convert_arg(viskores::cont::internal::DynamicTransformTagStatic,
405 const Trampoline& trampoline,
408 using popped_sig = ListRemoveFirst<ContParams>;
409 for_each_dynamic_arg<LeftToProcess - 1>()(
410 trampoline, popped_sig(), std::forward<Args>(args)..., std::forward<T>(t));
413 template <std::size_t LeftToProcess,
418 inline void convert_arg(viskores::cont::internal::DynamicTransformTagCastAndCall,
421 const Trampoline& trampoline,
425 using popped_sig = ListRemoveFirst<ContParams>;
427 not_nullptr(t, LeftToProcess, 1);
429 convert_arg_wrapper<LeftToProcess, tag_check>(),
432 std::forward<Args>(args)...);
435 template <std::
size_t LeftToProcess>
436 struct for_each_dynamic_arg
438 template <
typename Trampoline,
typename ContParams,
typename T,
typename... Args>
439 void operator()(
const Trampoline& trampoline, ContParams&& sig, T&& t, Args&&... args)
const
442 using Type = viskores::internal::remove_pointer_and_decay<T>;
443 using tag =
typename viskores::cont::internal::DynamicTransformTraits<Type>::DynamicTag;
445 convert_arg<LeftToProcess>(
446 tag(), std::forward<T>(t), sig, trampoline, std::forward<Args>(args)...);
451 struct for_each_dynamic_arg<0>
453 template <
typename Trampoline,
typename ContParams,
typename... Args>
454 void operator()(
const Trampoline& trampoline, ContParams&&, Args&&... args)
const
456 trampoline.StartInvokeDynamic(std::false_type(), std::forward<Args>(args)...);
460 template <
typename Trampoline,
typename ContParams,
typename... Args>
461 inline void deduce(Trampoline&& trampoline, ContParams&& sig, Args&&... args)
463 for_each_dynamic_arg<
sizeof...(Args)>()(std::forward<Trampoline>(trampoline), sig, args...);
470 template <viskores::IdComponent MaxIndexAllowed>
471 struct PlaceholderValidator
473 PlaceholderValidator() {}
477 void operator()(viskores::internal::meta::Type<viskores::placeholders::Arg<N>>)
const
479 static_assert(N <= MaxIndexAllowed,
480 "An argument in the execution signature"
481 " (usually _2, _3, _4, etc.) refers to a control signature argument that"
482 " does not exist. For example, you will get this error if you have _3 (or"
483 " _4 or _5 or so on) as one of the execution signature arguments, but you"
484 " have fewer than 3 (or 4 or 5 or so on) arguments in the control signature.");
487 template <
typename DerivedType>
488 void operator()(viskores::internal::meta::Type<DerivedType>)
const
496 template <
typename DerivedClass,
typename WorkletType,
typename BaseWorkletType>
500 using MyType = DispatcherBase<DerivedClass, WorkletType, BaseWorkletType>;
502 friend struct detail::for_each_dynamic_arg<0>;
505 using ControlInterface =
506 viskores::internal::FunctionInterface<typename WorkletType::ControlSignature>;
510 using ExecutionSignature =
511 typename viskores::placeholders::GetExecSig<WorkletType>::ExecutionSignature;
512 using ExecutionInterface = viskores::internal::FunctionInterface<ExecutionSignature>;
519 using ControlSignatureCheck =
typename ControlInterface::template StaticTransformType<
520 detail::DispatcherBaseControlSignatureTagCheck>::type;
521 using ExecutionSignatureCheck =
typename ExecutionInterface::template StaticTransformType<
522 detail::DispatcherBaseExecutionSignatureTagCheck>::type;
524 template <
typename... Args>
527 using ParameterInterface =
528 viskores::internal::FunctionInterface<void(viskores::internal::remove_cvref<Args>...)>;
531 "Dispatcher Invoke called with wrong number of arguments.");
534 std::is_base_of<BaseWorkletType, WorkletType>::value,
535 "The worklet being scheduled by this dispatcher doesn't match the type of the dispatcher");
539 using ComponentSig =
typename ExecutionInterface::ComponentSig;
549 using ParamTypes =
typename ParameterInterface::ParameterSig;
552 this->StartInvokeDynamic(HasDynamicTypes(), std::forward<Args>(args)...);
555 template <
typename... Args>
556 VISKORES_CONT void StartInvokeDynamic(std::true_type, Args&&... args)
const
562 using ContParamsInfo =
563 viskores::internal::detail::FunctionSigInfo<typename WorkletType::ControlSignature>;
564 typename ContParamsInfo::Parameters parameters;
565 detail::deduce(*
this, parameters, std::forward<Args>(args)...);
568 template <
typename... Args>
569 VISKORES_CONT void StartInvokeDynamic(std::false_type, Args&&... args)
const
571 using ParameterInterface =
572 viskores::internal::FunctionInterface<void(viskores::internal::remove_cvref<Args>...)>;
577 using ParamTypes =
typename ParameterInterface::ParameterSig;
578 using ContSigTypes =
typename viskores::internal::detail::FunctionSigInfo<
579 typename WorkletType::ControlSignature>::Parameters;
580 using ParamZip = detail::ZipControlParam<
590 viskores::internal::make_FunctionInterface<void, viskores::internal::remove_cvref<Args>...>(
592 auto ivc = viskores::internal::Invocation<ParameterInterface,
595 WorkletType::InputDomain::INDEX,
596 viskores::internal::NullType,
597 viskores::internal::NullType>(
598 fi, viskores::internal::NullType{}, viskores::internal::NullType{});
599 static_cast<const DerivedClass*
>(
this)->DoInvoke(ivc);
614 using ScatterType =
typename WorkletType::ScatterType;
615 using MaskType =
typename WorkletType::MaskType;
617 template <
typename... Args>
621 "Invoking Worklet: '%s'",
622 viskores::cont::TypeToString<DerivedClass>().c_str());
623 this->StartInvoke(std::forward<Args>(args)...);
632 DispatcherBase(
const WorkletType& worklet = WorkletType(),
633 const ScatterType& scatter = ScatterType(),
634 const MaskType& mask = MaskType())
638 , Device(
viskores::cont::DeviceAdapterTagAny())
647 DispatcherBase(
const ScatterType& scatter,
const MaskType& mask = MaskType())
648 : Worklet(WorkletType())
651 , Device(
viskores::cont::DeviceAdapterTagAny())
660 DispatcherBase(
const WorkletType& worklet,
661 const MaskType& mask,
662 const ScatterType& scatter = ScatterType())
666 , Device(
viskores::cont::DeviceAdapterTagAny())
675 DispatcherBase(
const MaskType& mask,
const ScatterType& scatter = ScatterType())
676 : Worklet(WorkletType())
679 , Device(
viskores::cont::DeviceAdapterTagAny())
683 friend struct internal::detail::DispatcherBaseTryExecuteFunctor;
685 template <
typename Invocation>
690 internal::detail::DispatcherBaseTryExecuteFunctor(),
700 template <
typename Invocation>
703 this->BasicInvoke(invocation,
viskores::Id3(dimensions[0], dimensions[1], 1));
706 template <
typename Invocation>
711 internal::detail::DispatcherBaseTryExecuteFunctor(),
727 DispatcherBase(
const MyType&) =
delete;
728 void operator=(
const MyType&) =
delete;
732 template <
typename Invocation,
733 typename InputRangeType,
734 typename OutputRangeType,
735 typename ThreadRangeType,
736 typename DeviceAdapter>
737 VISKORES_CONT void InvokeTransportParameters(Invocation& invocation,
738 const InputRangeType& inputRange,
739 OutputRangeType&& outputRange,
740 ThreadRangeType&& threadRange,
741 DeviceAdapter device)
const
756 using ParameterInterfaceType =
typename Invocation::ParameterInterface;
757 ParameterInterfaceType& parameters = invocation.Parameters;
759 using TransportFunctorType =
760 detail::DispatcherBaseTransportFunctor<
typename Invocation::ControlInterface,
761 typename Invocation::InputDomainType,
763 using ExecObjectParameters =
764 typename ParameterInterfaceType::template StaticTransformType<TransportFunctorType>::type;
766 ExecObjectParameters execObjectParameters = parameters.StaticTransformCont(
767 TransportFunctorType(invocation.GetInputDomain(), inputRange, outputRange, token));
770 typename ScatterType::OutputToInputMapType outputToInputMap =
771 this->Scatter.GetOutputToInputMap(inputRange);
772 typename ScatterType::VisitArrayType visitArray = this->Scatter.GetVisitArray(inputRange);
775 typename MaskType::ThreadToOutputMapType threadToOutputMap =
776 this->Mask.GetThreadToOutputMap(outputRange);
780 viskores::internal::Invocation<ExecObjectParameters,
781 typename Invocation::ControlInterface,
782 typename Invocation::ExecutionInterface,
783 Invocation::InputDomainIndex,
784 decltype(outputToInputMap.PrepareForInput(device, token)),
785 decltype(visitArray.PrepareForInput(device, token)),
786 decltype(threadToOutputMap.PrepareForInput(device, token)),
788 changedInvocation(execObjectParameters,
789 outputToInputMap.PrepareForInput(device, token),
790 visitArray.PrepareForInput(device, token),
791 threadToOutputMap.PrepareForInput(device, token));
793 this->InvokeSchedule(changedInvocation, threadRange, device);
796 template <
typename Invocation,
typename RangeType,
typename DeviceAdapter>
797 VISKORES_CONT void InvokeSchedule(
const Invocation& invocation,
812 TaskTypes::MakeTask(this->Worklet, invocation, range,
typename WorkletType::Hints{});
813 Algorithm::ScheduleTask(task, range);
820 #endif //viskores_worklet_internal_DispatcherBase_h