diff --git a/Common/ImplicitArrays/CMakeLists.txt b/Common/ImplicitArrays/CMakeLists.txt index 3cb1c39d89..fa8dccdd8a 100644 --- a/Common/ImplicitArrays/CMakeLists.txt +++ b/Common/ImplicitArrays/CMakeLists.txt @@ -36,6 +36,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 "vtkIndexedImplicitBackendInstantiate") list(APPEND _list "vtkStdFunctionArrayInstantiate") # generate cxx file to instantiate template with this type @@ -64,6 +65,7 @@ set(nowrap_headers set(nowrap_template_classes vtkImplicitArray vtkCompositeImplicitBackend + vtkIndexedImplicitBackend ) set(sources diff --git a/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt b/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt index 463fe0c4be..3c47128b93 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 + TestIndexedImplicitBackend.cxx TestStdFunctionArray.cxx ) diff --git a/Common/ImplicitArrays/Testing/Cxx/TestIndexedImplicitBackend.cxx b/Common/ImplicitArrays/Testing/Cxx/TestIndexedImplicitBackend.cxx new file mode 100644 index 0000000000..1261fccb4a --- /dev/null +++ b/Common/ImplicitArrays/Testing/Cxx/TestIndexedImplicitBackend.cxx @@ -0,0 +1,169 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: TestIndexedImplicitBackend.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 "vtkIndexedImplicitBackend.h" + +#include "vtkDataArrayRange.h" +#include "vtkIdList.h" +#include "vtkIntArray.h" + +#include +#include +#include +#include + +namespace +{ + +int LoopAndTest(vtkIdList* handles, vtkIndexedImplicitBackend& backend) +{ + for (int idx = 0; idx < handles->GetNumberOfIds(); idx++) + { + if (backend(idx) != static_cast(handles->GetId(idx))) + { + std::cout << "Indexed backend evaluation failed with: " << backend(idx) + << " != " << handles->GetId(idx) << std::endl; + return EXIT_FAILURE; + } + } + return EXIT_SUCCESS; +} + +int TestWithIDList() +{ + 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); + { + 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); + for (vtkIdType idx = 0; idx < 100; idx++) + { + handles->SetId(idx, buffer[idx]); + } + } + + vtkIndexedImplicitBackend backend(handles, baseArray); + + int res = LoopAndTest(handles, backend); + + vtkNew baseMultiArray; + baseMultiArray->SetNumberOfComponents(3); + baseMultiArray->SetNumberOfTuples(100); + auto multiRange = vtk::DataArrayValueRange<3>(baseMultiArray); + std::iota(multiRange.begin(), multiRange.end(), 0); + + vtkNew multiHandles; + multiHandles->SetNumberOfIds(300); + { + std::vector buffer(100); + std::iota(buffer.begin(), buffer.end(), 0); + std::random_device randdev; + std::mt19937 generator(randdev()); + std::shuffle(buffer.begin(), buffer.end(), generator); + for (vtkIdType idx = 0; idx < 100; idx++) + { + for (vtkIdType comp = 0; comp < 3; comp++) + { + multiHandles->SetId(3 * idx + comp, 3 * buffer[idx] + comp); + } + } + } + + vtkIndexedImplicitBackend multiBackend(multiHandles, baseMultiArray); + return LoopAndTest(multiHandles, multiBackend) == EXIT_SUCCESS ? res : EXIT_FAILURE; +} + +int LoopAndTest(vtkIntArray* handles, vtkIndexedImplicitBackend& backend) +{ + for (int idx = 0; idx < handles->GetNumberOfTuples(); idx++) + { + if (backend(idx) != static_cast(handles->GetValue(idx))) + { + std::cout << "Indexed backend evaluation failed with: " << backend(idx) + << " != " << handles->GetValue(idx) << std::endl; + return EXIT_FAILURE; + } + } + return EXIT_SUCCESS; +} + +int TestWithDataArrayIndexing() +{ + vtkNew baseArray; + baseArray->SetNumberOfComponents(1); + baseArray->SetNumberOfTuples(100); + auto range = vtk::DataArrayValueRange<1>(baseArray); + std::iota(range.begin(), range.end(), 0); + + vtkNew handles; + handles->SetNumberOfComponents(1); + handles->SetNumberOfTuples(100); + { + std::vector buffer(100); + std::iota(buffer.begin(), buffer.end(), 0); + std::random_device randdev; + std::mt19937 generator(randdev()); + std::shuffle(buffer.begin(), buffer.end(), generator); + auto handleRange = vtk::DataArrayValueRange<1>(handles); + std::copy(buffer.begin(), buffer.end(), handleRange.begin()); + } + + vtkIndexedImplicitBackend backend(handles, baseArray); + int res = LoopAndTest(handles, backend); + + // and with multi component entries + + vtkNew baseMultiArray; + baseMultiArray->SetNumberOfComponents(3); + baseMultiArray->SetNumberOfTuples(100); + auto multiRange = vtk::DataArrayValueRange<3>(baseMultiArray); + std::iota(multiRange.begin(), multiRange.end(), 0); + + vtkNew multiHandles; + multiHandles->SetNumberOfComponents(1); + multiHandles->SetNumberOfTuples(300); + { + std::vector buffer(100); + std::iota(buffer.begin(), buffer.end(), 0); + std::random_device randdev; + std::mt19937 generator(randdev()); + std::shuffle(buffer.begin(), buffer.end(), generator); + for (vtkIdType idx = 0; idx < 100; idx++) + { + for (vtkIdType comp = 0; comp < 3; comp++) + { + multiHandles->SetValue(3 * idx + comp, 3 * buffer[idx] + comp); + } + } + } + + vtkIndexedImplicitBackend multiBackend(multiHandles, baseMultiArray); + return LoopAndTest(multiHandles, multiBackend) == EXIT_SUCCESS ? res : EXIT_FAILURE; +} +} + +int TestIndexedImplicitBackend(int, char*[]) +{ + int res = ::TestWithIDList(); + return ::TestWithDataArrayIndexing() == EXIT_SUCCESS ? res : EXIT_FAILURE; +} diff --git a/Common/ImplicitArrays/vtkIndexedImplicitBackend.h b/Common/ImplicitArrays/vtkIndexedImplicitBackend.h new file mode 100644 index 0000000000..cc7af20ea1 --- /dev/null +++ b/Common/ImplicitArrays/vtkIndexedImplicitBackend.h @@ -0,0 +1,59 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkIndexedImplicitBackend.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 vtkIndexedImplicitBackend_h +#define vtkIndexedImplicitBackend_h + +#include "vtkCommonImplicitArraysModule.h" + +#include + +VTK_ABI_NAMESPACE_BEGIN +class vtkDataArray; +class vtkIdList; +template +class vtkIndexedImplicitBackend +{ +public: + ///@{ + /** + * Constructor + * @param indexes list of indexes to use for indirection of the array + * @param array base array of interest + */ + vtkIndexedImplicitBackend(vtkIdList* indexes, vtkDataArray* array); + vtkIndexedImplicitBackend(vtkDataArray* indexes, vtkDataArray* array); + ///@} + ~vtkIndexedImplicitBackend(); + + /** + * Indexing operation for the indexed array respecting the backend expectations of + * `vtkImplicitArray` + */ + ValueType operator()(int idx) const; + +private: + struct Internals; + std::unique_ptr Internal; +}; +VTK_ABI_NAMESPACE_END + +#endif // vtkIndexedImplicitBackend_h + +#ifdef VTK_INDEXED_BACKEND_INSTANTIATING +#define VTK_INSTANTIATE_INDEXED_BACKEND(ValueType) \ + VTK_ABI_NAMESPACE_BEGIN \ + template class VTKCOMMONIMPLICITARRAYS_EXPORT vtkIndexedImplicitBackend; \ + VTK_ABI_NAMESPACE_END +#endif diff --git a/Common/ImplicitArrays/vtkIndexedImplicitBackend.txx b/Common/ImplicitArrays/vtkIndexedImplicitBackend.txx new file mode 100644 index 0000000000..1951a6aa12 --- /dev/null +++ b/Common/ImplicitArrays/vtkIndexedImplicitBackend.txx @@ -0,0 +1,203 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkIndexedImplicitBackend.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 "vtkIndexedImplicitBackend.h" + +#include "vtkArrayDispatch.h" +#include "vtkArrayDispatchImplicitArrayList.h" +#include "vtkDataArrayRange.h" +#include "vtkIdList.h" +#include "vtkImplicitArray.h" +#include "vtkTypeList.h" + +#include + +namespace +{ +//----------------------------------------------------------------------- +template +struct TypedArrayCache +{ + virtual ValueType GetValue(int idx) const = 0; + virtual ~TypedArrayCache() = default; +}; + +template +struct SpecializedCache : public TypedArrayCache +{ +public: + SpecializedCache(ArrayT* arr) + : Array(arr) + { + } + + ValueType GetValue(int idx) const override + { + return static_cast(this->Array->GetValue(idx)); + } + +private: + vtkSmartPointer Array; +}; + +template +struct SpecializedCache : public TypedArrayCache +{ +public: + SpecializedCache(vtkDataArray* arr) + : Array(arr) + { + } + + ValueType GetValue(int idx) const override + { + int iTup = idx / this->Array->GetNumberOfComponents(); + int iComp = idx - iTup * this->Array->GetNumberOfComponents(); + return static_cast(this->Array->GetComponent(iTup, iComp)); + } + +private: + vtkSmartPointer Array; +}; + +//----------------------------------------------------------------------- +template +struct CacheDispatchWorker +{ + template + void operator()(ArrayT* arr, std::shared_ptr>& cache) + { + cache = std::make_shared>(arr); + } +}; + +//----------------------------------------------------------------------- +template +struct TypedCacheWrapper +{ + TypedCacheWrapper(vtkDataArray* arr) + { + CacheDispatchWorker worker; + if (!Dispatcher::Execute(arr, worker, this->Cache)) + { + worker(arr, this->Cache); + } + } + + ValueType operator()(int idx) const { return this->Cache->GetValue(idx); } + +private: + using Dispatcher = vtkArrayDispatch::DispatchByArray; + std::shared_ptr> Cache = nullptr; +}; + +//----------------------------------------------------------------------- +struct IdListWrapper +{ + IdListWrapper(vtkIdList* indexes) + : Handles(indexes) + { + } + + vtkIdType operator()(int idx) const { return this->Handles->GetId(idx); } + + vtkSmartPointer Handles; +}; + +} + +VTK_ABI_NAMESPACE_BEGIN +//----------------------------------------------------------------------- +template +struct vtkIndexedImplicitBackend::Internals +{ + using InternalArrayList = vtkTypeList::Append>>::Result; + + Internals(vtkIdList* indexes, vtkDataArray* array) + { + if (!indexes || !array) + { + vtkErrorWithObjectMacro(nullptr, "Either index array or array itself is nullptr"); + return; + } + vtkNew> newHandles; + newHandles->SetBackend(std::make_shared(indexes)); + newHandles->SetNumberOfComponents(1); + newHandles->SetNumberOfTuples(indexes->GetNumberOfIds()); + this->Handles = this->TypeCacheArray(newHandles); + this->Array = this->TypeCacheArray(array); + } + + Internals(vtkDataArray* indexes, vtkDataArray* array) + { + if (!indexes || !array) + { + vtkErrorWithObjectMacro(nullptr, "Either index array or array itself is nullptr"); + return; + } + if (indexes->GetNumberOfComponents() != 1) + { + vtkErrorWithObjectMacro(nullptr, + "Passed a vtkDataArray with multiple components as indexing array to vtkIndexedArray"); + return; + } + this->Handles = this->TypeCacheArray(indexes); + this->Array = this->TypeCacheArray(array); + } + + template + static vtkSmartPointer>> + TypeCacheArray(vtkDataArray* da) + { + vtkNew>> wrapped; + wrapped->SetBackend(std::make_shared<::TypedCacheWrapper>(da)); + wrapped->SetNumberOfComponents(1); + wrapped->SetNumberOfTuples(da->GetNumberOfTuples() * da->GetNumberOfComponents()); + return wrapped; + } + + vtkSmartPointer>> Array; + vtkSmartPointer>> Handles; +}; + +//----------------------------------------------------------------------- +template +vtkIndexedImplicitBackend::vtkIndexedImplicitBackend( + vtkIdList* indexes, vtkDataArray* array) + : Internal(std::unique_ptr(new Internals(indexes, array))) +{ +} + +//----------------------------------------------------------------------- +template +vtkIndexedImplicitBackend::vtkIndexedImplicitBackend( + vtkDataArray* indexes, vtkDataArray* array) + : Internal(std::unique_ptr(new Internals(indexes, array))) +{ +} + +//----------------------------------------------------------------------- +template +vtkIndexedImplicitBackend::~vtkIndexedImplicitBackend() +{ +} + +//----------------------------------------------------------------------- +template +ValueType vtkIndexedImplicitBackend::operator()(int idx) const +{ + return this->Internal->Array->GetValue(this->Internal->Handles->GetValue(idx)); +} +VTK_ABI_NAMESPACE_END diff --git a/Common/ImplicitArrays/vtkIndexedImplicitBackendInstantiate.cxx.in b/Common/ImplicitArrays/vtkIndexedImplicitBackendInstantiate.cxx.in new file mode 100644 index 0000000000..98c0817673 --- /dev/null +++ b/Common/ImplicitArrays/vtkIndexedImplicitBackendInstantiate.cxx.in @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkIndexedImplicitBackend.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_BACKEND_INSTANTIATING +#include "vtkIndexedImplicitBackend.h" +#include "vtkIndexedImplicitBackend.txx" + +VTK_INSTANTIATE_INDEXED_BACKEND(@INSTANTIATION_VALUE_TYPE@)