diff --git a/Common/ImplicitArrays/CMakeLists.txt b/Common/ImplicitArrays/CMakeLists.txt index fa8dccdd8a..4e8f0e51b2 100644 --- a/Common/ImplicitArrays/CMakeLists.txt +++ b/Common/ImplicitArrays/CMakeLists.txt @@ -1,11 +1,13 @@ option(VTK_DISPATCH_AFFINE_ARRAYS "Include implicit vtkDataArray subclasses based on an affine function backend in dispatcher" OFF) option(VTK_DISPATCH_COMPOSITE_ARRAYS "Include implicit vtkDataArray subclasses based on a composite binary tree backend in dispatcher" OFF) option(VTK_DISPATCH_CONSTANT_ARRAYS "Include implicit vtkDataArray subclasses based on a constant backend in dispatcher" OFF) +option(VTK_DISPATCH_INDEXED_ARRAYS "Include implicit vtkDataArray subclasses based on an index referencing backend in dispatcher" OFF) option(VTK_DISPATCH_STD_FUNCTION_ARRAYS "Include implicit vtkDataArray subclasses based on std::function in dispatcher" OFF) mark_as_advanced( VTK_DISPATCH_AFFINE_ARRAYS VTK_DISPATCH_COMPOSITE_ARRAYS VTK_DISPATCH_CONSTANT_ARRAYS + VTK_DISPATCH_INDEXED_ARRAYS VTK_DISPATCH_STD_FUNCTION_ARRAYS ) @@ -36,6 +38,7 @@ foreach (INSTANTIATION_VALUE_TYPE IN LISTS vtkArrayDispatchImplicit_all_types) list(APPEND _list "vtkCompositeArrayInstantiate") list(APPEND _list "vtkCompositeImplicitBackendInstantiate") list(APPEND _list "vtkConstantArrayInstantiate") + list(APPEND _list "vtkIndexedArrayInstantiate") list(APPEND _list "vtkIndexedImplicitBackendInstantiate") list(APPEND _list "vtkStdFunctionArrayInstantiate") @@ -57,6 +60,7 @@ set(nowrap_headers vtkConstantArray.h vtkConstantImplicitBackend.h vtkImplicitArrayTraits.h + vtkIndexedArray.h vtkStdFunctionArray.h "${CMAKE_CURRENT_BINARY_DIR}/vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h" "${CMAKE_CURRENT_BINARY_DIR}/vtkArrayDispatchImplicitArrayList.h" diff --git a/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt b/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt index 3c47128b93..b3010bb0ec 100644 --- a/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt +++ b/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt @@ -6,6 +6,7 @@ vtk_add_test_cxx(vtkCommonImplicitArrayCxxTests tests TestConstantArray.cxx TestImplicitArraysBase.cxx TestImplicitArrayTraits.cxx + TestIndexedArray.cxx TestIndexedImplicitBackend.cxx TestStdFunctionArray.cxx ) diff --git a/Common/ImplicitArrays/Testing/Cxx/TestIndexedArray.cxx b/Common/ImplicitArrays/Testing/Cxx/TestIndexedArray.cxx new file mode 100644 index 0000000000..e110e0307a --- /dev/null +++ b/Common/ImplicitArrays/Testing/Cxx/TestIndexedArray.cxx @@ -0,0 +1,133 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: TestIndexedArray.cxx + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm 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. + +=========================================================================*/ +#include "vtkIndexedArray.h" + +#include "vtkDataArrayRange.h" +#include "vtkIdList.h" +#include "vtkIntArray.h" +#include "vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h" + +#ifdef VTK_DISPATCH_INDEXED_ARRAYS +#include "vtkArrayDispatch.h" +#include "vtkArrayDispatchImplicitArrayList.h" +#endif // VTK_DISPATCH_INDEXED_ARRAYS + +#include +#include +#include + +#ifdef VTK_DISPATCH_INDEXED_ARRAYS +namespace +{ +struct ScaleWorker +{ + template + void operator()(SrcArray* srcArr, DstArray* dstArr, double scale) + { + using SrcType = vtk::GetAPIType; + using DstType = vtk::GetAPIType; + + const auto srcRange = vtk::DataArrayValueRange(srcArr); + auto dstRange = vtk::DataArrayValueRange(dstArr); + + if (srcRange.size() != dstRange.size()) + { + std::cout << "Different array sizes in ScaleWorker" << std::endl; + return; + } + + auto dstIter = dstRange.begin(); + for (SrcType srcVal : srcRange) + { + *dstIter++ = static_cast(srcVal * scale); + } + } +}; +} +#endif // VTK_DISPATCH_INDEXED_ARRAYS + +int TestIndexedArray(int vtkNotUsed(argc), char* vtkNotUsed(argv)[]) +{ + int res = EXIT_SUCCESS; + + vtkNew baseArray; + baseArray->SetNumberOfComponents(1); + baseArray->SetNumberOfTuples(1000); + auto range = vtk::DataArrayValueRange<1>(baseArray); + std::iota(range.begin(), range.end(), 0); + + vtkNew handles; + handles->SetNumberOfIds(100); + std::random_device randdev; + std::mt19937 generator(randdev()); + auto index_rand = std::bind(std::uniform_int_distribution(0, 999), generator); + for (vtkIdType idx = 0; idx < 100; idx++) + { + handles->SetId(idx, index_rand()); + } + + vtkNew> indexed; + indexed->SetBackend(std::make_shared>(handles, baseArray)); + indexed->SetNumberOfComponents(1); + indexed->SetNumberOfTuples(100); + + for (vtkIdType iArr = 0; iArr < 100; iArr++) + { + if (indexed->GetValue(iArr) != static_cast(handles->GetId(iArr))) + { + res = EXIT_FAILURE; + std::cout << "get value failed with vtkIndexedArray" << std::endl; + } + } + + int iArr = 0; + for (auto val : vtk::DataArrayValueRange<1>(indexed)) + { + if (val != static_cast(handles->GetId(iArr))) + { + res = EXIT_FAILURE; + std::cout << "range iterator failed with vtkIndexedArray" << std::endl; + } + iArr++; + } + +#ifdef VTK_DISPATCH_INDEXED_ARRAYS + std::cout << "vtkIndexedArray: performing dispatch tests" << std::endl; + vtkNew destination; + destination->SetNumberOfTuples(100); + destination->SetNumberOfComponents(1); + using Dispatcher = + vtkArrayDispatch::Dispatch2ByArray; + ::ScaleWorker worker; + if (!Dispatcher::Execute(indexed, destination, worker, 3.0)) + { + res = EXIT_FAILURE; + std::cout << "vtkArrayDispatch failed with vtkIndexedArray" << std::endl; + worker(indexed.Get(), destination.Get(), 3.0); + } + + iArr = 0; + for (auto val : vtk::DataArrayValueRange<1>(destination)) + { + if (val != 3 * static_cast(handles->GetId(iArr))) + { + res = EXIT_FAILURE; + std::cout << "dispatch failed to populate the array with the correct values" << std::endl; + } + iArr++; + } +#endif // VTK_DISPATCH_INDEXED_ARRAYS + return res; +}; diff --git a/Common/ImplicitArrays/Testing/Cxx/TestIndexedImplicitBackend.cxx b/Common/ImplicitArrays/Testing/Cxx/TestIndexedImplicitBackend.cxx index 1261fccb4a..9d0d3caa21 100644 --- a/Common/ImplicitArrays/Testing/Cxx/TestIndexedImplicitBackend.cxx +++ b/Common/ImplicitArrays/Testing/Cxx/TestIndexedImplicitBackend.cxx @@ -53,9 +53,9 @@ int TestWithIDList() { std::vector buffer(100); std::iota(buffer.begin(), buffer.end(), 0); - std::random_device rd; - std::mt19937 g(rd()); - std::shuffle(buffer.begin(), buffer.end(), g); + std::random_device randdev; + std::mt19937 generator(randdev()); + std::shuffle(buffer.begin(), buffer.end(), generator); for (vtkIdType idx = 0; idx < 100; idx++) { handles->SetId(idx, buffer[idx]); diff --git a/Common/ImplicitArrays/vtkCreateArrayDispatchImplicitList.cmake b/Common/ImplicitArrays/vtkCreateArrayDispatchImplicitList.cmake index ffe672ac3b..52c301430b 100644 --- a/Common/ImplicitArrays/vtkCreateArrayDispatchImplicitList.cmake +++ b/Common/ImplicitArrays/vtkCreateArrayDispatchImplicitList.cmake @@ -137,6 +137,14 @@ if (VTK_DISPATCH_COMPOSITE_ARRAYS) ) endif() +if (VTK_DISPATCH_INDEXED_ARRAYS) + list(APPEND vtkArrayDispatchImplicit_containers vtkIndexedArray) + set(vtkArrayDispatchImplicit_vtkIndexedArray_header vtkIndexedArray.h) + set(vtkArrayDispatchImplicit_vtkIndexedArray_types + ${vtkArrayDispatchImplicit_all_types} + ) +endif() + endmacro() # Create a header that declares the vtkArrayDispatch::Arrays TypeList. diff --git a/Common/ImplicitArrays/vtkImplicitArray.h b/Common/ImplicitArrays/vtkImplicitArray.h index c6b9626bfd..630df8d768 100644 --- a/Common/ImplicitArrays/vtkImplicitArray.h +++ b/Common/ImplicitArrays/vtkImplicitArray.h @@ -316,6 +316,8 @@ template class vtkCompositeImplicitBackend; template struct vtkConstantImplicitBackend; +template +class vtkIndexedImplicitBackend; VTK_ABI_NAMESPACE_END #include @@ -337,6 +339,8 @@ VTK_ABI_NAMESPACE_END vtkImplicitArray>, ValueType) \ VTK_INSTANTIATE_VALUERANGE_ARRAYTYPE( \ vtkImplicitArray>, ValueType) \ + VTK_INSTANTIATE_VALUERANGE_ARRAYTYPE( \ + vtkImplicitArray>, ValueType) \ VTK_INSTANTIATE_VALUERANGE_ARRAYTYPE(vtkImplicitArray>, ValueType) #elif defined(VTK_USE_EXTERN_TEMPLATE) // VTK_IMPLICIT_VALUERANGE_INSTANTIATING @@ -357,6 +361,8 @@ template class vtkCompositeImplicitBackend; template struct vtkConstantImplicitBackend; +template +class vtkIndexedImplicitBackend; VTK_ABI_NAMESPACE_END #include @@ -391,6 +397,8 @@ VTK_ABI_NAMESPACE_END vtkImplicitArray>, ValueType) \ VTK_DECLARE_VALUERANGE_ARRAYTYPE( \ vtkImplicitArray>, ValueType) \ + VTK_DECLARE_VALUERANGE_ARRAYTYPE( \ + vtkImplicitArray>, ValueType) \ VTK_DECLARE_VALUERANGE_ARRAYTYPE(vtkImplicitArray>, ValueType) #define VTK_DECLARE_VALUERANGE_IMPLICIT_BACKENDTYPE(BackendT) \ @@ -414,6 +422,7 @@ VTK_ABI_NAMESPACE_BEGIN VTK_DECLARE_VALUERANGE_IMPLICIT_BACKENDTYPE(vtkAffineImplicitBackend) VTK_DECLARE_VALUERANGE_IMPLICIT_BACKENDTYPE(vtkConstantImplicitBackend) VTK_DECLARE_VALUERANGE_IMPLICIT_BACKENDTYPE(vtkCompositeImplicitBackend) +VTK_DECLARE_VALUERANGE_IMPLICIT_BACKENDTYPE(vtkIndexedImplicitBackend) VTK_DECLARE_VALUERANGE_ARRAYTYPE(vtkImplicitArray>, double) VTK_DECLARE_VALUERANGE_ARRAYTYPE(vtkImplicitArray>, double) diff --git a/Common/ImplicitArrays/vtkIndexedArray.h b/Common/ImplicitArrays/vtkIndexedArray.h new file mode 100644 index 0000000000..c54b899dd1 --- /dev/null +++ b/Common/ImplicitArrays/vtkIndexedArray.h @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkIndexedArray.h + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm 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. + +=========================================================================*/ + +#ifndef vtkIndexedArray_h +#define vtkIndexedArray_h + +#ifdef VTK_INDEXED_ARRAY_INSTANTIATING +#define VTK_IMPLICIT_VALUERANGE_INSTANTIATING +#include "vtkDataArrayPrivate.txx" +#endif + +#include "vtkCommonImplicitArraysModule.h" // for export macro +#include "vtkImplicitArray.h" +#include "vtkIndexedImplicitBackend.h" // for the array backend + +#ifdef VTK_INDEXED_ARRAY_INSTANTIATING +#undef VTK_IMPLICIT_VALUERANGE_INSTANTIATING +#endif + +#include + +/** + * \var vtkIndexedArray + * \brief A utility alias for creating a wrapper array around an existing array and reindexing its + * components + * + * In order to be usefully included in the dispatchers, these arrays need to be instantiated at the + * vtk library compile time. + * + * An example of potential usage: + * ``` + * vtkNew baseArray; + * baseArray->SetNumberOfComponents(1); + * baseArray->SetNumberOfTuples(100); + * auto range = vtk::DataArrayValueRange<1>(baseArray); + * std::iota(range.begin(), range.end(), 0); + * + * vtkNew handles; + * handles->SetNumberOfIds(100); + * for (vtkIdType idx = 0; idx < 100; idx++) + * { + * handles->SetId(idx, 99-idx); + * } + * + * vtkNew> indexedArr; + * indexedArr->SetBackend(std::make_shared>(handles, baseArray)); + * indexedArr->SetNumberOfComponents(1); + * indexedArr->SetNumberOfTuples(100); + * CHECK(indexedArr->GetValue(57) == 42); // always true + * ``` + * + * @sa + * vtkImplicitArray vtkIndexedImplicitBackend + */ + +VTK_ABI_NAMESPACE_BEGIN +template +using vtkIndexedArray = vtkImplicitArray>; +VTK_ABI_NAMESPACE_END + +#endif // vtkIndexedArray_h + +#ifdef VTK_INDEXED_ARRAY_INSTANTIATING + +#define VTK_INSTANTIATE_INDEXED_ARRAY(ValueType) \ + VTK_ABI_NAMESPACE_BEGIN \ + template class VTKCOMMONIMPLICITARRAYS_EXPORT \ + vtkImplicitArray>; \ + VTK_ABI_NAMESPACE_END \ + namespace vtkDataArrayPrivate \ + { \ + VTK_ABI_NAMESPACE_BEGIN \ + VTK_INSTANTIATE_VALUERANGE_ARRAYTYPE( \ + vtkImplicitArray>, double) \ + VTK_ABI_NAMESPACE_END \ + } + +#endif diff --git a/Common/ImplicitArrays/vtkIndexedArrayInstantiate.cxx.in b/Common/ImplicitArrays/vtkIndexedArrayInstantiate.cxx.in new file mode 100644 index 0000000000..4f033334a4 --- /dev/null +++ b/Common/ImplicitArrays/vtkIndexedArrayInstantiate.cxx.in @@ -0,0 +1,18 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkIndexedArray.cxx + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm 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. + +=========================================================================*/ +#define VTK_INDEXED_ARRAY_INSTANTIATING +#include "vtkIndexedArray.h" + +VTK_INSTANTIATE_INDEXED_ARRAY(@INSTANTIATION_VALUE_TYPE@) diff --git a/Common/ImplicitArrays/vtkIndexedImplicitBackend.h b/Common/ImplicitArrays/vtkIndexedImplicitBackend.h index cc7af20ea1..940335cb53 100644 --- a/Common/ImplicitArrays/vtkIndexedImplicitBackend.h +++ b/Common/ImplicitArrays/vtkIndexedImplicitBackend.h @@ -15,6 +15,44 @@ #ifndef vtkIndexedImplicitBackend_h #define vtkIndexedImplicitBackend_h +/** + * \class vtkIndexedImplicitBackend + * + * A backend for the `vtkImplicitArray` framework allowing one to use a subset of a given data + * array, by providing a `vtkIdList` or `vtkDataArray` of indexes as indirection, as another + * `vtkDataArray` without any excess memory consumption. + * + * This structure can be classified as a closure and can be called using syntax similar to a + * function call. + * + * An example of potential usage in a `vtkImplicitArray`: + * ``` + * vtkNew baseArray; + * baseArray->SetNumberOfComponents(1); + * baseArray->SetNumberOfTuples(100); + * auto range = vtk::DataArrayValueRange<1>(baseArray); + * std::iota(range.begin(), range.end(), 0); + * + * vtkNew handles; + * handles->SetNumberOfIds(100); + * for (vtkIdType idx = 0; idx < 100; idx++) + * { + * handles->SetId(idx, 99-idx); + * } + * + * vtkNew>> indexedArr; // More compact with + * // `vtkIndexedArray` + * // if available + * indexedArr->SetBackend(std::make_shared>(handles, baseArray)); + * indexedArr->SetNumberOfComponents(1); + * indexedArr->SetNumberOfTuples(100); + * CHECK(indexedArr->GetValue(57) == 42); + * ``` + * + * @sa + * vtkImplicitArray, vtkIndexedArray + */ + #include "vtkCommonImplicitArraysModule.h" #include diff --git a/Common/ImplicitArrays/vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h.in b/Common/ImplicitArrays/vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h.in index 55769121ba..bfd4a7f866 100644 --- a/Common/ImplicitArrays/vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h.in +++ b/Common/ImplicitArrays/vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h.in @@ -22,6 +22,8 @@ #cmakedefine VTK_DISPATCH_COMPOSITE_ARRAYS // defined if VTK dispatches the vtkConstantArray class #cmakedefine VTK_DISPATCH_CONSTANT_ARRAYS +// defined if VTK dispatches the vtkIndexedArray class +#cmakedefine VTK_DISPATCH_INDEXED_ARRAYS // defined if VTK dispatches the vtkStdFunctionArray class #cmakedefine VTK_DISPATCH_STD_FUNCTION_ARRAYS