Viskores  1.0
ArrayHandleDecorator.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_ArrayHandleDecorator_h
19 #define viskores_ArrayHandleDecorator_h
20 
23 #include <viskores/cont/Storage.h>
24 
25 #include <viskores/List.h>
26 #include <viskores/StaticAssert.h>
27 #include <viskores/Tuple.h>
28 #include <viskores/VecTraits.h>
29 
31 
32 #include <viskoresstd/integer_sequence.h>
33 
34 #include <array>
35 #include <numeric>
36 #include <type_traits>
37 #include <utility>
38 
39 namespace viskores
40 {
41 namespace internal
42 {
43 
44 namespace decor
45 {
46 
47 // Generic InverseFunctor implementation that does nothing.
48 struct NoOpInverseFunctor
49 {
50  NoOpInverseFunctor() = default;
51  template <typename... Ts>
52  VISKORES_EXEC_CONT NoOpInverseFunctor(Ts...)
53  {
54  }
55  template <typename VT>
56  VISKORES_EXEC_CONT void operator()(viskores::Id, VT) const
57  {
58  }
59 };
60 
61 } // namespace decor
62 
63 // The portal for ArrayHandleDecorator. Get calls FunctorType::operator(), and
64 // Set calls InverseFunctorType::operator(), but only if the DecoratorImpl
65 // provides an inverse.
66 template <typename ValueType_, typename FunctorType_, typename InverseFunctorType_>
67 class VISKORES_ALWAYS_EXPORT ArrayPortalDecorator
68 {
69 public:
70  using ValueType = ValueType_;
71  using FunctorType = FunctorType_;
72  using InverseFunctorType = InverseFunctorType_;
73  using ReadOnly = std::is_same<InverseFunctorType, decor::NoOpInverseFunctor>;
74 
76  ArrayPortalDecorator() {}
77 
79  ArrayPortalDecorator(FunctorType func, InverseFunctorType iFunc, viskores::Id numValues)
80  : Functor(func)
81  , InverseFunctor(iFunc)
82  , NumberOfValues(numValues)
83  {
84  }
85 
87  viskores::Id GetNumberOfValues() const { return this->NumberOfValues; }
88 
90  ValueType Get(viskores::Id index) const { return this->Functor(index); }
91 
92  template <typename ReadOnly_ = ReadOnly,
93  typename = typename std::enable_if<!ReadOnly_::value>::type>
94  VISKORES_EXEC_CONT void Set(viskores::Id index, const ValueType& value) const
95  {
96  this->InverseFunctor(index, value);
97  }
98 
99 private:
100  FunctorType Functor;
101  InverseFunctorType InverseFunctor;
102  viskores::Id NumberOfValues;
103 };
104 }
105 } // namespace viskores::internal
106 
107 namespace viskores
108 {
109 namespace cont
110 {
111 
112 namespace internal
113 {
114 
115 namespace decor
116 {
117 
118 // Ensures that all types in variadic container ArrayHandleList are subclasses
119 // of ArrayHandleBase.
120 template <typename ArrayHandleList>
121 using AllAreArrayHandles =
123 
124 namespace detail
125 {
126 
127 // Tests whether DecoratorImplT has a CreateInverseFunctor(Portals...) method.
128 template <typename DecoratorImplT, typename PortalList>
129 struct IsFunctorInvertibleImpl;
130 
131 template <typename DecoratorImplT, template <typename...> class List, typename... PortalTs>
132 struct IsFunctorInvertibleImpl<DecoratorImplT, List<PortalTs...>>
133 {
134 private:
135  template <
136  typename T,
137  typename U = decltype(std::declval<T>().CreateInverseFunctor(std::declval<PortalTs&&>()...))>
138  static std::true_type InverseExistsTest(int);
139 
140  template <typename T>
141  static std::false_type InverseExistsTest(...);
142 
143 public:
144  using type = decltype(InverseExistsTest<DecoratorImplT>(0));
145 };
146 
147 // Tests whether DecoratorImplT has an AllocateSourceArrays(size, Arrays...) method.
148 template <typename DecoratorImplT, typename ArrayList>
149 struct IsDecoratorAllocatableImpl;
150 
151 template <typename DecoratorImplT, template <typename...> class List, typename... ArrayTs>
152 struct IsDecoratorAllocatableImpl<DecoratorImplT, List<ArrayTs...>>
153 {
154 private:
155  template <typename T,
156  typename U = decltype(std::declval<T>().AllocateSourceArrays(
157  0,
159  std::declval<viskores::cont::Token&>(),
160  std::declval<ArrayTs&>()...))>
161  static std::true_type Exists(int);
162  template <typename T>
163  static std::false_type Exists(...);
164 
165 public:
166  using type = decltype(Exists<DecoratorImplT>(0));
167 };
168 
169 // Deduces the type returned by DecoratorImplT::CreateFunctor when given
170 // the specified portals.
171 template <typename DecoratorImplT, typename PortalList>
172 struct GetFunctorTypeImpl;
173 
174 template <typename DecoratorImplT, template <typename...> class List, typename... PortalTs>
175 struct GetFunctorTypeImpl<DecoratorImplT, List<PortalTs...>>
176 {
177  using type =
178  decltype(std::declval<DecoratorImplT>().CreateFunctor(std::declval<PortalTs&&>()...));
179 };
180 
181 // Deduces the type returned by DecoratorImplT::CreateInverseFunctor when given
182 // the specified portals. If DecoratorImplT doesn't have a CreateInverseFunctor
183 // method, a NoOp functor will be used instead.
184 template <typename CanWrite, typename DecoratorImplT, typename PortalList>
185 struct GetInverseFunctorTypeImpl;
186 
187 template <typename DecoratorImplT, template <typename...> class List, typename... PortalTs>
188 struct GetInverseFunctorTypeImpl<std::true_type, DecoratorImplT, List<PortalTs...>>
189 {
190  using type =
191  decltype(std::declval<DecoratorImplT>().CreateInverseFunctor(std::declval<PortalTs&&>()...));
192 };
193 
194 template <typename DecoratorImplT, typename PortalList>
195 struct GetInverseFunctorTypeImpl<std::false_type, DecoratorImplT, PortalList>
196 {
197  using type = viskores::internal::decor::NoOpInverseFunctor;
198 };
199 
200 // Get appropriate portals from a source array.
201 // See note below about using non-writable portals in invertible functors.
202 // We need to sub in const portals when writable ones don't exist.
203 template <typename ArrayT>
204 typename std::decay<ArrayT>::type::WritePortalType GetWritePortalImpl(
205  std::true_type,
206  ArrayT&& array,
208  viskores::cont::Token& token)
209 {
210  return ArrayT::StorageType::CreateWritePortal(array.GetBuffers(), device, token);
211 }
212 
213 template <typename ArrayT>
214 typename std::decay<ArrayT>::type::ReadPortalType GetWritePortalImpl(
215  std::false_type,
216  ArrayT&& array,
218  viskores::cont::Token& token)
219 {
220  return ArrayT::StorageType::CreateReadPortal(array.GetBuffers(), device, token);
221 }
222 
223 } // namespace detail
224 
225 // Get portal types:
226 // We allow writing to an AHDecorator if *any* of the ArrayHandles are writable.
227 // This means we have to avoid calling PrepareForOutput, etc on non-writable
228 // array handles, since these may throw. On non-writable handles, use the
229 // const array handles so we can at least read from them in the inverse
230 // functors.
231 template <typename ArrayT>
232 using GetWritePortalType = std::conditional_t<
233  viskores::internal::PortalSupportsSets<typename std::decay<ArrayT>::type::WritePortalType>::value,
234  typename std::decay<ArrayT>::type::WritePortalType,
235  typename std::decay<ArrayT>::type::ReadPortalType>;
236 
237 template <typename ArrayT>
238 using GetReadPortalType = typename std::decay<ArrayT>::type::ReadPortalType;
239 
240 // Get portal objects:
241 // See note above -- we swap in const portals sometimes.
242 template <typename ArrayT>
243 GetWritePortalType<typename std::decay<ArrayT>::type>
244 WritePortal(ArrayT&& array, viskores::cont::DeviceAdapterId device, viskores::cont::Token& token)
245 {
246  return detail::GetWritePortalImpl(
247  IsWritableArrayHandle<ArrayT>{}, std::forward<ArrayT>(array), device, token);
248 }
249 
250 template <typename ArrayT>
251 GetReadPortalType<typename std::decay<ArrayT>::type> ReadPortal(
252  const ArrayT& array,
254  viskores::cont::Token& token)
255 {
256  return ArrayT::StorageType::CreateReadPortal(array.GetBuffers(), device, token);
257 }
258 
259 // Equivalent to std::true_type if *any* portal in PortalList can be written to.
260 // If all are read-only, std::false_type is used instead.
261 template <typename PortalList>
263 
264 // Set to std::true_type if DecoratorImplT::CreateInverseFunctor can be called
265 // with the supplied portals, or std::false_type otherwise.
266 template <typename DecoratorImplT, typename PortalList>
267 using IsFunctorInvertible =
268  typename detail::IsFunctorInvertibleImpl<DecoratorImplT, PortalList>::type;
269 
270 // Set to std::true_type if DecoratorImplT::AllocateSourceArrays can be called
271 // with the supplied arrays, or std::false_type otherwise.
272 template <typename DecoratorImplT, typename ArrayList>
273 using IsDecoratorAllocatable =
274  typename detail::IsDecoratorAllocatableImpl<DecoratorImplT, ArrayList>::type;
275 
276 // std::true_type/std::false_type depending on whether the decorator impl has a
277 // CreateInversePortal method AND any of the arrays are writable.
278 template <typename DecoratorImplT, typename PortalList>
279 using CanWriteToFunctor =
280  viskores::internal::meta::And<IsFunctorInvertible<DecoratorImplT, PortalList>,
281  AnyPortalIsWritable<PortalList>>;
282 
283 // The FunctorType for the provided implementation and portal types.
284 template <typename DecoratorImplT, typename PortalList>
285 using GetFunctorType = typename detail::GetFunctorTypeImpl<DecoratorImplT, PortalList>::type;
286 
287 // The InverseFunctorType for the provided implementation and portal types.
288 // Will detect when inversion is not possible and return a NoOp functor instead.
289 template <typename DecoratorImplT, typename PortalList>
290 using GetInverseFunctorType =
291  typename detail::GetInverseFunctorTypeImpl<CanWriteToFunctor<DecoratorImplT, PortalList>,
292  DecoratorImplT,
293  PortalList>::type;
294 
295 // Convert a sequence of array handle types to a list of portals:
296 
297 // Some notes on this implementation:
298 // - A more straightforward way to implement these to types would be to take
299 // a simple template that takes a viskores::List of array types and convert
300 // that with viskores::ListTransform<ArrayList, GetWritePortalType>. However,
301 // this causes a strange compiler error in VS 2017 when evaluating the
302 // `ValueType` in `DecoratorStorageTraits`. (It does not recognize the
303 // decorator impl functor as a function taking one argument, even when it
304 // effectively is.) A previous similar implementation caused an ICE in
305 // VS 2015 (although that compiler is no longer supported anyway).
306 // - The same problem happens with VS 2017 if you just try to create a list
307 // with viskores::List<GetWritePortalType<ArrayTs>...>.
308 // - So we jump through some decltype/declval hoops here to get this to work:
309 template <typename... ArrayTs>
310 using GetReadPortalList =
312  std::declval<viskores::cont::DeviceAdapterId>(),
313  std::declval<viskores::cont::Token&>())))...>;
314 
315 template <typename... ArrayTs>
316 using GetWritePortalList =
318  std::declval<viskores::cont::DeviceAdapterId>(),
319  std::declval<viskores::cont::Token&>())))...>;
320 
321 template <typename DecoratorImplT, std::size_t NumArrays>
322 struct DecoratorMetaData
323 {
324  DecoratorImplT Implementation;
325  viskores::Id NumberOfValues = 0;
326  std::array<std::size_t, NumArrays + 1> BufferOffsets;
327 
328  template <typename... ArrayTs>
329  DecoratorMetaData(const DecoratorImplT& implementation,
330  viskores::Id numValues,
331  const ArrayTs... arrays)
332  : Implementation(implementation)
333  , NumberOfValues(numValues)
334  {
335  auto numBuffers = { std::size_t{ 1 }, arrays.GetBuffers().size()... };
336  std::partial_sum(numBuffers.begin(), numBuffers.end(), this->BufferOffsets.begin());
337  }
338 
339  DecoratorMetaData() = default;
340 };
341 
342 template <typename DecoratorImplT, typename... ArrayTs>
343 struct DecoratorStorageTraits
344 {
345  using ArrayList = viskores::List<ArrayTs...>;
346 
347  VISKORES_STATIC_ASSERT_MSG(sizeof...(ArrayTs) > 0,
348  "Must specify at least one source array handle for "
349  "ArrayHandleDecorator. Consider using "
350  "ArrayHandleImplicit instead.");
351 
352  // Need to check this here, since this traits struct is used in the
353  // ArrayHandleDecorator superclass definition before any other
354  // static_asserts could be used.
355  VISKORES_STATIC_ASSERT_MSG(decor::AllAreArrayHandles<ArrayList>::value,
356  "Trailing template parameters for "
357  "ArrayHandleDecorator must be a list of ArrayHandle "
358  "types.");
359 
360  using ArrayTupleType = viskores::Tuple<ArrayTs...>;
361 
362  // size_t integral constants that index ArrayTs:
363  using IndexList = viskoresstd::make_index_sequence<sizeof...(ArrayTs)>;
364 
365  using MetaData = DecoratorMetaData<DecoratorImplT, sizeof...(ArrayTs)>;
366 
367  static MetaData& GetMetaData(const std::vector<viskores::cont::internal::Buffer>& buffers)
368  {
369  return buffers[0].GetMetaData<MetaData>();
370  }
371 
372  // Converts a buffers array to the ArrayHandle at the given index.
373  template <viskores::IdComponent I>
374  static viskores::TupleElement<I, ArrayTupleType> BuffersToArray(
375  const std::vector<viskores::cont::internal::Buffer>& buffers)
376  {
377  const MetaData& metaData = GetMetaData(buffers);
378  std::vector<viskores::cont::internal::Buffer> subBuffers(
379  buffers.begin() + metaData.BufferOffsets[I], buffers.begin() + metaData.BufferOffsets[I + 1]);
380  return viskores::TupleElement<I, ArrayTupleType>(std::move(subBuffers));
381  }
382 
383  // true_type/false_type depending on whether the decorator supports Allocate:
384  using IsAllocatable = IsDecoratorAllocatable<DecoratorImplT, ArrayList>;
385 
386  // Portal lists:
387  // NOTE we have to pass the parameter pack here instead of using ArrayList
388  // with viskores::ListTransform, since that's causing problems with VS 2017:
389  using WritePortalList = GetWritePortalList<ArrayTs...>;
390  using ReadPortalList = GetReadPortalList<ArrayTs...>;
391 
392  // Functors:
393  using WriteFunctorType = GetFunctorType<DecoratorImplT, WritePortalList>;
394  using ReadFunctorType = GetFunctorType<DecoratorImplT, ReadPortalList>;
395 
396  // Inverse functors:
397  using InverseWriteFunctorType = GetInverseFunctorType<DecoratorImplT, WritePortalList>;
398 
399  using InverseReadFunctorType = viskores::internal::decor::NoOpInverseFunctor;
400 
401  // Misc:
402  // ValueType is derived from DecoratorImplT::CreateFunctor(...)'s operator().
403  using ValueType = decltype(std::declval<WriteFunctorType>()(0));
404 
405  // Decorator portals:
406  using WritePortalType =
407  viskores::internal::ArrayPortalDecorator<ValueType, WriteFunctorType, InverseWriteFunctorType>;
408 
409  using ReadPortalType =
410  viskores::internal::ArrayPortalDecorator<ValueType, ReadFunctorType, InverseReadFunctorType>;
411 
412  // helper for constructing portals with the appropriate functors. This is
413  // where we decide whether or not to call `CreateInverseFunctor` on the
414  // implementation class.
415  // Do not use these directly, they are helpers for the MakePortal[...]
416  // methods below.
417  template <typename DecoratorPortalType, typename... PortalTs>
418  VISKORES_CONT static
419  typename std::enable_if<DecoratorPortalType::ReadOnly::value, DecoratorPortalType>::type
420  CreatePortalDecorator(viskores::Id numVals, const DecoratorImplT& impl, PortalTs&&... portals)
421  { // Portal is read only:
422  return { impl.CreateFunctor(std::forward<PortalTs>(portals)...),
423  typename DecoratorPortalType::InverseFunctorType{},
424  numVals };
425  }
426 
427  template <typename DecoratorPortalType, typename... PortalTs>
428  VISKORES_CONT static
429  typename std::enable_if<!DecoratorPortalType::ReadOnly::value, DecoratorPortalType>::type
430  CreatePortalDecorator(viskores::Id numVals, const DecoratorImplT& impl, PortalTs... portals)
431  { // Portal is read/write:
432  return { impl.CreateFunctor(portals...), impl.CreateInverseFunctor(portals...), numVals };
433  }
434 
435  // Static dispatch for calling AllocateSourceArrays on supported implementations:
436  VISKORES_CONT [[noreturn]] static void CallAllocate(
437  std::false_type,
438  viskores::Id,
439  const std::vector<viskores::cont::internal::Buffer>&,
442  ArrayTs...)
443  {
444  throw viskores::cont::ErrorBadType("Allocate not supported by this ArrayHandleDecorator.");
445  }
446 
447  VISKORES_CONT static void CallAllocate(
448  std::true_type,
449  viskores::Id newSize,
450  const std::vector<viskores::cont::internal::Buffer>& buffers,
451  viskores::CopyFlag preserve,
452  viskores::cont::Token& token,
453  ArrayTs... arrays)
454  {
455  MetaData& metadata = GetMetaData(buffers);
456  metadata.Implementation.AllocateSourceArrays(newSize, preserve, token, arrays...);
457  metadata.NumberOfValues = newSize;
458  }
459 
460 
461  // Portal construction methods. These actually create portals.
462  template <std::size_t... Indices>
463  VISKORES_CONT static WritePortalType CreateWritePortal(
464  const std::vector<viskores::cont::internal::Buffer>& buffers,
465  viskores::Id numValues,
466  viskoresstd::index_sequence<Indices...>,
468  viskores::cont::Token& token)
469  {
470  return CreatePortalDecorator<WritePortalType>(
471  numValues,
472  GetMetaData(buffers).Implementation,
473  WritePortal(BuffersToArray<Indices>(buffers), device, token)...);
474  }
475 
476  template <std::size_t... Indices>
477  VISKORES_CONT static ReadPortalType CreateReadPortal(
478  const std::vector<viskores::cont::internal::Buffer>& buffers,
479  viskores::Id numValues,
480  viskoresstd::index_sequence<Indices...>,
482  viskores::cont::Token& token)
483  {
484  return CreatePortalDecorator<ReadPortalType>(
485  numValues,
486  GetMetaData(buffers).Implementation,
487  ReadPortal(BuffersToArray<Indices>(buffers), device, token)...);
488  }
489 
490  template <std::size_t... Indices>
491  VISKORES_CONT static void AllocateSourceArrays(
492  viskores::Id numValues,
493  const std::vector<viskores::cont::internal::Buffer>& buffers,
494  viskores::CopyFlag preserve,
495  viskores::cont::Token& token,
496  viskoresstd::index_sequence<Indices...>)
497  {
498  CallAllocate(
499  IsAllocatable{}, numValues, buffers, preserve, token, BuffersToArray<Indices>(buffers)...);
500  }
501 };
502 
503 } // end namespace decor
504 
505 template <typename DecoratorImplT, typename... ArrayTs>
506 struct VISKORES_ALWAYS_EXPORT StorageTagDecorator
507 {
508 };
509 
510 template <typename DecoratorImplT, typename... ArrayTs>
511 class Storage<typename decor::DecoratorStorageTraits<DecoratorImplT, ArrayTs...>::ValueType,
512  StorageTagDecorator<DecoratorImplT, ArrayTs...>>
513 {
514  using Traits = decor::DecoratorStorageTraits<DecoratorImplT, ArrayTs...>;
515  using IndexList = typename Traits::IndexList;
516  using MetaData = typename Traits::MetaData;
517 
518 public:
519  using ReadPortalType = typename Traits::ReadPortalType;
520  using WritePortalType = typename Traits::WritePortalType;
521 
522 private:
523  VISKORES_CONT static viskores::IdComponent GetNumberOfComponentsFlatImpl(
525  {
527  }
528 
529  VISKORES_CONT static viskores::IdComponent GetNumberOfComponentsFlatImpl(
531  {
532  // Currently only support getting the number of components for statically sized types.
533  return 0;
534  }
535 
536 public:
537  VISKORES_CONT static viskores::IdComponent GetNumberOfComponentsFlat(
538  const std::vector<viskores::cont::internal::Buffer>&)
539  {
540  return GetNumberOfComponentsFlatImpl(
542  }
543 
544  VISKORES_CONT static viskores::Id GetNumberOfValues(
545  const std::vector<viskores::cont::internal::Buffer>& buffers)
546  {
547  return Traits::GetMetaData(buffers).NumberOfValues;
548  }
549 
550  VISKORES_CONT static void ResizeBuffers(
551  viskores::Id numValues,
552  const std::vector<viskores::cont::internal::Buffer>& buffers,
553  viskores::CopyFlag preserve,
554  viskores::cont::Token& token)
555  {
556  if (numValues != GetNumberOfValues(buffers))
557  {
558  Traits::AllocateSourceArrays(numValues, buffers, preserve, token, IndexList{});
559  }
560  else
561  {
562  // Do nothing. We have this condition to allow allocating the same size when the
563  // array cannot be resized.
564  }
565  }
566 
567  VISKORES_CONT static ReadPortalType CreateReadPortal(
568  const std::vector<viskores::cont::internal::Buffer>& buffers,
570  viskores::cont::Token& token)
571  {
572  return Traits::CreateReadPortal(
573  buffers, GetNumberOfValues(buffers), IndexList{}, device, token);
574  }
575 
576  VISKORES_CONT static WritePortalType CreateWritePortal(
577  const std::vector<viskores::cont::internal::Buffer>& buffers,
579  viskores::cont::Token& token)
580  {
581  return Traits::CreateWritePortal(
582  buffers, GetNumberOfValues(buffers), IndexList{}, device, token);
583  }
584 
585  VISKORES_CONT static std::vector<viskores::cont::internal::Buffer> CreateBuffers(
586  const DecoratorImplT& implementation,
587  viskores::Id numValues,
588  const ArrayTs&... arrays)
589  {
590  return viskores::cont::internal::CreateBuffers(MetaData(implementation, numValues, arrays...),
591  arrays...);
592  }
593 
594  VISKORES_CONT static std::vector<viskores::cont::internal::Buffer> CreateBuffers()
595  {
596  return CreateBuffers(DecoratorImplT{}, 0, ArrayTs{}...);
597  }
598 };
599 
600 template <typename DecoratorImplT, typename... ArrayTs>
601 struct DecoratorHandleTraits
602 {
603  using StorageTraits = decor::DecoratorStorageTraits<DecoratorImplT, ArrayTs...>;
604  using ValueType = typename StorageTraits::ValueType;
605  using StorageTag = StorageTagDecorator<DecoratorImplT, ArrayTs...>;
607 };
608 
609 } // namespace internal
610 
683 template <typename DecoratorImplT, typename... ArrayTs>
685  : public internal::DecoratorHandleTraits<typename std::decay<DecoratorImplT>::type,
686  typename std::decay<ArrayTs>::type...>::Superclass
687 {
688 private:
689  using Traits = internal::DecoratorHandleTraits<typename std::decay<DecoratorImplT>::type,
690  typename std::decay<ArrayTs>::type...>;
691 
692 public:
694  (ArrayHandleDecorator<typename std::decay<DecoratorImplT>::type,
695  typename std::decay<ArrayTs>::type...>),
696  (typename Traits::Superclass));
697 
700  const typename std::decay<DecoratorImplT>::type& impl,
701  const typename std::decay<ArrayTs>::type&... arrays)
702  : Superclass{ StorageType::CreateBuffers(impl, numValues, arrays...) }
703  {
704  }
705 };
706 
710 template <typename DecoratorImplT, typename... ArrayTs>
711 VISKORES_CONT ArrayHandleDecorator<typename std::decay<DecoratorImplT>::type,
712  typename std::decay<ArrayTs>::type...>
713 make_ArrayHandleDecorator(viskores::Id numValues, DecoratorImplT&& f, ArrayTs&&... arrays)
714 {
716  VISKORES_STATIC_ASSERT_MSG(sizeof...(ArrayTs) > 0,
717  "Must specify at least one source array handle for "
718  "ArrayHandleDecorator. Consider using "
719  "ArrayHandleImplicit instead.");
720  VISKORES_STATIC_ASSERT_MSG(internal::decor::AllAreArrayHandles<AHList>::value,
721  "Trailing template parameters for "
722  "ArrayHandleDecorator must be a list of ArrayHandle "
723  "types.");
724 
725  return { numValues, std::forward<DecoratorImplT>(f), std::forward<ArrayTs>(arrays)... };
726 }
727 }
728 } // namespace viskores::cont
729 
730 #ifdef VISKORES_USE_TAO_SEQ
731 #undef VISKORES_USE_TAO_SEQ
732 #endif
733 
734 #endif //viskores_ArrayHandleDecorator_h
viskores::VecFlat
Treat a Vec or Vec-like object as a flat Vec.
Definition: VecFlat.h:240
ArrayHandle.h
viskores::CopyFlag::Off
@ Off
ArrayPortalHelpers.h
viskores::VecTraitsTagSizeStatic
A tag for vectors where the number of components are known at compile time.
Definition: VecTraits.h:44
viskores::cont::ErrorBadType
This class is thrown when Viskores encounters data of a type that is incompatible with the current op...
Definition: ErrorBadType.h:33
viskores::TupleElement
typename detail::TupleElementImpl< Index, TupleType >::type TupleElement
Becomes the type of the given index for the given viskores::Tuple.
Definition: Tuple.h:71
viskores::cont::ArrayHandleDecorator::Traits
internal::DecoratorHandleTraits< typename std::decay< DecoratorImplT >::type, typename std::decay< ArrayTs >::type... > Traits
Definition: ArrayHandleDecorator.h:690
viskores::VecTraitsTagSizeVariable
A tag for vectors where the number of components are not determined until run time.
Definition: VecTraits.h:51
Storage.h
viskores::cont::ArrayHandle
Manages an array-worth of data.
Definition: ArrayHandle.h:313
viskores::ListAny
viskores::ListReduce< viskores::ListTransform< List, Predicate >, viskores::internal::meta::Or, std::false_type > ListAny
Determines whether any of the types in the list are "true.".
Definition: List.h:891
viskores::IdComponent
viskores::Int32 IdComponent
Base type to use to index small lists.
Definition: Types.h:202
VISKORES_EXEC_CONT
#define VISKORES_EXEC_CONT
Definition: ExportMacros.h:60
viskores::List
A template used to hold a list of types.
Definition: List.h:47
viskores::Id
viskores::Int64 Id
Base type to use to index arrays.
Definition: Types.h:235
VISKORES_CONT
#define VISKORES_CONT
Definition: ExportMacros.h:65
viskores
Groups connected points that have the same field value.
Definition: Atomic.h:27
viskores::ListAll
viskores::ListReduce< viskores::ListTransform< List, Predicate >, viskores::internal::meta::And, std::true_type > ListAll
Determines whether all the types in the list are "true.".
Definition: List.h:865
viskores::cont::ArrayHandleDecorator
A fancy ArrayHandle that can be used to modify the results from one or more source ArrayHandle.
Definition: ArrayHandleDecorator.h:684
VISKORES_STATIC_ASSERT_MSG
#define VISKORES_STATIC_ASSERT_MSG(condition, message)
Definition: StaticAssert.h:26
viskores::cont::DeviceAdapterId
An object used to specify a device.
Definition: DeviceAdapterTag.h:66
viskores::cont::make_ArrayHandleDecorator
ArrayHandleDecorator< typename std::decay< DecoratorImplT >::type, typename std::decay< ArrayTs >::type... > make_ArrayHandleDecorator(viskores::Id numValues, DecoratorImplT &&f, ArrayTs &&... arrays)
Create an ArrayHandleDecorator with the specified number of values that uses the provided DecoratorIm...
Definition: ArrayHandleDecorator.h:713
StaticAssert.h
viskores::cont::ArrayHandleDecorator::ArrayHandleDecorator
ArrayHandleDecorator(viskores::Id numValues, const typename std::decay< DecoratorImplT >::type &impl, const typename std::decay< ArrayTs >::type &... arrays)
Definition: ArrayHandleDecorator.h:699
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::Tuple
Viskores replacement for std::tuple.
Definition: Tuple.h:43
viskores::Get
auto Get(const viskores::Tuple< Ts... > &tuple)
Retrieve the object from a viskores::Tuple at the given index.
Definition: Tuple.h:89
ErrorBadType.h
viskores::cont::ArrayHandleDecorator::Superclass
typename viskores::cont::detail::GetTypeInParentheses< void(typename Traits::Superclass) >::type Superclass
Definition: ArrayHandleDecorator.h:696
viskores::CopyFlag
CopyFlag
Identifier used to specify whether a function should deep copy data.
Definition: Flags.h:25
viskores::cont::Token
A token to hold the scope of an ArrayHandle or other object.
Definition: Token.h:43
Tuple.h
VecTraits.h
List.h