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