diff --git a/vtkm/internal/FunctionInterface.h b/vtkm/internal/FunctionInterface.h index 665f0cf98..714e671d8 100644 --- a/vtkm/internal/FunctionInterface.h +++ b/vtkm/internal/FunctionInterface.h @@ -247,7 +247,7 @@ struct IdentityFunctor { f(BOOST_PP_ENUM_SHIFTED(NumParamsPlusOne, VTK_M_DO_INVOKE_TPARAM, )); \ } #define VTK_M_DO_INVOKE_REPEAT(z, NumParams, data) \ - VTK_M_DO_INVOKE(BOOST_PP_INC(NumParams)); + VTK_M_DO_INVOKE(BOOST_PP_INC(NumParams)) #define VTK_M_DO_INVOKE_NAME DoInvokeCont #define VTK_M_DO_INVOKE_EXPORT VTKM_CONT_EXPORT @@ -318,6 +318,69 @@ struct FunctionInterfaceCopyParameters<0, ParameterIndex> { } }; +template +struct FunctionInterfaceStaticTransformType; + +// The following code uses the Boost preprocessor utilities to create +// definitions of DoStaticTransform functions for all supported number of +// arguments. The created functions are conceptually defined as follows: +// +// template +// VTKM_CONT_EXPORT +// void DoStaticTransformCont( +// const Transform &transform, +// const ParameterContainer &originalParameters, +// ParameterContainer &transformedParameters) +// { +// transformedParameters.Parameter1 = transform(originalParameters.Parameter1); +// transformedParameters.Parameter2 = transform(originalParameters.Parameter2); +// ... +// } +// +// We define multiple DoStaticTransformCont and DoStaticTransformExec that do +// identical things with different exports. It is important to have these +// separate definitions instead of a single version with VTKM_EXEC_CONT_EXPORT +// because the transform to be invoked may only be viable in one or the other. + +#define VTK_M_DO_STATIC_TRANSFORM_ASSIGN(z, count, data) \ + BOOST_PP_IF(count, \ + BOOST_PP_CAT(transformedParameters.Parameter, count) = \ + transform(BOOST_PP_CAT(originalParameters.Parameter, count));,) + +#define VTK_M_DO_STATIC_TRANSFORM(NumParamsPlusOne) \ + template \ + VTK_M_DO_STATIC_TRANSFORM_EXPORT \ + void VTK_M_DO_STATIC_TRANSFORM_NAME( \ + const Transform &transform, \ + ParameterContainer &originalParameters, \ + ParameterContainer &transformedParameters) \ + { \ + (void)transform; \ + (void)originalParameters; \ + (void)transformedParameters; \ + BOOST_PP_REPEAT(NumParamsPlusOne, VTK_M_DO_STATIC_TRANSFORM_ASSIGN,) \ + } +#define VTK_M_DO_STATIC_TRANSFORM_REPEAT(z, NumParams, data) \ + VTK_M_DO_STATIC_TRANSFORM(BOOST_PP_INC(NumParams)) + +#define VTK_M_DO_STATIC_TRANSFORM_NAME DoStaticTransformCont +#define VTK_M_DO_STATIC_TRANSFORM_EXPORT VTKM_CONT_EXPORT +BOOST_PP_REPEAT(BOOST_PP_INC(VTKM_MAX_FUNCTION_PARAMETERS), + VTK_M_DO_STATIC_TRANSFORM_REPEAT,) +#undef VTK_M_DO_STATIC_TRANSFORM_EXPORT +#undef VTK_M_DO_STATIC_TRANSFORM_NAME + +#define VTK_M_DO_STATIC_TRANSFORM_NAME DoStaticTransformExec +#define VTK_M_DO_STATIC_TRANSFORM_EXPORT VTKM_EXEC_EXPORT +BOOST_PP_REPEAT(BOOST_PP_INC(VTKM_MAX_FUNCTION_PARAMETERS), + VTK_M_DO_STATIC_TRANSFORM_REPEAT,) +#undef VTK_M_DO_STATIC_TRANSFORM_EXPORT +#undef VTK_M_DO_STATIC_TRANSFORM_NAME + template + struct StaticTransformType { + typedef FunctionInterface< + typename detail::FunctionInterfaceStaticTransformType< + FunctionSignature,Transform>::type> type; + }; + + /// \brief Transforms the \c FunctionInterface based on compile-time + /// information. + /// + /// The \c StaticTransform method transforms all the parameters of this \c + /// FunctionInterface to different types and values based on compile-time + /// information. It operates by accepting a functor that defines a unary + /// function whose argument is the parameter to transform and the return + /// value is the transformed value. The functor must also contain a templated + /// struct name ReturnType with an internal type named \c type that defines + /// the return type of the transform for a given input type. + /// + /// The transformation is only applied to the parameters of the function. The + /// return argument is uneffected. + /// + /// The return type can be determined with the \c StaticTransformType + /// template. + /// + /// Here is an example of a transformation that converts a \c + /// FunctionInterface to another \c FunctionInterface containing pointers to + /// all of the parameters. + /// + /// \code + /// struct MyTransformFunctor { + /// template + /// struct ReturnType { + /// typedef const T *type; + /// }; + /// + /// template + /// DAX_CONT_EXPORT + /// const T *operator()(const T &x) const { + /// return &x; + /// } + /// }; + /// + /// template + /// typename vtkm::internal::FunctionInterface::template StaticTransformType::type + /// ImportantStuff(const vtkm::internal::FunctionInterface &funcInterface) + /// { + /// return funcInterface.StaticTransformCont(MyTransformFunctor()); + /// } + /// \endcode + /// + template + VTKM_CONT_EXPORT + typename StaticTransformType::type + StaticTransformCont(const Transform &transform) + { + typename StaticTransformType::type newFuncInterface; + detail::DoStaticTransformCont(transform, + this->Parameters, + newFuncInterface.Parameters); + return newFuncInterface; + } + template + VTKM_EXEC_EXPORT + typename StaticTransformType::type + StaticTransformExec(const Transform &transform) + { + typename StaticTransformType::type newFuncInterface; + detail::DoStaticTransformExec(transform, + this->Parameters, + newFuncInterface.Parameters); + return newFuncInterface; + } + /// \brief Transforms the \c FunctionInterface based on run-time information. /// /// The \c DynamicTransform method transforms all the parameters of this \c @@ -655,6 +791,46 @@ private: namespace detail { +// The following code uses the Boost preprocessor utilities to create +// definitions of FunctionInterfaceStaticTransformType for all supported number +// of arguments. The created classes are conceptually defined as follows: +// +// template +// struct FunctionInterfaceStaticTransformType { +// typedef P0(type)(typename Transform::template ReturnType::type, +// typename Transform::template ReturnType::type, ...); +// }; + +#define VTK_M_STATIC_TRANSFORM_TPARAM(z, ParamIndex, data) \ + BOOST_PP_IF( \ + ParamIndex, \ + typename Transform::template ReturnType::type,) + +#define VTK_M_STATIC_TRANSFORM_TYPE(NumParamsPlusOne) \ + template \ + struct FunctionInterfaceStaticTransformType< \ + P0(BOOST_PP_ENUM_SHIFTED_PARAMS(NumParamsPlusOne, P)), \ + Transform> \ + { \ + typedef P0(type)( \ + BOOST_PP_ENUM_SHIFTED(NumParamsPlusOne, VTK_M_STATIC_TRANSFORM_TPARAM,) \ + ); \ + }; +#define VTK_M_STATIC_TRANSFORM_TYPE_REPEAT(z, NumParams, data) \ + VTK_M_STATIC_TRANSFORM_TYPE(BOOST_PP_INC(NumParams)) + +BOOST_PP_REPEAT(BOOST_PP_INC(VTKM_MAX_FUNCTION_PARAMETERS), + VTK_M_STATIC_TRANSFORM_TYPE_REPEAT,) + +#undef VTK_M_STATIC_TRANSFORM_TYPE_REPEAT +#undef VTK_M_STATIC_TRANSFORM_TYPE +#undef VTK_M_STATIC_TRANSFORM_TPARAM + + template + struct ReturnType { + typedef const T *type; + }; + + template + const T *operator()(const T &x) const { + return &x; + } +}; + struct ThreePointerArgFunctor { void operator()(const Type1 *a1, const Type2 *a2, const Type3 *a3) const { - std::cout << "In 3 arg functor." << std::endl; + std::cout << "In 3 point arg functor." << std::endl; VTKM_TEST_ASSERT(*a1 == Arg1, "Arg 1 incorrect."); VTKM_TEST_ASSERT(*a2 == Arg2, "Arg 2 incorrect."); @@ -409,6 +421,35 @@ void TestTransformInvoke() "Got bad result from invoke."); } +void TestStaticTransform() +{ + std::cout << "Trying static transform." << std::endl; + typedef vtkm::internal::FunctionInterface + OriginalType; + OriginalType funcInterface = + vtkm::internal::make_FunctionInterface(Arg1, Arg2, Arg3); + + std::cout << "Transform with reported type." << std::endl; + typedef OriginalType::StaticTransformType::type + ReportedType; + ReportedType funcInterfaceTransform1 = + funcInterface.StaticTransformCont(PointerTransform()); + funcInterfaceTransform1.InvokeCont(ThreePointerArgFunctor()); + funcInterfaceTransform1 = + funcInterface.StaticTransformExec(PointerTransform()); + funcInterfaceTransform1.InvokeExec(ThreePointerArgFunctor()); + + std::cout << "Transform with expected type." << std::endl; + typedef vtkm::internal::FunctionInterface + ExpectedType; + ReportedType funcInterfaceTransform2 = + funcInterface.StaticTransformCont(PointerTransform()); + funcInterfaceTransform2.InvokeCont(ThreePointerArgFunctor()); + funcInterfaceTransform2 = + funcInterface.StaticTransformExec(PointerTransform()); + funcInterfaceTransform2.InvokeExec(ThreePointerArgFunctor()); +} + void TestDynamicTransform() { std::cout << "Trying dynamic transform." << std::endl; @@ -487,6 +528,7 @@ void TestFunctionInterface() TestInvokeResult(); TestAppend(); TestTransformInvoke(); + TestStaticTransform(); TestDynamicTransform(); TestInvokeTime(); }