adjacent_find.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@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_ADJACENT_FIND_HPP
  11. #define BOOST_COMPUTE_ALGORITHM_ADJACENT_FIND_HPP
  12. #include <iterator>
  13. #include <boost/static_assert.hpp>
  14. #include <boost/compute/command_queue.hpp>
  15. #include <boost/compute/lambda.hpp>
  16. #include <boost/compute/system.hpp>
  17. #include <boost/compute/container/detail/scalar.hpp>
  18. #include <boost/compute/detail/iterator_range_size.hpp>
  19. #include <boost/compute/detail/meta_kernel.hpp>
  20. #include <boost/compute/functional/operator.hpp>
  21. #include <boost/compute/type_traits/vector_size.hpp>
  22. #include <boost/compute/type_traits/is_device_iterator.hpp>
  23. namespace boost {
  24. namespace compute {
  25. namespace detail {
  26. template<class InputIterator, class Compare>
  27. inline InputIterator
  28. serial_adjacent_find(InputIterator first,
  29. InputIterator last,
  30. Compare compare,
  31. command_queue &queue)
  32. {
  33. if(first == last){
  34. return last;
  35. }
  36. const context &context = queue.get_context();
  37. detail::scalar<uint_> output(context);
  38. detail::meta_kernel k("serial_adjacent_find");
  39. size_t size_arg = k.add_arg<const uint_>("size");
  40. size_t output_arg = k.add_arg<uint_ *>(memory_object::global_memory, "output");
  41. k << k.decl<uint_>("result") << " = size;\n"
  42. << "for(uint i = 0; i < size - 1; i++){\n"
  43. << " if(" << compare(first[k.expr<uint_>("i")],
  44. first[k.expr<uint_>("i+1")]) << "){\n"
  45. << " result = i;\n"
  46. << " break;\n"
  47. << " }\n"
  48. << "}\n"
  49. << "*output = result;\n";
  50. k.set_arg<const uint_>(
  51. size_arg, static_cast<uint_>(detail::iterator_range_size(first, last))
  52. );
  53. k.set_arg(output_arg, output.get_buffer());
  54. k.exec_1d(queue, 0, 1, 1);
  55. return first + output.read(queue);
  56. }
  57. template<class InputIterator, class Compare>
  58. inline InputIterator
  59. adjacent_find_with_atomics(InputIterator first,
  60. InputIterator last,
  61. Compare compare,
  62. command_queue &queue)
  63. {
  64. if(first == last){
  65. return last;
  66. }
  67. const context &context = queue.get_context();
  68. size_t count = detail::iterator_range_size(first, last);
  69. // initialize output to the last index
  70. detail::scalar<uint_> output(context);
  71. output.write(static_cast<uint_>(count), queue);
  72. detail::meta_kernel k("adjacent_find_with_atomics");
  73. size_t output_arg = k.add_arg<uint_ *>(memory_object::global_memory, "output");
  74. k << "const uint i = get_global_id(0);\n"
  75. << "if(" << compare(first[k.expr<uint_>("i")],
  76. first[k.expr<uint_>("i+1")]) << "){\n"
  77. << " atomic_min(output, i);\n"
  78. << "}\n";
  79. k.set_arg(output_arg, output.get_buffer());
  80. k.exec_1d(queue, 0, count - 1, 1);
  81. return first + output.read(queue);
  82. }
  83. } // end detail namespace
  84. /// Searches the range [\p first, \p last) for two identical adjacent
  85. /// elements and returns an iterator pointing to the first.
  86. ///
  87. /// \param first first element in the range to search
  88. /// \param last last element in the range to search
  89. /// \param compare binary comparison function
  90. /// \param queue command queue to perform the operation
  91. ///
  92. /// \return \c InputIteratorm to the first element which compares equal
  93. /// to the following element. If none are equal, returns \c last.
  94. ///
  95. /// Space complexity: \Omega(1)
  96. ///
  97. /// \see find(), adjacent_difference()
  98. template<class InputIterator, class Compare>
  99. inline InputIterator
  100. adjacent_find(InputIterator first,
  101. InputIterator last,
  102. Compare compare,
  103. command_queue &queue = system::default_queue())
  104. {
  105. BOOST_STATIC_ASSERT(is_device_iterator<InputIterator>::value);
  106. size_t count = detail::iterator_range_size(first, last);
  107. if(count < 32){
  108. return detail::serial_adjacent_find(first, last, compare, queue);
  109. }
  110. else {
  111. return detail::adjacent_find_with_atomics(first, last, compare, queue);
  112. }
  113. }
  114. /// \overload
  115. template<class InputIterator>
  116. inline InputIterator
  117. adjacent_find(InputIterator first,
  118. InputIterator last,
  119. command_queue &queue = system::default_queue())
  120. {
  121. BOOST_STATIC_ASSERT(is_device_iterator<InputIterator>::value);
  122. typedef typename std::iterator_traits<InputIterator>::value_type value_type;
  123. using ::boost::compute::lambda::_1;
  124. using ::boost::compute::lambda::_2;
  125. using ::boost::compute::lambda::all;
  126. if(vector_size<value_type>::value == 1){
  127. return ::boost::compute::adjacent_find(
  128. first, last, _1 == _2, queue
  129. );
  130. }
  131. else {
  132. return ::boost::compute::adjacent_find(
  133. first, last, all(_1 == _2), queue
  134. );
  135. }
  136. }
  137. } // end compute namespace
  138. } // end boost namespace
  139. #endif // BOOST_COMPUTE_ALGORITHM_ADJACENT_FIND_HPP