stable_sort_by_key.hpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2016 Jakub Szuppe <j.szuppe@gmail.com>
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. // See http://boostorg.github.com/compute for more information.
  9. //---------------------------------------------------------------------------//
  10. #ifndef BOOST_COMPUTE_ALGORITHM_STABLE_SORT_BY_KEY_HPP
  11. #define BOOST_COMPUTE_ALGORITHM_STABLE_SORT_BY_KEY_HPP
  12. #include <iterator>
  13. #include <boost/static_assert.hpp>
  14. #include <boost/compute/system.hpp>
  15. #include <boost/compute/command_queue.hpp>
  16. #include <boost/compute/algorithm/sort_by_key.hpp>
  17. #include <boost/compute/detail/iterator_range_size.hpp>
  18. #include <boost/compute/type_traits/is_device_iterator.hpp>
  19. namespace boost {
  20. namespace compute {
  21. namespace detail {
  22. template<class KeyIterator, class ValueIterator>
  23. inline void
  24. dispatch_gpu_ssort_by_key(KeyIterator keys_first,
  25. KeyIterator keys_last,
  26. ValueIterator values_first,
  27. less<typename std::iterator_traits<KeyIterator>::value_type> compare,
  28. command_queue &queue,
  29. typename boost::enable_if_c<
  30. is_radix_sortable<
  31. typename std::iterator_traits<KeyIterator>::value_type
  32. >::value
  33. >::type* = 0)
  34. {
  35. size_t count = detail::iterator_range_size(keys_first, keys_last);
  36. if(count < 32){
  37. detail::serial_insertion_sort_by_key(
  38. keys_first, keys_last, values_first, compare, queue
  39. );
  40. }
  41. else {
  42. detail::radix_sort_by_key(
  43. keys_first, keys_last, values_first, queue
  44. );
  45. }
  46. }
  47. template<class KeyIterator, class ValueIterator>
  48. inline void
  49. dispatch_gpu_ssort_by_key(KeyIterator keys_first,
  50. KeyIterator keys_last,
  51. ValueIterator values_first,
  52. greater<typename std::iterator_traits<KeyIterator>::value_type> compare,
  53. command_queue &queue,
  54. typename boost::enable_if_c<
  55. is_radix_sortable<
  56. typename std::iterator_traits<KeyIterator>::value_type
  57. >::value
  58. >::type* = 0)
  59. {
  60. size_t count = detail::iterator_range_size(keys_first, keys_last);
  61. if(count < 32){
  62. detail::serial_insertion_sort_by_key(
  63. keys_first, keys_last, values_first, compare, queue
  64. );
  65. }
  66. else {
  67. // radix sorts in descending order
  68. detail::radix_sort_by_key(
  69. keys_first, keys_last, values_first, false, queue
  70. );
  71. }
  72. }
  73. template<class KeyIterator, class ValueIterator, class Compare>
  74. inline void dispatch_gpu_ssort_by_key(KeyIterator keys_first,
  75. KeyIterator keys_last,
  76. ValueIterator values_first,
  77. Compare compare,
  78. command_queue &queue)
  79. {
  80. size_t count = detail::iterator_range_size(keys_first, keys_last);
  81. if(count < 32){
  82. detail::serial_insertion_sort_by_key(
  83. keys_first, keys_last, values_first,
  84. compare, queue
  85. );
  86. } else {
  87. detail::merge_sort_by_key_on_gpu(
  88. keys_first, keys_last, values_first,
  89. compare, true /* stable */, queue
  90. );
  91. }
  92. }
  93. template<class KeyIterator, class ValueIterator, class Compare>
  94. inline void dispatch_ssort_by_key(KeyIterator keys_first,
  95. KeyIterator keys_last,
  96. ValueIterator values_first,
  97. Compare compare,
  98. command_queue &queue)
  99. {
  100. if(queue.get_device().type() & device::gpu) {
  101. dispatch_gpu_ssort_by_key(
  102. keys_first, keys_last, values_first, compare, queue
  103. );
  104. return;
  105. }
  106. ::boost::compute::detail::merge_sort_by_key_on_cpu(
  107. keys_first, keys_last, values_first, compare, queue
  108. );
  109. }
  110. } // end detail namespace
  111. /// Performs a key-value stable sort using the keys in the range [\p keys_first,
  112. /// \p keys_last) on the values in the range [\p values_first,
  113. /// \p values_first \c + (\p keys_last \c - \p keys_first)) using \p compare.
  114. ///
  115. /// If no compare function is specified, \c less is used.
  116. ///
  117. /// Space complexity: \Omega(2n)
  118. ///
  119. /// \see sort()
  120. template<class KeyIterator, class ValueIterator, class Compare>
  121. inline void stable_sort_by_key(KeyIterator keys_first,
  122. KeyIterator keys_last,
  123. ValueIterator values_first,
  124. Compare compare,
  125. command_queue &queue = system::default_queue())
  126. {
  127. BOOST_STATIC_ASSERT(is_device_iterator<KeyIterator>::value);
  128. BOOST_STATIC_ASSERT(is_device_iterator<ValueIterator>::value);
  129. ::boost::compute::detail::dispatch_ssort_by_key(
  130. keys_first, keys_last, values_first, compare, queue
  131. );
  132. }
  133. /// \overload
  134. template<class KeyIterator, class ValueIterator>
  135. inline void stable_sort_by_key(KeyIterator keys_first,
  136. KeyIterator keys_last,
  137. ValueIterator values_first,
  138. command_queue &queue = system::default_queue())
  139. {
  140. BOOST_STATIC_ASSERT(is_device_iterator<KeyIterator>::value);
  141. BOOST_STATIC_ASSERT(is_device_iterator<ValueIterator>::value);
  142. typedef typename std::iterator_traits<KeyIterator>::value_type key_type;
  143. ::boost::compute::stable_sort_by_key(
  144. keys_first, keys_last, values_first, less<key_type>(), queue
  145. );
  146. }
  147. } // end compute namespace
  148. } // end boost namespace
  149. #endif // BOOST_COMPUTE_ALGORITHM_STABLE_SORT_BY_KEY_HPP