Viskores  1.0
FunctorsGeneral.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_internal_FunctorsGeneral_h
19 #define viskores_cont_internal_FunctorsGeneral_h
20 
23 #include <viskores/LowerBound.h>
24 #include <viskores/TypeTraits.h>
26 #include <viskores/UpperBound.h>
28 
30 
31 #include <algorithm>
32 #include <atomic>
33 #include <iterator>
34 
35 namespace viskores
36 {
37 namespace cont
38 {
39 namespace internal
40 {
41 
42 // Binary function object wrapper which can detect and handle calling the
43 // wrapped operator with complex value types such as
44 // ArrayPortalValueReference which happen when passed an input array that
45 // is implicit.
46 template <typename ResultType, typename Function>
47 struct WrappedBinaryOperator
48 {
49  Function m_f;
50 
52  WrappedBinaryOperator(const Function& f)
53  : m_f(f)
54  {
55  }
56 
58  template <typename Argument1, typename Argument2>
59  VISKORES_EXEC_CONT ResultType operator()(const Argument1& x, const Argument2& y) const
60  {
61  return static_cast<ResultType>(m_f(x, y));
62  }
63 
65  template <typename Argument1, typename Argument2>
66  VISKORES_EXEC_CONT ResultType
67  operator()(const viskores::internal::ArrayPortalValueReference<Argument1>& x,
68  const viskores::internal::ArrayPortalValueReference<Argument2>& y) const
69  {
70  using ValueTypeX = typename viskores::internal::ArrayPortalValueReference<Argument1>::ValueType;
71  using ValueTypeY = typename viskores::internal::ArrayPortalValueReference<Argument2>::ValueType;
72  return static_cast<ResultType>(m_f((ValueTypeX)x, (ValueTypeY)y));
73  }
74 
76  template <typename Argument1, typename Argument2>
77  VISKORES_EXEC_CONT ResultType
78  operator()(const Argument1& x,
79  const viskores::internal::ArrayPortalValueReference<Argument2>& y) const
80  {
81  using ValueTypeY = typename viskores::internal::ArrayPortalValueReference<Argument2>::ValueType;
82  return static_cast<ResultType>(m_f(x, (ValueTypeY)y));
83  }
84 
86  template <typename Argument1, typename Argument2>
87  VISKORES_EXEC_CONT ResultType
88  operator()(const viskores::internal::ArrayPortalValueReference<Argument1>& x,
89  const Argument2& y) const
90  {
91  using ValueTypeX = typename viskores::internal::ArrayPortalValueReference<Argument1>::ValueType;
92  return static_cast<ResultType>(m_f((ValueTypeX)x, y));
93  }
94 };
95 
96 using DefaultCompareFunctor = viskores::SortLess;
97 
98 //needs to be in a location that TBB DeviceAdapterAlgorithm can reach
99 template <typename T, typename U, class BinaryCompare = DefaultCompareFunctor>
100 struct KeyCompare
101 {
102  KeyCompare()
103  : CompareFunctor()
104  {
105  }
106  explicit KeyCompare(BinaryCompare c)
107  : CompareFunctor(c)
108  {
109  }
110 
113  bool operator()(const viskores::Pair<T, U>& a, const viskores::Pair<T, U>& b) const
114  {
115  return CompareFunctor(a.first, b.first);
116  }
117 
118 private:
119  BinaryCompare CompareFunctor;
120 };
121 
122 template <typename PortalConstType, typename T, typename BinaryFunctor>
123 struct ReduceKernel : viskores::exec::FunctorBase
124 {
125  PortalConstType Portal;
126  T InitialValue;
127  BinaryFunctor BinaryOperator;
128  viskores::Id PortalLength;
129 
131  ReduceKernel()
132  : Portal()
133  , InitialValue()
134  , BinaryOperator()
135  , PortalLength(0)
136  {
137  }
138 
140  ReduceKernel(const PortalConstType& portal, T initialValue, BinaryFunctor binary_functor)
141  : Portal(portal)
142  , InitialValue(initialValue)
143  , BinaryOperator(binary_functor)
144  , PortalLength(portal.GetNumberOfValues())
145  {
146  }
147 
150  T operator()(viskores::Id index) const
151  {
152  const viskores::Id reduceWidth = 16;
153  const viskores::Id offset = index * reduceWidth;
154 
155  if (offset + reduceWidth >= this->PortalLength)
156  {
157  //This will only occur for a single index value, so this is the case
158  //that needs to handle the initialValue
159  T partialSum = static_cast<T>(BinaryOperator(this->InitialValue, this->Portal.Get(offset)));
160  viskores::Id currentIndex = offset + 1;
161  while (currentIndex < this->PortalLength)
162  {
163  partialSum = static_cast<T>(BinaryOperator(partialSum, this->Portal.Get(currentIndex)));
164  ++currentIndex;
165  }
166  return partialSum;
167  }
168  else
169  {
170  //optimize the usecase where all values are valid and we don't
171  //need to check that we might go out of bounds
172  T partialSum =
173  static_cast<T>(BinaryOperator(this->Portal.Get(offset), this->Portal.Get(offset + 1)));
174  for (int i = 2; i < reduceWidth; ++i)
175  {
176  partialSum = static_cast<T>(BinaryOperator(partialSum, this->Portal.Get(offset + i)));
177  }
178  return partialSum;
179  }
180  }
181 };
182 
183 struct ReduceKeySeriesStates
184 {
185  bool fStart; // START of a segment
186  bool fEnd; // END of a segment
187 
190  ReduceKeySeriesStates(bool start = false, bool end = false)
191  : fStart(start)
192  , fEnd(end)
193  {
194  }
195 };
196 
197 template <typename InputPortalType, typename KeyStatePortalType>
198 struct ReduceStencilGeneration : viskores::exec::FunctorBase
199 {
200  InputPortalType Input;
201  KeyStatePortalType KeyState;
202 
204  ReduceStencilGeneration(const InputPortalType& input, const KeyStatePortalType& kstate)
205  : Input(input)
206  , KeyState(kstate)
207  {
208  }
209 
212  void operator()(viskores::Id centerIndex) const
213  {
214  using ValueType = typename InputPortalType::ValueType;
215  using KeyStateType = typename KeyStatePortalType::ValueType;
216 
217  const viskores::Id leftIndex = centerIndex - 1;
218  const viskores::Id rightIndex = centerIndex + 1;
219 
220  //we need to determine which of three states this
221  //index is. It can be:
222  // 1. Middle of a set of equivalent keys.
223  // 2. Start of a set of equivalent keys.
224  // 3. End of a set of equivalent keys.
225  // 4. Both the start and end of a set of keys
226 
227  //we don't have to worry about an array of length 1, as
228  //the calling code handles that use case
229 
230  if (centerIndex == 0)
231  {
232  //this means we are at the start of the array
233  //means we are automatically START
234  //just need to check if we are END
235  const ValueType centerValue = this->Input.Get(centerIndex);
236  const ValueType rightValue = this->Input.Get(rightIndex);
237  const KeyStateType state = ReduceKeySeriesStates(true, rightValue != centerValue);
238  this->KeyState.Set(centerIndex, state);
239  }
240  else if (rightIndex == this->Input.GetNumberOfValues())
241  {
242  //this means we are at the end, so we are at least END
243  //just need to check if we are START
244  const ValueType centerValue = this->Input.Get(centerIndex);
245  const ValueType leftValue = this->Input.Get(leftIndex);
246  const KeyStateType state = ReduceKeySeriesStates(leftValue != centerValue, true);
247  this->KeyState.Set(centerIndex, state);
248  }
249  else
250  {
251  const ValueType centerValue = this->Input.Get(centerIndex);
252  const bool leftMatches(this->Input.Get(leftIndex) == centerValue);
253  const bool rightMatches(this->Input.Get(rightIndex) == centerValue);
254 
255  //assume it is the middle, and check for the other use-case
256  KeyStateType state = ReduceKeySeriesStates(!leftMatches, !rightMatches);
257  this->KeyState.Set(centerIndex, state);
258  }
259  }
260 };
261 
262 template <typename BinaryFunctor>
263 struct ReduceByKeyAdd
264 {
265  BinaryFunctor BinaryOperator;
266 
267  ReduceByKeyAdd(BinaryFunctor binary_functor)
268  : BinaryOperator(binary_functor)
269  {
270  }
271 
272  template <typename T>
276  {
277  using ReturnType = viskores::Pair<T, ReduceKeySeriesStates>;
278  //need too handle how we are going to add two numbers together
279  //based on the keyStates that they have
280 
281  // Make it work for parallel inclusive scan. Will end up with all start bits = 1
282  // the following logic should change if you use a different parallel scan algorithm.
283  if (!b.second.fStart)
284  {
285  // if b is not START, then it's safe to sum a & b.
286  // Propagate a's start flag to b
287  // so that later when b's START bit is set, it means there must exists a START between a and b
288  return ReturnType(this->BinaryOperator(a.first, b.first),
289  ReduceKeySeriesStates(a.second.fStart, b.second.fEnd));
290  }
291  return b;
292  }
293 };
294 
295 struct ReduceByKeyUnaryStencilOp
296 {
298  bool operator()(ReduceKeySeriesStates keySeriesState) const { return keySeriesState.fEnd; }
299 };
300 
301 template <typename T,
302  typename InputPortalType,
303  typename KeyStatePortalType,
304  typename OutputPortalType>
305 struct ShiftCopyAndInit : viskores::exec::FunctorBase
306 {
307  InputPortalType Input;
308  KeyStatePortalType KeyState;
309  OutputPortalType Output;
310  T initValue;
311 
312  ShiftCopyAndInit(const InputPortalType& _input,
313  const KeyStatePortalType& kstate,
314  OutputPortalType& _output,
315  T _init)
316  : Input(_input)
317  , KeyState(kstate)
318  , Output(_output)
319  , initValue(_init)
320  {
321  }
322 
324  void operator()(viskores::Id index) const
325  {
326  if (this->KeyState.Get(index).fStart)
327  {
328  Output.Set(index, initValue);
329  }
330  else
331  {
332  Output.Set(index, Input.Get(index - 1));
333  }
334  }
335 };
336 
337 template <class BitsPortal, class IndicesPortal>
338 struct BitFieldToUnorderedSetFunctor : public viskores::exec::FunctorBase
339 {
340  using WordType = typename BitsPortal::WordTypePreferred;
341 
342  // This functor executes a number of instances, where each instance handles
343  // two cachelines worth of data. Figure out how many words that is:
344  static constexpr viskores::Id CacheLineSize = VISKORES_ALLOCATION_ALIGNMENT;
345  static constexpr viskores::Id WordsPerCacheLine =
346  CacheLineSize / static_cast<viskores::Id>(sizeof(WordType));
347  static constexpr viskores::Id CacheLinesPerInstance = 2;
348  static constexpr viskores::Id WordsPerInstance = CacheLinesPerInstance * WordsPerCacheLine;
349 
351  VISKORES_PASS_COMMAS(std::is_same<typename IndicesPortal::ValueType, viskores::Id>::value));
352 
354  BitFieldToUnorderedSetFunctor(const BitsPortal& input,
355  IndicesPortal& output,
356  std::atomic<viskores::UInt64>& popCount)
357  : Input{ input }
358  , Output{ output }
359  , PopCount(popCount)
360  , FinalWordIndex{ input.GetNumberOfWords() - 1 }
361  , FinalWordMask(input.GetFinalWordMask())
362  {
363  }
364 
365  VISKORES_CONT viskores::Id GetNumberOfInstances() const
366  {
367  const auto numWords = this->Input.GetNumberOfWords();
368  return (numWords + WordsPerInstance - 1) / WordsPerInstance;
369  }
370 
371  VISKORES_EXEC void operator()(viskores::Id instanceIdx) const
372  {
373  const viskores::Id numWords = this->Input.GetNumberOfWords();
374  const viskores::Id wordStart = viskores::Min(instanceIdx * WordsPerInstance, numWords);
375  const viskores::Id wordEnd = viskores::Min(wordStart + WordsPerInstance, numWords);
376 
377  if (wordStart != wordEnd) // range is valid
378  {
379  this->ExecuteRange(wordStart, wordEnd);
380  }
381  }
382 
383  VISKORES_EXEC void ExecuteRange(viskores::Id wordStart, viskores::Id wordEnd) const
384  {
385 #ifndef VISKORES_CUDA_DEVICE_PASS // for std::atomic call from VISKORES_EXEC function:
386  // Count bits and allocate space for output:
387  viskores::UInt64 chunkBits = this->CountChunkBits(wordStart, wordEnd);
388  if (chunkBits > 0)
389  {
390  viskores::UInt64 outIdx = this->PopCount.fetch_add(chunkBits, std::memory_order_relaxed);
391 
392  this->ProcessWords(wordStart, wordEnd, static_cast<viskores::Id>(outIdx));
393  }
394 #else
395  (void)wordStart;
396  (void)wordEnd;
397 #endif
398  }
399 
400  VISKORES_CONT viskores::UInt64 GetPopCount() const
401  {
402  return PopCount.load(std::memory_order_relaxed);
403  }
404 
405 private:
406  VISKORES_EXEC viskores::UInt64 CountChunkBits(viskores::Id wordStart, viskores::Id wordEnd) const
407  {
408  // Need to mask out trailing bits from the final word:
409  const bool isFinalChunk = wordEnd == (this->FinalWordIndex + 1);
410 
411  if (isFinalChunk)
412  {
413  wordEnd = this->FinalWordIndex;
414  }
415 
416  viskores::Int32 tmp = 0;
417  for (viskores::Id i = wordStart; i < wordEnd; ++i)
418  {
419  tmp += viskores::CountSetBits(this->Input.GetWord(i));
420  }
421 
422  if (isFinalChunk)
423  {
424  tmp +=
425  viskores::CountSetBits(this->Input.GetWord(this->FinalWordIndex) & this->FinalWordMask);
426  }
427 
428  return static_cast<viskores::UInt64>(tmp);
429  }
430 
431  VISKORES_EXEC void ProcessWords(viskores::Id wordStart,
432  viskores::Id wordEnd,
433  viskores::Id outputStartIdx) const
434  {
435  // Need to mask out trailing bits from the final word:
436  const bool isFinalChunk = wordEnd == (this->FinalWordIndex + 1);
437 
438  if (isFinalChunk)
439  {
440  wordEnd = this->FinalWordIndex;
441  }
442 
443  for (viskores::Id i = wordStart; i < wordEnd; ++i)
444  {
445  const viskores::Id firstBitIdx = i * static_cast<viskores::Id>(sizeof(WordType)) * CHAR_BIT;
446  WordType word = this->Input.GetWord(i);
447  while (word != 0) // have bits
448  {
449  // Find next bit. FindFirstSetBit starts counting at 1.
451  this->Output.Set(outputStartIdx++, firstBitIdx + bit); // Write index of bit
452  word ^= (1 << bit); // clear bit
453  }
454  }
455 
456  if (isFinalChunk)
457  {
458  const viskores::Id i = this->FinalWordIndex;
459  const viskores::Id firstBitIdx = i * static_cast<viskores::Id>(sizeof(WordType)) * CHAR_BIT;
460  WordType word = this->Input.GetWord(i) & this->FinalWordMask;
461  while (word != 0) // have bits
462  {
463  // Find next bit. FindFirstSetBit starts counting at 1.
465  this->Output.Set(outputStartIdx++, firstBitIdx + bit); // Write index of bit
466  word ^= (1 << bit); // clear bit
467  }
468  }
469  }
470 
471  BitsPortal Input;
472  IndicesPortal Output;
473  std::atomic<viskores::UInt64>& PopCount;
474  // Used to mask trailing bits the in last word.
475  viskores::Id FinalWordIndex{ 0 };
476  WordType FinalWordMask{ 0 };
477 };
478 
479 template <class InputPortalType, class OutputPortalType>
480 struct CopyKernel
481 {
482  InputPortalType InputPortal;
483  OutputPortalType OutputPortal;
484  viskores::Id InputOffset;
485  viskores::Id OutputOffset;
486 
488  CopyKernel(InputPortalType inputPortal,
489  OutputPortalType outputPortal,
490  viskores::Id inputOffset = 0,
491  viskores::Id outputOffset = 0)
492  : InputPortal(inputPortal)
493  , OutputPortal(outputPortal)
494  , InputOffset(inputOffset)
495  , OutputOffset(outputOffset)
496  {
497  }
498 
500  void operator()(viskores::Id index) const
501  {
502  using ValueType = typename OutputPortalType::ValueType;
503  this->OutputPortal.Set(
504  index + this->OutputOffset,
505  static_cast<ValueType>(this->InputPortal.Get(index + this->InputOffset)));
506  }
507 
509  void SetErrorMessageBuffer(const viskores::exec::internal::ErrorMessageBuffer&) {}
510 };
511 
512 template <typename BitsPortal>
513 struct CountSetBitsFunctor : public viskores::exec::FunctorBase
514 {
515  using WordType = typename BitsPortal::WordTypePreferred;
516 
517  // This functor executes a number of instances, where each instance handles
518  // two cachelines worth of data. This reduces the number of atomic operations.
519  // Figure out how many words that is:
520  static constexpr viskores::Id CacheLineSize = VISKORES_ALLOCATION_ALIGNMENT;
521  static constexpr viskores::Id WordsPerCacheLine =
522  CacheLineSize / static_cast<viskores::Id>(sizeof(WordType));
523  static constexpr viskores::Id CacheLinesPerInstance = 2;
524  static constexpr viskores::Id WordsPerInstance = CacheLinesPerInstance * WordsPerCacheLine;
525 
527  CountSetBitsFunctor(const BitsPortal& input, std::atomic<viskores::UInt64>& popCount)
528  : Input{ input }
529  , PopCount(popCount)
530  , FinalWordIndex{ input.GetNumberOfWords() - 1 }
531  , FinalWordMask{ input.GetFinalWordMask() }
532  {
533  }
534 
535  VISKORES_CONT viskores::Id GetNumberOfInstances() const
536  {
537  const auto numWords = this->Input.GetNumberOfWords();
538  return (numWords + WordsPerInstance - 1) / WordsPerInstance;
539  }
540 
541  VISKORES_EXEC void operator()(viskores::Id instanceIdx) const
542  {
543  const viskores::Id numWords = this->Input.GetNumberOfWords();
544  const viskores::Id wordStart = viskores::Min(instanceIdx * WordsPerInstance, numWords);
545  const viskores::Id wordEnd = viskores::Min(wordStart + WordsPerInstance, numWords);
546 
547  if (wordStart != wordEnd) // range is valid
548  {
549  this->ExecuteRange(wordStart, wordEnd);
550  }
551  }
552 
553  VISKORES_CONT viskores::UInt64 GetPopCount() const
554  {
555  return PopCount.load(std::memory_order_relaxed);
556  }
557 
558 private:
559  VISKORES_EXEC void ExecuteRange(viskores::Id wordStart, viskores::Id wordEnd) const
560  {
561 #ifndef VISKORES_CUDA_DEVICE_PASS // for std::atomic call from VISKORES_EXEC function:
562  // Count bits and allocate space for output:
563  viskores::UInt64 chunkBits = this->CountChunkBits(wordStart, wordEnd);
564  this->PopCount.fetch_add(chunkBits, std::memory_order_relaxed);
565 #else
566  (void)wordStart;
567  (void)wordEnd;
568 #endif
569  }
570 
571  VISKORES_EXEC viskores::UInt64 CountChunkBits(viskores::Id wordStart, viskores::Id wordEnd) const
572  {
573  // Need to mask out trailing bits from the final word:
574  const bool isFinalChunk = wordEnd == (this->FinalWordIndex + 1);
575 
576  if (isFinalChunk)
577  {
578  wordEnd = this->FinalWordIndex;
579  }
580 
581  viskores::Int32 tmp = 0;
582  for (viskores::Id i = wordStart; i < wordEnd; ++i)
583  {
584  tmp += viskores::CountSetBits(this->Input.GetWord(i));
585  }
586 
587  if (isFinalChunk)
588  {
589  tmp +=
590  viskores::CountSetBits(this->Input.GetWord(this->FinalWordIndex) & this->FinalWordMask);
591  }
592 
593  return static_cast<viskores::UInt64>(tmp);
594  }
595 
596  BitsPortal Input;
597  std::atomic<viskores::UInt64>& PopCount;
598  // Used to mask trailing bits the in last word.
599  viskores::Id FinalWordIndex{ 0 };
600  WordType FinalWordMask{ 0 };
601 };
602 
603 // For a given unsigned integer less than 32 bits, repeat its bits until we
604 // have a 32 bit pattern. This is used to make all fill patterns at least
605 // 32 bits in size, since concurrently writing to adjacent locations smaller
606 // than 32 bits may race on some platforms.
607 template <typename WordType, typename = typename std::enable_if<(sizeof(WordType) >= 4)>::type>
608 static constexpr VISKORES_CONT WordType RepeatTo32BitsIfNeeded(WordType pattern)
609 { // for 32 bits or more, just pass the type through.
610  return pattern;
611 }
612 
613 static inline constexpr VISKORES_CONT viskores::UInt32 RepeatTo32BitsIfNeeded(
614  viskores::UInt16 pattern)
615 {
616  return static_cast<viskores::UInt32>(pattern << 16 | pattern);
617 }
618 
619 static inline constexpr VISKORES_CONT viskores::UInt32 RepeatTo32BitsIfNeeded(
620  viskores::UInt8 pattern)
621 {
622  return RepeatTo32BitsIfNeeded(static_cast<viskores::UInt16>(pattern << 8 | pattern));
623 }
624 
625 template <typename BitsPortal, typename WordType>
626 struct FillBitFieldFunctor : public viskores::exec::FunctorBase
627 {
629  FillBitFieldFunctor(const BitsPortal& portal, WordType mask)
630  : Portal{ portal }
631  , Mask{ mask }
632  {
633  }
634 
635  VISKORES_EXEC void operator()(viskores::Id wordIdx) const
636  {
637  this->Portal.SetWord(wordIdx, this->Mask);
638  }
639 
640 private:
641  BitsPortal Portal;
642  WordType Mask;
643 };
644 
645 template <typename PortalType>
646 struct FillArrayHandleFunctor : public viskores::exec::FunctorBase
647 {
648  using ValueType = typename PortalType::ValueType;
649 
651  FillArrayHandleFunctor(const PortalType& portal, ValueType value)
652  : Portal{ portal }
653  , Value{ value }
654  {
655  }
656 
657  VISKORES_EXEC void operator()(viskores::Id idx) const { this->Portal.Set(idx, this->Value); }
658 
659 private:
660  PortalType Portal;
661  ValueType Value;
662 };
663 
664 template <typename Iterator, typename IteratorTag>
665 VISKORES_EXEC static inline viskores::Id IteratorDistanceImpl(const Iterator& from,
666  const Iterator& to,
667  IteratorTag)
668 {
669  viskores::Id dist = 0;
670  for (auto it = from; it != to; ++it)
671  {
672  ++dist;
673  }
674  return dist;
675 }
676 
677 template <typename Iterator>
678 VISKORES_EXEC static inline viskores::Id IteratorDistanceImpl(const Iterator& from,
679  const Iterator& to,
680  std::random_access_iterator_tag)
681 {
682  return static_cast<viskores::Id>(to - from);
683 }
684 
685 #if defined(VISKORES_HIP)
686 
687 template <typename Iterator>
688 __host__ static inline viskores::Id IteratorDistance(const Iterator& from, const Iterator& to)
689 {
690  return static_cast<viskores::Id>(std::distance(from, to));
691 }
692 
693 template <typename Iterator>
694 __device__ static inline viskores::Id IteratorDistance(const Iterator& from, const Iterator& to)
695 {
696  return IteratorDistanceImpl(
697  from, to, typename std::iterator_traits<Iterator>::iterator_category{});
698 }
699 
700 #else
701 
702 template <typename Iterator>
703 VISKORES_EXEC static inline viskores::Id IteratorDistance(const Iterator& from, const Iterator& to)
704 {
705 #ifndef VISKORES_CUDA_DEVICE_PASS
706  return static_cast<viskores::Id>(std::distance(from, to));
707 #else
708  return IteratorDistanceImpl(
709  from, to, typename std::iterator_traits<Iterator>::iterator_category{});
710 #endif
711 }
712 
713 #endif
714 
715 template <class InputPortalType, class ValuesPortalType, class OutputPortalType>
716 struct LowerBoundsKernel
717 {
718  InputPortalType InputPortal;
719  ValuesPortalType ValuesPortal;
720  OutputPortalType OutputPortal;
721 
723  LowerBoundsKernel(InputPortalType inputPortal,
724  ValuesPortalType valuesPortal,
725  OutputPortalType outputPortal)
726  : InputPortal(inputPortal)
727  , ValuesPortal(valuesPortal)
728  , OutputPortal(outputPortal)
729  {
730  }
731 
734  void operator()(viskores::Id index) const
735  {
736  // This method assumes that (1) InputPortalType can return working
737  // iterators in the execution environment and that (2) methods not
738  // specified with VISKORES_EXEC (such as the STL algorithms) can be
739  // called from the execution environment. Neither one of these is
740  // necessarily true, but it is true for the current uses of this general
741  // function and I don't want to compete with STL if I don't have to.
742 
744  InputIteratorsType inputIterators(this->InputPortal);
745  auto resultPos = viskores::LowerBound(
746  inputIterators.GetBegin(), inputIterators.GetEnd(), this->ValuesPortal.Get(index));
747 
748  viskores::Id resultIndex = IteratorDistance(inputIterators.GetBegin(), resultPos);
749  this->OutputPortal.Set(index, resultIndex);
750  }
751 
753  void SetErrorMessageBuffer(const viskores::exec::internal::ErrorMessageBuffer&) {}
754 };
755 
756 template <class InputPortalType,
757  class ValuesPortalType,
758  class OutputPortalType,
759  class BinaryCompare>
760 struct LowerBoundsComparisonKernel
761 {
762  InputPortalType InputPortal;
763  ValuesPortalType ValuesPortal;
764  OutputPortalType OutputPortal;
765  BinaryCompare CompareFunctor;
766 
768  LowerBoundsComparisonKernel(InputPortalType inputPortal,
769  ValuesPortalType valuesPortal,
770  OutputPortalType outputPortal,
771  BinaryCompare binary_compare)
772  : InputPortal(inputPortal)
773  , ValuesPortal(valuesPortal)
774  , OutputPortal(outputPortal)
775  , CompareFunctor(binary_compare)
776  {
777  }
778 
781  void operator()(viskores::Id index) const
782  {
783  // This method assumes that (1) InputPortalType can return working
784  // iterators in the execution environment and that (2) methods not
785  // specified with VISKORES_EXEC (such as the STL algorithms) can be
786  // called from the execution environment. Neither one of these is
787  // necessarily true, but it is true for the current uses of this general
788  // function and I don't want to compete with STL if I don't have to.
789 
791  InputIteratorsType inputIterators(this->InputPortal);
792  auto resultPos = viskores::LowerBound(inputIterators.GetBegin(),
793  inputIterators.GetEnd(),
794  this->ValuesPortal.Get(index),
795  this->CompareFunctor);
796 
797  viskores::Id resultIndex = IteratorDistance(inputIterators.GetBegin(), resultPos);
798  this->OutputPortal.Set(index, resultIndex);
799  }
800 
802  void SetErrorMessageBuffer(const viskores::exec::internal::ErrorMessageBuffer&) {}
803 };
804 
805 template <typename PortalType>
806 struct SetConstantKernel
807 {
808  using ValueType = typename PortalType::ValueType;
809  PortalType Portal;
810  ValueType Value;
811 
813  SetConstantKernel(const PortalType& portal, ValueType value)
814  : Portal(portal)
815  , Value(value)
816  {
817  }
818 
821  void operator()(viskores::Id index) const { this->Portal.Set(index, this->Value); }
822 
824  void SetErrorMessageBuffer(const viskores::exec::internal::ErrorMessageBuffer&) {}
825 };
826 
827 template <typename PortalType, typename BinaryCompare>
828 struct BitonicSortMergeKernel : viskores::exec::FunctorBase
829 {
830  PortalType Portal;
831  BinaryCompare Compare;
832  viskores::Id GroupSize;
833 
835  BitonicSortMergeKernel(const PortalType& portal,
836  const BinaryCompare& compare,
837  viskores::Id groupSize)
838  : Portal(portal)
839  , Compare(compare)
840  , GroupSize(groupSize)
841  {
842  }
843 
846  void operator()(viskores::Id index) const
847  {
848  using ValueType = typename PortalType::ValueType;
849 
850  viskores::Id groupIndex = index % this->GroupSize;
851  viskores::Id blockSize = 2 * this->GroupSize;
852  viskores::Id blockIndex = index / this->GroupSize;
853 
854  viskores::Id lowIndex = blockIndex * blockSize + groupIndex;
855  viskores::Id highIndex = lowIndex + this->GroupSize;
856 
857  if (highIndex < this->Portal.GetNumberOfValues())
858  {
859  ValueType lowValue = this->Portal.Get(lowIndex);
860  ValueType highValue = this->Portal.Get(highIndex);
861  if (this->Compare(highValue, lowValue))
862  {
863  this->Portal.Set(highIndex, lowValue);
864  this->Portal.Set(lowIndex, highValue);
865  }
866  }
867  }
868 };
869 
870 template <typename PortalType, typename BinaryCompare>
871 struct BitonicSortCrossoverKernel : viskores::exec::FunctorBase
872 {
873  PortalType Portal;
874  BinaryCompare Compare;
875  viskores::Id GroupSize;
876 
878  BitonicSortCrossoverKernel(const PortalType& portal,
879  const BinaryCompare& compare,
880  viskores::Id groupSize)
881  : Portal(portal)
882  , Compare(compare)
883  , GroupSize(groupSize)
884  {
885  }
886 
889  void operator()(viskores::Id index) const
890  {
891  using ValueType = typename PortalType::ValueType;
892 
893  viskores::Id groupIndex = index % this->GroupSize;
894  viskores::Id blockSize = 2 * this->GroupSize;
895  viskores::Id blockIndex = index / this->GroupSize;
896 
897  viskores::Id lowIndex = blockIndex * blockSize + groupIndex;
898  viskores::Id highIndex = blockIndex * blockSize + (blockSize - groupIndex - 1);
899 
900  if (highIndex < this->Portal.GetNumberOfValues())
901  {
902  ValueType lowValue = this->Portal.Get(lowIndex);
903  ValueType highValue = this->Portal.Get(highIndex);
904  if (this->Compare(highValue, lowValue))
905  {
906  this->Portal.Set(highIndex, lowValue);
907  this->Portal.Set(lowIndex, highValue);
908  }
909  }
910  }
911 };
912 
913 template <class StencilPortalType, class OutputPortalType, class UnaryPredicate>
914 struct StencilToIndexFlagKernel
915 {
916  using StencilValueType = typename StencilPortalType::ValueType;
917  StencilPortalType StencilPortal;
918  OutputPortalType OutputPortal;
919  UnaryPredicate Predicate;
920 
922  StencilToIndexFlagKernel(StencilPortalType stencilPortal,
923  OutputPortalType outputPortal,
924  UnaryPredicate unary_predicate)
925  : StencilPortal(stencilPortal)
926  , OutputPortal(outputPortal)
927  , Predicate(unary_predicate)
928  {
929  }
930 
933  void operator()(viskores::Id index) const
934  {
935  StencilValueType value = this->StencilPortal.Get(index);
936  this->OutputPortal.Set(index, this->Predicate(value) ? 1 : 0);
937  }
938 
940  void SetErrorMessageBuffer(const viskores::exec::internal::ErrorMessageBuffer&) {}
941 };
942 
943 template <class InputPortalType,
944  class StencilPortalType,
945  class IndexPortalType,
946  class OutputPortalType,
947  class PredicateOperator>
948 struct CopyIfKernel
949 {
950  InputPortalType InputPortal;
951  StencilPortalType StencilPortal;
952  IndexPortalType IndexPortal;
953  OutputPortalType OutputPortal;
954  PredicateOperator Predicate;
955 
957  CopyIfKernel(InputPortalType inputPortal,
958  StencilPortalType stencilPortal,
959  IndexPortalType indexPortal,
960  OutputPortalType outputPortal,
961  PredicateOperator unary_predicate)
962  : InputPortal(inputPortal)
963  , StencilPortal(stencilPortal)
964  , IndexPortal(indexPortal)
965  , OutputPortal(outputPortal)
966  , Predicate(unary_predicate)
967  {
968  }
969 
972  void operator()(viskores::Id index) const
973  {
974  using StencilValueType = typename StencilPortalType::ValueType;
975  StencilValueType stencilValue = this->StencilPortal.Get(index);
976  if (Predicate(stencilValue))
977  {
978  viskores::Id outputIndex = this->IndexPortal.Get(index);
979 
980  using OutputValueType = typename OutputPortalType::ValueType;
981  OutputValueType value = this->InputPortal.Get(index);
982 
983  this->OutputPortal.Set(outputIndex, value);
984  }
985  }
986 
988  void SetErrorMessageBuffer(const viskores::exec::internal::ErrorMessageBuffer&) {}
989 };
990 
991 template <class InputPortalType, class StencilPortalType>
992 struct ClassifyUniqueKernel
993 {
994  InputPortalType InputPortal;
995  StencilPortalType StencilPortal;
996 
998  ClassifyUniqueKernel(InputPortalType inputPortal, StencilPortalType stencilPortal)
999  : InputPortal(inputPortal)
1000  , StencilPortal(stencilPortal)
1001  {
1002  }
1003 
1006  void operator()(viskores::Id index) const
1007  {
1008  using ValueType = typename StencilPortalType::ValueType;
1009  if (index == 0)
1010  {
1011  // Always copy first value.
1012  this->StencilPortal.Set(index, ValueType(1));
1013  }
1014  else
1015  {
1016  ValueType flag = ValueType(this->InputPortal.Get(index - 1) != this->InputPortal.Get(index));
1017  this->StencilPortal.Set(index, flag);
1018  }
1019  }
1020 
1022  void SetErrorMessageBuffer(const viskores::exec::internal::ErrorMessageBuffer&) {}
1023 };
1024 
1025 template <class InputPortalType, class StencilPortalType, class BinaryCompare>
1026 struct ClassifyUniqueComparisonKernel
1027 {
1028  InputPortalType InputPortal;
1029  StencilPortalType StencilPortal;
1030  BinaryCompare CompareFunctor;
1031 
1033  ClassifyUniqueComparisonKernel(InputPortalType inputPortal,
1034  StencilPortalType stencilPortal,
1035  BinaryCompare binary_compare)
1036  : InputPortal(inputPortal)
1037  , StencilPortal(stencilPortal)
1038  , CompareFunctor(binary_compare)
1039  {
1040  }
1041 
1044  void operator()(viskores::Id index) const
1045  {
1046  using ValueType = typename StencilPortalType::ValueType;
1047  if (index == 0)
1048  {
1049  // Always copy first value.
1050  this->StencilPortal.Set(index, ValueType(1));
1051  }
1052  else
1053  {
1054  //comparison predicate returns true when they match
1055  const bool same =
1056  !(this->CompareFunctor(this->InputPortal.Get(index - 1), this->InputPortal.Get(index)));
1057  ValueType flag = ValueType(same);
1058  this->StencilPortal.Set(index, flag);
1059  }
1060  }
1061 
1063  void SetErrorMessageBuffer(const viskores::exec::internal::ErrorMessageBuffer&) {}
1064 };
1065 
1066 template <class InputPortalType, class ValuesPortalType, class OutputPortalType>
1067 struct UpperBoundsKernel
1068 {
1069  InputPortalType InputPortal;
1070  ValuesPortalType ValuesPortal;
1071  OutputPortalType OutputPortal;
1072 
1074  UpperBoundsKernel(InputPortalType inputPortal,
1075  ValuesPortalType valuesPortal,
1076  OutputPortalType outputPortal)
1077  : InputPortal(inputPortal)
1078  , ValuesPortal(valuesPortal)
1079  , OutputPortal(outputPortal)
1080  {
1081  }
1082 
1085  void operator()(viskores::Id index) const
1086  {
1087  // This method assumes that (1) InputPortalType can return working
1088  // iterators in the execution environment and that (2) methods not
1089  // specified with VISKORES_EXEC (such as the STL algorithms) can be
1090  // called from the execution environment. Neither one of these is
1091  // necessarily true, but it is true for the current uses of this general
1092  // function and I don't want to compete with STL if I don't have to.
1093 
1095  InputIteratorsType inputIterators(this->InputPortal);
1096  auto resultPos = viskores::UpperBound(
1097  inputIterators.GetBegin(), inputIterators.GetEnd(), this->ValuesPortal.Get(index));
1098 
1099  viskores::Id resultIndex = IteratorDistance(inputIterators.GetBegin(), resultPos);
1100  this->OutputPortal.Set(index, resultIndex);
1101  }
1102 
1104  void SetErrorMessageBuffer(const viskores::exec::internal::ErrorMessageBuffer&) {}
1105 };
1106 
1107 template <class InputPortalType,
1108  class ValuesPortalType,
1109  class OutputPortalType,
1110  class BinaryCompare>
1111 struct UpperBoundsKernelComparisonKernel
1112 {
1113  InputPortalType InputPortal;
1114  ValuesPortalType ValuesPortal;
1115  OutputPortalType OutputPortal;
1116  BinaryCompare CompareFunctor;
1117 
1119  UpperBoundsKernelComparisonKernel(InputPortalType inputPortal,
1120  ValuesPortalType valuesPortal,
1121  OutputPortalType outputPortal,
1122  BinaryCompare binary_compare)
1123  : InputPortal(inputPortal)
1124  , ValuesPortal(valuesPortal)
1125  , OutputPortal(outputPortal)
1126  , CompareFunctor(binary_compare)
1127  {
1128  }
1129 
1132  void operator()(viskores::Id index) const
1133  {
1134  // This method assumes that (1) InputPortalType can return working
1135  // iterators in the execution environment and that (2) methods not
1136  // specified with VISKORES_EXEC (such as the STL algorithms) can be
1137  // called from the execution environment. Neither one of these is
1138  // necessarily true, but it is true for the current uses of this general
1139  // function and I don't want to compete with STL if I don't have to.
1140 
1142  InputIteratorsType inputIterators(this->InputPortal);
1143  auto resultPos = viskores::UpperBound(inputIterators.GetBegin(),
1144  inputIterators.GetEnd(),
1145  this->ValuesPortal.Get(index),
1146  this->CompareFunctor);
1147 
1148  viskores::Id resultIndex = IteratorDistance(inputIterators.GetBegin(), resultPos);
1149  this->OutputPortal.Set(index, resultIndex);
1150  }
1151 
1153  void SetErrorMessageBuffer(const viskores::exec::internal::ErrorMessageBuffer&) {}
1154 };
1155 
1156 template <typename InPortalType, typename OutPortalType, typename BinaryFunctor>
1157 struct InclusiveToExclusiveKernel : viskores::exec::FunctorBase
1158 {
1159  using ValueType = typename InPortalType::ValueType;
1160 
1161  InPortalType InPortal;
1162  OutPortalType OutPortal;
1163  BinaryFunctor BinaryOperator;
1164  ValueType InitialValue;
1165 
1167  InclusiveToExclusiveKernel(const InPortalType& inPortal,
1168  const OutPortalType& outPortal,
1169  BinaryFunctor& binaryOperator,
1170  ValueType initialValue)
1171  : InPortal(inPortal)
1172  , OutPortal(outPortal)
1173  , BinaryOperator(binaryOperator)
1174  , InitialValue(initialValue)
1175  {
1176  }
1177 
1180  void operator()(viskores::Id index) const
1181  {
1182  const ValueType result = (index == 0)
1183  ? this->InitialValue
1184  : this->BinaryOperator(this->InitialValue, this->InPortal.Get(index - 1));
1185 
1186  this->OutPortal.Set(index, result);
1187  }
1188 };
1189 
1190 template <typename InPortalType, typename OutPortalType, typename BinaryFunctor>
1191 struct InclusiveToExtendedKernel : viskores::exec::FunctorBase
1192 {
1193  using ValueType = typename InPortalType::ValueType;
1194 
1195  InPortalType InPortal;
1196  OutPortalType OutPortal;
1197  BinaryFunctor BinaryOperator;
1198  ValueType InitialValue;
1199  ValueType FinalValue;
1200 
1202  InclusiveToExtendedKernel(const InPortalType& inPortal,
1203  const OutPortalType& outPortal,
1204  BinaryFunctor& binaryOperator,
1205  ValueType initialValue,
1206  ValueType finalValue)
1207  : InPortal(inPortal)
1208  , OutPortal(outPortal)
1209  , BinaryOperator(binaryOperator)
1210  , InitialValue(initialValue)
1211  , FinalValue(finalValue)
1212  {
1213  }
1214 
1217  void operator()(viskores::Id index) const
1218  {
1219  // The output array has one more value than the input, which holds the
1220  // total sum.
1221  const ValueType result = (index == 0) ? this->InitialValue
1222  : (index == this->InPortal.GetNumberOfValues())
1223  ? this->FinalValue
1224  : this->BinaryOperator(this->InitialValue, this->InPortal.Get(index - 1));
1225 
1226  this->OutPortal.Set(index, result);
1227  }
1228 };
1229 
1230 template <typename PortalType, typename BinaryFunctor>
1231 struct ScanKernel : viskores::exec::FunctorBase
1232 {
1233  PortalType Portal;
1234  BinaryFunctor BinaryOperator;
1235  viskores::Id Stride;
1237  viskores::Id Distance;
1238 
1240  ScanKernel(const PortalType& portal,
1241  BinaryFunctor binary_functor,
1242  viskores::Id stride,
1243  viskores::Id offset)
1244  : Portal(portal)
1245  , BinaryOperator(binary_functor)
1246  , Stride(stride)
1247  , Offset(offset)
1248  , Distance(stride / 2)
1249  {
1250  }
1251 
1254  void operator()(viskores::Id index) const
1255  {
1256  using ValueType = typename PortalType::ValueType;
1257 
1258  viskores::Id leftIndex = this->Offset + index * this->Stride;
1259  viskores::Id rightIndex = leftIndex + this->Distance;
1260 
1261  if (rightIndex < this->Portal.GetNumberOfValues())
1262  {
1263  ValueType leftValue = this->Portal.Get(leftIndex);
1264  ValueType rightValue = this->Portal.Get(rightIndex);
1265  this->Portal.Set(rightIndex, BinaryOperator(leftValue, rightValue));
1266  }
1267  }
1268 };
1269 
1270 template <typename InPortalType1,
1271  typename InPortalType2,
1272  typename OutPortalType,
1273  typename BinaryFunctor>
1274 struct BinaryTransformKernel : viskores::exec::FunctorBase
1275 {
1276  InPortalType1 InPortal1;
1277  InPortalType2 InPortal2;
1278  OutPortalType OutPortal;
1279  BinaryFunctor BinaryOperator;
1280 
1282  BinaryTransformKernel(const InPortalType1& inPortal1,
1283  const InPortalType2& inPortal2,
1284  const OutPortalType& outPortal,
1285  BinaryFunctor binaryOperator)
1286  : InPortal1(inPortal1)
1287  , InPortal2(inPortal2)
1288  , OutPortal(outPortal)
1289  , BinaryOperator(binaryOperator)
1290  {
1291  }
1292 
1295  void operator()(viskores::Id index) const
1296  {
1297  this->OutPortal.Set(
1298  index, this->BinaryOperator(this->InPortal1.Get(index), this->InPortal2.Get(index)));
1299  }
1300 };
1301 }
1302 }
1303 } // namespace viskores::cont::internal
1304 
1305 #endif //viskores_cont_internal_FunctorsGeneral_h
Offset
viskores::Float32 Offset
Definition: Wireframer.h:410
viskores::exec::FunctorBase
Base class for all user worklets invoked in the execution environment from a call to viskores::cont::...
Definition: FunctorBase.h:38
viskores::SortLess
Binary Predicate that takes two arguments argument x, and y and returns True if and only if x is less...
Definition: BinaryPredicates.h:53
UnaryPredicates.h
ArrayPortalToIterators.h
VISKORES_ALLOCATION_ALIGNMENT
#define VISKORES_ALLOCATION_ALIGNMENT
Definition: Configure.h:116
viskores::UpperBound
IterT UpperBound(IterT first, IterT last, const T &val, Comp comp)
Implementation of std::upper_bound that is appropriate for both control and execution environments.
Definition: UpperBound.h:38
VISKORES_SUPPRESS_EXEC_WARNINGS
#define VISKORES_SUPPRESS_EXEC_WARNINGS
Definition: ExportMacros.h:61
viskores::UInt16
uint16_t UInt16
Base type to use for 16-bit unsigned integer numbers.
Definition: Types.h:185
viskores::LowerBound
IterT LowerBound(IterT first, IterT last, const T &val, Comp comp)
Implementation of std::lower_bound that is appropriate for both control and execution environments.
Definition: LowerBound.h:38
viskores::FindFirstSetBit
viskores::Int32 FindFirstSetBit(viskores::UInt32 word)
Bitwise operations.
Definition: Math.h:2852
VISKORES_EXEC_CONT
#define VISKORES_EXEC_CONT
Definition: ExportMacros.h:60
TypeTraits.h
viskores::Id
viskores::Int64 Id
Base type to use to index arrays.
Definition: Types.h:235
LowerBound.h
VISKORES_CONT
#define VISKORES_CONT
Definition: ExportMacros.h:65
viskores
Groups connected points that have the same field value.
Definition: Atomic.h:27
viskores::Pair::first
FirstType first
The pair's first object.
Definition: Pair.h:58
FunctorBase.h
viskores::CountSetBits
viskores::Int32 CountSetBits(viskores::UInt32 word)
Count the total number of bits set in word.
Definition: Math.h:2948
VISKORES_PASS_COMMAS
#define VISKORES_PASS_COMMAS(...)
Definition: Configure.h:372
viskores::cont::ArrayPortalToIterators
Definition: ArrayPortalToIterators.h:35
viskores::Pair
A viskores::Pair is essentially the same as an STL pair object except that the methods (constructors ...
Definition: Pair.h:37
BinaryOperators.h
viskores::UInt64
unsigned long long UInt64
Base type to use for 64-bit signed integer numbers.
Definition: Types.h:215
viskores::UInt8
uint8_t UInt8
Base type to use for 8-bit unsigned integer numbers.
Definition: Types.h:177
viskores::Int32
int32_t Int32
Base type to use for 32-bit signed integer numbers.
Definition: Types.h:189
BinaryPredicates.h
viskores::Pair::second
SecondType second
The pair's second object.
Definition: Pair.h:63
UpperBound.h
viskores::UInt32
uint32_t UInt32
Base type to use for 32-bit unsigned integer numbers.
Definition: Types.h:193
VISKORES_EXEC
#define VISKORES_EXEC
Definition: ExportMacros.h:59
VISKORES_STATIC_ASSERT
#define VISKORES_STATIC_ASSERT(condition)
Definition: StaticAssert.h:24