From dac47ee5507882cf2e0de54bef83b4b4b410e6e6 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Wed, 30 Apr 2014 09:34:49 -0600 Subject: [PATCH] Add DynamicTransform class. This is used with the FunctionInterface::DynamicTransformCont method to convert a call of arguments using dynamic array handles to a function templated on concrete types. --- vtkm/cont/DynamicArrayHandle.h | 16 ++ vtkm/cont/internal/CMakeLists.txt | 1 + vtkm/cont/internal/DynamicTransform.h | 121 +++++++++++++++ vtkm/cont/internal/testing/CMakeLists.txt | 1 + .../testing/UnitTestDynamicTransform.cxx | 139 ++++++++++++++++++ vtkm/internal/FunctionInterface.h | 4 +- 6 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 vtkm/cont/internal/DynamicTransform.h create mode 100644 vtkm/cont/internal/testing/UnitTestDynamicTransform.cxx diff --git a/vtkm/cont/DynamicArrayHandle.h b/vtkm/cont/DynamicArrayHandle.h index 3080e0537..642559260 100644 --- a/vtkm/cont/DynamicArrayHandle.h +++ b/vtkm/cont/DynamicArrayHandle.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -246,6 +247,9 @@ template class DynamicArrayHandleCast : public vtkm::cont::DynamicArrayHandle { public: + VTKM_CONT_EXPORT + DynamicArrayHandleCast() : DynamicArrayHandle() { } + VTKM_CONT_EXPORT DynamicArrayHandleCast(const vtkm::cont::DynamicArrayHandle &array) : DynamicArrayHandle(array) { } @@ -285,6 +289,18 @@ public: } }; +template<> +struct DynamicTransformTraits { + typedef vtkm::cont::internal::DynamicTransformTagCastAndCall DynamicTag; +}; + +template +struct DynamicTransformTraits< + vtkm::cont::internal::DynamicArrayHandleCast > +{ + typedef vtkm::cont::internal::DynamicTransformTagCastAndCall DynamicTag; +}; + } // namespace internal } diff --git a/vtkm/cont/internal/CMakeLists.txt b/vtkm/cont/internal/CMakeLists.txt index 4214ac793..776eba2f8 100644 --- a/vtkm/cont/internal/CMakeLists.txt +++ b/vtkm/cont/internal/CMakeLists.txt @@ -32,6 +32,7 @@ set(headers DeviceAdapterError.h DeviceAdapterTag.h DeviceAdapterTagSerial.h + DynamicTransform.h IteratorFromArrayPortal.h SimplePolymorphicContainer.h ) diff --git a/vtkm/cont/internal/DynamicTransform.h b/vtkm/cont/internal/DynamicTransform.h new file mode 100644 index 000000000..5fcd95e71 --- /dev/null +++ b/vtkm/cont/internal/DynamicTransform.h @@ -0,0 +1,121 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +// Copyright 2014 Sandia Corporation. +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014. Los Alamos National Security +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ +#ifndef vtk_m_cont_internal_DynamicTransform_h +#define vtk_m_cont_internal_DynamicTransform_h + +#include "vtkm/internal/ExportMacros.h" + +namespace vtkm { +namespace cont { +namespace internal { + +namespace detail { + +template +struct DynamicArrayTransformCastAndCall +{ + const ContinueFunctor &Continue; + + VTKM_CONT_EXPORT + DynamicArrayTransformCastAndCall(const ContinueFunctor &continueFunc) + : Continue(continueFunc) { } + + template + VTKM_CONT_EXPORT + void operator()(const T &x) const { + this->Continue(x); + } +}; + +} // namespace detail + +/// Tag used to identify an object that is a dynamic object that contains a +/// CastAndCall method that iterates over all possible dynamic choices to run +/// templated code. +/// +struct DynamicTransformTagCastAndCall { }; + +/// Tag used to identify an object that is a static object that, when used with +/// a \c DynamicTransform should just pass itself as a concrete object. +/// +struct DynamicTransformTagStatic { }; + +/// A traits class that identifies whether an object used in a \c +/// DynamicTransform should use a \c CastAndCall functionality or treated as a +/// static object. The default implementation identifies the object as static +/// (as most objects are bound to be). Dynamic objects that implement +/// \c CastAndCall should specialize (or partially specialize) this traits class +/// to identify the object as dynamic. VTK-m classes like \c DynamicArray are +/// already specialized. +/// +template +struct DynamicTransformTraits { + /// A type set to either \c DynamicTransformTagStatic or \c + /// DynamicTransformTagCastAndCall. The default implementation is set to \c + /// DynamicTransformTagStatic. Dynamic objects that implement \c CastAndCall + /// should specialize this class redefine it to \c + /// DynamicTransformTagCastAndCall. + /// + typedef vtkm::cont::internal::DynamicTransformTagStatic DynamicTag; +}; + +/// This functor can be used as the transform in the \c DynamicTransformCont +/// method of \c FunctionInterface. It will allow dynamic objects like +/// \c DynamicArray to be cast to their concrete types for templated operation. +/// +struct DynamicTransform +{ + template + VTKM_CONT_EXPORT + void operator()(const InputType &input, + const ContinueFunctor &continueFunc) const + { + this->DoTransform( + input, + continueFunc, + typename vtkm::cont::internal::DynamicTransformTraits::DynamicTag()); + } + +private: + template + VTKM_CONT_EXPORT + void DoTransform(const InputType &input, + const ContinueFunctor &continueFunc, + vtkm::cont::internal::DynamicTransformTagStatic) const + { + continueFunc(input); + } + + template + VTKM_CONT_EXPORT + void DoTransform(const InputType &dynamicInput, + const ContinueFunctor &continueFunc, + vtkm::cont::internal::DynamicTransformTagCastAndCall) const + { + dynamicInput.CastAndCall( + detail::DynamicArrayTransformCastAndCall(continueFunc)); + } +}; + +} +} +} // namespace vtkm::cont::internal + +#endif //vtk_m_cont_internal_DynamicTransform_h diff --git a/vtkm/cont/internal/testing/CMakeLists.txt b/vtkm/cont/internal/testing/CMakeLists.txt index 9ab49343b..da7041298 100644 --- a/vtkm/cont/internal/testing/CMakeLists.txt +++ b/vtkm/cont/internal/testing/CMakeLists.txt @@ -22,6 +22,7 @@ set(unit_tests UnitTestArrayManagerExecutionShareWithControl.cxx UnitTestArrayPortalFromIterators.cxx + UnitTestDynamicTransform.cxx UnitTestIteratorFromArrayPortal.cxx ) vtkm_unit_tests(SOURCES ${unit_tests}) diff --git a/vtkm/cont/internal/testing/UnitTestDynamicTransform.cxx b/vtkm/cont/internal/testing/UnitTestDynamicTransform.cxx new file mode 100644 index 000000000..7b49cb012 --- /dev/null +++ b/vtkm/cont/internal/testing/UnitTestDynamicTransform.cxx @@ -0,0 +1,139 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +// Copyright 2014 Sandia Corporation. +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014. Los Alamos National Security +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ + +#include "vtkm/cont/internal/DynamicTransform.h" + +#include "vtkm/cont/ArrayHandle.h" +#include "vtkm/cont/DynamicArrayHandle.h" + +#include "vtkm/internal/FunctionInterface.h" + +#include "vtkm/cont/testing/Testing.h" + +namespace { + +static int g_FunctionCalls; + +#define TRY_TRANSFORM(expr) \ + g_FunctionCalls = 0; \ + expr; \ + VTKM_TEST_ASSERT(g_FunctionCalls == 1, "Functor not called correctly.") + +struct TypeListTagString : vtkm::ListTagBase { }; + +struct ScalarFunctor { + void operator()(vtkm::Scalar) const { + std::cout << " In Scalar functor." << std::endl; + g_FunctionCalls++; + } +}; + +struct ArrayHandleScalarFunctor { + template + void operator()(const vtkm::cont::ArrayHandle &) const { + VTKM_TEST_FAIL("Called wrong form of functor operator."); + } + void operator()(const vtkm::cont::ArrayHandle &) const { + std::cout << " In ArrayHandle functor." << std::endl; + g_FunctionCalls++; + } +}; + +struct ArrayHandleStringFunctor { + void operator()(const vtkm::cont::ArrayHandle &) const { + std::cout << " In ArrayHandle functor." << std::endl; + g_FunctionCalls++; + } +}; + +struct FunctionInterfaceFunctor { + template + void operator()(const vtkm::internal::FunctionInterface &) const { + VTKM_TEST_FAIL("Called wrong form of functor operator."); + } + void operator()( + const vtkm::internal::FunctionInterface< + void(vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)> &) const { + std::cout << " In FunctionInterface<...> functor." << std::endl; + g_FunctionCalls++; + } +}; + +void TestBasicTransform() +{ + std::cout << "Testing basic transform." << std::endl; + + vtkm::cont::internal::DynamicTransform transform; + + std::cout << " Trying with simple scalar." << std::endl; + TRY_TRANSFORM(transform(vtkm::Scalar(5), ScalarFunctor())); + + std::cout << " Trying with basic scalar array." << std::endl; + vtkm::cont::ArrayHandle concreteArray; + TRY_TRANSFORM(transform(concreteArray, ArrayHandleScalarFunctor())); + + std::cout << " Trying scalar dynamic array." << std::endl; + vtkm::cont::DynamicArrayHandle dynamicArray = concreteArray; + TRY_TRANSFORM(transform(dynamicArray, ArrayHandleScalarFunctor())); + + std::cout << " Trying with unusual (string) dynamic array." << std::endl; + dynamicArray = vtkm::cont::ArrayHandle(); + TRY_TRANSFORM(transform(dynamicArray.ResetTypeList(TypeListTagString()), + ArrayHandleStringFunctor())); +} + +void TestFunctionTransform() +{ + std::cout << "Testing transforms in FunctionInterface." << std::endl; + + vtkm::cont::ArrayHandle scalarArray; + vtkm::cont::ArrayHandle stringArray; + + std::cout << " Trying basic functor call w/o transform (make sure it works)." + << std::endl; + TRY_TRANSFORM(FunctionInterfaceFunctor()( + vtkm::internal::make_FunctionInterface(scalarArray, + scalarArray, + stringArray))); + + std::cout << " Trying dynamic cast" << std::endl; + TRY_TRANSFORM( + vtkm::internal::make_FunctionInterface( + scalarArray, + vtkm::cont::DynamicArrayHandle(scalarArray), + vtkm::cont::DynamicArrayHandle(stringArray).ResetTypeList(TypeListTagString())) + .DynamicTransformCont(vtkm::cont::internal::DynamicTransform(), + FunctionInterfaceFunctor())); +} + +void TestDynamicTransform() +{ + TestBasicTransform(); + TestFunctionTransform(); +} + +} // anonymous namespace + +int UnitTestDynamicTransform(int, char *[]) +{ + return vtkm::cont::testing::Testing::Run(TestDynamicTransform); +} diff --git a/vtkm/internal/FunctionInterface.h b/vtkm/internal/FunctionInterface.h index 665f0cf98..cb2e8a5ef 100644 --- a/vtkm/internal/FunctionInterface.h +++ b/vtkm/internal/FunctionInterface.h @@ -583,9 +583,9 @@ public: /// template /// VTKM_CONT_EXPORT /// void operator()(const InputType &input, - /// const ContinueFunctor &continue) const + /// const ContinueFunctor &continueFunc) const /// { - /// continue(input); + /// continueFunc(input); /// } /// /// template