transform_if.hpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013-2015 Kyle Lutz <[email protected]>
  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_TRANSFORM_IF_HPP
  11. #define BOOST_COMPUTE_ALGORITHM_TRANSFORM_IF_HPP
  12. #include <boost/static_assert.hpp>
  13. #include <boost/compute/cl.hpp>
  14. #include <boost/compute/system.hpp>
  15. #include <boost/compute/command_queue.hpp>
  16. #include <boost/compute/algorithm/count.hpp>
  17. #include <boost/compute/algorithm/count_if.hpp>
  18. #include <boost/compute/algorithm/exclusive_scan.hpp>
  19. #include <boost/compute/container/vector.hpp>
  20. #include <boost/compute/detail/meta_kernel.hpp>
  21. #include <boost/compute/detail/iterator_range_size.hpp>
  22. #include <boost/compute/iterator/discard_iterator.hpp>
  23. #include <boost/compute/type_traits/is_device_iterator.hpp>
  24. namespace boost {
  25. namespace compute {
  26. namespace detail {
  27. // Space complexity: O(2n)
  28. template<class InputIterator, class OutputIterator, class UnaryFunction, class Predicate>
  29. inline OutputIterator transform_if_impl(InputIterator first,
  30. InputIterator last,
  31. OutputIterator result,
  32. UnaryFunction function,
  33. Predicate predicate,
  34. bool copyIndex,
  35. command_queue &queue)
  36. {
  37. typedef typename std::iterator_traits<OutputIterator>::difference_type difference_type;
  38. size_t count = detail::iterator_range_size(first, last);
  39. if(count == 0){
  40. return result;
  41. }
  42. const context &context = queue.get_context();
  43. // storage for destination indices
  44. ::boost::compute::vector<cl_uint> indices(count, context);
  45. // write counts
  46. ::boost::compute::detail::meta_kernel k1("transform_if_write_counts");
  47. k1 << indices.begin()[k1.get_global_id(0)] << " = "
  48. << predicate(first[k1.get_global_id(0)]) << " ? 1 : 0;\n";
  49. k1.exec_1d(queue, 0, count);
  50. // scan indices
  51. size_t copied_element_count = (indices.cend() - 1).read(queue);
  52. ::boost::compute::exclusive_scan(
  53. indices.begin(), indices.end(), indices.begin(), queue
  54. );
  55. copied_element_count += (indices.cend() - 1).read(queue); // last scan element plus last mask element
  56. // copy values
  57. ::boost::compute::detail::meta_kernel k2("transform_if_do_copy");
  58. k2 << "if(" << predicate(first[k2.get_global_id(0)]) << ")" <<
  59. " " << result[indices.begin()[k2.get_global_id(0)]] << "=";
  60. if(copyIndex){
  61. k2 << k2.get_global_id(0) << ";\n";
  62. }
  63. else {
  64. k2 << function(first[k2.get_global_id(0)]) << ";\n";
  65. }
  66. k2.exec_1d(queue, 0, count);
  67. return result + static_cast<difference_type>(copied_element_count);
  68. }
  69. template<class InputIterator, class UnaryFunction, class Predicate>
  70. inline discard_iterator transform_if_impl(InputIterator first,
  71. InputIterator last,
  72. discard_iterator result,
  73. UnaryFunction function,
  74. Predicate predicate,
  75. bool copyIndex,
  76. command_queue &queue)
  77. {
  78. (void) function;
  79. (void) copyIndex;
  80. return result + count_if(first, last, predicate, queue);
  81. }
  82. } // end detail namespace
  83. /// Copies each element in the range [\p first, \p last) for which
  84. /// \p predicate returns \c true to the range beginning at \p result.
  85. ///
  86. /// Space complexity: O(2n)
  87. template<class InputIterator, class OutputIterator, class UnaryFunction, class Predicate>
  88. inline OutputIterator transform_if(InputIterator first,
  89. InputIterator last,
  90. OutputIterator result,
  91. UnaryFunction function,
  92. Predicate predicate,
  93. command_queue &queue = system::default_queue())
  94. {
  95. BOOST_STATIC_ASSERT(is_device_iterator<InputIterator>::value);
  96. BOOST_STATIC_ASSERT(is_device_iterator<OutputIterator>::value);
  97. return detail::transform_if_impl(
  98. first, last, result, function, predicate, false, queue
  99. );
  100. }
  101. } // end compute namespace
  102. } // end boost namespace
  103. #endif // BOOST_COMPUTE_ALGORITHM_TRANSFORM_IF_HPP