UnknownArrayHandle.h 42.7 KB
Newer Older
Kenneth Moreland's avatar
Kenneth Moreland committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//============================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt 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 vtk_m_cont_UnknownArrayHandle_h
#define vtk_m_cont_UnknownArrayHandle_h

#include <vtkm/cont/vtkm_cont_export.h>

15
#include <vtkm/cont/ArrayExtractComponent.h>
Kenneth Moreland's avatar
Kenneth Moreland committed
16
17
18
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
19
#include <vtkm/cont/ArrayHandleRecombineVec.h>
20
#include <vtkm/cont/ArrayHandleStride.h>
21
#include <vtkm/cont/CastAndCall.h>
Kenneth Moreland's avatar
Kenneth Moreland committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <vtkm/cont/DefaultTypes.h>

#include <memory>
#include <typeindex>

namespace vtkm
{
namespace cont
{

namespace detail
{

template <typename T, typename S>
static void UnknownAHDelete(void* mem)
{
  using AH = vtkm::cont::ArrayHandle<T, S>;
  AH* arrayHandle = reinterpret_cast<AH*>(mem);
  delete arrayHandle;
}

template <typename T, typename S>
44
static void* UnknownAHNewInstance()
Kenneth Moreland's avatar
Kenneth Moreland committed
45
46
47
48
49
50
51
52
53
54
55
56
{
  return new vtkm::cont::ArrayHandle<T, S>;
}

template <typename T, typename S>
static vtkm::Id UnknownAHNumberOfValues(void* mem)
{
  using AH = vtkm::cont::ArrayHandle<T, S>;
  AH* arrayHandle = reinterpret_cast<AH*>(mem);
  return arrayHandle->GetNumberOfValues();
}

57
58
59
60
61
62
63
64
65
66
67
68
69
template <typename T, typename StaticSize = typename vtkm::VecTraits<T>::IsSizeStatic>
struct UnknownAHNumberOfComponentsImpl;
template <typename T>
struct UnknownAHNumberOfComponentsImpl<T, vtkm::VecTraitsTagSizeStatic>
{
  static constexpr vtkm::IdComponent Value = vtkm::VecTraits<T>::NUM_COMPONENTS;
};
template <typename T>
struct UnknownAHNumberOfComponentsImpl<T, vtkm::VecTraitsTagSizeVariable>
{
  static constexpr vtkm::IdComponent Value = 0;
};

Kenneth Moreland's avatar
Kenneth Moreland committed
70
71
72
template <typename T>
static vtkm::IdComponent UnknownAHNumberOfComponents()
{
73
  return UnknownAHNumberOfComponentsImpl<T>::Value;
Kenneth Moreland's avatar
Kenneth Moreland committed
74
75
}

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
template <typename T, typename StaticSize = typename vtkm::VecTraits<T>::IsSizeStatic>
struct UnknownAHNumberOfComponentsFlatImpl;
template <typename T>
struct UnknownAHNumberOfComponentsFlatImpl<T, vtkm::VecTraitsTagSizeStatic>
{
  static constexpr vtkm::IdComponent Value = vtkm::VecFlat<T>::NUM_COMPONENTS;
};
template <typename T>
struct UnknownAHNumberOfComponentsFlatImpl<T, vtkm::VecTraitsTagSizeVariable>
{
  static constexpr vtkm::IdComponent Value = 0;
};

template <typename T>
static vtkm::IdComponent UnknownAHNumberOfComponentsFlat()
{
  return UnknownAHNumberOfComponentsFlatImpl<T>::Value;
}

95
template <typename T, typename S>
96
97
98
99
static void UnknownAHAllocate(void* mem,
                              vtkm::Id numValues,
                              vtkm::CopyFlag preserve,
                              vtkm::cont::Token& token)
100
101
102
{
  using AH = vtkm::cont::ArrayHandle<T, S>;
  AH* arrayHandle = reinterpret_cast<AH*>(mem);
103
  arrayHandle->Allocate(numValues, preserve, token);
104
105
}

106
107
108
109
110
111
112
113
114
115
116
template <typename T, typename S>
static std::vector<vtkm::cont::internal::Buffer>
UnknownAHExtractComponent(void* mem, vtkm::IdComponent componentIndex, vtkm::CopyFlag allowCopy)
{
  using AH = vtkm::cont::ArrayHandle<T, S>;
  AH* arrayHandle = reinterpret_cast<AH*>(mem);
  auto componentArray = vtkm::cont::ArrayExtractComponent(*arrayHandle, componentIndex, allowCopy);
  vtkm::cont::internal::Buffer* buffers = componentArray.GetBuffers();
  return std::vector<vtkm::cont::internal::Buffer>(buffers, buffers + 2);
}

Kenneth Moreland's avatar
Kenneth Moreland committed
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
template <typename T, typename S>
static void UnknownAHReleaseResources(void* mem)
{
  using AH = vtkm::cont::ArrayHandle<T, S>;
  AH* arrayHandle = reinterpret_cast<AH*>(mem);
  arrayHandle->ReleaseResources();
}

template <typename T, typename S>
static void UnknownAHReleaseResourcesExecution(void* mem)
{
  using AH = vtkm::cont::ArrayHandle<T, S>;
  AH* arrayHandle = reinterpret_cast<AH*>(mem);
  arrayHandle->ReleaseResourcesExecution();
}

template <typename T, typename S>
static void UnknownAHPrintSummary(void* mem, std::ostream& out, bool full)
{
  using AH = vtkm::cont::ArrayHandle<T, S>;
  AH* arrayHandle = reinterpret_cast<AH*>(mem);
  vtkm::cont::printSummary_ArrayHandle(*arrayHandle, out, full);
}

struct VTKM_CONT_EXPORT UnknownAHContainer;

struct MakeUnknownAHContainerFunctor
{
  template <typename T, typename S>
  std::shared_ptr<UnknownAHContainer> operator()(const vtkm::cont::ArrayHandle<T, S>& array) const;
};

149
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
struct VTKM_CONT_EXPORT UnknownAHComponentInfo
{
  std::type_index Type;
  bool IsIntegral;
  bool IsFloat;
  bool IsSigned;
  std::size_t Size;

  UnknownAHComponentInfo() = delete;

  bool operator==(const UnknownAHComponentInfo& rhs);

  template <typename T>
  static UnknownAHComponentInfo Make()
  {
    return UnknownAHComponentInfo{ typeid(T),
                                   std::is_integral<T>::value,
                                   std::is_floating_point<T>::value,
                                   std::is_signed<T>::value,
                                   sizeof(T) };
  }

private:
  UnknownAHComponentInfo(std::type_index&& type,
                         bool isIntegral,
                         bool isFloat,
                         bool isSigned,
                         std::size_t size)
    : Type(std::move(type))
    , IsIntegral(isIntegral)
    , IsFloat(isFloat)
    , IsSigned(isSigned)
    , Size(size)
  {
  }
};

Kenneth Moreland's avatar
Kenneth Moreland committed
186
187
188
189
190
191
struct VTKM_CONT_EXPORT UnknownAHContainer
{
  void* ArrayHandlePointer;

  std::type_index ValueType;
  std::type_index StorageType;
192
  UnknownAHComponentInfo BaseComponentType;
Kenneth Moreland's avatar
Kenneth Moreland committed
193
194
195
196
197

  using DeleteType = void(void*);
  DeleteType* DeleteFunction;

  using NewInstanceType = void*();
198
199
200
201
  NewInstanceType* NewInstance;

  using NewInstanceBasicType = std::shared_ptr<UnknownAHContainer>();
  NewInstanceBasicType* NewInstanceBasic;
202
  NewInstanceBasicType* NewInstanceFloatBasic;
Kenneth Moreland's avatar
Kenneth Moreland committed
203
204
205
206
207
208

  using NumberOfValuesType = vtkm::Id(void*);
  NumberOfValuesType* NumberOfValues;

  using NumberOfComponentsType = vtkm::IdComponent();
  NumberOfComponentsType* NumberOfComponents;
209
210
  NumberOfComponentsType* NumberOfComponentsFlat;

211
  using AllocateType = void(void*, vtkm::Id, vtkm::CopyFlag, vtkm::cont::Token&);
212
213
  AllocateType* Allocate;

214
215
216
217
  using ExtractComponentType = std::vector<vtkm::cont::internal::Buffer>(void*,
                                                                         vtkm::IdComponent,
                                                                         vtkm::CopyFlag);
  ExtractComponentType* ExtractComponent;
Kenneth Moreland's avatar
Kenneth Moreland committed
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241

  using ReleaseResourcesType = void(void*);
  ReleaseResourcesType* ReleaseResources;
  ReleaseResourcesType* ReleaseResourcesExecution;

  using PrintSummaryType = void(void*, std::ostream&, bool);
  PrintSummaryType* PrintSummary;

  void operator=(const UnknownAHContainer&) = delete;

  ~UnknownAHContainer() { this->DeleteFunction(this->ArrayHandlePointer); }

  std::shared_ptr<UnknownAHContainer> MakeNewInstance() const;

  template <typename T, typename S>
  static std::shared_ptr<UnknownAHContainer> Make(const vtkm::cont::ArrayHandle<T, S>& array)
  {
    return std::shared_ptr<UnknownAHContainer>(new UnknownAHContainer(array));
  }

  template <typename TargetT, typename SourceT, typename SourceS>
  static std::shared_ptr<UnknownAHContainer> Make(
    const vtkm::cont::ArrayHandle<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceS>>& array)
  {
242
243
244
    vtkm::cont::ArrayHandleCast<TargetT, vtkm::cont::ArrayHandle<SourceT, SourceS>> castArray =
      array;
    return Make(castArray.GetSourceArray());
Kenneth Moreland's avatar
Kenneth Moreland committed
245
246
247
248
249
250
  }

  template <typename T, typename... Ss>
  static std::shared_ptr<UnknownAHContainer> Make(
    const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& array)
  {
251
252
    auto&& variant = vtkm::cont::ArrayHandleMultiplexer<vtkm::cont::ArrayHandle<T, Ss>...>(array)
                       .GetArrayHandleVariant();
Kenneth Moreland's avatar
Kenneth Moreland committed
253
254
255
256
257
258
259
260
261
262
263
264
265
266
    if (variant.IsValid())
    {
      return variant.CastAndCall(MakeUnknownAHContainerFunctor{});
    }
    else
    {
      return std::shared_ptr<UnknownAHContainer>{};
    }
  }

private:
  UnknownAHContainer(const UnknownAHContainer&) = default;

  template <typename T, typename S>
267
  explicit UnknownAHContainer(const vtkm::cont::ArrayHandle<T, S>& array);
Kenneth Moreland's avatar
Kenneth Moreland committed
268
269
};

270
template <typename T>
271
static std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceBasic(vtkm::VecTraitsTagSizeStatic)
272
273
274
275
{
  return UnknownAHContainer::Make(vtkm::cont::ArrayHandleBasic<T>{});
}
template <typename T>
276
static std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceBasic(vtkm::VecTraitsTagSizeVariable)
277
278
279
280
281
{
  throw vtkm::cont::ErrorBadType("Cannot create a basic array container from with ValueType of " +
                                 vtkm::cont::TypeToString<T>());
}
template <typename T>
282
static std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceBasic()
283
{
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  return UnknownAHNewInstanceBasic<T>(typename vtkm::VecTraits<T>::IsSizeStatic{});
}

template <typename T>
static std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceFloatBasic(
  vtkm::VecTraitsTagSizeStatic)
{
  using FloatT = typename vtkm::VecTraits<T>::template ReplaceBaseComponentType<vtkm::FloatDefault>;
  return UnknownAHContainer::Make(vtkm::cont::ArrayHandleBasic<FloatT>{});
}
template <typename T>
static std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceFloatBasic(
  vtkm::VecTraitsTagSizeVariable)
{
  throw vtkm::cont::ErrorBadType("Cannot create a basic array container from with ValueType of " +
                                 vtkm::cont::TypeToString<T>());
}
template <typename T>
static std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceFloatBasic()
{
  return UnknownAHNewInstanceFloatBasic<T>(typename vtkm::VecTraits<T>::IsSizeStatic{});
305
306
307
308
309
310
311
}

template <typename T, typename S>
inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle<T, S>& array)
  : ArrayHandlePointer(new vtkm::cont::ArrayHandle<T, S>(array))
  , ValueType(typeid(T))
  , StorageType(typeid(S))
312
313
  , BaseComponentType(
      UnknownAHComponentInfo::Make<typename vtkm::VecTraits<T>::BaseComponentType>())
314
  , DeleteFunction(detail::UnknownAHDelete<T, S>)
315
316
317
  , NewInstance(detail::UnknownAHNewInstance<T, S>)
  , NewInstanceBasic(detail::UnknownAHNewInstanceBasic<T>)
  , NewInstanceFloatBasic(detail::UnknownAHNewInstanceFloatBasic<T>)
318
319
320
321
322
323
324
325
326
327
328
  , NumberOfValues(detail::UnknownAHNumberOfValues<T, S>)
  , NumberOfComponents(detail::UnknownAHNumberOfComponents<T>)
  , NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat<T>)
  , Allocate(detail::UnknownAHAllocate<T, S>)
  , ExtractComponent(detail::UnknownAHExtractComponent<T, S>)
  , ReleaseResources(detail::UnknownAHReleaseResources<T, S>)
  , ReleaseResourcesExecution(detail::UnknownAHReleaseResourcesExecution<T, S>)
  , PrintSummary(detail::UnknownAHPrintSummary<T, S>)
{
}

Kenneth Moreland's avatar
Kenneth Moreland committed
329
330
331
332
333
334
335
336
337
template <typename T, typename S>
inline std::shared_ptr<UnknownAHContainer> MakeUnknownAHContainerFunctor::operator()(
  const vtkm::cont::ArrayHandle<T, S>& array) const
{
  return UnknownAHContainer::Make(array);
};

} // namespace detail

Kenneth Moreland's avatar
Kenneth Moreland committed
338
339
340
341
342
// Forward declaration. Include UncertainArrayHandle.h if using this.
template <typename ValueTypeList, typename StorageTypeList>
class UncertainArrayHandle;

/// \brief An ArrayHandle of an unknown value type and storage.
Kenneth Moreland's avatar
Kenneth Moreland committed
343
344
///
/// `UnknownArrayHandle` holds an `ArrayHandle` object using runtime polymorphism
Kenneth Moreland's avatar
Kenneth Moreland committed
345
/// to manage different value and storage types rather than compile-time templates.
Kenneth Moreland's avatar
Kenneth Moreland committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
/// This adds a programming convenience that helps avoid a proliferation of
/// templates. It also provides the management necessary to interface VTK-m with
/// data sources where types will not be known until runtime and is the storage
/// mechanism for classes like `DataSet` and `Field` that can hold numerous
/// types.
///
/// To interface between the runtime polymorphism and the templated algorithms
/// in VTK-m, `UnknownArrayHandle` contains a method named `CastAndCallForTypes`
/// that determines the correct type from some known list of value types and
/// storage. This mechanism is used internally by VTK-m's worklet invocation
/// mechanism to determine the type when running algorithms.
///
/// If the `UnknownArrayHandle` is used in a context where the possible array
/// types can be whittled down to a finite list (or you have to), you can
/// specify lists of value types and storage using the `ResetTypesAndStorage`
/// method. This will convert this object to an `UncertainArrayHandle` of the
/// given types. In cases where a finite set of types need to specified but
/// there is no known subset, `VTKM_DEFAULT_TYPE_LIST` and
/// `VTKM_DEFAULT_STORAGE_LIST` can be used.
///
/// `ArrayHandleCast` and `ArrayHandleMultiplexer` are treated special. If
/// the `UnknownArrayHandle` is set to an `ArrayHandle` of one of these
/// types, it will actually store the `ArrayHandle` contained. Likewise,
/// if the `ArrayHandle` is retrieved as one of these types, it will
/// automatically convert it if possible.
///
class VTKM_CONT_EXPORT UnknownArrayHandle
{
  std::shared_ptr<detail::UnknownAHContainer> Container;

  VTKM_CONT bool IsValueTypeImpl(std::type_index type) const;
  VTKM_CONT bool IsStorageTypeImpl(std::type_index type) const;
378
  VTKM_CONT bool IsBaseComponentTypeImpl(const detail::UnknownAHComponentInfo& type) const;
Kenneth Moreland's avatar
Kenneth Moreland committed
379
380
381

public:
  VTKM_CONT UnknownArrayHandle() = default;
382
  UnknownArrayHandle(const UnknownArrayHandle&) = default;
Kenneth Moreland's avatar
Kenneth Moreland committed
383
384
385
386
387
388
389

  template <typename T, typename S>
  VTKM_CONT UnknownArrayHandle(const vtkm::cont::ArrayHandle<T, S>& array)
    : Container(detail::UnknownAHContainer::Make(array))
  {
  }

390
391
  UnknownArrayHandle& operator=(const vtkm::cont::UnknownArrayHandle&) = default;

392
393
394
395
396
397
398
399
  /// \brief Returns whether an array is stored in this `UnknownArrayHandle`.
  ///
  /// If the `UnknownArrayHandle` is constructed without an `ArrayHandle`, it
  /// will not have an underlying type, and therefore the operations will be
  /// invalid. It is still possible to set this `UnknownArrayHandle` to an
  /// `ArrayHandle`.
  VTKM_CONT bool IsValid() const;

Kenneth Moreland's avatar
Kenneth Moreland committed
400
401
402
  /// \brief Create a new array of the same type as this array.
  ///
  /// This method creates a new array that is the same type as this one and
Kenneth Moreland's avatar
Kenneth Moreland committed
403
  /// returns a new `UnknownArrayHandle` for it. This method is convenient when
Kenneth Moreland's avatar
Kenneth Moreland committed
404
405
  /// creating output arrays that should be the same type as some input array.
  ///
406
407
408
409
410
411
412
413
414
415
  VTKM_CONT UnknownArrayHandle NewInstance() const;

  /// \brief Create a new `ArrayHandleBasic` with the same `ValueType` as this array.
  ///
  /// This method creates a new `ArrayHandleBasic` that has the same `ValueType` as the
  /// array held by this one and returns a new `UnknownArrayHandle` for it. This method
  /// is convenient when creating output arrays that should have the same types of values
  /// of the input, but the input might not be a writable array.
  ///
  VTKM_CONT UnknownArrayHandle NewInstanceBasic() const;
Kenneth Moreland's avatar
Kenneth Moreland committed
416

417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  /// \brief Create a new `ArrayHandleBasic` with the base component of `FloatDefault`
  ///
  /// This method creates a new `ArrayHandleBasic` that has a `ValueType` that is similar
  /// to the array held by this one except that the base component type is replaced with
  /// `vtkm::FloatDefault`. For example, if the contained array has `vtkm::Int32` value types,
  /// the returned array will have `vtkm::FloatDefault` value types. If the contained array
  /// has `vtkm::Id3` value types, the returned array will have `vtkm::Vec3f` value types.
  /// If the contained array already has `vtkm::FloatDefault` as the base component (e.g.
  /// `vtkm::FloatDefault`, `vtkm::Vec3f`, `vtkm::Vec<vtkm::Vec2f, 3>`), then the value type
  /// will be preserved.
  ///
  /// The created array is returned in a new `UnknownArrayHandle`.
  ///
  /// This method is used to convert an array of an unknown type to an array of an almost
  /// known type.
  ///
  VTKM_CONT UnknownArrayHandle NewInstanceFloatBasic() const;

435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
  /// \brief Returns the name of the value type stored in the array.
  ///
  /// Returns an empty string if no array is stored.
  VTKM_CONT std::string GetValueTypeName() const;

  /// \brief Returns the name of the base component of the value type stored in the array.
  ///
  /// Returns an empty string if no array is stored.
  VTKM_CONT std::string GetBaseComponentTypeName() const;

  /// \brief Returns the name of the storage tag for the array.
  ///
  /// Returns an empty string if no array is stored.
  VTKM_CONT std::string GetStorageTypeName() const;

Kenneth Moreland's avatar
Kenneth Moreland committed
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  /// Returns true if this array matches the ValueType template argument.
  ///
  template <typename ValueType>
  VTKM_CONT bool IsValueType() const
  {
    return this->IsValueTypeImpl(typeid(ValueType));
  }

  /// Returns true if this array matches the StorageType template argument.
  ///
  template <typename StorageType>
  VTKM_CONT bool IsStorageType() const
  {
    return this->IsStorageTypeImpl(typeid(StorageType));
  }

466
467
468
469
470
471
472
473
474
475
476
477
478
479
  /// \brief Returns true if this array's `ValueType` has the provided base component type.
  ///
  /// The base component type is the recursive component type of any `Vec`-like object. So
  /// if the array's `ValueType` is `vtkm::Vec<vtkm::Float32, 3>`, then the base component
  /// type will be `vtkm::Float32`. Likewise, if the `ValueType` is
  /// `vtkm::Vec<vtkm::Vec<vtkm::Float32, 3>, 2>`, then the base component type is still
  /// `vtkm::Float32`.
  ///
  /// If the `ValueType` is not `Vec`-like type, then the base component type is the same.
  /// So a `ValueType` of `vtkm::Float32` has a base component type of `vtkm::Float32`.
  ///
  template <typename BaseComponentType>
  VTKM_CONT bool IsBaseComponentType() const
  {
480
    return this->IsBaseComponentTypeImpl(detail::UnknownAHComponentInfo::Make<BaseComponentType>());
481
482
  }

Kenneth Moreland's avatar
Kenneth Moreland committed
483
484
485
486
487
488
489
490
491
492
  /// Returns true if this array matches the ArrayHandleType template argument.
  ///
  template <typename ArrayHandleType>
  VTKM_CONT bool IsType() const
  {
    VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
    return (this->IsValueType<typename ArrayHandleType::ValueType>() &&
            this->IsStorageType<typename ArrayHandleType::StorageTag>());
  }

Kenneth Moreland's avatar
Kenneth Moreland committed
493
494
495
496
497
498
499
500
501
502
503
504
505
  /// \brief Assigns potential value and storage types.
  ///
  /// Calling this method will return an `UncertainArrayHandle` with the provided
  /// value and storage type lists. The returned object will hold the same
  /// `ArrayHandle`, but `CastAndCall`s on the returned object will be constrained
  /// to the given types.
  ///
  // Defined in UncertainArrayHandle.h
  template <typename NewValueTypeList, typename NewStorageTypeList>
  VTKM_CONT vtkm::cont::UncertainArrayHandle<NewValueTypeList, NewStorageTypeList> ResetTypes(
    NewValueTypeList = NewValueTypeList{},
    NewStorageTypeList = NewStorageTypeList{}) const;

506
507
508
509
510
511
512
513
514
  template <typename NewValueTypeList>
  VTKM_DEPRECATED(1.6, "Specify both value types and storage types.")
  VTKM_CONT
    vtkm::cont::UncertainArrayHandle<NewValueTypeList, VTKM_DEFAULT_STORAGE_LIST> ResetTypes(
      NewValueTypeList = NewValueTypeList{}) const
  {
    return this->ResetTypes<NewValueTypeList, VTKM_DEFAULT_STORAGE_LIST>();
  }

Kenneth Moreland's avatar
Kenneth Moreland committed
515
516
  /// \brief Returns the number of values in the array.
  ///
517
  VTKM_CONT vtkm::Id GetNumberOfValues() const;
Kenneth Moreland's avatar
Kenneth Moreland committed
518
519
520
521
522

  /// \brief Returns the number of components for each value in the array.
  ///
  /// If the array holds `vtkm::Vec` objects, this will return the number of components
  /// in each value. If the array holds a basic C type (such as `float`), this will return 1.
523
524
  /// If the array holds `Vec`-like objects that have the number of components that can vary
  /// at runtime, this method will return 0 (because there is no consistent answer).
Kenneth Moreland's avatar
Kenneth Moreland committed
525
  ///
526
  VTKM_CONT vtkm::IdComponent GetNumberOfComponents() const;
Kenneth Moreland's avatar
Kenneth Moreland committed
527

528
529
530
531
532
533
534
535
536
537
538
539
  /// \brief Returns the total number of components for each value in the array.
  ///
  /// If the array holds `vtkm::Vec` objects, this will return the total number of components
  /// in each value assuming the object is flattened out to one level of `Vec` objects.
  /// If the array holds a basic C type (such as `float`), this will return 1.
  /// If the array holds a simple `Vec` (such as `vtkm::Vec3f`), this will return the number
  /// of components (in this case 3).
  /// If the array holds a hierarchy of `Vec`s (such as `vtkm::Vec<vtkm::Vec3f, 2>`), this will
  /// return the total number of vecs (in this case 6).
  /// If the array holds `Vec`-like objects that have the number of components that can vary
  /// at runtime, this method will return 0 (because there is no consistent answer).
  ///
540
541
542
543
  VTKM_CONT vtkm::IdComponent GetNumberOfComponentsFlat() const;

  /// \brief Reallocate the data in the array.
  ///
544
545
546
547
548
549
550
551
  /// The allocation works the same as the `Allocate` method of `vtkm::cont::ArrayHandle`.
  ///
  /// @{
  VTKM_CONT void Allocate(vtkm::Id numValues,
                          vtkm::CopyFlag preserve,
                          vtkm::cont::Token& token) const;
  VTKM_CONT void Allocate(vtkm::Id numValues, vtkm::CopyFlag preserve = vtkm::CopyFlag::Off) const;
  /// @}
552

Kenneth Moreland's avatar
Kenneth Moreland committed
553
554
555
556
557
558
559
560
561
562
  /// \brief Determine if the contained array can be passed to the given array type.
  ///
  /// This method will return true if calling `AsArrayHandle` of the given type will
  /// succeed. The result is similar to `IsType`, and if `IsType` returns true, then
  /// this will return true. However, this method will also return true for other
  /// types such as an `ArrayHandleMultiplexer` that can contain the array.
  ///
  template <typename ArrayHandleType>
  VTKM_CONT bool CanConvert() const;

563
564
565
566
567
568
569
570
  // MSVC will issue deprecation warnings here if this template is instantiated with
  // a deprecated class even if the template is used from a section of code where
  // deprecation warnings are suppressed. This is annoying behavior since this template
  // has no control over what class it is used with. To get around it, we have to
  // suppress all deprecation warnings here.
#ifdef VTKM_MSVC
  VTKM_DEPRECATED_SUPPRESS_BEGIN
#endif
Kenneth Moreland's avatar
Kenneth Moreland committed
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
  ///@{
  /// Returns this array cast appropriately and stored in the given `ArrayHandle` type.
  /// Throws an `ErrorBadType` if the stored array cannot be stored in the given array type.
  /// Use the `IsType` method to determine if the array can be returned with the given type.
  ///
  template <typename T, typename S>
  VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T, S>& array) const
  {
    using ArrayType = vtkm::cont::ArrayHandle<T, S>;
    if (!this->IsType<ArrayType>())
    {
      VTKM_LOG_CAST_FAIL(*this, decltype(array));
      throwFailedDynamicCast(vtkm::cont::TypeToString(*this), vtkm::cont::TypeToString(array));
    }

    array = *reinterpret_cast<ArrayType*>(this->Container->ArrayHandlePointer);
  }

  template <typename T, typename... Ss>
  VTKM_CONT void AsArrayHandle(
    vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& array) const;

  template <typename TargetT, typename SourceT, typename SourceS>
  VTKM_CONT void AsArrayHandle(
    vtkm::cont::ArrayHandle<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceS>>& array) const
  {
    using ContainedArrayType = vtkm::cont::ArrayHandle<SourceT, SourceS>;
    array = vtkm::cont::ArrayHandleCast<TargetT, ContainedArrayType>(
      this->AsArrayHandle<ContainedArrayType>());
  }

  template <typename ArrayType>
  VTKM_CONT ArrayType AsArrayHandle() const
  {
    VTKM_IS_ARRAY_HANDLE(ArrayType);
    ArrayType array;
    this->AsArrayHandle(array);
    return array;
  }
  ///@}
611
612
613
#ifdef VTKM_MSVC
  VTKM_DEPRECATED_SUPPRESS_END
#endif
Kenneth Moreland's avatar
Kenneth Moreland committed
614

615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
  // For code still expecting a VariantArrayHandle
  template <typename ArrayHandleType>
  VTKM_DEPRECATED(1.6, "Use AsArrayHandle.")
  VTKM_CONT ArrayHandleType Cast() const
  {
    return this->AsArrayHandle<ArrayHandleType>();
  }
  template <typename ArrayHandleType>
  VTKM_DEPRECATED(1.6, "Use AsArrayHandle.")
  VTKM_CONT void CopyTo(ArrayHandleType& array) const
  {
    this->AsArrayHandle(array);
  }
  template <typename MultiplexerType>
  VTKM_DEPRECATED(1.6, "Use AsArrayHandle.")
  VTKM_CONT MultiplexerType AsMultiplexer() const
  {
    return this->AsArrayHandle<MultiplexerType>();
  }
  template <typename MultiplexerType>
  VTKM_DEPRECATED(1.6, "Use AsArrayHandle.")
  VTKM_CONT void AsMultiplexer(MultiplexerType& result) const
  {
    result = this->AsArrayHandle<MultiplexerType>();
  }

641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
  /// \brief Extract a component of the array.
  ///
  /// This method returns an array that holds the data for a given flat component of the data.
  /// The `BaseComponentType` has to be specified and must match the contained array (i.e.
  /// the result of `IsBaseComponentType` must succeed for the given type).
  ///
  /// This method treats each value in the array as a flat `Vec` even if it is a `Vec` of
  /// `Vec`s. For example, if the array actually holds values of type `Vec<Vec<T, 3>, 2>`,
  /// it is treated as if it holds a `Vec<T, 6>`. See `vtkm::VecFlat` for details on how
  /// vectors are flattened.
  ///
  /// The point of using `ExtractComponent` over `AsArrayHandle` is that it drastically reduces
  /// the amount of types you have to try. Most of the type the base component type is one of
  /// the basic C types (i.e. `int`, `long`, `float`, etc.). You do not need to know what shape
  /// the containing `Vec` is in, nor do you need to know the actual storage of the array.
  ///
  /// Note that the type of the array returned is `ArrayHandleStride`. Using this type of
  /// array handle has a slight overhead over basic arrays like `ArrayHandleBasic` and
  /// `ArrayHandleSOA`.
  ///
  /// When extracting a component of an array, a shallow pointer to the data is returned
  /// whenever possible. However, in some circumstances it is impossible to conform the
  /// array. In these cases, the data are by default copied. If copying the data would
  /// cause problems (for example, you are writing into the array), you can select the
  /// optional `allowCopy` flag to `vtkm::CopyFlag::Off`. In this case, an exception
  /// will be thrown if the result cannot be represented by a shallow copy.
  ///
  template <typename BaseComponentType>
  VTKM_CONT vtkm::cont::ArrayHandleStride<BaseComponentType> ExtractComponent(
    vtkm::IdComponent componentIndex,
    vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) const
  {
    using ComponentArrayType = vtkm::cont::ArrayHandleStride<BaseComponentType>;
    if (!this->IsBaseComponentType<BaseComponentType>())
    {
      VTKM_LOG_CAST_FAIL(*this, ComponentArrayType);
      throwFailedDynamicCast(vtkm::cont::TypeToString(*this),
                             "component array of " + vtkm::cont::TypeToString<BaseComponentType>());
    }

    auto buffers = this->Container->ExtractComponent(
      this->Container->ArrayHandlePointer, componentIndex, allowCopy);
    return ComponentArrayType(buffers);
  }

686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
  /// \brief Extract the array knowing only the component type of the array.
  ///
  /// This method returns an `ArrayHandle` that points to the data in the array. This method
  /// differs from `AsArrayHandle` because you do not need to know the exact `ValueType` and
  /// `StorageTag` of the array. Instead, you only need to know the base component type.
  ///
  /// `ExtractArrayFromComponents` works by calling the `ExtractComponent` method and then
  /// combining them together in a fancy `ArrayHandle`. This allows you to ignore the storage
  /// type of the underlying array as well as any `Vec` structure of the value type. However,
  /// it also places some limitations on how the data can be pulled from the data.
  ///
  /// First, you have to specify the base component type. This must match the data in the
  /// underlying array (as reported by `IsBaseComponentType`).
  ///
  /// Second, the array returned will have the `Vec`s flattened. For example, if the underlying
  /// array has a `ValueType` of `Vec<Vec<T, 3>, 3>`, then this method will tread the data as
  /// if it was `Vec<T, 9>`. There is no way to get an array with `Vec` of `Vec` values.
  ///
  /// Third, because the `Vec` length of the values in the returned `ArrayHandle` must be
  /// determined at runtime, that can break many assumptions of using `Vec` objects. The
  /// type is not going to be a `Vec<T,N>` type but rather an internal class that is intended
  /// to behave like that. The type should behave mostly like a `Vec`, but will have some
  /// differences that can lead to unexpected behavior. For example, this `Vec`-like object
  /// will not have a `NUM_COMPONENTS` constant static expression because it is not known
  /// at compile time. (Use the `GetNumberOfComponents` method instead.) And for the same
  /// reason you will not be able to pass these objects to classes overloaded or templated
  /// on the `Vec` type. Also, these `Vec`-like objects cannot be created as new instances.
  /// Thus, you will likely have to iterate over all components rather than do operations on
  /// the whole `Vec`.
  ///
  /// Fourth, because `ExtractArrayFromComponents` uses `ExtractComponent` to pull data from
  /// the array (which in turn uses `ArrayExtractComponent`), there are some `ArrayHandle` types
  /// that will require copying data to a new array. This could be problematic in cases where
  /// you want to write to the array. To prevent data from being copied, set the optional
  ///  `allowCopy` to `vtkm::CopyFlag::Off`. This will cause an exception to be thrown if
  /// the resulting array cannot reference the memory held in this `UnknownArrayHandle`.
722
  ///
723
724
725
726
  /// Fifth, component arrays are extracted using `ArrayHandleStride` as the representation
  /// for each component. This array adds a slight overhead for each lookup as it performs the
  /// arithmetic for finding the index of each component.
  ///
727
  template <typename BaseComponentType>
728
729
  VTKM_CONT vtkm::cont::ArrayHandleRecombineVec<BaseComponentType> ExtractArrayFromComponents(
    vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) const
730
  {
731
    vtkm::cont::ArrayHandleRecombineVec<BaseComponentType> result;
732
733
734
    vtkm::IdComponent numComponents = this->GetNumberOfComponentsFlat();
    for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
    {
735
      result.AppendComponentArray(this->ExtractComponent<BaseComponentType>(cIndex, allowCopy));
736
    }
737
    return result;
738
739
  }

Kenneth Moreland's avatar
Kenneth Moreland committed
740
741
  /// \brief Call a functor using the underlying array type.
  ///
742
  /// `CastAndCallForTypes` attempts to cast the held array to a specific value type,
Kenneth Moreland's avatar
Kenneth Moreland committed
743
744
745
  /// and then calls the given functor with the cast array. You must specify
  /// the `TypeList` and `StorageList` as template arguments.
  ///
746
747
748
  /// After the functor argument you may add any number of arguments that will be
  /// passed to the functor after the converted `ArrayHandle`.
  ///
Kenneth Moreland's avatar
Kenneth Moreland committed
749
750
751
  template <typename TypeList, typename StorageList, typename Functor, typename... Args>
  VTKM_CONT void CastAndCallForTypes(Functor&& functor, Args&&... args) const;

752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
  /// \brief Call a functor on an array extracted from the components.
  ///
  /// `CastAndCallWithExtractedArray` behaves similarly to `CastAndCallForTypes`.
  /// It converts the contained data to an `ArrayHandle` and calls a functor with
  /// that `ArrayHandle` (and any number of optionally specified arguments).
  ///
  /// The advantage of `CastAndCallWithExtractedArray` is that you do not need to
  /// specify any `TypeList` or `StorageList`. Instead, it internally uses
  /// `ExtractArrayFromComponents` to work with most `ArrayHandle` types with only
  /// about 10 instances of the functor. In contrast, calling `CastAndCallForTypes`
  /// with, for example, `VTKM_DEFAULT_TYPE_LIST` and `VTKM_DEFAULT_STORAGE_LIST`
  /// results in many more instances of the functor but handling many fewer types
  /// of `ArrayHandle`.
  ///
  /// There are, however, costs to using this method. Details of these costs are
  /// documented for the `ExtractArrayFromComponents` method, but briefly they
  /// are that `Vec` types get flattened, the resulting array has a strange `Vec`-like
  /// value type that has many limitations on its use, there is an overhead for
  /// retrieving each value from the array, and there is a potential that data
  /// must be copied.
  ///
  template <typename Functor, typename... Args>
  VTKM_CONT void CastAndCallWithExtractedArray(Functor&& functor, Args&&... args) const;

776
777
778
779
780
781
782
783
784
785
  template <typename FunctorOrStorageList, typename... Args>
  VTKM_CONT VTKM_DEPRECATED(1.6, "Use CastAndCallForTypes.") void CastAndCall(
    FunctorOrStorageList&& functorOrStorageList,
    Args&&... args) const
  {
    this->CastAndCallImpl(vtkm::internal::IsList<FunctorOrStorageList>{},
                          std::forward<FunctorOrStorageList>(functorOrStorageList),
                          std::forward<Args>(args)...);
  }

Kenneth Moreland's avatar
Kenneth Moreland committed
786
787
788
  /// Releases any resources being used in the execution environment (that are
  /// not being shared by the control environment).
  ///
789
  VTKM_CONT void ReleaseResourcesExecution() const;
Kenneth Moreland's avatar
Kenneth Moreland committed
790
791
792

  /// Releases all resources in both the control and execution environments.
  ///
793
  VTKM_CONT void ReleaseResources() const;
Kenneth Moreland's avatar
Kenneth Moreland committed
794

795
  VTKM_CONT void PrintSummary(std::ostream& out, bool full = false) const;
796
797
798
799
800
801
802
803
804
805
806
807
808
809

private:
  // Remove this when deprecated CastAndCall is removed.
  template <typename... Args>
  VTKM_CONT void CastAndCallImpl(std::false_type, Args&&... args) const
  {
    this->CastAndCallForTypes<VTKM_DEFAULT_TYPE_LIST, VTKM_DEFAULT_STORAGE_LIST>(
      std::forward<Args>(args)...);
  }
  template <typename StorageList, typename... Args>
  VTKM_CONT void CastAndCallImpl(std::true_type, StorageList, Args&&... args) const
  {
    this->CastAndCallForTypes<VTKM_DEFAULT_TYPE_LIST, StorageList>(std::forward<Args>(args)...);
  }
Kenneth Moreland's avatar
Kenneth Moreland committed
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
};

//=============================================================================
// Out of class implementations

namespace detail
{

template <typename T, typename S>
struct UnknownArrayHandleCanConvert
{
  VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
  {
    return array.IsType<vtkm::cont::ArrayHandle<T, S>>();
  }
};

template <typename TargetT, typename SourceT, typename SourceS>
struct UnknownArrayHandleCanConvert<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceS>>
{
  VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
  {
    return UnknownArrayHandleCanConvert<SourceT, SourceS>{}(array);
  }
};

template <typename T>
struct UnknownArrayHandleCanConvertTry
{
  template <typename S>
  VTKM_CONT void operator()(S, const vtkm::cont::UnknownArrayHandle& array, bool& canConvert) const
  {
    canConvert |= UnknownArrayHandleCanConvert<T, S>{}(array);
  }
};

template <typename T, typename... Ss>
struct UnknownArrayHandleCanConvert<T, vtkm::cont::StorageTagMultiplexer<Ss...>>
{
  VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
  {
    bool canConvert = false;
    vtkm::ListForEach(UnknownArrayHandleCanConvertTry<T>{}, vtkm::List<Ss...>{}, array, canConvert);
    return canConvert;
  }
};

} // namespace detail

template <typename ArrayHandleType>
VTKM_CONT bool UnknownArrayHandle::CanConvert() const
{
  VTKM_IS_ARRAY_HANDLE(ArrayHandleType);

  return detail::UnknownArrayHandleCanConvert<typename ArrayHandleType::ValueType,
                                              typename ArrayHandleType::StorageTag>{}(*this);
}

namespace detail
{

struct UnknownArrayHandleMultplexerCastTry
{
  template <typename T, typename S, typename... Ss>
  VTKM_CONT void operator()(
    S,
    const vtkm::cont::UnknownArrayHandle& unknownArray,
    vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& outputArray,
    bool& converted) const
  {
    using ArrayType = vtkm::cont::ArrayHandle<T, S>;
881
    if (unknownArray.CanConvert<ArrayType>())
Kenneth Moreland's avatar
Kenneth Moreland committed
882
    {
883
884
885
886
887
888
889
890
891
      if (converted && !unknownArray.IsType<ArrayType>())
      {
        // The array has already been converted and pushed in the multiplexer. It is
        // possible that multiple array types can be put in the ArrayHandleMultiplexer
        // (for example, and ArrayHandle or an ArrayHandle that has been cast). Exact
        // matches will override other matches (hence, the second part of the condition),
        // but at this point we have already found a better array to put inside.
        return;
      }
892
893
      outputArray = vtkm::cont::ArrayHandleMultiplexer<vtkm::cont::ArrayHandle<T, Ss>...>(
        unknownArray.AsArrayHandle<ArrayType>());
Kenneth Moreland's avatar
Kenneth Moreland committed
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
      converted = true;
    }
  }
};

} // namespace detail

template <typename T, typename... Ss>
void UnknownArrayHandle::AsArrayHandle(
  vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& array) const
{
  bool converted = false;
  vtkm::ListForEach(
    detail::UnknownArrayHandleMultplexerCastTry{}, vtkm::List<Ss...>{}, *this, array, converted);

  if (!converted)
  {
    VTKM_LOG_CAST_FAIL(*this, decltype(array));
    throwFailedDynamicCast(vtkm::cont::TypeToString(*this), vtkm::cont::TypeToString(array));
  }
}

namespace detail
{

struct UnknownArrayHandleTry
{
  template <typename T, typename S, typename Functor, typename... Args>
  void operator()(vtkm::List<T, S>,
                  Functor&& f,
                  bool& called,
                  const vtkm::cont::UnknownArrayHandle& unknownArray,
                  Args&&... args) const
  {
    using DerivedArrayType = vtkm::cont::ArrayHandle<T, S>;
929
    if (!called && unknownArray.CanConvert<DerivedArrayType>())
Kenneth Moreland's avatar
Kenneth Moreland committed
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
    {
      called = true;
      DerivedArrayType derivedArray;
      unknownArray.AsArrayHandle(derivedArray);
      VTKM_LOG_CAST_SUCC(unknownArray, derivedArray);

      // If you get a compile error here, it means that you have called CastAndCall for a
      // vtkm::cont::UnknownArrayHandle and the arguments of the functor do not match those
      // being passed. This is often because it is calling the functor with an ArrayHandle
      // type that was not expected. Either add overloads to the functor to accept all
      // possible array types or constrain the types tried for the CastAndCall. Note that
      // the functor will be called with an array of type vtkm::cont::ArrayHandle<T, S>.
      // Directly using a subclass of ArrayHandle (e.g. vtkm::cont::ArrayHandleConstant<T>)
      // might not work.
      f(derivedArray, std::forward<Args>(args)...);
    }
  }
};

template <typename T>
struct IsUndefinedArrayType
{
};
953
954
template <typename T, typename S>
struct IsUndefinedArrayType<vtkm::List<T, S>> : vtkm::cont::internal::IsInvalidArrayHandle<T, S>
Kenneth Moreland's avatar
Kenneth Moreland committed
955
956
957
{
};

958
template <typename ValueTypeList, typename StorageTypeList>
Kenneth Moreland's avatar
Kenneth Moreland committed
959
using ListAllArrayTypes =
960
  vtkm::ListRemoveIf<vtkm::ListCross<ValueTypeList, StorageTypeList>, IsUndefinedArrayType>;
Kenneth Moreland's avatar
Kenneth Moreland committed
961
962
963
964
965
966
967
968


VTKM_CONT_EXPORT void ThrowCastAndCallException(const vtkm::cont::UnknownArrayHandle&,
                                                const std::type_info&);

} // namespace detail

template <typename TypeList, typename StorageTagList, typename Functor, typename... Args>
969
inline void UnknownArrayHandle::CastAndCallForTypes(Functor&& f, Args&&... args) const
Kenneth Moreland's avatar
Kenneth Moreland committed
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
{
  using crossProduct = detail::ListAllArrayTypes<TypeList, StorageTagList>;

  bool called = false;
  vtkm::ListForEach(detail::UnknownArrayHandleTry{},
                    crossProduct{},
                    std::forward<Functor>(f),
                    called,
                    *this,
                    std::forward<Args>(args)...);
  if (!called)
  {
    // throw an exception
    VTKM_LOG_CAST_FAIL(*this, TypeList);
    detail::ThrowCastAndCallException(*this, typeid(TypeList));
  }
}

988
989
990
991
992
993
994
995
996
997
998
999
1000

//=============================================================================
// Free function casting helpers

/// Returns true if \c variant matches the type of ArrayHandleType.
///
template <typename ArrayHandleType>
VTKM_CONT inline bool IsType(const vtkm::cont::UnknownArrayHandle& array)
{
  return array.template IsType<ArrayHandleType>();
}

/// Returns \c variant cast to the given \c ArrayHandle type. Throws \c
For faster browsing, not all history is shown. View entire blame