VTK-m  2.2
ArrayHandleCast.h
Go to the documentation of this file.
1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10 #ifndef vtk_m_cont_ArrayHandleCast_h
11 #define vtk_m_cont_ArrayHandleCast_h
12 
14 
15 #include <vtkm/cont/Logging.h>
16 
17 #include <vtkm/Range.h>
18 #include <vtkm/VecTraits.h>
19 
20 #include <limits>
21 
22 namespace vtkm
23 {
24 namespace cont
25 {
26 
27 template <typename SourceT, typename SourceStorage>
29 {
30 };
31 
32 namespace internal
33 {
34 
35 template <typename FromType, typename ToType>
37 {
38 // The following operator looks like it should never issue a cast warning because of
39 // the static_cast (and we don't want it to issue a warning). However, if ToType is
40 // an object that has a constructor that takes a value that FromType can be cast to,
41 // that cast can cause a warning. For example, if FromType is vtkm::Float64 and ToType
42 // is vtkm::Vec<vtkm::Float32, 3>, the static_cast will first implicitly cast the
43 // Float64 to a Float32 (which causes a warning) before using the static_cast to
44 // construct the Vec with the Float64. The easiest way around the problem is to
45 // just disable all conversion warnings here. (The pragmas are taken from those
46 // used in Types.h for the VecBase class.)
47 #if (!(defined(VTKM_CUDA) && (__CUDACC_VER_MAJOR__ < 8)))
48 #if (defined(VTKM_GCC) || defined(VTKM_CLANG))
49 #pragma GCC diagnostic push
50 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
51 #pragma GCC diagnostic ignored "-Wpragmas"
52 #pragma GCC diagnostic ignored "-Wconversion"
53 #pragma GCC diagnostic ignored "-Wfloat-conversion"
54 #endif // gcc || clang
55 #endif //not using cuda < 8
56 #if defined(VTKM_MSVC)
57 #pragma warning(push)
58 #pragma warning(disable : 4244)
59 #endif
60 
62  ToType operator()(const FromType& val) const { return static_cast<ToType>(val); }
63 
64 #if (!(defined(VTKM_CUDA) && (__CUDACC_VER_MAJOR__ < 8)))
65 #if (defined(VTKM_GCC) || defined(VTKM_CLANG))
66 #pragma GCC diagnostic pop
67 #endif // gcc || clang
68 #endif // not using cuda < 8
69 #if defined(VTKM_MSVC)
70 #pragma warning(pop)
71 #endif
72 };
73 
74 namespace detail
75 {
76 
77 template <typename TargetT, typename SourceT, typename SourceStorage, bool... CastFlags>
78 struct ArrayHandleCastTraits;
79 
80 template <typename TargetT, typename SourceT, typename SourceStorage>
81 struct ArrayHandleCastTraits<TargetT, SourceT, SourceStorage>
82  : ArrayHandleCastTraits<TargetT,
83  SourceT,
84  SourceStorage,
85  std::is_convertible<SourceT, TargetT>::value,
86  std::is_convertible<TargetT, SourceT>::value>
87 {
88 };
89 
90 // Case where the forward cast is invalid, so this array is invalid.
91 template <typename TargetT, typename SourceT, typename SourceStorage, bool CanCastBackward>
92 struct ArrayHandleCastTraits<TargetT, SourceT, SourceStorage, false, CanCastBackward>
93 {
94  struct StorageSuperclass : vtkm::cont::internal::UndefinedStorage
95  {
96  using PortalType = vtkm::cont::internal::detail::UndefinedArrayPortal<TargetT>;
97  using PortalConstType = vtkm::cont::internal::detail::UndefinedArrayPortal<TargetT>;
98  };
99 };
100 
101 // Case where the forward cast is valid but the backward cast is invalid.
102 template <typename TargetT, typename SourceT, typename SourceStorage>
103 struct ArrayHandleCastTraits<TargetT, SourceT, SourceStorage, true, false>
104 {
105  using StorageTagSuperclass = StorageTagTransform<vtkm::cont::ArrayHandle<SourceT, SourceStorage>,
106  vtkm::cont::internal::Cast<SourceT, TargetT>>;
107  using StorageSuperclass = vtkm::cont::internal::Storage<TargetT, StorageTagSuperclass>;
108 };
109 
110 // Case where both forward and backward casts are valid.
111 template <typename TargetT, typename SourceT, typename SourceStorage>
112 struct ArrayHandleCastTraits<TargetT, SourceT, SourceStorage, true, true>
113 {
114  using StorageTagSuperclass = StorageTagTransform<vtkm::cont::ArrayHandle<SourceT, SourceStorage>,
115  vtkm::cont::internal::Cast<SourceT, TargetT>,
116  vtkm::cont::internal::Cast<TargetT, SourceT>>;
117  using StorageSuperclass = vtkm::cont::internal::Storage<TargetT, StorageTagSuperclass>;
118 };
119 
120 } // namespace detail
121 
122 template <typename TargetT, typename SourceT, typename SourceStorage_>
123 struct Storage<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceStorage_>>
124  : detail::ArrayHandleCastTraits<TargetT, SourceT, SourceStorage_>::StorageSuperclass
125 {
126  using Superclass =
127  typename detail::ArrayHandleCastTraits<TargetT, SourceT, SourceStorage_>::StorageSuperclass;
128 
129  using Superclass::Superclass;
130 };
131 
132 } // namespace internal
133 
140 template <typename T, typename ArrayHandleType>
142  : public vtkm::cont::ArrayHandle<
143  T,
144  StorageTagCast<typename ArrayHandleType::ValueType, typename ArrayHandleType::StorageTag>>
145 {
146 public:
151  T,
153 
155  ArrayHandleCast(const vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
156  typename ArrayHandleType::StorageTag>& handle)
157  : Superclass(Superclass::StorageType::CreateBuffers(handle))
158  {
159  this->ValidateTypeCast<typename ArrayHandleType::ValueType>();
160  }
161 
162  // Implemented so that it is defined exclusively in the control environment.
163  // If there is a separate device for the execution environment (for example,
164  // with CUDA), then the automatically generated destructor could be
165  // created for all devices, and it would not be valid for all devices.
167 
169  ArrayHandleType GetSourceArray() const
170  {
171  return Superclass::StorageType::GetArray(this->GetBuffers());
172  }
173 
174 private:
175  // Log warnings if type cast is valid but lossy:
176  template <typename SrcValueType>
177  VTKM_CONT static typename std::enable_if<!std::is_same<T, SrcValueType>::value>::type
179  {
180 #ifdef VTKM_ENABLE_LOGGING
181  using DstValueType = T;
182  using SrcComp = typename vtkm::VecTraits<SrcValueType>::BaseComponentType;
183  using DstComp = typename vtkm::VecTraits<DstValueType>::BaseComponentType;
184  using SrcLimits = std::numeric_limits<SrcComp>;
185  using DstLimits = std::numeric_limits<DstComp>;
186 
187  const vtkm::Range SrcRange{ SrcLimits::lowest(), SrcLimits::max() };
188  const vtkm::Range DstRange{ DstLimits::lowest(), DstLimits::max() };
189 
190  const bool RangeLoss = (SrcRange.Max > DstRange.Max || SrcRange.Min < DstRange.Min);
191  const bool PrecLoss = SrcLimits::digits > DstLimits::digits;
192 
193  if (RangeLoss && PrecLoss)
194  {
196  "ArrayHandleCast: Casting ComponentType of "
197  "%s to %s reduces range and precision.",
198  vtkm::cont::TypeToString<SrcValueType>().c_str(),
199  vtkm::cont::TypeToString<DstValueType>().c_str());
200  }
201  else if (RangeLoss)
202  {
204  "ArrayHandleCast: Casting ComponentType of "
205  "%s to %s reduces range.",
206  vtkm::cont::TypeToString<SrcValueType>().c_str(),
207  vtkm::cont::TypeToString<DstValueType>().c_str());
208  }
209  else if (PrecLoss)
210  {
212  "ArrayHandleCast: Casting ComponentType of "
213  "%s to %s reduces precision.",
214  vtkm::cont::TypeToString<SrcValueType>().c_str(),
215  vtkm::cont::TypeToString<DstValueType>().c_str());
216  }
217 #endif // Logging
218  }
219 
220  template <typename SrcValueType>
221  VTKM_CONT static typename std::enable_if<std::is_same<T, SrcValueType>::value>::type
223  {
224  //no-op if types match
225  }
226 };
227 
228 namespace detail
229 {
230 
231 template <typename CastType, typename OriginalType, typename ArrayType>
232 struct MakeArrayHandleCastImpl
233 {
235 
236  VTKM_CONT static ReturnType DoMake(const ArrayType& array) { return ReturnType(array); }
237 };
238 
239 template <typename T, typename ArrayType>
240 struct MakeArrayHandleCastImpl<T, T, ArrayType>
241 {
242  using ReturnType = ArrayType;
243 
244  VTKM_CONT static ReturnType DoMake(const ArrayType& array) { return array; }
245 };
246 
247 } // namespace detail
248 
252 template <typename T, typename ArrayType>
253 VTKM_CONT
254  typename detail::MakeArrayHandleCastImpl<T, typename ArrayType::ValueType, ArrayType>::ReturnType
255  make_ArrayHandleCast(const ArrayType& array, const T& = T())
256 {
257  VTKM_IS_ARRAY_HANDLE(ArrayType);
258  using MakeImpl = detail::MakeArrayHandleCastImpl<T, typename ArrayType::ValueType, ArrayType>;
259  return MakeImpl::DoMake(array);
260 }
261 }
262 } // namespace vtkm::cont
263 
264 //=============================================================================
265 // Specializations of serialization related classes
267 
268 namespace vtkm
269 {
270 namespace cont
271 {
272 
273 template <typename T, typename AH>
274 struct SerializableTypeString<vtkm::cont::ArrayHandleCast<T, AH>>
275 {
276  static VTKM_CONT const std::string& Get()
277  {
278  static std::string name =
280  return name;
281  }
282 };
283 
284 template <typename T1, typename T2, typename S>
285 struct SerializableTypeString<vtkm::cont::ArrayHandle<T1, vtkm::cont::StorageTagCast<T2, S>>>
286  : SerializableTypeString<vtkm::cont::ArrayHandleCast<T1, vtkm::cont::ArrayHandle<T2, S>>>
287 {
288 };
289 }
290 } // namespace vtkm::cont
291 
292 namespace mangled_diy_namespace
293 {
294 
295 template <typename TargetT, typename SourceT, typename SourceStorage>
296 struct Serialization<
297  vtkm::cont::ArrayHandle<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceStorage>>>
298 {
299 private:
300  using BaseType =
302 
303 public:
304  static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
305  {
307  castArray = obj;
308  vtkmdiy::save(bb, castArray.GetSourceArray());
309  }
310 
311  static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)
312  {
314  vtkmdiy::load(bb, array);
315  obj = vtkm::cont::make_ArrayHandleCast<TargetT>(array);
316  }
317 };
318 
319 template <typename TargetT, typename AH>
320 struct Serialization<vtkm::cont::ArrayHandleCast<TargetT, AH>>
321  : Serialization<vtkm::cont::ArrayHandle<
322  TargetT,
323  vtkm::cont::StorageTagCast<typename AH::ValueType, typename AH::StorageTag>>>
324 {
325 };
326 
327 } // diy
329 
330 #endif // vtk_m_cont_ArrayHandleCast_h
vtkm::cont::ArrayHandle
Manages an array-worth of data.
Definition: ArrayHandle.h:300
vtkm::cont::ArrayHandle< T, StorageTagCast< ArrayHandleType::ValueType, ArrayHandleType::StorageTag > >::GetBuffers
const std::vector< vtkm::cont::internal::Buffer > & GetBuffers() const
Returns the internal Buffer structures that hold the data.
Definition: ArrayHandle.h:721
vtkm::exec::arg::load
T load(const U &u, vtkm::Id v)
Definition: FetchTagArrayDirectIn.h:36
vtkm::cont::make_ArrayHandleCast
detail::MakeArrayHandleCastImpl< T, typename ArrayType::ValueType, ArrayType >::ReturnType make_ArrayHandleCast(const ArrayType &array, const T &=T())
make_ArrayHandleCast is convenience function to generate an ArrayHandleCast.
Definition: ArrayHandleCast.h:255
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
vtkm::Get
auto Get(const vtkm::Tuple< Ts... > &tuple)
Retrieve the object from a vtkm::Tuple at the given index.
Definition: Tuple.h:81
VTKM_ARRAY_HANDLE_SUBCLASS
#define VTKM_ARRAY_HANDLE_SUBCLASS(classname, fullclasstype, superclass)
Macro to make default methods in ArrayHandle subclasses.
Definition: ArrayHandle.h:243
vtkm::cont::ArrayHandleCast::~ArrayHandleCast
~ArrayHandleCast()
Definition: ArrayHandleCast.h:166
vtkm::cont::LogLevel::Warn
@ Warn
Less important user errors, such as out-of-bounds parameters.
VTKM_EXEC_CONT
#define VTKM_EXEC_CONT
Definition: ExportMacros.h:52
vtkm::cont::ArrayHandleCast::ValidateTypeCast
static std::enable_if<!std::is_same< T, SrcValueType >::value >::type ValidateTypeCast()
Definition: ArrayHandleCast.h:178
ArrayHandleTransform.h
mangled_diy_namespace
Definition: Particle.h:351
vtkm::VecTraits::BaseComponentType
T BaseComponentType
Base component type in the vector.
Definition: VecTraits.h:78
vtkm::cont::StorageTagCast
Definition: ArrayHandleCast.h:28
vtkm::cont::ArrayHandleCast::ValidateTypeCast
static std::enable_if< std::is_same< T, SrcValueType >::value >::type ValidateTypeCast()
Definition: ArrayHandleCast.h:222
vtkm::cont::ArrayHandleCast::GetSourceArray
ArrayHandleType GetSourceArray() const
Returns the ArrayHandle that is being transformed.
Definition: ArrayHandleCast.h:169
vtkm::cont::ArrayHandleCast::StorageType
typename Superclass::StorageType StorageType
Definition: ArrayHandleCast.h:152
VTKM_IS_ARRAY_HANDLE
#define VTKM_IS_ARRAY_HANDLE(T)
Checks that the given type is a vtkm::cont::ArrayHandle.
Definition: ArrayHandle.h:137
Range.h
VTKM_LOG_F
#define VTKM_LOG_F(level,...)
Writes a message using printf syntax to the indicated log level.
Definition: Logging.h:209
VTKM_CONT
#define VTKM_CONT
Definition: ExportMacros.h:57
vtkm::cont::ArrayHandleCast::ArrayHandleCast
ArrayHandleCast(const vtkm::cont::ArrayHandle< typename ArrayHandleType::ValueType, typename ArrayHandleType::StorageTag > &handle)
Construct an ArrayHandleCast from a source array handle.
Definition: ArrayHandleCast.h:155
vtkm::cont::Cast
ArrayHandleType Cast(const vtkm::cont::UnknownArrayHandle &array)
Returns variant cast to the given ArrayHandle type.
Definition: UnknownArrayHandle.h:1246
vtkm::cont::ArrayHandleCast::Superclass
typename vtkm::cont::detail::GetTypeInParentheses< void(vtkm::cont::ArrayHandle< T, StorageTagCast< typename ArrayHandleType::ValueType, typename ArrayHandleType::StorageTag > >) >::type Superclass
Definition: ArrayHandleCast.h:152
vtkm::cont::ArrayHandleCast
Cast the values of an array to the specified type, on demand.
Definition: ArrayHandleCast.h:141
VTKM_ALWAYS_EXPORT
#define VTKM_ALWAYS_EXPORT
Definition: ExportMacros.h:89
Logging.h
Logging utilities.
VecTraits.h
vtkm::Range
Represent a continuous scalar range of values.
Definition: Range.h:31