vtkArrayDispatch.h 17.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*=========================================================================

  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.

=========================================================================*/
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
 * @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.
 *
38
 * The vtkDataArrayRange.h utilities are worth mentioning here, as they allow
39
40
41
42
43
44
45
46
47
48
49
50
51
52
 * 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
luz.paz's avatar
luz.paz committed
53
 *   itself to only use arrays that match this criteria.
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
 * - 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
 *
111
 * For convenience, the dispatcher may be aliased to a shorter name, e.g.:
112
113
 *
 * @code
114
 * using MyDispatcher = vtkArrayDispatch::SomeDispatcher<...>;
115
 * MyWorker worker;
116
 * bool result = MyDispatcher::Execute(array, worker);
117
118
119
120
121
122
123
124
125
126
 * @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.
127
128
129
 * 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).
130
 * Workers are passed by reference, so stateful functors are permitted if
131
132
 * additional input/output data is needed and not being passed as additional
 * parameters to the Execute method.
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
 *
 * 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.
 *
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
 * 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
 *
187
 * Examples:
188
189
 * See TestArrayDispatchers.cxx for examples of each dispatch type and
 * ExampleDataArrayRangeDispatch.cxx for more real-world examples.
190
191
192
 *
 * @sa
 * vtkDataArrayAccessor
193
 */
194
195
196
197
198
199
200
201

#ifndef vtkArrayDispatch_h
#define vtkArrayDispatch_h

#include "vtkArrayDispatchArrayList.h"
#include "vtkType.h"
#include "vtkTypeList.h"

202
203
namespace vtkArrayDispatch
{
204
VTK_ABI_NAMESPACE_BEGIN
205

206
207
208
/**
 * A TypeList containing all real ValueTypes.
 */
209
typedef vtkTypeList::Create<double, float> Reals;
210

211
212
213
/**
 * A Typelist containing all integral ValueTypes.
 */
214
typedef vtkTypeList::Unique<
215
  vtkTypeList::Create<char, int, long, long long, short, signed char, unsigned char, unsigned int,
216
    unsigned long, unsigned long long, unsigned short, vtkIdType>>::Result Integrals;
217

218
219
220
/**
 * A Typelist containing all standard VTK array ValueTypes.
 */
221
typedef vtkTypeList::Append<Reals, Integrals>::Result AllTypes;
222
223

//------------------------------------------------------------------------------
224
225
226
227
228
229
/**
 * 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).
 */
230
231
232
struct Dispatch;

//------------------------------------------------------------------------------
233
234
235
236
237
238
/**
 * 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).
 */
239
240
241
242
template <typename ArrayList>
struct DispatchByArray;

//------------------------------------------------------------------------------
243
244
245
246
247
248
249
/**
 * 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).
 */
250
251
252
253
template <typename ValueTypeList>
struct DispatchByValueType;

//------------------------------------------------------------------------------
254
255
256
257
258
259
260
/**
 * 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).
 */
261
262
263
struct Dispatch2;

//------------------------------------------------------------------------------
264
265
266
267
268
269
270
271
/**
 * 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).
 */
272
273
274
struct Dispatch2SameValueType;

//------------------------------------------------------------------------------
275
276
277
278
279
280
281
282
283
/**
 * 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).
 */
284
template <typename ArrayList1, typename ArrayList2>
285
286
287
struct Dispatch2ByArray;

//------------------------------------------------------------------------------
288
289
290
291
292
293
294
295
296
297
298
/**
 * 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).
 */
299
template <typename ValueTypeList1, typename ValueTypeList2>
300
301
302
struct Dispatch2ByValueType;

//------------------------------------------------------------------------------
303
304
305
306
307
308
309
310
311
312
/**
 * 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).
 */
313
template <typename ArrayList1, typename ArrayList2>
314
315
316
struct Dispatch2ByArrayWithSameValueType;

//------------------------------------------------------------------------------
317
318
319
320
321
322
323
324
325
326
327
/**
 * 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).
 */
328
329
330
331
template <typename ValueTypeList>
struct Dispatch2BySameValueType;

//------------------------------------------------------------------------------
332
333
334
335
336
337
338
/**
 * 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).
 */
339
340
341
struct Dispatch3;

//------------------------------------------------------------------------------
342
343
344
345
346
347
348
349
/**
 * 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).
 */
350
351
352
struct Dispatch3SameValueType;

//------------------------------------------------------------------------------
353
354
355
356
357
358
359
360
361
362
/**
 * 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).
 */
363
template <typename ArrayList1, typename ArrayList2, typename ArrayList3>
364
365
366
struct Dispatch3ByArray;

//------------------------------------------------------------------------------
367
368
369
370
371
372
373
374
375
376
377
378
/**
 * 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).
 */
379
template <typename ValueTypeList1, typename ValueTypeList2, typename ValueTypeList3>
380
381
382
struct Dispatch3ByValueType;

//------------------------------------------------------------------------------
383
384
385
386
387
388
389
390
391
392
/**
 * 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).
 */
393
template <typename ArrayList1, typename ArrayList2, typename ArrayList3>
394
395
396
struct Dispatch3ByArrayWithSameValueType;

//------------------------------------------------------------------------------
397
398
399
400
401
402
403
404
405
406
407
/**
 * 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).
 */
408
409
410
411
template <typename ValueTypeList>
struct Dispatch3BySameValueType;

//------------------------------------------------------------------------------
412
413
414
415
/**
 * Filter the ArrayList to contain only arrays with ArrayType::ValueType that
 * exist in ValueList. The result TypeList is stored in Result.
 */
416
417
418
template <typename ArrayList, typename ValueList>
struct FilterArraysByValueType;

419
VTK_ABI_NAMESPACE_END
420
421
422
423
424
425
} // end namespace vtkArrayDispatch

#include "vtkArrayDispatch.txx"

#endif // vtkArrayDispatch_h
// VTK-HeaderTest-Exclude: vtkArrayDispatch.h