Hi Will,
In these cases, it’s important to be careful with the distinction between arrays of the same type and arrays of the same value type.
In this snippet, newPts
will always construct a default layout AOS array with the same valuetype as inPts
– but if inPts
contains a user-provided SOA array, then these arrays will not have the same type (only the same valuetype) and a double dispatch is needed.
To handle this case (same valuetype, possibly different memory layout), the vtkArrayDispatch::Dispatch2BySameValueType<vtkArrayDispatch::Reals>
dispatcher should be used. When VTK is built with SOA support, it will generate fast-paths for:
Path# | inPts | newPts |
---|---|---|
1 | AOS,float | AOS,float |
2 | AOS,float | SOA,float |
3 | SOA,float | AOS,float |
4 | SOA,float | SOA,float |
5 | AOS,double | AOS,double |
6 | AOS,double | SOA,double |
7 | SOA,double | AOS,double |
8 | SOA,double | SOA,double |
When SOA support is off, only paths 1 and 5 will be generated (which turns into a single dispatch plus a downcast).
For an example, this pattern is currently used in vtkPointCloudFilter
to accomplish a similar goal.
OTOH, if both arrays are known to have exactly the same valuetype and memory layout, you can just dispatch one of them, pass the other as a vtkDataArray*
, and then cast it inside the functor once the full type information is available:
struct Worker
{
template <typename ArrayType>
void operator()(ArrayType *array1, vtkDataArray *dataArray2)
{
ArrayType *array2 = vtkArrayDownCast<ArrayType>(dataArray2);
// do work with array1 / array2
}
};
void doDispatch(vtkDataArray *dataArray1, vtkDataArray *dataArray2)
{
using Dispatcher = vtkArrayDispatch::DispatchByValueType<vtkArrayDispatch::Reals>;
// This is safe if and only if both arrays are known to have
// exactly the same type.
if (!Dispatcher::Execute(dataArray1, Worker{}, dataArray2))
{ // Fallback in case valuetype is not `Real`.
Worker{}(dataArray1, dataArray2);
}
}