You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
425 lines
17 KiB
C++
425 lines
17 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkArrayDispatch.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.
|
|
|
|
=========================================================================*/
|
|
/**
|
|
* @class vtkArrayDispatch
|
|
* @brief vtkDataArray code generator/dispatcher.
|
|
*
|
|
* vtkArrayDispatch implements a mechanism for generating optimized code for
|
|
* multiple subclasses of vtkDataArray at once. Using a TypeList based
|
|
* approach (see vtkTypeList), a templated worker implementation is generated
|
|
* for a restricted or unrestricted set of vtkDataArray subclasses.
|
|
*
|
|
* A more detailed description of this class and related tools can be found
|
|
* \ref VTK-7-1-ArrayDispatch "here".
|
|
*
|
|
* The primary goals of this class are to simplify multi-array dispatch
|
|
* implementations, and provide tools to lower compilation time and binary
|
|
* size (i.e. avoiding 'template explosions').
|
|
*
|
|
* vtkArrayDispatch is also intended to replace code that currently relies on
|
|
* the encapsulation-breaking vtkDataArray::GetVoidPointer method. Not all
|
|
* subclasses of vtkDataArray use the memory layout assumed by GetVoidPointer;
|
|
* calling this method on, e.g. a vtkSOADataArrayTemplate will trigger a deep
|
|
* copy of the array data into an AOS buffer. This is very inefficient and
|
|
* should be avoided.
|
|
*
|
|
* The vtkDataArrayRange.h utilities are worth mentioning here, as they allow
|
|
* vtkArrayDispatch workers to operate on selected concrete subclasses for
|
|
* 'fast paths', yet fallback to using the slower vtkDataArray API for uncommon
|
|
* array types. This helps mitigate the "template explosion" issues that can
|
|
* result from instantiating a large worker functions for many array types.
|
|
*
|
|
* These dispatchers extend the basic functionality of vtkTemplateMacro with
|
|
* the following features:
|
|
* - Multiarray dispatch: A single call can dispatch up to 3 arrays at once.
|
|
* - Array restriction: The set of valid arrays for a particular dispatch
|
|
* can be restricted. For example, if only vtkDoubleArray or vtkFloatArray
|
|
* will be passed into the call, the dispatcher will only generate code paths
|
|
* that use those arrays.
|
|
* - ValueType restriction: If both SoA and AoS arrays need to be supported,
|
|
* but only certain ValueTypes are expected, the dispatcher can restrict
|
|
* itself to only use arrays that match this criteria.
|
|
* - Application-wide array restrictions: If a VTK application uses only a few
|
|
* arraytype / valuetype combinations, certain dispatchers will eliminate
|
|
* paths using unsupported arrays at compile time.
|
|
*
|
|
* The basic Dispatch implementation will generate code paths for all arrays
|
|
* in the application-wide array list, and operates on a single array.
|
|
*
|
|
* Dispatchers that start with Dispatch2 operate on 2 arrays simultaneously,
|
|
* while those that begin with Dispatch3 operate on 3 arrays.
|
|
*
|
|
* To reduce compile time and binary size, the following dispatchers can be
|
|
* used to restrict the set of arrays that will be used. There are versions of
|
|
* these that operate on 1, 2, or 3 arrays:
|
|
*
|
|
* - DispatchByArray:
|
|
* Accepts an explicit TypeList of arrays to consider.
|
|
* These dispatchers do NOT respect the application-wide array restrictions.
|
|
* Example usecase: A filter that creates either vtkFloatArray or
|
|
* vtkDoubleArray depending on configuration can use this to restrict itself
|
|
* to only these specific types.
|
|
* Note that these should not be used for operating on filter inputs, instead
|
|
* use DispatchByValueType, which also considers variations in vtkDataArray
|
|
* subclasses and respects the application-wide array restrictions.
|
|
*
|
|
* - DispatchByValueType:
|
|
* Accepts an explicit TypeList of ValueTypes to consider.
|
|
* These dispatchers respect the application-wide array restrictions.
|
|
* Example usecase: An image filter that operates on an input array that must
|
|
* have either a float or unsigned char ValueType.
|
|
*
|
|
* - DispatchNByArrayWithSameValueType:
|
|
* Multiarray dispatcher that accepts an explicit TypeList of arrays for
|
|
* consideration. Generated code paths are further restricted to enforce that
|
|
* all dispatched arrays will have the same ValueType.
|
|
* Example usecase: A filter that creates and operates on multiple arrays at
|
|
* the same time, where the arrays are guaranteed to have the same ValueType.
|
|
* Note that these should not be used for operating on filter inputs, instead
|
|
* use DispatchNBySameValueType, which also considers variations in
|
|
* vtkDataArray subclasses and respects the application-wide array
|
|
* restrictions.
|
|
*
|
|
* - DispatchNBySameValueType:
|
|
* Multiarray dispatcher that accepts an explicit TypeList of ValueTypes to
|
|
* consider. Generated code paths are further restricted to enforce that
|
|
* all dispatched arrays will have the same ValueType.
|
|
* Example usecase: A filter that creates a modified version of an input
|
|
* array using NewInstance(). Both arrays may be passed into the dispatcher
|
|
* using a worker function that produces the output from the input.
|
|
*
|
|
* Execution:
|
|
* There are three components to a dispatch: The dispatcher, the worker, and
|
|
* the array(s). They are combined like so:
|
|
*
|
|
* @code
|
|
* bool result = Dispatcher<...>::Execute(array, worker);
|
|
* @endcode
|
|
*
|
|
* For convenience, the dispatcher may be aliased to a shorter name, e.g.:
|
|
*
|
|
* @code
|
|
* using MyDispatcher = vtkArrayDispatch::SomeDispatcher<...>;
|
|
* MyWorker worker;
|
|
* bool result = MyDispatcher::Execute(array, worker);
|
|
* @endcode
|
|
*
|
|
* Return value:
|
|
* The Execute method of the dispatcher will return true if a code path matching
|
|
* the array arguments is found, or false if the arrays are not supported. If
|
|
* false is returned, the arrays will not be modified, and the worker will not
|
|
* be executed.
|
|
*
|
|
* Workers:
|
|
* The dispatch requires a Worker functor that performs the work.
|
|
* For single array, the functor must be callable where the first parameter is
|
|
* an array object. For 2-array dispatch, the first two arguments must be (array1, array2).
|
|
* For 3-array dispatch, the first three arguments must be (array1, array2, array3).
|
|
* Workers are passed by reference, so stateful functors are permitted if
|
|
* additional input/output data is needed and not being passed as additional
|
|
* parameters to the Execute method.
|
|
*
|
|
* A simple worker implementation for triple dispatch:
|
|
* @code
|
|
* struct MyWorker
|
|
* {
|
|
* template <typename Array1T, typename Array2T, typename Array3T>
|
|
* void operator()(Array1T *array1, Array2T *array2, Array3T *array3)
|
|
* {
|
|
* // Do work using vtkGenericDataArray API...
|
|
* }
|
|
* };
|
|
* @endcode
|
|
*
|
|
* Note that optimized implementations (e.g. for AoS arrays vs SoA arrays) can
|
|
* be supported by providing overloads of operator() that have more restrictive
|
|
* template parameters.
|
|
*
|
|
* A worker's operator() implementation can accept additional parameters that
|
|
* follow the arrays. These parameters are passed to the dispatcher during
|
|
* execution. For instance, this worker scales an array by a runtime-value,
|
|
* writing it into a second array:
|
|
*
|
|
* @code
|
|
* struct ScaleArray
|
|
* {
|
|
* template <typename ArraySrc, typename ArrayDst>
|
|
* void operator()(ArraySrc *srcArray, ArrayDst *dstArray,
|
|
* double scaleFactor) const
|
|
* {
|
|
* using SrcType = vtk::GetAPIType<ArraySrc>;
|
|
* using DstType = vtk::GetAPIType<ArrayDst>;
|
|
*
|
|
* const auto srcRange = vtk::DataArrayValueRange(srcArray);
|
|
* auto dstRange = vtk::DataArrayValueRange(dstArray);
|
|
*
|
|
* assert(srcRange.size() == dstRange.size());
|
|
*
|
|
* auto dstIter = dstRange.begin();
|
|
* for (SrcType srcVal : srcRange)
|
|
* {
|
|
* *dstIter++ = static_cast<DstType>(srcVal * scaleFactor);
|
|
* }
|
|
* }
|
|
* };
|
|
*
|
|
* vtkDataArray *src = ...;
|
|
* vtkDataArray *dst = ...;
|
|
* // Scale src by 3 (scaleFactor) and store in dst:
|
|
* if (!vtkArrayDispatch::Dispatch2::Execute(src, dst, ScaleArray, 3))
|
|
* {
|
|
* scaleArray(src, dst, 3);
|
|
* }
|
|
* @endcode
|
|
*
|
|
* Examples:
|
|
* See TestArrayDispatchers.cxx for examples of each dispatch type and
|
|
* ExampleDataArrayRangeDispatch.cxx for more real-world examples.
|
|
*
|
|
* @sa
|
|
* vtkDataArrayAccessor
|
|
*/
|
|
|
|
#ifndef vtkArrayDispatch_h
|
|
#define vtkArrayDispatch_h
|
|
|
|
#include "vtkArrayDispatchArrayList.h"
|
|
#include "vtkConfigure.h"
|
|
#include "vtkType.h"
|
|
#include "vtkTypeList.h"
|
|
|
|
namespace vtkArrayDispatch
|
|
{
|
|
|
|
/**
|
|
* A TypeList containing all real ValueTypes.
|
|
*/
|
|
typedef vtkTypeList::Create<double, float> Reals;
|
|
|
|
/**
|
|
* A Typelist containing all integral ValueTypes.
|
|
*/
|
|
typedef vtkTypeList::Unique<
|
|
vtkTypeList::Create<char, int, long, long long, short, signed char, unsigned char, unsigned int,
|
|
unsigned long, unsigned long long, unsigned short, vtkIdType> >::Result Integrals;
|
|
|
|
/**
|
|
* A Typelist containing all standard VTK array ValueTypes.
|
|
*/
|
|
typedef vtkTypeList::Append<Reals, Integrals>::Result AllTypes;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch a single array against all array types in the application-wide
|
|
* vtkArrayDispatch::Arrays list.
|
|
* The entry point is:
|
|
* bool Dispatch::Execute(vtkDataArray *array, Worker &worker).
|
|
*/
|
|
struct Dispatch;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch a single array against all array types mentioned in the ArrayList
|
|
* template parameter.
|
|
* The entry point is:
|
|
* bool DispatchByArray<...>::Execute(vtkDataArray *array, Worker &worker).
|
|
*/
|
|
template <typename ArrayList>
|
|
struct DispatchByArray;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch a single array against all array types in the application-wide
|
|
* vtkArrayDispatch::Arrays list with the added restriction that the array
|
|
* must have a type that appears the ValueTypeList TypeList.
|
|
* The entry point is:
|
|
* bool DispatchByValueType<...>::Execute(vtkDataArray *array, Worker &worker).
|
|
*/
|
|
template <typename ValueTypeList>
|
|
struct DispatchByValueType;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch two arrays using all array types in the application-wide
|
|
* vtkArrayDispatch::Arrays list.
|
|
* The entry point is:
|
|
* bool Dispatch2::Execute(vtkDataArray *array, vtkDataArray *array2,
|
|
* Worker &worker).
|
|
*/
|
|
struct Dispatch2;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch two arrays, restricting the valid code paths to use only arrays that
|
|
* have the same ValueType.
|
|
* All application-wide arrays in vtkArrayDispatch::Arrays are used.
|
|
* The entry point is:
|
|
* bool Dispatch2SameValueType::Execute(
|
|
* vtkDataArray *a1, vtkDataArray *a2, Worker &worker).
|
|
*/
|
|
struct Dispatch2SameValueType;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch two arrays with the restriction that the type of the first array is
|
|
* in the ArrayList1 TypeList, and the second is in ArrayList2.
|
|
* If all application-wide arrays are desired, use vtkArrayDispatch::Arrays for
|
|
* the first two template parameters.
|
|
* The entry point is:
|
|
* bool Dispatch2ByArray<...>::Execute(vtkDataArray *a1, vtkDataArray *a2,
|
|
* Worker &worker).
|
|
*/
|
|
template <typename ArrayList1, typename ArrayList2>
|
|
struct Dispatch2ByArray;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch two arrays, restricting the valid code paths to use
|
|
* ValueType-filtered versions of the application-wide vtkArrayDispatch::Arrays
|
|
* TypeList. The first array's ValueType must be in the ValueTypeList1 TypeList,
|
|
* and the second's must be in ValueTypeList2.
|
|
* If all types are to be considered, use vtkArrayDispatch::AllTypes for the
|
|
* first two template parameters.
|
|
* The entry point is:
|
|
* bool Dispatch2ByValueType<...>::Execute(vtkDataArray *a1, vtkDataArray *a2,
|
|
* Worker &worker).
|
|
*/
|
|
template <typename ValueTypeList1, typename ValueTypeList2>
|
|
struct Dispatch2ByValueType;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch two arrays, restricting the valid code paths to use only array types
|
|
* specified in the ArrayList TypeList, additionally enforcing that all arrays
|
|
* must have the same ValueType.
|
|
* If all application-wide arrays are desired, use vtkArrayDispatch::Arrays for
|
|
* the first two template parameters.
|
|
* The entry point is:
|
|
* bool Dispatch2ByArrayWithSameValueType<...>::Execute(
|
|
* vtkDataArray *a1, vtkDataArray *a2, Worker &worker).
|
|
*/
|
|
template <typename ArrayList1, typename ArrayList2>
|
|
struct Dispatch2ByArrayWithSameValueType;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch two arrays, restricting the valid code paths to use only array types
|
|
* found in application-wide vtkArrayDispatch::Arrays TypeList that have a
|
|
* ValueType contained in the ValueTypeList TypeList. This dispatcher also
|
|
* enforces that all arrays have the same ValueType.
|
|
* If all types are to be considered, use vtkArrayDispatch::AllTypes for the
|
|
* first two template parameters.
|
|
* The entry point is:
|
|
* bool Dispatch2BySameValueType<...>::Execute(
|
|
* vtkDataArray *a1, vtkDataArray *a2, Worker &worker).
|
|
*/
|
|
template <typename ValueTypeList>
|
|
struct Dispatch2BySameValueType;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch three arrays using all array types in the application-wide
|
|
* vtkArrayDispatch::Arrays list.
|
|
* The entry point is:
|
|
* bool Dispatch3::Execute(vtkDataArray *array1, vtkDataArray *array2,
|
|
* vtkDataArray *array3, Worker &worker).
|
|
*/
|
|
struct Dispatch3;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch three arrays, restricting the valid code paths to use only arrays
|
|
* that have the same ValueType.
|
|
* All application-wide arrays in vtkArrayDispatch::Arrays are used.
|
|
* The entry point is:
|
|
* bool Dispatch3SameValueType::Execute(
|
|
* vtkDataArray *a1, vtkDataArray *a2, vtkDataArray *a3, Worker &worker).
|
|
*/
|
|
struct Dispatch3SameValueType;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch three arrays with the restriction that the type of the first array
|
|
* is in the ArrayList1 TypeList, the second is in ArrayList2, and the third
|
|
* is in ArrayList3.
|
|
* If all application-wide arrays are desired, use vtkArrayDispatch::Arrays for
|
|
* the first three template parameters.
|
|
* The entry point is:
|
|
* bool Dispatch3ByArray::Execute<...>(vtkDataArray *a1, vtkDataArray *a2,
|
|
* vtkDataArray *a3, Worker &worker).
|
|
*/
|
|
template <typename ArrayList1, typename ArrayList2, typename ArrayList3>
|
|
struct Dispatch3ByArray;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch three arrays, restricting the valid code paths to use
|
|
* ValueType-filtered versions of the application-wide vtkArrayDispatch::Arrays
|
|
* TypeList. The first array's ValueType must be in the ValueTypeList1 TypeList,
|
|
* the second's must be in ValueTypeList2, and the third's must be in
|
|
* ValueTypeList3.
|
|
* If all types are to be considered, use vtkArrayDispatch::AllTypes for the
|
|
* first three template parameters.
|
|
* The entry point is:
|
|
* bool Dispatch3ByValueType<...>::Execute(vtkDataArray *a1, vtkDataArray *a2,
|
|
* vtkDataArray *a3, Worker &worker).
|
|
*/
|
|
template <typename ValueTypeList1, typename ValueTypeList2, typename ValueTypeList3>
|
|
struct Dispatch3ByValueType;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch three arrays, restricting the valid code paths to use only array
|
|
* types specified in the ArrayList TypeList, additionally enforcing that all
|
|
* arrays must have the same ValueType.
|
|
* If all application-wide arrays are desired, use vtkArrayDispatch::Arrays for
|
|
* the first three template parameters.
|
|
* The entry point is:
|
|
* bool Dispatch3ByArrayWithSameValueType<...>::Execute(
|
|
* vtkDataArray *a1, vtkDataArray *a2, vtkDataArray *a3, Worker &worker).
|
|
*/
|
|
template <typename ArrayList1, typename ArrayList2, typename ArrayList3>
|
|
struct Dispatch3ByArrayWithSameValueType;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Dispatch three arrays, restricting the valid code paths to use only array
|
|
* types found in application-wide vtkArrayDispatch::Arrays TypeList that have a
|
|
* ValueType contained in the ValueTypeList TypeList. This dispatcher also
|
|
* enforces that all arrays have the same ValueType.
|
|
* If all types are to be considered, use vtkArrayDispatch::AllTypes for the
|
|
* first three template parameters.
|
|
* The entry point is:
|
|
* bool Dispatch3BySameValueType<...>::Execute(
|
|
* vtkDataArray *a1, vtkDataArray *a2, vtkDataArray *a3, Worker &worker).
|
|
*/
|
|
template <typename ValueTypeList>
|
|
struct Dispatch3BySameValueType;
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
* Filter the ArrayList to contain only arrays with ArrayType::ValueType that
|
|
* exist in ValueList. The result TypeList is stored in Result.
|
|
*/
|
|
template <typename ArrayList, typename ValueList>
|
|
struct FilterArraysByValueType;
|
|
|
|
} // end namespace vtkArrayDispatch
|
|
|
|
#include "vtkArrayDispatch.txx"
|
|
|
|
#endif // vtkArrayDispatch_h
|
|
// VTK-HeaderTest-Exclude: vtkArrayDispatch.h
|