RAJA
RAJA provides a collection of platform portability abstractions for C++ HPC applications.
sort.hpp
Go to the documentation of this file.
1 
11 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
12 // Copyright (c) Lawrence Livermore National Security, LLC and other
13 // RAJA Project Developers. See top-level LICENSE and COPYRIGHT
14 // files for dates and other details. No copyright assignment is required
15 // to contribute to RAJA.
16 //
17 // SPDX-License-Identifier: (BSD-3-Clause)
18 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
19 
20 #ifndef RAJA_util_sort_HPP
21 #define RAJA_util_sort_HPP
22 
23 #include "RAJA/config.hpp"
24 
25 #include <iterator>
26 #include <memory>
27 
29 
30 #include "RAJA/util/macros.hpp"
31 #include "RAJA/util/concepts.hpp"
32 #include "RAJA/util/math.hpp"
33 
34 namespace RAJA
35 {
36 
37 namespace detail
38 {
39 
44 template<typename Iter, typename Predicate>
45 RAJA_HOST_DEVICE RAJA_INLINE Iter partition(Iter begin,
46  Iter end,
47  Predicate pred)
48 {
50 
51  if (begin == end)
52  {
53  return begin;
54  }
55 
56  // advance to first false
57  Iter first_false = begin;
58  for (; first_false != end; ++first_false)
59  {
60 
61  if (!pred(first_false))
62  {
63  break;
64  }
65  }
66 
67  // return if none were false
68  if (first_false == end)
69  {
70  return first_false;
71  }
72 
73  // advance through rest of list to find the next true
74  for (Iter next_true = RAJA::next(first_false); next_true != end; ++next_true)
75  {
76 
77  // find the end of a range of falses [first_false, next_true)
78  if (pred(next_true))
79  {
80 
81  // shift the known range of falses forward
82  // by swapping the true to the beginning of the range
83  safe_iter_swap(first_false, next_true);
84  ++first_false;
85  }
86  }
87 
88  return first_false;
89 }
90 
95 template<typename Iter, typename Compare>
96 RAJA_HOST_DEVICE RAJA_INLINE void insertion_sort(Iter begin,
97  Iter end,
98  Compare comp)
99 {
101 
102  if (begin == end)
103  {
104  return;
105  }
106 
107  // for each unsorted item in the right side of the range
108  for (Iter next_unsorted = RAJA::next(begin); next_unsorted != end;
109  ++next_unsorted)
110  {
111 
112  // insert unsorted item into the sorted left side of the range
113  for (Iter to_insert = next_unsorted; to_insert != begin; --to_insert)
114  {
115 
116  Iter next_sorted = RAJA::prev(to_insert);
117 
118  // compare with next item to left
119  if (comp(*to_insert, *next_sorted))
120  {
121 
122  // swap down if should be before
123  safe_iter_swap(next_sorted, to_insert);
124  }
125  else
126  {
127 
128  // stop if in correct position
129  break;
130  }
131  }
132  }
133 }
134 
138 RAJA_HOST_DEVICE RAJA_INLINE constexpr size_t num_shell_strides() { return 39; }
139 
143 RAJA_HOST_DEVICE RAJA_INLINE constexpr long long unsigned get_shell_stride(
144  int i)
145 {
146  using array_type = long long unsigned[num_shell_strides()];
147  return (array_type {
148  // strides from M. Ciura 2001
149  1llu, 4llu, 10llu, 23llu, 57llu, 132llu, 301llu, 701llu, 1750llu,
150  // extended up to 2^47 with strides[n] = floor(2.25*strides[n-1])
151  3937llu, 8858llu, 19930llu, 44842llu, 100894llu, 227011llu, 510774llu,
152  1149241llu, 2585792llu, 5818032llu, 13090572llu, 29453787llu, 66271020llu,
153  149109795llu, 335497038llu, 754868335llu, 1698453753llu, 3821520944llu,
154  8598422124llu, 19346449779llu, 43529512002llu, 97941402004llu,
155  220368154509llu, 495828347645llu, 1115613782201llu, 2510131009952llu,
156  5647794772392llu, 12707538237882llu, 28591961035234llu,
157  64331912329276llu})[i];
158 }
159 
164 template<typename Iter, typename Compare>
165 RAJA_HOST_DEVICE RAJA_INLINE void shell_sort(Iter begin, Iter end, Compare comp)
166 {
168  using diff_type = ::RAJA::detail::IterDiff<Iter>;
169 
170  diff_type n = end - begin;
171 
172  if (n <= static_cast<diff_type>(1))
173  {
174  return;
175  }
176  else if (get_shell_stride(1) < static_cast<unsigned long long>(n))
177  {
178 
179  int i_stride = 2;
180  // find first stride larger than n
181  constexpr int num_strides = num_shell_strides();
182  for (; i_stride < num_strides; ++i_stride)
183  {
184  if (get_shell_stride(i_stride) >= static_cast<unsigned long long>(n))
185  {
186  break;
187  }
188  }
189  // back up to first stride smaller than n
190  i_stride -= 1;
191 
192  // for each stride size smaller than n, largest to smallest, not including 1
193  // sort strided ranges with stride stride
194  for (; i_stride > 0; --i_stride)
195  {
196  diff_type stride = static_cast<diff_type>(get_shell_stride(i_stride));
197 
198  // for each unsorted item in the right side of each strided range
199  for (diff_type i_next_unsorted = stride; i_next_unsorted != n;
200  ++i_next_unsorted)
201  {
202 
203  // insert unsorted item into the sorted left side of the strided range
204  for (diff_type i_to_insert = i_next_unsorted; i_to_insert >= stride;
205  i_to_insert -= stride)
206  {
207 
208  Iter to_insert = begin + i_to_insert;
209  Iter next_sorted = to_insert - stride;
210 
211  // compare with next item to left
212  if (comp(*to_insert, *next_sorted))
213  {
214 
215  // swap down if should be before
216  safe_iter_swap(next_sorted, to_insert);
217  }
218  else
219  {
220 
221  // stop if in correct position
222  break;
223  }
224  }
225  }
226  }
227  }
228 
229  // finish with stride size of 1, which is just normal insertion_sort
230  RAJA::detail::insertion_sort(begin, end, comp);
231 }
232 
238 template<typename Iter, typename Compare>
239 RAJA_HOST_DEVICE RAJA_INLINE void heapify(Iter begin,
240  Iter root,
241  Iter end,
242  Compare comp)
243 {
244  using RAJA::safe_iter_swap;
245 
246  auto N = end - begin;
247 
248  // heapify the root node into place
249  // until this is a max heap again
250  for (auto i = root - begin; 2 * i + 1 < N; i = root - begin)
251  {
252 
253  // find the max item amongst the root, left child, and right child
254  Iter maxit = root;
255 
256  // left child
257  Iter child = begin + 2 * i + 1;
258  if (comp(*maxit, *child))
259  {
260  maxit = child;
261  }
262 
263  // right child
264  ++child;
265  if (child != end && comp(*maxit, *child))
266  {
267  maxit = child;
268  }
269 
270  if (maxit == root)
271  {
272  // root is the max, done
273  break;
274  }
275 
276  // swap max child with root
277  safe_iter_swap(root, maxit);
278  // continue to heapify with the former max child
279  root = maxit;
280  }
281 }
282 
287 template<typename Iter, typename Compare>
288 RAJA_HOST_DEVICE inline void heap_sort(Iter begin, Iter end, Compare comp)
289 {
290  using RAJA::safe_iter_swap;
291 
292  auto N = end - begin;
293 
294  if (N < 2)
295  {
296  // already sorted
297  return;
298  }
299 
300  // make range into a max heap by
301  // going through nodes with children one-by-one in reverse order
302  for (Iter root = begin + (N - 1) / 2; root != begin; --root)
303  {
304  // heapify a sub-heap
305  heapify(begin, root, end, comp);
306  }
307  // finish heapifying
308  heapify(begin, begin, end, comp);
309 
310  // remove one element from max heap repeatedly until sorted
311  for (--end; begin != end; --end)
312  {
313 
314  // swap max element into sorted position at end of heap
315  safe_iter_swap(begin, end);
316 
317  // fix top item of heap
318  heapify(begin, begin, end, comp);
319  }
320 }
321 
326 {
327  static constexpr unsigned get() { return 4; }
328 };
329 
334 {
335  static constexpr size_t get() { return 16; }
336 };
337 
342 template<typename Iter, typename Compare>
343 RAJA_HOST_DEVICE inline void intro_sort_depth(Iter begin,
344  Iter end,
345  Compare comp,
346  unsigned depth)
347 {
348  using RAJA::safe_iter_swap;
349  using diff_type = ::RAJA::detail::IterDiff<Iter>;
350 
351  diff_type N = end - begin;
352 
353  // cutoff to use insertion sort
354  constexpr diff_type insertion_sort_cutoff =
355  static_cast<diff_type>(intro_sort_insertion_sort_cutoff::get());
356 
357  if (N < 2)
358  {
359 
360  // already sorted
361  }
362  else if (N < insertion_sort_cutoff)
363  {
364 
365  // use insertion sort for small inputs
366  detail::insertion_sort(begin, end, comp);
367  }
368  else if (depth == 0)
369  {
370 
371  // use heap sort if recurse too deep
372  detail::heap_sort(begin, end, comp);
373  }
374  else
375  {
376 
377  // use quick sort
378  // choose pivot with median of 3 (N >= insertion_sort_cutoff)
379  Iter mid = begin + N / 2;
380  Iter last = end - 1;
381  Iter pivot =
382  comp(*begin, *mid)
383  ? (comp(*mid, *last) ? mid : (comp(*begin, *last) ? last : begin))
384  : (comp(*mid, *last) ? (comp(*begin, *last) ? begin : last) : mid);
385 
386  // swap pivot to last
387  if (pivot != last)
388  {
389  safe_iter_swap(pivot, last);
390  pivot = last;
391  }
392 
393  // partition
394  mid = partition(begin, last, [&](Iter it) {
395  return comp(*it, *pivot);
396  });
397 
398  // swap pivot to sorted position
399  if (mid != pivot)
400  {
401  safe_iter_swap(mid, pivot);
402  pivot = mid;
403  }
404 
405  // recurse to sort first and second parts, ignoring already sorted pivot
406  // by construction pivot is always in the range [begin, last]
407  detail::intro_sort_depth(begin, pivot, comp, depth - 1);
408  detail::intro_sort_depth(RAJA::next(pivot), end, comp, depth - 1);
409  }
410 }
411 
416 template<typename Iter, typename Compare>
417 RAJA_HOST_DEVICE inline void intro_sort(Iter begin, Iter end, Compare comp)
418 {
419  auto N = end - begin;
420 
421  // set max depth to 2*lg(N)
422  unsigned max_depth = 2 * RAJA::log2(N);
423 
424 #if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__)
425  // limit max_depth statically in device code to allow compiler to remove
426  // recursion
428  {
430  }
431 #endif
432 
433  detail::intro_sort_depth(begin, end, comp, max_depth);
434 }
435 
440 template<typename Iter, typename Compare>
441 void RAJA_INLINE inplace_merge(Iter first, Iter middle, Iter last, Compare comp)
442 {
443  using diff_type = RAJA::detail::IterDiff<Iter>;
444  using value_type = RAJA::detail::IterVal<Iter>;
445 
446  diff_type copylen = middle - first;
447 
448  if (first == middle || middle == last)
449  {
450  // at least one side empty, already sorted
451  return;
452  }
453 
454  if (!comp(*middle, *(middle - 1)))
455  {
456  // everything already in order, done
457  return;
458  }
459 
460  // Manage the lifetime of the buffer and objects constructed in the buffer
461  using buf_deleter_type = FreeAlignedType<value_type, diff_type>;
462  buf_deleter_type buf_deleter;
463 
464  std::unique_ptr<value_type, buf_deleter_type&> copy_buf(
465  RAJA::allocate_aligned_type<value_type>(RAJA::DATA_ALIGN,
466  copylen * sizeof(value_type)),
467  buf_deleter);
468 
469  value_type* copyarr = copy_buf.get();
470 
471  // check memory allocation worked
472  if (copyarr == nullptr)
473  {
474  RAJA_ABORT_OR_THROW("inplace_merge temporary memory allocation failed");
475  }
476 
477  // move construct input into buffer storage
478  // use buf_deleter.size as index to keep track of objects constructed
479  for (diff_type& cc = buf_deleter.size; cc < copylen; ++cc)
480  {
481  new (&copyarr[cc]) value_type(std::move(first[cc]));
482  }
483 
484  // merge
485  for (diff_type cur = 0; cur < copylen;)
486  {
487  if (middle >= last) // moved all second half, put copy into remainder
488  {
489  std::move(copyarr + cur, copyarr + copylen, first);
490  break;
491  }
492  else if (first == middle) // everything prior to middle is sorted, done
493  {
494  break;
495  }
496 
497  if (comp(*middle, copyarr[cur]))
498  {
499  *first = std::move(*middle);
500  ++middle;
501  }
502  else
503  {
504  *first = std::move(copyarr[cur]);
505  ++cur;
506  }
507  ++first;
508  }
509  return;
510 }
511 
516 template<typename Iter1, typename Iter2, typename OutIter, typename Compare>
517 // constexpr OutIter // <-- std:: return value
518 void RAJA_INLINE
519 merge_like_std(Iter1 first1,
520  Iter1 last1,
521  Iter2 first2,
522  Iter2 last2,
523  OutIter d_first, // using this as direct access to result
524  Compare comp)
525 {
527 
528  if (first1 == last2 - 1) // should never need to do this
529  {
530  return;
531  }
532 
533  if ((last2 - first1) == 2) // only 2 elements, simple swap
534  {
535  if (!comp(*d_first, *(d_first + 1)))
536  {
537  safe_iter_swap(d_first, d_first + 1);
538  }
539  return;
540  }
541 
542  while (first1 < last1 || first2 < last2)
543  {
544  if (first1 >= last1) // first half done
545  {
546  *d_first = std::move(*first2);
547  ++first2;
548  }
549  else if (first2 >= last2) // second half done
550  {
551  *d_first = std::move(*first1);
552  ++first1;
553  }
554  else // neither half done
555  {
556  if (comp(*first2, *first1))
557  {
558  *d_first = std::move(*first2);
559  ++first2;
560  }
561  else
562  {
563  *d_first = std::move(*first1);
564  ++first1;
565  }
566  }
567 
568  ++d_first; // advance output
569  }
570 
571  return;
572 }
573 
578 template<typename Iter, typename Compare>
579 RAJA_INLINE void merge_sort(Iter begin, Iter end, Compare comp)
580 {
581  using diff_type = RAJA::detail::IterDiff<Iter>;
582  using value_type = RAJA::detail::IterVal<Iter>;
583 
584  // iterative mergesort (bottom up) for future parallelism
585 
586  // min helper
587  auto minlam = [](diff_type a, diff_type b) {
588  return (a < b) ? a : b;
589  };
590 
591  // insertion sort for sizes <= 16
592  diff_type len = end - begin;
593  static constexpr diff_type insertion_sort_cutoff = 16;
594  if (len <= insertion_sort_cutoff && len > 0)
595  {
596  detail::insertion_sort(begin, end, comp);
597  }
598  else
599  {
600  // insertion sort on 16-element chunks, then merge
601  for (diff_type start = 0; start < len; start += insertion_sort_cutoff)
602  {
603  diff_type lastchunk = minlam(insertion_sort_cutoff, len - start);
604  detail::insertion_sort(begin + start, begin + start + lastchunk, comp);
605  }
606 
607  // merge using extra storage
608 
609  // Manage the lifetime of the buffer and objects constructed in the buffer
610  using buf_deleter_type = FreeAlignedType<value_type, diff_type>;
611  buf_deleter_type buf_deleter;
612 
613  std::unique_ptr<value_type, buf_deleter_type&> copy_buf(
614  RAJA::allocate_aligned_type<value_type>(RAJA::DATA_ALIGN,
615  len * sizeof(value_type)),
616  buf_deleter);
617 
618  value_type* copyarr = copy_buf.get();
619 
620  // check memory allocation worked
621  if (copyarr == nullptr)
622  {
623  RAJA_ABORT_OR_THROW("merge_sort temporary memory allocation failed");
624  }
625 
626  // move construct input into buffer storage
627  // use buf_deleter.size as index to keep track of objects constructed
628  for (diff_type& cc = buf_deleter.size; cc < len; ++cc)
629  {
630  new (&copyarr[cc]) value_type(std::move(begin[cc]));
631  }
632 
633  bool copyvalid = true;
634  // for ( diff_type midpoint = 1; midpoint < len; midpoint *= 2 ) // O(log
635  // n) loop
636  for (diff_type midpoint = 16; midpoint < len;
637  midpoint *= 2) // O(log n) loop
638  {
639  for (diff_type start = 0; start < len;
640  start += midpoint * 2) // O(n) merging loop (can be parallelized)
641  {
642  diff_type finish = minlam(start + midpoint * 2, len);
643  if (finish > len)
644  {
646  "merge_sort invalid finish point"); // sanity check
647  }
648 
649  if (start + midpoint >= len)
650  {
651  // copy sorted remainder over
652  if (copyvalid)
653  {
654  std::move(copyarr + start, copyarr + finish, begin + start);
655  }
656  else
657  {
658  std::move(begin + start, begin + finish, copyarr + start);
659  }
660  break; // skip merge if no second half exists
661  }
662 
663  if (copyvalid) // switch arrays per level of merging to avoid copying
664  // back to copyarr
665  {
666  detail::merge_like_std(copyarr + start, copyarr + start + midpoint,
667  copyarr + start + midpoint, copyarr + finish,
668  begin + start, comp);
669  }
670  else
671  {
672  detail::merge_like_std(begin + start, begin + start + midpoint,
673  begin + start + midpoint, begin + finish,
674  copyarr + start, comp);
675  }
676  }
677 
678  copyvalid = !copyvalid; // switch arrays per level of merging to avoid
679  // copying back to copyarr
680  }
681 
682  // update copy if necessary
683  if (copyvalid)
684  {
685  std::move(copyarr, copyarr + len, begin);
686  }
687  }
688  // else
689  //{
690  // Possible TBD: in-place mergesort
691  // Would shift (like insertion sort) when performing merge.
692  // PRO - Can use on GPU, O(1) storage required.
693  // CON - Shifting would cause slowdown O(n^2 log n).
694  //}
695 }
696 
697 } // namespace detail
698 
703 template<typename Container,
704  typename Compare = operators::less<detail::ContainerVal<Container>>>
705 RAJA_HOST_DEVICE RAJA_INLINE
706  concepts::enable_if<type_traits::is_range<Container>>
707  insertion_sort(Container&& c, Compare comp = Compare {})
708 {
709  using std::begin;
710  using std::end;
712  static_assert(type_traits::is_binary_function<Compare, bool, T, T>::value,
713  "Compare must model BinaryFunction");
714  static_assert(type_traits::is_random_access_range<Container>::value,
715  "Container must model RandomAccessRange");
716 
717  auto begin_it = begin(c);
718  auto end_it = end(c);
719 
720  if (begin_it != end_it)
721  {
722  auto next = begin_it;
723  if (++next != end_it)
724  {
725  detail::insertion_sort(begin_it, end_it, comp);
726  }
727  }
728 }
729 
734 template<typename Container,
735  typename Compare = operators::less<detail::ContainerVal<Container>>>
736 RAJA_HOST_DEVICE RAJA_INLINE
737  concepts::enable_if<type_traits::is_range<Container>>
738  shell_sort(Container&& c, Compare comp = Compare {})
739 {
740  using std::begin;
741  using std::end;
743  static_assert(type_traits::is_binary_function<Compare, bool, T, T>::value,
744  "Compare must model BinaryFunction");
745  static_assert(type_traits::is_random_access_range<Container>::value,
746  "Container must model RandomAccessRange");
747 
748  auto begin_it = begin(c);
749  auto end_it = end(c);
750 
751  if (begin_it != end_it)
752  {
753  auto next = begin_it;
754  if (++next != end_it)
755  {
756  detail::shell_sort(begin_it, end_it, comp);
757  }
758  }
759 }
760 
765 template<typename Container,
766  typename Compare = operators::less<detail::ContainerVal<Container>>>
767 RAJA_HOST_DEVICE RAJA_INLINE
768  concepts::enable_if<type_traits::is_range<Container>>
769  heap_sort(Container&& c, Compare comp = Compare {})
770 {
771  using std::begin;
772  using std::end;
774  static_assert(type_traits::is_binary_function<Compare, bool, T, T>::value,
775  "Compare must model BinaryFunction");
776  static_assert(type_traits::is_random_access_range<Container>::value,
777  "Container must model RandomAccessRange");
778 
779  auto begin_it = begin(c);
780  auto end_it = end(c);
781 
782  if (begin_it != end_it)
783  {
784  auto next = begin_it;
785  if (++next != end_it)
786  {
787  detail::heap_sort(begin_it, end_it, comp);
788  }
789  }
790 }
791 
796 template<typename Container,
797  typename Compare = operators::less<detail::ContainerVal<Container>>>
798 RAJA_HOST_DEVICE RAJA_INLINE
799  concepts::enable_if<type_traits::is_range<Container>>
800  intro_sort(Container&& c, Compare comp = Compare {})
801 {
802  using std::begin;
803  using std::end;
805  static_assert(type_traits::is_binary_function<Compare, bool, T, T>::value,
806  "Compare must model BinaryFunction");
807  static_assert(type_traits::is_random_access_range<Container>::value,
808  "Container must model RandomAccessRange");
809 
810  auto begin_it = begin(c);
811  auto end_it = end(c);
812 
813  if (begin_it != end_it)
814  {
815  auto next = begin_it;
816  if (++next != end_it)
817  {
818  detail::intro_sort(begin_it, end_it, comp);
819  }
820  }
821 }
822 
827 template<typename Container,
828  typename Compare = operators::less<detail::ContainerVal<Container>>>
829 RAJA_INLINE concepts::enable_if<type_traits::is_range<Container>> merge_sort(
830  Container&& c,
831  Compare comp = Compare {})
832 {
833  using std::begin;
834  using std::end;
836  static_assert(type_traits::is_binary_function<Compare, bool, T, T>::value,
837  "Compare must model BinaryFunction");
838  static_assert(type_traits::is_random_access_range<Container>::value,
839  "Container must model RandomAccessRange");
840 
841  auto begin_it = begin(c);
842  auto end_it = end(c);
843 
844  if (begin_it != end_it)
845  {
846  auto next = begin_it;
847  if (++next != end_it)
848  {
849  detail::merge_sort(begin_it, end_it, comp);
850  }
851  }
852 }
853 
854 } // namespace RAJA
855 
856 #endif
Header file for RAJA algorithm definitions.
Header file for RAJA concept definitions.
Header file for common RAJA internal macro definitions.
RAJA_HOST_DEVICE void RAJA_ABORT_OR_THROW(const char *str)
Definition: macros.hpp:143
#define RAJA_HOST_DEVICE
Definition: macros.hpp:65
Header file providing RAJA math templates.
RAJA_HOST_DEVICE constexpr RAJA_INLINE size_t num_shell_strides()
get number of strides for shell sort
Definition: sort.hpp:138
void RAJA_INLINE inplace_merge(Iter first, Iter middle, Iter last, Compare comp)
merge a range with midpoint using comparison function with local range/2 copy
Definition: sort.hpp:441
RAJA_HOST_DEVICE RAJA_INLINE void heapify(Iter begin, Iter root, Iter end, Compare comp)
insert the given element into the heaps below it using comparison function and using O(lg(N)) compari...
Definition: sort.hpp:239
camp::decay< decltype(*camp::val< camp::iterator_from< Container > >())> ContainerVal
Definition: algorithm.hpp:51
void RAJA_INLINE merge_like_std(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2, OutIter d_first, Compare comp)
merge given two ranges using comparison function while copies are outside, somewhat follows STL API
Definition: sort.hpp:519
RAJA_HOST_DEVICE void heap_sort(Iter begin, Iter end, Compare comp)
unstable heap sort given range inplace using comparison function and using O(N*lg(N)) comparisons and...
Definition: sort.hpp:288
RAJA_HOST_DEVICE constexpr RAJA_INLINE long long unsigned get_shell_stride(int i)
get strides for shell sort
Definition: sort.hpp:143
RAJA_HOST_DEVICE RAJA_INLINE Iter partition(Iter begin, Iter end, Predicate pred)
unstable partition given range inplace using predicate function and using O(N) predicate evaluations ...
Definition: sort.hpp:45
RAJA_HOST_DEVICE void intro_sort_depth(Iter begin, Iter end, Compare comp, unsigned depth)
unstable intro sort given range inplace using comparison function and using O(N*lg(N)) comparisons an...
Definition: sort.hpp:343
RAJA_HOST_DEVICE RAJA_INLINE void insertion_sort(Iter begin, Iter end, Compare comp)
stable insertion sort given range inplace using comparison function and using O(N^2) comparisons and ...
Definition: sort.hpp:96
typename ::std::iterator_traits< Iter >::difference_type IterDiff
Definition: algorithm.hpp:44
typename ::std::iterator_traits< Iter >::value_type IterVal
Definition: algorithm.hpp:38
RAJA_INLINE void merge_sort(Iter begin, Iter end, Compare comp)
stable merge sort given range inplace using comparison function and using O(N*lg(N)) comparisons and ...
Definition: sort.hpp:579
RAJA_HOST_DEVICE RAJA_INLINE void shell_sort(Iter begin, Iter end, Compare comp)
unstable shell sort given range inplace using comparison function and using O(N^?) comparisons and O(...
Definition: sort.hpp:165
RAJA_HOST_DEVICE void intro_sort(Iter begin, Iter end, Compare comp)
unstable intro sort given range inplace using comparison function and using O(N*lg(N)) comparisons an...
Definition: sort.hpp:417
Definition: AlignedRangeIndexSetBuilders.cpp:35
RAJA_HOST_DEVICE RAJA_INLINE Iter next(Iter it)
returns iterator to next item
Definition: algorithm.hpp:90
RAJA_HOST_DEVICE RAJA_INLINE concepts::enable_if< type_traits::is_range< Container > > insertion_sort(Container &&c, Compare comp=Compare {})
stable insertion sort given range inplace using comparison function and using O(N^2) comparisons and ...
Definition: sort.hpp:707
RAJA_INLINE concepts::enable_if< type_traits::is_range< Container > > merge_sort(Container &&c, Compare comp=Compare {})
stable merge sort given range inplace using comparison function and using O(N*lg(N)) comparisons and ...
Definition: sort.hpp:829
RAJA_HOST_DEVICE RAJA_INLINE concepts::enable_if< type_traits::is_range< Container > > heap_sort(Container &&c, Compare comp=Compare {})
unstable heap sort given range inplace using comparison function and using O(N*lg(N)) comparisons and...
Definition: sort.hpp:769
RAJA_HOST_DEVICE constexpr RAJA_INLINE T log2(T n) noexcept
evaluate log base 2 of n
Definition: math.hpp:40
RAJA_HOST_DEVICE RAJA_INLINE void safe_iter_swap(Iter lhs, Iter rhs)
swap values at iterators lhs and rhs
Definition: algorithm.hpp:75
RAJA_HOST_DEVICE RAJA_INLINE concepts::enable_if< type_traits::is_range< Container > > shell_sort(Container &&c, Compare comp=Compare {})
unstable shell sort given range inplace using comparison function and using O(N^?) comparisons and O(...
Definition: sort.hpp:738
RAJA_HOST_DEVICE RAJA_INLINE Iter prev(Iter it)
returns iterator to next item
Definition: algorithm.hpp:100
RAJA_HOST_DEVICE RAJA_INLINE concepts::enable_if< type_traits::is_range< Container > > intro_sort(Container &&c, Compare comp=Compare {})
unstable intro sort given range inplace using comparison function and using O(N*lg(N)) comparisons an...
Definition: sort.hpp:800
Definition: MemUtils_CPU.hpp:109
max recursion depth for intro sort when compiling device code.
Definition: sort.hpp:326
static constexpr unsigned get()
Definition: sort.hpp:327
cutoff for intro sort to use insertion sort on small ranges.
Definition: sort.hpp:334
static constexpr size_t get()
Definition: sort.hpp:335