Commit 1688a73d authored by David C. Lonie's avatar David C. Lonie

Add vtkDataArrayAccessor.

parent 2a72d697
......@@ -290,6 +290,7 @@ set(${vtk-module}_HDRS
vtkAtomicTypeConcepts.h
vtkAtomicTypes.h
vtkAutoInit.h
vtkDataArrayAccessor.h
vtkDataArrayIteratorMacro.h
vtkDataArrayTemplate.h
vtkGenericDataArray.h
......
......@@ -124,6 +124,9 @@
//
// Examples:
// See TestArrayDispatchers.cxx for examples of each dispatch type.
//
// .SEE ALSO
// vtkDataArrayAccessor
#ifndef vtkArrayDispatch_h
#define vtkArrayDispatch_h
......
This diff is collapsed.
/*=========================================================================
Program: Visualization Toolkit
Module: vtkDataArrayAccessor.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.
=========================================================================*/
// .NAME vtkDataArrayAccessor - Efficient templated access to vtkDataArray.
//
// .SECTION Description
// vtkDataArrayAccessor provides access to data stored in a vtkDataArray. It
// is intended to be used in conjunction with vtkArrayDispatcher.
//
// The goal of this helper template is to allow developers to write a single
// templated worker function that will generates code to use the efficient typed
// APIs provided by vtkGenericDataArray when the array type is known, but
// fallback to the slower vtkDataArray virtual double API if needed.
//
// This can be used to reduce template-explosion issues by restricting the
// vtkArrayDispatch call to only dispatch a few common cases/array types, and
// route all other arrays through a slower implementation using vtkDataArray's
// API. With vtkDataArrayAccessor, a single templated worker function can be
// used to generate both.
//
// Note that while this interface provides both component-wise and tuple access,
// the tuple methods are discouraged as they are significantly slower due to
// copying, and prevent many advanced compiler optimizations that are possible
// when using the component accessors.
//
// A standard usage pattern of this class would be:
//
// // vtkArrayDispatch worker struct:
// struct Worker
// {
// // Templated worker function:
// template <typename ArrayT>
// void operator()(ArrayT *array)
// {
// // The accessor:
// vtkDataArrayAccessor<ArrayT> accessor(array);
// // The data type used by ArrayT's API, use this for
// // temporary/intermediate results:
// typedef typename vtkDataArrayAccessor<ArrayT>::APIType APIType;
//
// // Do work using accessor to set/get values....
// }
// };
//
// // Usage:
// Worker worker;
// vtkDataArray *array = ...;
// if (!vtkArrayDispatch::Dispatch::Execute(array, worker))
// {
// // Dispatch failed: unknown array type. Fallback to vtkDataArray API:
// worker(array);
// }
//
// We define Worker::operator() as the templated worker function, restricting
// all data accesses to go through the 'accessor' object (methods like
// GetNumberOfTuples, GetNumberOfComponents, etc should be called on the array
// itself).
//
// This worker is passed into an array dispatcher, which tests 'array' to see
// if it can figure out the array subclass. If it does, Worker is instantiated
// with ArrayT set to the array's subclass, resulting in efficient code. If
// Dispatch::Execute returns false (meaning the array type is not recognized),
// the worker is executed using the vtkDataArray pointer. While slower, this
// ensures that less-common cases will still be handled -- all from one worker
// function template.
//
// .SEE ALSO
// vtkArrayDispatch
#include "vtkDataArray.h"
#include "vtkGenericDataArray.h"
#ifndef vtkDataArrayAccessor_h
#define vtkDataArrayAccessor_h
// Generic form for all (non-bit) vtkDataArray subclasses.
template <typename ArrayT>
struct vtkDataArrayAccessor
{
typedef ArrayT ArrayType;
typedef typename ArrayType::ValueType APIType;
ArrayType *Array;
vtkDataArrayAccessor(ArrayType *array) : Array(array) {}
inline APIType Get(vtkIdType tupleIdx, int compIdx) const
{
return this->Array->GetTypedComponent(tupleIdx, compIdx);
}
inline void Set(vtkIdType tupleIdx, int compIdx, APIType val) const
{
this->Array->SetTypedComponent(tupleIdx, compIdx, val);
}
inline void Insert(vtkIdType tupleIdx, int compIdx, APIType val) const
{
this->Array->InsertTypedComponent(tupleIdx, compIdx, val);
}
inline void Get(vtkIdType tupleIdx, APIType *tuple) const
{
this->Array->GetTypedTuple(tupleIdx, tuple);
}
inline void Set(vtkIdType tupleIdx, const APIType *tuple) const
{
this->Array->SetTypedTuple(tupleIdx, tuple);
}
inline void Insert(vtkIdType tupleIdx, const APIType *tuple) const
{
this->Array->InsertTypedTuple(tupleIdx, tuple);
}
};
// Specialization for vtkDataArray.
template <>
struct vtkDataArrayAccessor<vtkDataArray>
{
typedef vtkDataArray ArrayType;
typedef double APIType;
ArrayType *Array;
vtkDataArrayAccessor(ArrayType *array) : Array(array) {}
inline APIType Get(vtkIdType tupleIdx, int compIdx) const
{
return this->Array->GetComponent(tupleIdx, compIdx);
}
inline void Set(vtkIdType tupleIdx, int compIdx, APIType val) const
{
this->Array->SetComponent(tupleIdx, compIdx, val);
}
inline void Insert(vtkIdType tupleIdx, int compIdx, APIType val) const
{
this->Array->InsertComponent(tupleIdx, compIdx, val);
}
inline void Get(vtkIdType tupleIdx, APIType *tuple) const
{
this->Array->GetTuple(tupleIdx, tuple);
}
inline void Set(vtkIdType tupleIdx, const APIType *tuple) const
{
this->Array->SetTuple(tupleIdx, tuple);
}
inline void Insert(vtkIdType tupleIdx, const APIType *tuple) const
{
this->Array->InsertTuple(tupleIdx, tuple);
}
};
#endif // vtkDataArrayAccessor_h
// VTK-HeaderTest-Exclude: vtkDataArrayAccessor.h
......@@ -15,7 +15,9 @@
#ifndef vtkDataArrayPrivate_txx
#define vtkDataArrayPrivate_txx
#include "vtkAssume.h"
#include "vtkDataArray.h"
#include "vtkDataArrayAccessor.h"
#include "vtkTypeTraits.h"
#include <algorithm>
#include <cassert> // for assert()
......@@ -60,17 +62,21 @@ using std::max;
}
//----------------------------------------------------------------------------
template <class ValueType, int NumComps, int RangeSize>
template <class APIType, int NumComps, int RangeSize>
struct ComputeScalarRange
{
template<class ArrayT>
bool operator()(ArrayT *array, double *ranges)
{
ValueType tempRange[RangeSize];
VTK_ASSUME(array->GetNumberOfComponents() == NumComps);
vtkDataArrayAccessor<ArrayT> access(array);
APIType tempRange[RangeSize];
for(int i = 0, j = 0; i < NumComps; ++i, j+=2)
{
tempRange[j] = vtkTypeTraits<ValueType>::Max();
tempRange[j+1] = vtkTypeTraits<ValueType>::Min();
tempRange[j] = vtkTypeTraits<APIType>::Max();
tempRange[j+1] = vtkTypeTraits<APIType>::Min();
}
//compute the range for each component of the data array at the same time
......@@ -79,10 +85,10 @@ struct ComputeScalarRange
{
for(int compIdx = 0, j = 0; compIdx < NumComps; ++compIdx, j+=2)
{
tempRange[j] = detail::min(tempRange[j],
array->GetTypedComponent(tupleIdx, compIdx));
tempRange[j] = detail::min(tempRange[j],
access.Get(tupleIdx, compIdx));
tempRange[j+1] = detail::max(tempRange[j+1],
array->GetTypedComponent(tupleIdx, compIdx));
access.Get(tupleIdx, compIdx));
}
}
......@@ -100,7 +106,9 @@ struct ComputeScalarRange
template <typename ArrayT>
bool DoComputeScalarRange(ArrayT *array, double *ranges)
{
typedef typename ArrayT::ValueType ValueType;
vtkDataArrayAccessor<ArrayT> access(array);
typedef typename vtkDataArrayAccessor<ArrayT>::APIType APIType;
const int numTuples = array->GetNumberOfTuples();
const int numComp = array->GetNumberOfComponents();
......@@ -121,48 +129,48 @@ bool DoComputeScalarRange(ArrayT *array, double *ranges)
//compiler detect it can perform loop optimizations.
if (numComp == 1)
{
return ComputeScalarRange<ValueType,1,2>()(array, ranges);
return ComputeScalarRange<APIType,1,2>()(array, ranges);
}
else if (numComp == 2)
{
return ComputeScalarRange<ValueType,2,4>()(array, ranges);
return ComputeScalarRange<APIType,2,4>()(array, ranges);
}
else if (numComp == 3)
{
return ComputeScalarRange<ValueType,3,6>()(array, ranges);
return ComputeScalarRange<APIType,3,6>()(array, ranges);
}
else if (numComp == 4)
{
return ComputeScalarRange<ValueType,4,8>()(array, ranges);
return ComputeScalarRange<APIType,4,8>()(array, ranges);
}
else if (numComp == 5)
{
return ComputeScalarRange<ValueType,5,10>()(array, ranges);
return ComputeScalarRange<APIType,5,10>()(array, ranges);
}
else if (numComp == 6)
{
return ComputeScalarRange<ValueType,6,12>()(array, ranges);
return ComputeScalarRange<APIType,6,12>()(array, ranges);
}
else if (numComp == 7)
{
return ComputeScalarRange<ValueType,7,14>()(array, ranges);
return ComputeScalarRange<APIType,7,14>()(array, ranges);
}
else if (numComp == 8)
{
return ComputeScalarRange<ValueType,8,16>()(array, ranges);
return ComputeScalarRange<APIType,8,16>()(array, ranges);
}
else if (numComp == 9)
{
return ComputeScalarRange<ValueType,9,18>()(array, ranges);
return ComputeScalarRange<APIType,9,18>()(array, ranges);
}
else
{
//initialize the temp range storage to min/max pairs
ValueType* tempRange = new ValueType[numComp*2];
APIType* tempRange = new APIType[numComp*2];
for (int i = 0, j = 0; i < numComp; ++i, j+=2)
{
tempRange[j] = vtkTypeTraits<ValueType>::Max();
tempRange[j+1] = vtkTypeTraits<ValueType>::Min();
tempRange[j] = vtkTypeTraits<APIType>::Max();
tempRange[j+1] = vtkTypeTraits<APIType>::Min();
}
//compute the range for each component of the data array at the same time
......@@ -170,10 +178,10 @@ bool DoComputeScalarRange(ArrayT *array, double *ranges)
{
for(int compIdx = 0, j = 0; compIdx < numComp; ++compIdx, j+=2)
{
tempRange[j] = detail::min(tempRange[j],
array->GetTypedComponent(tupleIdx, compIdx));
tempRange[j] = detail::min(tempRange[j],
access.Get(tupleIdx, compIdx));
tempRange[j+1] = detail::max(tempRange[j+1],
array->GetTypedComponent(tupleIdx, compIdx));
access.Get(tupleIdx, compIdx));
}
}
......@@ -191,80 +199,12 @@ bool DoComputeScalarRange(ArrayT *array, double *ranges)
}
}
//----------------------------------------------------------------------------
bool DoComputeScalarRangeFallback(vtkDataArray *array, double *ranges)
{
const int numTuples = array->GetNumberOfTuples();
const int numComp = array->GetNumberOfComponents();
//setup the initial ranges to be the max,min for double
for (int i = 0, j = 0; i < numComp; ++i, j+=2)
{
ranges[j] = vtkTypeTraits<double>::Max();
ranges[j+1] = vtkTypeTraits<double>::Min();
}
//do this after we make sure range is max to min
if (numTuples == 0)
{
return false;
}
//compute the range for each component of the data array at the same time
for (vtkIdType tupleIdx = 0; tupleIdx < numTuples; ++tupleIdx)
{
for(int compIdx = 0, j = 0; compIdx < numComp; ++compIdx, j+=2)
{
double val = array->GetComponent(tupleIdx, compIdx);
ranges[j] = detail::min(ranges[j], val);
ranges[j+1] = detail::max(ranges[j+1], val);
}
}
return true;
}
//----------------------------------------------------------------------------
template <typename ArrayT>
bool DoComputeVectorRange(ArrayT *array, double range[2])
{
const int numTuples = array->GetNumberOfTuples();
const int numComps = array->GetNumberOfComponents();
vtkDataArrayAccessor<ArrayT> access(array);
range[0] = vtkTypeTraits<double>::Max();
range[1] = vtkTypeTraits<double>::Min();
//do this after we make sure range is max to min
if (numTuples == 0)
{
return false;
}
//iterate over all the tuples
for (vtkIdType tupleIdx = 0; tupleIdx < numTuples; ++tupleIdx)
{
double squaredSum = 0.0;
for (int compIdx = 0; compIdx < numComps; ++compIdx)
{
const double t =
static_cast<double>(array->GetTypedComponent(tupleIdx, compIdx));
squaredSum += t * t;
}
range[0] = detail::min(range[0], squaredSum);
range[1] = detail::max(range[1], squaredSum);
}
//now that we have computed the smallest and largest value, take the
//square root of that value.
range[0] = sqrt(range[0]);
range[1] = sqrt(range[1]);
return true;
}
//----------------------------------------------------------------------------
bool DoComputeVectorRangeFallback(vtkDataArray *array, double range[2])
{
const int numTuples = array->GetNumberOfTuples();
const int numComps = array->GetNumberOfComponents();
......@@ -283,7 +223,7 @@ bool DoComputeVectorRangeFallback(vtkDataArray *array, double range[2])
double squaredSum = 0.0;
for (int compIdx = 0; compIdx < numComps; ++compIdx)
{
const double t = array->GetComponent(tupleIdx, compIdx);
const double t = static_cast<double>(access.Get(tupleIdx, compIdx));
squaredSum += t * t;
}
range[0] = detail::min(range[0], squaredSum);
......@@ -298,6 +238,6 @@ bool DoComputeVectorRangeFallback(vtkDataArray *array, double range[2])
return true;
}
}
} // end namespace vtkDataArrayPrivate
#endif
// VTK-HeaderTest-Exclude: vtkDataArrayPrivate.txx
......@@ -14,10 +14,12 @@
=========================================================================*/
#include "vtkAppendPolyData.h"
#include "vtkAssume.h"
#include "vtkArrayDispatch.h"
#include "vtkAlgorithmOutput.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkDataArrayAccessor.h"
#include "vtkDataSetAttributes.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
......@@ -724,27 +726,18 @@ struct AppendDataWorker
template <typename Array1T, typename Array2T>
void operator()(Array1T *dest, Array2T *src)
{
const vtkIdType numTuples = src->GetNumberOfTuples();
const int numComps = src->GetNumberOfComponents();
for (vtkIdType t = 0; t < numTuples; ++t)
{
for (int c = 0; c < numComps; ++c)
{
dest->SetTypedComponent(t + this->Offset, c,
src->GetTypedComponent(t, c));
}
}
}
vtkDataArrayAccessor<Array1T> d(dest);
vtkDataArrayAccessor<Array2T> s(src);
VTK_ASSUME(src->GetNumberOfComponents() == dest->GetNumberOfComponents());
void Fallback(vtkDataArray *dest, vtkDataArray *src)
{
const vtkIdType numTuples = src->GetNumberOfTuples();
const int numComps = src->GetNumberOfComponents();
for (vtkIdType t = 0; t < numTuples; ++t)
{
for (int c = 0; c < numComps; ++c)
{
dest->SetComponent(t + this->Offset, c, src->GetComponent(t, c));
d.Set(t + this->Offset, c, s.Get(t, c));
}
}
}
......@@ -764,7 +757,7 @@ void vtkAppendPolyData::AppendData(vtkDataArray *dest, vtkDataArray *src,
if (!vtkArrayDispatch::Dispatch2SameValueType::Execute(dest, src, worker))
{
// Use vtkDataArray API when fast-path dispatch fails.
worker.Fallback(dest, src);
worker(dest, src);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment