From d4163654476fa1267352bac26ec802ee9fc5e73f Mon Sep 17 00:00:00 2001 From: Julien Fausty Date: Wed, 16 Nov 2022 15:05:01 +0100 Subject: [PATCH 01/10] add(ImpCompositeBackend): implicit backend for composite arrays --- Common/ImplicitArrays/CMakeLists.txt | 1 + .../ImplicitArrays/Testing/Cxx/CMakeLists.txt | 1 + .../Cxx/TestCompositeImplicitBackend.cxx | 54 +++++++++++++ .../vtkCompositeImplicitBackend.h | 66 ++++++++++++++++ .../vtkCompositeImplicitBackend.txx | 77 +++++++++++++++++++ 5 files changed, 199 insertions(+) create mode 100644 Common/ImplicitArrays/Testing/Cxx/TestCompositeImplicitBackend.cxx create mode 100644 Common/ImplicitArrays/vtkCompositeImplicitBackend.h create mode 100644 Common/ImplicitArrays/vtkCompositeImplicitBackend.txx diff --git a/Common/ImplicitArrays/CMakeLists.txt b/Common/ImplicitArrays/CMakeLists.txt index bfd144f579..2ecf46b8d2 100644 --- a/Common/ImplicitArrays/CMakeLists.txt +++ b/Common/ImplicitArrays/CMakeLists.txt @@ -57,6 +57,7 @@ set(nowrap_headers set(nowrap_template_classes vtkImplicitArray + vtkCompositeImplicitBackend ) set(sources diff --git a/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt b/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt index 8f1aafc808..3b54b70ae8 100644 --- a/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt +++ b/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt @@ -1,6 +1,7 @@ vtk_add_test_cxx(vtkCommonImplicitArrayCxxTests tests NO_DATA NO_OUTPUT NO_VALID TestAffineArray.cxx + TestCompositeImplicitBackend.cxx TestConstantArray.cxx TestImplicitArraysBase.cxx TestImplicitArrayTraits.cxx diff --git a/Common/ImplicitArrays/Testing/Cxx/TestCompositeImplicitBackend.cxx b/Common/ImplicitArrays/Testing/Cxx/TestCompositeImplicitBackend.cxx new file mode 100644 index 0000000000..23cea1b735 --- /dev/null +++ b/Common/ImplicitArrays/Testing/Cxx/TestCompositeImplicitBackend.cxx @@ -0,0 +1,54 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: TestCompositeImplicitBackend.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 "vtkCompositeImplicitBackend.h" +#include "vtkCompositeImplicitBackend.txx" +#include "vtkDataArrayRange.h" + +#include "vtkIntArray.h" + +#include +#include + +int TestCompositeImplicitBackend(int, char*[]) +{ + // Setup branches + vtkNew left; + left->SetNumberOfComponents(1); + left->SetNumberOfTuples(10); + auto leftRange = vtk::DataArrayValueRange<1>(left); + std::iota(leftRange.begin(), leftRange.end(), 0); + + vtkNew right; + right->SetNumberOfComponents(1); + right->SetNumberOfTuples(10); + auto rightRange = vtk::DataArrayValueRange<1>(right); + std::iota(rightRange.begin(), rightRange.end(), 10); + + // Make structure + vtkCompositeImplicitBackend composite(left, right); + + // Do checks on structure + for (int i = 0; i < 20; ++i) + { + if (i != composite(i)) + { + std::cout << "Composite backend operator not functioning: " << i << " != " << composite(i) + << std::endl; + return EXIT_FAILURE; + } + } + + return EXIT_SUCCESS; +} diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackend.h b/Common/ImplicitArrays/vtkCompositeImplicitBackend.h new file mode 100644 index 0000000000..fecce60891 --- /dev/null +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.h @@ -0,0 +1,66 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkCompositeImplicitBackend.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 vtkCompositeImplicitBackend_h +#define vtkCompositeImplicitBackend_h + +/** + * \class vtkCompositeImplicitBackend + * \brief A utility structure serving as a backend for composite arrays: an array composed of + * multiple arrays concatenated together + * + * This structure can be classified as a closure and can be called using syntax similar to a + * function call. + * + * The class implements a binary tree like structure for facilitating fast access. + * + * At construction it takes two arrays in order to represent their concatenation. + * + * An example of potential usage in a vtkImplicitArray + * ``` + * vtkNew leftArr; + * leftArr->SetNumberOfComponents(1); + * leftArr->SetNumberOfTuples(1); + * leftArr->SetValue(0, 0); + * vtkNew rightArr; + * rightArr->SetNumberOfComponents(1); + * rightArr->SetNumberOfTuples(1); + * rightArr->SetValue(0, 1); + * vtkNew>> compositeArr; + * compositeArr->SetBackend(std::make_shared>(leftArr, rightArr)); + * CHECK(compositArr->GetValue(1) == 1); + * ``` + */ + +#include "vtkSmartPointer.h" // for internal variables + +VTK_ABI_NAMESPACE_BEGIN +class vtkDataArray; +template +class vtkCompositeImplicitBackend +{ +public: + vtkCompositeImplicitBackend(vtkDataArray* leftArr, vtkDataArray* rightArr); + ~vtkCompositeImplicitBackend() = default; + + ValueType operator()(int idx) const; + +protected: + vtkSmartPointer Left = nullptr; + vtkSmartPointer Right = nullptr; + int Offset = 0; +}; +VTK_ABI_NAMESPACE_END + +#endif // vtkCompositeImplicitBackend_h diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx new file mode 100644 index 0000000000..9faefdabd5 --- /dev/null +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx @@ -0,0 +1,77 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkCompositeImplicitBackend.txx + + 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 "vtkCompositeImplicitBackend.h" + +#include "vtkArrayDispatch.h" +#include "vtkArrayDispatchImplicitArrayList.h" +#include "vtkDataArray.h" + +//----------------------------------------------------------------------- +namespace +{ + +template +struct GetValueDispatch +{ + template + void operator()(ArrayT* arr, int& idx, ValueType& val) const + { + val = static_cast(arr->GetValue(idx)); + } +}; + +} + +VTK_ABI_NAMESPACE_BEGIN +//----------------------------------------------------------------------- +template +vtkCompositeImplicitBackend::vtkCompositeImplicitBackend( + vtkDataArray* leftArr, vtkDataArray* rightArr) + : Left(leftArr) + , Right(rightArr) +{ + this->Offset = this->Left->GetDataSize(); +} + +//----------------------------------------------------------------------- +template +ValueType vtkCompositeImplicitBackend::operator()(int idx) const +{ + int nxtIdx = idx; + vtkDataArray* branch; + if (idx < this->Offset) + { + branch = this->Left; + } + else + { + nxtIdx -= this->Offset; + branch = this->Right; + } + + using DisArrays = vtkArrayDispatch::AllArrays; + using Dispatcher = vtkArrayDispatch::DispatchByArray; + + ValueType val; + ::GetValueDispatch worklet; + if (!Dispatcher::Execute(branch, worklet, nxtIdx, val)) + { + int iTup = nxtIdx / branch->GetNumberOfComponents(); + int iComp = iTup * branch->GetNumberOfComponents() - nxtIdx; + val = static_cast(branch->GetComponent(iTup, iComp)); + } + return val; +} +VTK_ABI_NAMESPACE_END From 139d236f13998b8a301b76b3e081235c0a465951 Mon Sep 17 00:00:00 2001 From: Julien Fausty Date: Wed, 16 Nov 2022 17:10:36 +0100 Subject: [PATCH 02/10] add(CompositeArray): include definition and instantiation --- Common/ImplicitArrays/CMakeLists.txt | 7 +- .../ImplicitArrays/Testing/Cxx/CMakeLists.txt | 1 + .../Testing/Cxx/TestCompositeArray.cxx | 147 ++++++++++++++++++ Common/ImplicitArrays/vtkCompositeArray.h | 83 ++++++++++ Common/ImplicitArrays/vtkCompositeArray.txx | 56 +++++++ .../vtkCompositeArrayInstantiate.cxx.in | 19 +++ .../vtkCompositeImplicitBackend.h | 7 + .../vtkCompositeImplicitBackend.txx | 5 + ...CompositeImplicitBackendInstantiate.cxx.in | 19 +++ .../vtkCreateArrayDispatchImplicitList.cmake | 7 + Common/ImplicitArrays/vtkImplicitArray.h | 9 ++ .../vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h.in | 6 +- 12 files changed, 363 insertions(+), 3 deletions(-) create mode 100644 Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx create mode 100644 Common/ImplicitArrays/vtkCompositeArray.h create mode 100644 Common/ImplicitArrays/vtkCompositeArray.txx create mode 100644 Common/ImplicitArrays/vtkCompositeArrayInstantiate.cxx.in create mode 100644 Common/ImplicitArrays/vtkCompositeImplicitBackendInstantiate.cxx.in diff --git a/Common/ImplicitArrays/CMakeLists.txt b/Common/ImplicitArrays/CMakeLists.txt index 2ecf46b8d2..27398f3328 100644 --- a/Common/ImplicitArrays/CMakeLists.txt +++ b/Common/ImplicitArrays/CMakeLists.txt @@ -1,9 +1,11 @@ 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_STD_FUNCTION_ARRAYS "Include implicit vtkDataArray subclasses based on std::function in dispatcher" OFF) mark_as_advanced( - VTK_DISPATCH_CONSTANT_ARRAYS VTK_DISPATCH_AFFINE_ARRAYS + VTK_DISPATCH_COMPOSITE_ARRAYS + VTK_DISPATCH_CONSTANT_ARRAYS VTK_DISPATCH_STD_FUNCTION_ARRAYS ) @@ -31,6 +33,8 @@ foreach (INSTANTIATION_VALUE_TYPE IN LISTS vtkArrayDispatchImplicit_all_types) string(REPLACE " " "_" _suffix "${INSTANTIATION_VALUE_TYPE}") list(APPEND _list "vtkAffineArrayInstantiate") + list(APPEND _list "vtkCompositeArrayInstantiate") + list(APPEND _list "vtkCompositeImplicitBackendInstantiate") list(APPEND _list "vtkConstantArrayInstantiate") list(APPEND _list "vtkStdFunctionArrayInstantiate") @@ -48,6 +52,7 @@ endforeach () set(nowrap_headers vtkAffineArray.h vtkAffineImplicitBackend.h + vtkCompositeArray.h vtkConstantArray.h vtkConstantImplicitBackend.h vtkImplicitArrayTraits.h diff --git a/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt b/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt index 3b54b70ae8..463fe0c4be 100644 --- a/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt +++ b/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt @@ -1,6 +1,7 @@ vtk_add_test_cxx(vtkCommonImplicitArrayCxxTests tests NO_DATA NO_OUTPUT NO_VALID TestAffineArray.cxx + TestCompositeArray.cxx TestCompositeImplicitBackend.cxx TestConstantArray.cxx TestImplicitArraysBase.cxx diff --git a/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx b/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx new file mode 100644 index 0000000000..5fdaa96537 --- /dev/null +++ b/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx @@ -0,0 +1,147 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: TestCompositeArray.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 "vtkCompositeArray.h" + +#include "vtkAffineArray.h" +#include "vtkDataArrayRange.h" +#include "vtkIntArray.h" +#include "vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h" + +#ifdef VTK_DISPATCH_COMPOSITE_ARRAYS +#include "vtkArrayDispatch.h" +#include "vtkArrayDispatchImplicitArrayList.h" +#endif // VTK_DISPATCH_AFFINE_ARRAYS + +#include +#include + +namespace +{ +#ifdef VTK_DISPATCH_COMPOSITE_ARRAYS +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_COMPOSITE_ARRAYS + +vtkSmartPointer> SetupCompositeArray(int length) +{ + std::vector>> affArrays(length / 20); + std::vector> intArrays(length / 20); + for (int i = 0; i < length / 20; ++i) + { + vtkNew> affine; + affine->SetBackend(std::make_shared>(1, i * 20)); + affine->SetNumberOfTuples(10); + affine->SetNumberOfComponents(1); + affArrays[i] = affine; + } + for (int i = 0; i < length / 20; ++i) + { + vtkNew iota; + iota->SetNumberOfTuples(10); + iota->SetNumberOfComponents(1); + auto range = vtk::DataArrayValueRange<1>(iota); + std::iota(range.begin(), range.end(), 10 * (2 * i + 1)); + intArrays[i] = iota; + } + + std::vector interleaf; + for (int i = 0; i < length / 20; ++i) + { + interleaf.emplace_back(affArrays[i]); + interleaf.emplace_back(intArrays[i]); + } + + return vtkCompositeArrayUtilities::Concatenate(interleaf); +} + +} + +int TestCompositeArray(int vtkNotUsed(argc), char* vtkNotUsed(argv)[]) +{ + int res = EXIT_SUCCESS; + + vtkSmartPointer> composite = ::SetupCompositeArray(100); + + for (int iArr = 0; iArr < 100; iArr++) + { + if (composite->GetValue(iArr) != iArr) + { + res = EXIT_FAILURE; + std::cout << "get value failed with vtkCompositeArray: " << iArr + << " != " << composite->GetValue(iArr) << std::endl; + } + } + + int iArr = 0; + for (auto val : vtk::DataArrayValueRange<1>(composite)) + { + if (val != iArr) + { + res = EXIT_FAILURE; + std::cout << "range iterator failed with vtkCompositerray" << std::endl; + } + iArr++; + } + +#ifdef VTK_DISPATCH_COMPOSITE_ARRAYS + std::cout << "vtkCompositeArray: performing dispatch tests" << std::endl; + vtkNew destination; + destination->SetNumberOfTuples(100); + destination->SetNumberOfComponents(1); + using Dispatcher = + vtkArrayDispatch::Dispatch2ByArray; + ::ScaleWorker worker; + if (!Dispatcher::Execute(composite, destination, worker, 3.0)) + { + res = EXIT_FAILURE; + std::cout << "vtkArrayDispatch failed with vtkCompositeArray" << std::endl; + worker(composite.Get(), destination.Get(), 3.0); + } + + iArr = 0; + for (auto val : vtk::DataArrayValueRange<1>(destination)) + { + if (val != 3 * iArr) + { + res = EXIT_FAILURE; + std::cout << "dispatch failed to populate the array with the correct values" << std::endl; + } + iArr++; + } +#endif // VTK_DISPATCH_COMPOSITE_ARRAYS + return res; +}; diff --git a/Common/ImplicitArrays/vtkCompositeArray.h b/Common/ImplicitArrays/vtkCompositeArray.h new file mode 100644 index 0000000000..7854f6f85a --- /dev/null +++ b/Common/ImplicitArrays/vtkCompositeArray.h @@ -0,0 +1,83 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkCompositeArray.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 vtkCompositeArray_h +#define vtkCompositeArray_h + +#ifdef VTK_COMPOSITE_ARRAY_INSTANTIATING +#define VTK_IMPLICIT_VALUERANGE_INSTANTIATING +#include "vtkDataArrayPrivate.txx" +#endif + +#include "vtkCompositeImplicitBackend.h" // for the array backend +#include "vtkImplicitArray.h" + +#ifdef VTK_COMPOSITE_ARRAY_INSTANTIATING +#undef VTK_IMPLICIT_VALUERANGE_INSTANTIATING +#endif + +#include + +/** + * \var vtkCompositeArray + * \brief A utility alias for concatenating arrays into an implicit array + * + * In order to be usefully included in the dispatchers, these arrays need to be instantiated at the + * vtk library compile time. + * + * @sa + * vtkImplicitArray vtkCompositeImplicitBackend + */ + +VTK_ABI_NAMESPACE_BEGIN +class vtkDataArray; +template +using vtkCompositeArray = vtkImplicitArray>; +VTK_ABI_NAMESPACE_END + +namespace vtkCompositeArrayUtilities +{ +VTK_ABI_NAMESPACE_BEGIN +template +vtkSmartPointer> Concatenate(const std::vector& arrays); +VTK_ABI_NAMESPACE_END +} + +#endif // vtkCompositeArray_h + +#ifdef VTK_COMPOSITE_ARRAY_INSTANTIATING + +#define VTK_INSTANTIATE_COMPOSITE_ARRAY(ValueType) \ + VTK_ABI_NAMESPACE_BEGIN \ + template class VTKCOMMONIMPLICITARRAYS_EXPORT \ + vtkImplicitArray>; \ + VTK_ABI_NAMESPACE_END \ + namespace vtkCompositeArrayUtilities \ + { \ + VTK_ABI_NAMESPACE_BEGIN \ + template VTKCOMMONIMPLICITARRAYS_EXPORT \ + vtkSmartPointer>> \ + Concatenate(const std::vector& arrays); \ + 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/vtkCompositeArray.txx b/Common/ImplicitArrays/vtkCompositeArray.txx new file mode 100644 index 0000000000..da3f18546f --- /dev/null +++ b/Common/ImplicitArrays/vtkCompositeArray.txx @@ -0,0 +1,56 @@ +#include "vtkCompositeArray.h" + +#include "vtkDataArray.h" + +//----------------------------------------------------------------------- +namespace vtkCompositeArrayUtilities +{ +VTK_ABI_NAMESPACE_BEGIN +template +vtkSmartPointer> Concatenate(const std::vector& arrays) +{ + if (arrays.size() < 2) + { + return nullptr; + } + vtkIdType nComps = arrays[0]->GetNumberOfComponents(); + for (auto arr : arrays) + { + if (arr->GetNumberOfComponents() != nComps) + { + vtkErrorWithObjectMacro(nullptr, "Number of components of all the arrays are not equal"); + return nullptr; + } + } + std::vector> lifetimeBuffer; + lifetimeBuffer.assign(arrays.begin(), arrays.end()); + std::vector>> newComps; + while (lifetimeBuffer.size() != 1) + { + newComps.clear(); + for (int i = 0; i < static_cast(lifetimeBuffer.size() - 1); i += 2) + { + vtkNew> composite; + composite->SetBackend( + std::make_shared>(lifetimeBuffer[i], lifetimeBuffer[i + 1])); + composite->SetNumberOfTuples( + lifetimeBuffer[i]->GetNumberOfTuples() + lifetimeBuffer[i + 1]->GetNumberOfTuples()); + composite->SetNumberOfComponents(lifetimeBuffer[i]->GetNumberOfComponents()); + newComps.emplace_back(composite); + } + if (lifetimeBuffer.size() % 2 != 0) + { + vtkNew> composite; + composite->SetBackend( + std::make_shared>(newComps.back(), lifetimeBuffer.back())); + composite->SetNumberOfTuples( + newComps.back()->GetNumberOfTuples() + lifetimeBuffer.back()->GetNumberOfTuples()); + composite->SetNumberOfComponents(lifetimeBuffer.back()->GetNumberOfComponents()); + newComps.back() = composite; + } + lifetimeBuffer.assign(newComps.begin(), newComps.end()); + } + return newComps[0]; +} +VTK_ABI_NAMESPACE_END +} diff --git a/Common/ImplicitArrays/vtkCompositeArrayInstantiate.cxx.in b/Common/ImplicitArrays/vtkCompositeArrayInstantiate.cxx.in new file mode 100644 index 0000000000..0822914bef --- /dev/null +++ b/Common/ImplicitArrays/vtkCompositeArrayInstantiate.cxx.in @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkCompositeArray.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_COMPOSITE_ARRAY_INSTANTIATING +#include "vtkCompositeArray.h" +#include "vtkCompositeArray.txx" + +VTK_INSTANTIATE_COMPOSITE_ARRAY(@INSTANTIATION_VALUE_TYPE@) diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackend.h b/Common/ImplicitArrays/vtkCompositeImplicitBackend.h index fecce60891..230491b6af 100644 --- a/Common/ImplicitArrays/vtkCompositeImplicitBackend.h +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.h @@ -64,3 +64,10 @@ protected: VTK_ABI_NAMESPACE_END #endif // vtkCompositeImplicitBackend_h + +#ifdef VTK_COMPOSITE_BACKEND_INSTANTIATING +#define VTK_INSTANTIATE_COMPOSITE_BACKEND(ValueType) \ + VTK_ABI_NAMESPACE_BEGIN \ + template class VTKCOMMONIMPLICITARRAYS_EXPORT vtkCompositeImplicitBackend; \ + VTK_ABI_NAMESPACE_END +#endif diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx index 9faefdabd5..9b1d7521b8 100644 --- a/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx @@ -42,6 +42,11 @@ vtkCompositeImplicitBackend::vtkCompositeImplicitBackend( : Left(leftArr) , Right(rightArr) { + if (this->Left == nullptr || this->Right == nullptr) + { + vtkWarningWithObjectMacro(nullptr, "Creating composite array with nullptr"); + return; + } this->Offset = this->Left->GetDataSize(); } diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackendInstantiate.cxx.in b/Common/ImplicitArrays/vtkCompositeImplicitBackendInstantiate.cxx.in new file mode 100644 index 0000000000..05ebd25475 --- /dev/null +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackendInstantiate.cxx.in @@ -0,0 +1,19 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkCompositeImplicitBackend.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_COMPOSITE_BACKEND_INSTANTIATING +#include "vtkCompositeImplicitBackend.h" +#include "vtkCompositeImplicitBackend.txx" + +VTK_INSTANTIATE_COMPOSITE_BACKEND(@INSTANTIATION_VALUE_TYPE@) diff --git a/Common/ImplicitArrays/vtkCreateArrayDispatchImplicitList.cmake b/Common/ImplicitArrays/vtkCreateArrayDispatchImplicitList.cmake index 0275874955..ffe672ac3b 100644 --- a/Common/ImplicitArrays/vtkCreateArrayDispatchImplicitList.cmake +++ b/Common/ImplicitArrays/vtkCreateArrayDispatchImplicitList.cmake @@ -129,6 +129,13 @@ if (VTK_DISPATCH_AFFINE_ARRAYS) ) endif() +if (VTK_DISPATCH_COMPOSITE_ARRAYS) + list(APPEND vtkArrayDispatchImplicit_containers vtkCompositeArray) + set(vtkArrayDispatchImplicit_vtkCompositeArray_header vtkCompositeArray.h) + set(vtkArrayDispatchImplicit_vtkCompositeArray_types + ${vtkArrayDispatchImplicit_all_types} + ) +endif() endmacro() diff --git a/Common/ImplicitArrays/vtkImplicitArray.h b/Common/ImplicitArrays/vtkImplicitArray.h index 335eb23a97..013b3f153d 100644 --- a/Common/ImplicitArrays/vtkImplicitArray.h +++ b/Common/ImplicitArrays/vtkImplicitArray.h @@ -313,6 +313,8 @@ VTK_ABI_NAMESPACE_BEGIN template struct vtkAffineImplicitBackend; template +class vtkCompositeImplicitBackend; +template struct vtkConstantImplicitBackend; VTK_ABI_NAMESPACE_END #include @@ -331,6 +333,8 @@ VTK_ABI_NAMESPACE_END #define VTK_INSTANTIATE_VALUERANGE_VALUETYPE(ValueType) \ VTK_INSTANTIATE_VALUERANGE_ARRAYTYPE( \ vtkImplicitArray>, ValueType) \ + VTK_INSTANTIATE_VALUERANGE_ARRAYTYPE( \ + vtkImplicitArray>, ValueType) \ VTK_INSTANTIATE_VALUERANGE_ARRAYTYPE( \ vtkImplicitArray>, ValueType) \ VTK_INSTANTIATE_VALUERANGE_ARRAYTYPE(vtkImplicitArray>, ValueType) @@ -350,6 +354,8 @@ VTK_ABI_NAMESPACE_BEGIN template struct vtkAffineImplicitBackend; template +class vtkCompositeImplicitBackend; +template struct vtkConstantImplicitBackend; VTK_ABI_NAMESPACE_END #include @@ -381,6 +387,8 @@ VTK_ABI_NAMESPACE_END #define VTK_DECLARE_VALUERANGE_VALUETYPE(ValueType) \ VTK_DECLARE_VALUERANGE_ARRAYTYPE( \ vtkImplicitArray>, ValueType) \ + VTK_DECLARE_VALUERANGE_ARRAYTYPE( \ + vtkImplicitArray>, ValueType) \ VTK_DECLARE_VALUERANGE_ARRAYTYPE( \ vtkImplicitArray>, ValueType) \ VTK_DECLARE_VALUERANGE_ARRAYTYPE(vtkImplicitArray>, ValueType) @@ -405,6 +413,7 @@ namespace vtkDataArrayPrivate 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_ARRAYTYPE(vtkImplicitArray>, double) VTK_DECLARE_VALUERANGE_ARRAYTYPE(vtkImplicitArray>, double) diff --git a/Common/ImplicitArrays/vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h.in b/Common/ImplicitArrays/vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h.in index f902946da8..55769121ba 100644 --- a/Common/ImplicitArrays/vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h.in +++ b/Common/ImplicitArrays/vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h.in @@ -16,10 +16,12 @@ #ifndef vtkVTK_DISPATCH_IMPLICIT_ARRAYS_h #define vtkVTK_DISPATCH_IMPLICIT_ARRAYS_h -// defined if VTK dispatches the vtkConstantArray class -#cmakedefine VTK_DISPATCH_CONSTANT_ARRAYS // defined if VTK dispatches the vtkAffineArray class #cmakedefine VTK_DISPATCH_AFFINE_ARRAYS +// defined if VTK dispatches the vtkCompositeArray class +#cmakedefine VTK_DISPATCH_COMPOSITE_ARRAYS +// defined if VTK dispatches the vtkConstantArray class +#cmakedefine VTK_DISPATCH_CONSTANT_ARRAYS // defined if VTK dispatches the vtkStdFunctionArray class #cmakedefine VTK_DISPATCH_STD_FUNCTION_ARRAYS From 73b84ead94162019762ba65f22567628e964a9a5 Mon Sep 17 00:00:00 2001 From: Julien Fausty Date: Fri, 18 Nov 2022 11:38:12 +0100 Subject: [PATCH 03/10] improve(CompositeArr): remove dispatch from implementation --- .../vtkCompositeImplicitBackend.h | 11 ++- .../vtkCompositeImplicitBackend.txx | 85 ++++++++----------- 2 files changed, 42 insertions(+), 54 deletions(-) diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackend.h b/Common/ImplicitArrays/vtkCompositeImplicitBackend.h index 230491b6af..8339200a7c 100644 --- a/Common/ImplicitArrays/vtkCompositeImplicitBackend.h +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.h @@ -42,8 +42,8 @@ * CHECK(compositArr->GetValue(1) == 1); * ``` */ - -#include "vtkSmartPointer.h" // for internal variables +#include "vtkCommonImplicitArraysModule.h" +#include VTK_ABI_NAMESPACE_BEGIN class vtkDataArray; @@ -52,14 +52,13 @@ class vtkCompositeImplicitBackend { public: vtkCompositeImplicitBackend(vtkDataArray* leftArr, vtkDataArray* rightArr); - ~vtkCompositeImplicitBackend() = default; + ~vtkCompositeImplicitBackend(); ValueType operator()(int idx) const; protected: - vtkSmartPointer Left = nullptr; - vtkSmartPointer Right = nullptr; - int Offset = 0; + struct Internals; + std::unique_ptr Internal; }; VTK_ABI_NAMESPACE_END diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx index 9b1d7521b8..b5224c8c9d 100644 --- a/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx @@ -17,66 +17,55 @@ #include "vtkArrayDispatch.h" #include "vtkArrayDispatchImplicitArrayList.h" #include "vtkDataArray.h" - -//----------------------------------------------------------------------- -namespace -{ - -template -struct GetValueDispatch -{ - template - void operator()(ArrayT* arr, int& idx, ValueType& val) const - { - val = static_cast(arr->GetValue(idx)); - } -}; - -} +#include "vtkDataArrayRange.h" +#include "vtkSmartPointer.h" VTK_ABI_NAMESPACE_BEGIN +//----------------------------------------------------------------------- +template +struct vtkCompositeImplicitBackend::Internals +{ + Internals(vtkDataArray* leftArr, vtkDataArray* rightArr) + : Left(leftArr) + , Right(rightArr) + { + if (this->Left == nullptr || this->Right == nullptr) + { + vtkWarningWithObjectMacro(nullptr, "Creating composite array with nullptr"); + return; + } + this->LeftRange = vtk::DataArrayValueRange(this->Left); + this->RightRange = vtk::DataArrayValueRange(this->Right); + this->Offset = LeftRange.size(); + } + + vtkSmartPointer Left; + vtk::detail::SelectValueRange::type LeftRange; + vtkSmartPointer Right; + vtk::detail::SelectValueRange::type RightRange; + int Offset = -1; +}; + //----------------------------------------------------------------------- template vtkCompositeImplicitBackend::vtkCompositeImplicitBackend( vtkDataArray* leftArr, vtkDataArray* rightArr) - : Left(leftArr) - , Right(rightArr) + : Internal(std::unique_ptr(new Internals(leftArr, rightArr))) +{ +} + +//----------------------------------------------------------------------- +template +vtkCompositeImplicitBackend::~vtkCompositeImplicitBackend() { - if (this->Left == nullptr || this->Right == nullptr) - { - vtkWarningWithObjectMacro(nullptr, "Creating composite array with nullptr"); - return; - } - this->Offset = this->Left->GetDataSize(); } //----------------------------------------------------------------------- template ValueType vtkCompositeImplicitBackend::operator()(int idx) const { - int nxtIdx = idx; - vtkDataArray* branch; - if (idx < this->Offset) - { - branch = this->Left; - } - else - { - nxtIdx -= this->Offset; - branch = this->Right; - } - - using DisArrays = vtkArrayDispatch::AllArrays; - using Dispatcher = vtkArrayDispatch::DispatchByArray; - - ValueType val; - ::GetValueDispatch worklet; - if (!Dispatcher::Execute(branch, worklet, nxtIdx, val)) - { - int iTup = nxtIdx / branch->GetNumberOfComponents(); - int iComp = iTup * branch->GetNumberOfComponents() - nxtIdx; - val = static_cast(branch->GetComponent(iTup, iComp)); - } - return val; + return static_cast((idx < this->Internal->Offset) + ? this->Internal->LeftRange[idx] + : this->Internal->RightRange[idx - this->Internal->Offset]); } VTK_ABI_NAMESPACE_END From 2bb46a9b06e1dac304afaf02fcc02222ad08b242 Mon Sep 17 00:00:00 2001 From: Julien Fausty Date: Fri, 18 Nov 2022 11:41:57 +0100 Subject: [PATCH 04/10] add(impArr): module headers for all arrays --- Common/ImplicitArrays/vtkAffineArray.h | 3 ++- Common/ImplicitArrays/vtkCompositeArray.h | 3 ++- Common/ImplicitArrays/vtkConstantArray.h | 3 ++- Common/ImplicitArrays/vtkStdFunctionArray.h | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Common/ImplicitArrays/vtkAffineArray.h b/Common/ImplicitArrays/vtkAffineArray.h index bc436e9fe0..31cef1ca3a 100644 --- a/Common/ImplicitArrays/vtkAffineArray.h +++ b/Common/ImplicitArrays/vtkAffineArray.h @@ -21,7 +21,8 @@ #include "vtkDataArrayPrivate.txx" #endif -#include "vtkAffineImplicitBackend.h" // for the array backend +#include "vtkAffineImplicitBackend.h" // for the array backend +#include "vtkCommonImplicitArraysModule.h" // for export macro #include "vtkImplicitArray.h" #ifdef VTK_AFFINE_ARRAY_INSTANTIATING diff --git a/Common/ImplicitArrays/vtkCompositeArray.h b/Common/ImplicitArrays/vtkCompositeArray.h index 7854f6f85a..0e1c068a8c 100644 --- a/Common/ImplicitArrays/vtkCompositeArray.h +++ b/Common/ImplicitArrays/vtkCompositeArray.h @@ -21,7 +21,8 @@ #include "vtkDataArrayPrivate.txx" #endif -#include "vtkCompositeImplicitBackend.h" // for the array backend +#include "vtkCommonImplicitArraysModule.h" // for export macro +#include "vtkCompositeImplicitBackend.h" // for the array backend #include "vtkImplicitArray.h" #ifdef VTK_COMPOSITE_ARRAY_INSTANTIATING diff --git a/Common/ImplicitArrays/vtkConstantArray.h b/Common/ImplicitArrays/vtkConstantArray.h index 02ff68f9bd..72432c0ade 100644 --- a/Common/ImplicitArrays/vtkConstantArray.h +++ b/Common/ImplicitArrays/vtkConstantArray.h @@ -21,7 +21,8 @@ #include "vtkDataArrayPrivate.txx" #endif -#include "vtkConstantImplicitBackend.h" // for the array backend +#include "vtkCommonImplicitArraysModule.h" // for export macro +#include "vtkConstantImplicitBackend.h" // for the array backend #include "vtkImplicitArray.h" #ifdef VTK_CONSTANT_ARRAY_INSTANTIATING diff --git a/Common/ImplicitArrays/vtkStdFunctionArray.h b/Common/ImplicitArrays/vtkStdFunctionArray.h index bfb9051d1c..1d990fc3b7 100644 --- a/Common/ImplicitArrays/vtkStdFunctionArray.h +++ b/Common/ImplicitArrays/vtkStdFunctionArray.h @@ -21,6 +21,7 @@ #include "vtkDataArrayPrivate.txx" #endif +#include "vtkCommonImplicitArraysModule.h" // for export macro #include "vtkImplicitArray.h" #ifdef VTK_STD_FUNCTION_ARRAY_INSTANTIATING From c0233ec6dd9f5c2161b53b272a2d29c47f1dd92f Mon Sep 17 00:00:00 2001 From: Julien Fausty Date: Fri, 18 Nov 2022 15:56:56 +0100 Subject: [PATCH 05/10] improve(CompositeArray): switch ordering of allocation --- Common/ImplicitArrays/vtkCompositeArray.txx | 4 ++-- Common/ImplicitArrays/vtkCompositeImplicitBackend.txx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/ImplicitArrays/vtkCompositeArray.txx b/Common/ImplicitArrays/vtkCompositeArray.txx index da3f18546f..40f1bcc264 100644 --- a/Common/ImplicitArrays/vtkCompositeArray.txx +++ b/Common/ImplicitArrays/vtkCompositeArray.txx @@ -33,9 +33,9 @@ vtkSmartPointer> Concatenate(const std::vector> composite; composite->SetBackend( std::make_shared>(lifetimeBuffer[i], lifetimeBuffer[i + 1])); + composite->SetNumberOfComponents(lifetimeBuffer[i]->GetNumberOfComponents()); composite->SetNumberOfTuples( lifetimeBuffer[i]->GetNumberOfTuples() + lifetimeBuffer[i + 1]->GetNumberOfTuples()); - composite->SetNumberOfComponents(lifetimeBuffer[i]->GetNumberOfComponents()); newComps.emplace_back(composite); } if (lifetimeBuffer.size() % 2 != 0) @@ -43,9 +43,9 @@ vtkSmartPointer> Concatenate(const std::vector> composite; composite->SetBackend( std::make_shared>(newComps.back(), lifetimeBuffer.back())); + composite->SetNumberOfComponents(lifetimeBuffer.back()->GetNumberOfComponents()); composite->SetNumberOfTuples( newComps.back()->GetNumberOfTuples() + lifetimeBuffer.back()->GetNumberOfTuples()); - composite->SetNumberOfComponents(lifetimeBuffer.back()->GetNumberOfComponents()); newComps.back() = composite; } lifetimeBuffer.assign(newComps.begin(), newComps.end()); diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx index b5224c8c9d..2bd09dad7a 100644 --- a/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx @@ -36,7 +36,7 @@ struct vtkCompositeImplicitBackend::Internals } this->LeftRange = vtk::DataArrayValueRange(this->Left); this->RightRange = vtk::DataArrayValueRange(this->Right); - this->Offset = LeftRange.size(); + this->Offset = this->LeftRange.size(); } vtkSmartPointer Left; From b9a5755f1921c38583fe688aeef4312b231ffeb4 Mon Sep 17 00:00:00 2001 From: Julien Fausty Date: Fri, 18 Nov 2022 18:17:58 +0100 Subject: [PATCH 06/10] add(changelog): describe `vtkCompositeArray` implementation --- .../release/dev/add-vtkCompositeArray.md | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/release/dev/add-vtkCompositeArray.md diff --git a/Documentation/release/dev/add-vtkCompositeArray.md b/Documentation/release/dev/add-vtkCompositeArray.md new file mode 100644 index 0000000000..cd6b1fa0e2 --- /dev/null +++ b/Documentation/release/dev/add-vtkCompositeArray.md @@ -0,0 +1,26 @@ +# `vtkCompositeArray`: a new implicit array that concatenates other arrays together + +`vtkCompositeArray` is now available in VTK! It is a family of `vtkImplicitArray`s that can concatenate arrays together to interface a group of arrays as if they were a single array. + +This new array relies on the `vtkCompositeImplicitBackend` template class to join `vtkDataArray`s two at a time. Creating a hiearchy of `vtkCompositeArray`s can generate a binary tree on the indexes of the composite array leading to access with $O(log_2(m))$ time where $m$ is the number of leaves (or base `vtkDataArray`s) composing the composite (or alternatively $O(l)$ where $l$ is the number of levels in the tree). + +To facilitate the creation of `vtkCompositeArray`s in practice, a templated utility function `vtkCompositeArrayUtilities::Concatenate` has been made available to users that can take an `std::vector` of `vtkDataArray`s and turn them into a single concatenated `vtkCompositeArray` whose tree structure should be balanced with respect to number of arrays (a possible improvement would be to balance with respect to number of tuples following a "Huffman coding" approach). + +A code snippet using this type of array: +``` +std::vector baseArrays(16); // 16 == 2^4, will make 4 levels in binary tree +vtkNew baseArray; +baseArray->SetNumberOfComponents(3); +baseArray->SetNumberOfTuples(10); +baseArray->Fill(0.0); + +std::fill(baseArrays.begin(), baseArrays.end(), baseArray); +vtkSmartPointer> composite = vtkCompositeArrayUtilities::Concatenate(baseArrays); // nTuples = 160 + +CHECK(composite->GetComponent(42, 1) == 0.0); // always true +``` + +> **WARNINGS** +> +> * Any two arrays composited into a `vtkCompositeArray` must have the same number of components. +> * Iteration over the composited array incurs a lot of overhead compared to an explicit memory array (~3x slower with only 1 level). The use case is truly when memory efficiency is more important than compute performance. From dca028f653a2a05043390923de5a6569b9f9ba7c Mon Sep 17 00:00:00 2001 From: Julien Fausty Date: Mon, 21 Nov 2022 10:34:04 +0100 Subject: [PATCH 07/10] add(TypeList): empty type list `CreateImpl` specialization Add an empty `vtkTypeList::CreateImpl` specialization for completeness and for when no `vtkImplicitArray`s are dispatched. --- Common/Core/vtkTypeList.txx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Common/Core/vtkTypeList.txx b/Common/Core/vtkTypeList.txx index 0728e00923..2ad280e7a5 100644 --- a/Common/Core/vtkTypeList.txx +++ b/Common/Core/vtkTypeList.txx @@ -55,6 +55,12 @@ struct CreateImpl using type = vtkTypeList::TypeList; }; +template <> +struct CreateImpl<> +{ + using type = vtkTypeList::NullType; +}; + template struct CreateImpl { From e7a38ffa715841fe17d2628859e2ad81f12bb1a0 Mon Sep 17 00:00:00 2001 From: Julien Fausty Date: Mon, 21 Nov 2022 19:07:38 +0100 Subject: [PATCH 08/10] build(impArr): include dispatch list header for module --- Common/ImplicitArrays/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Common/ImplicitArrays/CMakeLists.txt b/Common/ImplicitArrays/CMakeLists.txt index 27398f3328..3cb1c39d89 100644 --- a/Common/ImplicitArrays/CMakeLists.txt +++ b/Common/ImplicitArrays/CMakeLists.txt @@ -58,6 +58,7 @@ set(nowrap_headers vtkImplicitArrayTraits.h vtkStdFunctionArray.h "${CMAKE_CURRENT_BINARY_DIR}/vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h" + "${CMAKE_CURRENT_BINARY_DIR}/vtkArrayDispatchImplicitArrayList.h" ) set(nowrap_template_classes From 86a5ba59e2509dba1a4573a337257928fdb6ad79 Mon Sep 17 00:00:00 2001 From: Julien Fausty Date: Tue, 22 Nov 2022 11:40:06 +0100 Subject: [PATCH 09/10] review(CompositeArr): improve doc + refactor + improve testing - tone down changelog + add more details - add default keyword for `vtkCompositeImplicitBackend` destructor - add `const` in places where is useful - change warning of nullptr into error - improve documentation for both backend and array - refactor `vtkCompositeArrayUtilities` namespace in `vtk` namespace - improve multi component testing --- .../Testing/Cxx/TestCompositeArray.cxx | 2 +- .../Cxx/TestCompositeImplicitBackend.cxx | 24 +++++++++++++++++++ Common/ImplicitArrays/vtkCompositeArray.h | 23 ++++++++++++++---- Common/ImplicitArrays/vtkCompositeArray.txx | 5 ++-- .../vtkCompositeImplicitBackend.h | 13 +++++++++- .../vtkCompositeImplicitBackend.txx | 10 ++++---- .../release/dev/add-vtkCompositeArray.md | 6 ++--- 7 files changed, 66 insertions(+), 17 deletions(-) diff --git a/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx b/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx index 5fdaa96537..8a1c138711 100644 --- a/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx +++ b/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx @@ -85,7 +85,7 @@ vtkSmartPointer> SetupCompositeArray(int length) interleaf.emplace_back(intArrays[i]); } - return vtkCompositeArrayUtilities::Concatenate(interleaf); + return vtk::ConcatenateDataArrays(interleaf); } } diff --git a/Common/ImplicitArrays/Testing/Cxx/TestCompositeImplicitBackend.cxx b/Common/ImplicitArrays/Testing/Cxx/TestCompositeImplicitBackend.cxx index 23cea1b735..9a3da60966 100644 --- a/Common/ImplicitArrays/Testing/Cxx/TestCompositeImplicitBackend.cxx +++ b/Common/ImplicitArrays/Testing/Cxx/TestCompositeImplicitBackend.cxx @@ -50,5 +50,29 @@ int TestCompositeImplicitBackend(int, char*[]) } } + vtkNew leftMulti; + leftMulti->SetNumberOfComponents(3); + leftMulti->SetNumberOfTuples(10); + auto leftMultiRange = vtk::DataArrayValueRange<3>(leftMulti); + std::iota(leftMultiRange.begin(), leftMultiRange.end(), 0); + + vtkNew rightMulti; + rightMulti->SetNumberOfComponents(3); + rightMulti->SetNumberOfTuples(10); + auto rightMultiRange = vtk::DataArrayValueRange<3>(rightMulti); + std::iota(rightMultiRange.begin(), rightMultiRange.end(), 30); + + vtkCompositeImplicitBackend compositeMulti(leftMulti, rightMulti); + + for (int i = 0; i < 60; ++i) + { + if (i != compositeMulti(i)) + { + std::cout << "Composite backend operator not functioning: " << i + << " != " << compositeMulti(i) << std::endl; + return EXIT_FAILURE; + } + } + return EXIT_SUCCESS; } diff --git a/Common/ImplicitArrays/vtkCompositeArray.h b/Common/ImplicitArrays/vtkCompositeArray.h index 0e1c068a8c..460c5b24f1 100644 --- a/Common/ImplicitArrays/vtkCompositeArray.h +++ b/Common/ImplicitArrays/vtkCompositeArray.h @@ -38,6 +38,20 @@ * 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 leftArr; + * leftArr->SetNumberOfComponents(1); + * leftArr->SetNumberOfTuples(1); + * leftArr->SetValue(0, 0); + * vtkNew rightArr; + * rightArr->SetNumberOfComponents(1); + * rightArr->SetNumberOfTuples(1); + * rightArr->SetValue(0, 1); + * vtkNew> compositeArr; + * compositeArr->SetBackend(std::make_shared>(leftArr, rightArr)); + * CHECK(compositArr->GetValue(1) == 1); + * ``` * @sa * vtkImplicitArray vtkCompositeImplicitBackend */ @@ -48,11 +62,12 @@ template using vtkCompositeArray = vtkImplicitArray>; VTK_ABI_NAMESPACE_END -namespace vtkCompositeArrayUtilities +namespace vtk { VTK_ABI_NAMESPACE_BEGIN template -vtkSmartPointer> Concatenate(const std::vector& arrays); +vtkSmartPointer> ConcatenateDataArrays( + const std::vector& arrays); VTK_ABI_NAMESPACE_END } @@ -65,12 +80,12 @@ VTK_ABI_NAMESPACE_END template class VTKCOMMONIMPLICITARRAYS_EXPORT \ vtkImplicitArray>; \ VTK_ABI_NAMESPACE_END \ - namespace vtkCompositeArrayUtilities \ + namespace vtk \ { \ VTK_ABI_NAMESPACE_BEGIN \ template VTKCOMMONIMPLICITARRAYS_EXPORT \ vtkSmartPointer>> \ - Concatenate(const std::vector& arrays); \ + ConcatenateDataArrays(const std::vector& arrays); \ VTK_ABI_NAMESPACE_END \ } \ namespace vtkDataArrayPrivate \ diff --git a/Common/ImplicitArrays/vtkCompositeArray.txx b/Common/ImplicitArrays/vtkCompositeArray.txx index 40f1bcc264..9e6b5f1aa5 100644 --- a/Common/ImplicitArrays/vtkCompositeArray.txx +++ b/Common/ImplicitArrays/vtkCompositeArray.txx @@ -3,11 +3,12 @@ #include "vtkDataArray.h" //----------------------------------------------------------------------- -namespace vtkCompositeArrayUtilities +namespace vtk { VTK_ABI_NAMESPACE_BEGIN template -vtkSmartPointer> Concatenate(const std::vector& arrays) +vtkSmartPointer> ConcatenateDataArrays( + const std::vector& arrays) { if (arrays.size() < 2) { diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackend.h b/Common/ImplicitArrays/vtkCompositeImplicitBackend.h index 8339200a7c..c599b7df18 100644 --- a/Common/ImplicitArrays/vtkCompositeImplicitBackend.h +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.h @@ -37,7 +37,8 @@ * rightArr->SetNumberOfComponents(1); * rightArr->SetNumberOfTuples(1); * rightArr->SetValue(0, 1); - * vtkNew>> compositeArr; + * vtkNew>> compositeArr; // easier with + * `vtkNew> compositeArr;` if applicable * compositeArr->SetBackend(std::make_shared>(leftArr, rightArr)); * CHECK(compositArr->GetValue(1) == 1); * ``` @@ -51,9 +52,19 @@ template class vtkCompositeImplicitBackend { public: + /** + * Constructor for the backend + * @param leftArr the array starting the composite at index 0 + * @param rightArr the array following the leftArr and starting at index + * leftArr->GetNumberOfTuples() + */ vtkCompositeImplicitBackend(vtkDataArray* leftArr, vtkDataArray* rightArr); ~vtkCompositeImplicitBackend(); + /** + * Indexing operator for the composite of the two arrays respecting the `vtkImplicitArray` + * expectations + */ ValueType operator()(int idx) const; protected: diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx index 2bd09dad7a..f1384057df 100644 --- a/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx @@ -31,7 +31,7 @@ struct vtkCompositeImplicitBackend::Internals { if (this->Left == nullptr || this->Right == nullptr) { - vtkWarningWithObjectMacro(nullptr, "Creating composite array with nullptr"); + vtkErrorWithObjectMacro(nullptr, "Creating composite array with nullptr"); return; } this->LeftRange = vtk::DataArrayValueRange(this->Left); @@ -39,9 +39,9 @@ struct vtkCompositeImplicitBackend::Internals this->Offset = this->LeftRange.size(); } - vtkSmartPointer Left; + const vtkSmartPointer Left; vtk::detail::SelectValueRange::type LeftRange; - vtkSmartPointer Right; + const vtkSmartPointer Right; vtk::detail::SelectValueRange::type RightRange; int Offset = -1; }; @@ -56,9 +56,7 @@ vtkCompositeImplicitBackend::vtkCompositeImplicitBackend( //----------------------------------------------------------------------- template -vtkCompositeImplicitBackend::~vtkCompositeImplicitBackend() -{ -} +vtkCompositeImplicitBackend::~vtkCompositeImplicitBackend() = default; //----------------------------------------------------------------------- template diff --git a/Documentation/release/dev/add-vtkCompositeArray.md b/Documentation/release/dev/add-vtkCompositeArray.md index cd6b1fa0e2..52670c68ab 100644 --- a/Documentation/release/dev/add-vtkCompositeArray.md +++ b/Documentation/release/dev/add-vtkCompositeArray.md @@ -1,8 +1,8 @@ -# `vtkCompositeArray`: a new implicit array that concatenates other arrays together +## `vtkCompositeArray`: a new implicit array that concatenates other arrays together -`vtkCompositeArray` is now available in VTK! It is a family of `vtkImplicitArray`s that can concatenate arrays together to interface a group of arrays as if they were a single array. +The new `vtkCompositeArray` is a family of `vtkImplicitArray`s that can concatenate arrays together to interface a group of arrays as if they were a single array. This concatenation operates in the "tuple" direction and not in the "component" direction. -This new array relies on the `vtkCompositeImplicitBackend` template class to join `vtkDataArray`s two at a time. Creating a hiearchy of `vtkCompositeArray`s can generate a binary tree on the indexes of the composite array leading to access with $O(log_2(m))$ time where $m$ is the number of leaves (or base `vtkDataArray`s) composing the composite (or alternatively $O(l)$ where $l$ is the number of levels in the tree). +This new array relies on the `vtkCompositeImplicitBackend` template class to join two `vtkDataArray`s at a time. Creating a hiearchy of `vtkCompositeArray`s can generate a binary tree on the indexes of the composite array leading to access with $O(log_2(m))$ time where $m$ is the number of leaves (or base `vtkDataArray`s) composing the composite (or alternatively $O(l)$ where $l$ is the number of levels in the tree). To facilitate the creation of `vtkCompositeArray`s in practice, a templated utility function `vtkCompositeArrayUtilities::Concatenate` has been made available to users that can take an `std::vector` of `vtkDataArray`s and turn them into a single concatenated `vtkCompositeArray` whose tree structure should be balanced with respect to number of arrays (a possible improvement would be to balance with respect to number of tuples following a "Huffman coding" approach). From 121f39a8da86610c84ff035160f50bf96cb3a2fd Mon Sep 17 00:00:00 2001 From: Julien Fausty Date: Wed, 23 Nov 2022 12:01:12 +0100 Subject: [PATCH 10/10] review(CompositeArr): allow for nullptr in backend construction Also: - improve documentation --- .../Testing/Cxx/TestCompositeArray.cxx | 14 +++++++++++++ Common/ImplicitArrays/vtkCompositeArray.h | 10 ++++++++++ Common/ImplicitArrays/vtkCompositeArray.txx | 10 +++++++++- .../vtkCompositeImplicitBackend.h | 4 ++++ .../vtkCompositeImplicitBackend.txx | 20 ++++++++++++++----- .../release/dev/add-vtkCompositeArray.md | 2 +- 6 files changed, 53 insertions(+), 7 deletions(-) diff --git a/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx b/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx index 8a1c138711..1e8f9a7219 100644 --- a/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx +++ b/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx @@ -143,5 +143,19 @@ int TestCompositeArray(int vtkNotUsed(argc), char* vtkNotUsed(argv)[]) iArr++; } #endif // VTK_DISPATCH_COMPOSITE_ARRAYS + + // test a 1 composite + vtkSmartPointer> oneComposite = + vtk::ConcatenateDataArrays(std::vector({ composite })); + for (iArr = 0; iArr < 100; iArr++) + { + if (oneComposite->GetValue(iArr) != iArr) + { + res = EXIT_FAILURE; + std::cout << "get value failed with vtkCompositeArray for composite with one array: " << iArr + << " != " << composite->GetValue(iArr) << std::endl; + } + } + return res; }; diff --git a/Common/ImplicitArrays/vtkCompositeArray.h b/Common/ImplicitArrays/vtkCompositeArray.h index 460c5b24f1..6425de9fe1 100644 --- a/Common/ImplicitArrays/vtkCompositeArray.h +++ b/Common/ImplicitArrays/vtkCompositeArray.h @@ -50,6 +50,8 @@ * rightArr->SetValue(0, 1); * vtkNew> compositeArr; * compositeArr->SetBackend(std::make_shared>(leftArr, rightArr)); + * compositeArr->SetNumberOfComponents(1); + * compositeArr->SetNumberOfTuples(2); * CHECK(compositArr->GetValue(1) == 1); * ``` * @sa @@ -66,6 +68,14 @@ namespace vtk { VTK_ABI_NAMESPACE_BEGIN template +/** + * \fn ConcatenateDataArrays + * A method that can take a `std::vector` of `vtkDataArray`s and concatenate them together into a + * single `vtkCompositeArray`. Input arrays should all have the same number of components and the + * resulting composite array has as many tuples as the sum of all the inputs. + * + * The method is templated based on the value type of composite array the caller wishes as a result. + */ vtkSmartPointer> ConcatenateDataArrays( const std::vector& arrays); VTK_ABI_NAMESPACE_END diff --git a/Common/ImplicitArrays/vtkCompositeArray.txx b/Common/ImplicitArrays/vtkCompositeArray.txx index 9e6b5f1aa5..ae6a3b7b48 100644 --- a/Common/ImplicitArrays/vtkCompositeArray.txx +++ b/Common/ImplicitArrays/vtkCompositeArray.txx @@ -10,10 +10,18 @@ template vtkSmartPointer> ConcatenateDataArrays( const std::vector& arrays) { - if (arrays.size() < 2) + if (arrays.size() == 0) { return nullptr; } + if (arrays.size() == 1) + { + vtkNew> composite; + composite->SetBackend(std::make_shared>(arrays[0], nullptr)); + composite->SetNumberOfComponents(arrays[0]->GetNumberOfComponents()); + composite->SetNumberOfTuples(arrays[0]->GetNumberOfTuples()); + return composite; + } vtkIdType nComps = arrays[0]->GetNumberOfComponents(); for (auto arr : arrays) { diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackend.h b/Common/ImplicitArrays/vtkCompositeImplicitBackend.h index c599b7df18..939423b091 100644 --- a/Common/ImplicitArrays/vtkCompositeImplicitBackend.h +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.h @@ -42,6 +42,10 @@ * compositeArr->SetBackend(std::make_shared>(leftArr, rightArr)); * CHECK(compositArr->GetValue(1) == 1); * ``` + * + * > WARNING: + * > Arrays input to the backend are flattened upon use and are no longer sensitive to component + * > information. */ #include "vtkCommonImplicitArraysModule.h" #include diff --git a/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx index f1384057df..73ae191c3e 100644 --- a/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx @@ -14,6 +14,7 @@ =========================================================================*/ #include "vtkCompositeImplicitBackend.h" +#include "vtkAOSDataArrayTemplate.h" #include "vtkArrayDispatch.h" #include "vtkArrayDispatchImplicitArrayList.h" #include "vtkDataArray.h" @@ -29,19 +30,28 @@ struct vtkCompositeImplicitBackend::Internals : Left(leftArr) , Right(rightArr) { - if (this->Left == nullptr || this->Right == nullptr) + if (!this->Left && !this->Right) { - vtkErrorWithObjectMacro(nullptr, "Creating composite array with nullptr"); - return; + vtkWarningWithObjectMacro(nullptr, "Creating composite array with two nullptrs"); } + auto checkNullRectify = [](vtkSmartPointer& arr) { + if (!arr) + { + arr = vtkSmartPointer>::New(); + arr->SetNumberOfComponents(1); + arr->SetNumberOfTuples(0); + } + }; + checkNullRectify(this->Left); + checkNullRectify(this->Right); this->LeftRange = vtk::DataArrayValueRange(this->Left); this->RightRange = vtk::DataArrayValueRange(this->Right); this->Offset = this->LeftRange.size(); } - const vtkSmartPointer Left; + vtkSmartPointer Left; vtk::detail::SelectValueRange::type LeftRange; - const vtkSmartPointer Right; + vtkSmartPointer Right; vtk::detail::SelectValueRange::type RightRange; int Offset = -1; }; diff --git a/Documentation/release/dev/add-vtkCompositeArray.md b/Documentation/release/dev/add-vtkCompositeArray.md index 52670c68ab..e9a029d845 100644 --- a/Documentation/release/dev/add-vtkCompositeArray.md +++ b/Documentation/release/dev/add-vtkCompositeArray.md @@ -22,5 +22,5 @@ CHECK(composite->GetComponent(42, 1) == 0.0); // always true > **WARNINGS** > -> * Any two arrays composited into a `vtkCompositeArray` must have the same number of components. +> * Any two arrays composited into a `vtkCompositeArray` using the `vtk::ConcatenateDataArrays` method must have the same number of components. > * Iteration over the composited array incurs a lot of overhead compared to an explicit memory array (~3x slower with only 1 level). The use case is truly when memory efficiency is more important than compute performance.