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 { diff --git a/Common/ImplicitArrays/CMakeLists.txt b/Common/ImplicitArrays/CMakeLists.txt index bfd144f579..3cb1c39d89 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,15 +52,18 @@ endforeach () set(nowrap_headers vtkAffineArray.h vtkAffineImplicitBackend.h + vtkCompositeArray.h vtkConstantArray.h vtkConstantImplicitBackend.h vtkImplicitArrayTraits.h vtkStdFunctionArray.h "${CMAKE_CURRENT_BINARY_DIR}/vtkVTK_DISPATCH_IMPLICIT_ARRAYS.h" + "${CMAKE_CURRENT_BINARY_DIR}/vtkArrayDispatchImplicitArrayList.h" ) 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..463fe0c4be 100644 --- a/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt +++ b/Common/ImplicitArrays/Testing/Cxx/CMakeLists.txt @@ -1,6 +1,8 @@ vtk_add_test_cxx(vtkCommonImplicitArrayCxxTests tests NO_DATA NO_OUTPUT NO_VALID TestAffineArray.cxx + TestCompositeArray.cxx + TestCompositeImplicitBackend.cxx TestConstantArray.cxx TestImplicitArraysBase.cxx TestImplicitArrayTraits.cxx diff --git a/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx b/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx new file mode 100644 index 0000000000..1e8f9a7219 --- /dev/null +++ b/Common/ImplicitArrays/Testing/Cxx/TestCompositeArray.cxx @@ -0,0 +1,161 @@ +/*========================================================================= + + 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 vtk::ConcatenateDataArrays(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 + + // 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/Testing/Cxx/TestCompositeImplicitBackend.cxx b/Common/ImplicitArrays/Testing/Cxx/TestCompositeImplicitBackend.cxx new file mode 100644 index 0000000000..9a3da60966 --- /dev/null +++ b/Common/ImplicitArrays/Testing/Cxx/TestCompositeImplicitBackend.cxx @@ -0,0 +1,78 @@ +/*========================================================================= + + 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; + } + } + + 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/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 new file mode 100644 index 0000000000..6425de9fe1 --- /dev/null +++ b/Common/ImplicitArrays/vtkCompositeArray.h @@ -0,0 +1,109 @@ +/*========================================================================= + + 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 "vtkCommonImplicitArraysModule.h" // for export macro +#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. + * + * 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)); + * compositeArr->SetNumberOfComponents(1); + * compositeArr->SetNumberOfTuples(2); + * CHECK(compositArr->GetValue(1) == 1); + * ``` + * @sa + * vtkImplicitArray vtkCompositeImplicitBackend + */ + +VTK_ABI_NAMESPACE_BEGIN +class vtkDataArray; +template +using vtkCompositeArray = vtkImplicitArray>; +VTK_ABI_NAMESPACE_END + +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 +} + +#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 vtk \ + { \ + VTK_ABI_NAMESPACE_BEGIN \ + template VTKCOMMONIMPLICITARRAYS_EXPORT \ + vtkSmartPointer>> \ + ConcatenateDataArrays(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..ae6a3b7b48 --- /dev/null +++ b/Common/ImplicitArrays/vtkCompositeArray.txx @@ -0,0 +1,65 @@ +#include "vtkCompositeArray.h" + +#include "vtkDataArray.h" + +//----------------------------------------------------------------------- +namespace vtk +{ +VTK_ABI_NAMESPACE_BEGIN +template +vtkSmartPointer> ConcatenateDataArrays( + const std::vector& arrays) +{ + 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) + { + 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->SetNumberOfComponents(lifetimeBuffer[i]->GetNumberOfComponents()); + composite->SetNumberOfTuples( + lifetimeBuffer[i]->GetNumberOfTuples() + lifetimeBuffer[i + 1]->GetNumberOfTuples()); + newComps.emplace_back(composite); + } + if (lifetimeBuffer.size() % 2 != 0) + { + vtkNew> composite; + composite->SetBackend( + std::make_shared>(newComps.back(), lifetimeBuffer.back())); + composite->SetNumberOfComponents(lifetimeBuffer.back()->GetNumberOfComponents()); + composite->SetNumberOfTuples( + newComps.back()->GetNumberOfTuples() + lifetimeBuffer.back()->GetNumberOfTuples()); + 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 new file mode 100644 index 0000000000..939423b091 --- /dev/null +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.h @@ -0,0 +1,87 @@ +/*========================================================================= + + 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; // easier with + * `vtkNew> compositeArr;` if applicable + * 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 + +VTK_ABI_NAMESPACE_BEGIN +class vtkDataArray; +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: + struct Internals; + std::unique_ptr Internal; +}; +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 new file mode 100644 index 0000000000..73ae191c3e --- /dev/null +++ b/Common/ImplicitArrays/vtkCompositeImplicitBackend.txx @@ -0,0 +1,79 @@ +/*========================================================================= + + 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 "vtkAOSDataArrayTemplate.h" +#include "vtkArrayDispatch.h" +#include "vtkArrayDispatchImplicitArrayList.h" +#include "vtkDataArray.h" +#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 && !this->Right) + { + 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(); + } + + vtkSmartPointer Left; + vtk::detail::SelectValueRange::type LeftRange; + vtkSmartPointer Right; + vtk::detail::SelectValueRange::type RightRange; + int Offset = -1; +}; + +//----------------------------------------------------------------------- +template +vtkCompositeImplicitBackend::vtkCompositeImplicitBackend( + vtkDataArray* leftArr, vtkDataArray* rightArr) + : Internal(std::unique_ptr(new Internals(leftArr, rightArr))) +{ +} + +//----------------------------------------------------------------------- +template +vtkCompositeImplicitBackend::~vtkCompositeImplicitBackend() = default; + +//----------------------------------------------------------------------- +template +ValueType vtkCompositeImplicitBackend::operator()(int idx) const +{ + return static_cast((idx < this->Internal->Offset) + ? this->Internal->LeftRange[idx] + : this->Internal->RightRange[idx - this->Internal->Offset]); +} +VTK_ABI_NAMESPACE_END 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/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/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 c6f245699c..c6b9626bfd 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/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 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 diff --git a/Documentation/release/dev/add-vtkCompositeArray.md b/Documentation/release/dev/add-vtkCompositeArray.md new file mode 100644 index 0000000000..e9a029d845 --- /dev/null +++ b/Documentation/release/dev/add-vtkCompositeArray.md @@ -0,0 +1,26 @@ +## `vtkCompositeArray`: a new implicit array that concatenates other arrays together + +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 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). + +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` 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.