strided_iterator.hpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2015 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_ITERATOR_STRIDED_ITERATOR_HPP
  11. #define BOOST_COMPUTE_ITERATOR_STRIDED_ITERATOR_HPP
  12. #include <cstddef>
  13. #include <iterator>
  14. #include <boost/config.hpp>
  15. #include <boost/iterator/iterator_adaptor.hpp>
  16. #include <boost/compute/functional.hpp>
  17. #include <boost/compute/detail/meta_kernel.hpp>
  18. #include <boost/compute/detail/is_buffer_iterator.hpp>
  19. #include <boost/compute/detail/read_write_single_value.hpp>
  20. #include <boost/compute/iterator/detail/get_base_iterator_buffer.hpp>
  21. #include <boost/compute/type_traits/is_device_iterator.hpp>
  22. #include <boost/compute/type_traits/result_of.hpp>
  23. namespace boost {
  24. namespace compute {
  25. // forward declaration for strided_iterator
  26. template<class Iterator>
  27. class strided_iterator;
  28. namespace detail {
  29. // helper class which defines the iterator_adaptor super-class
  30. // type for strided_iterator
  31. template<class Iterator>
  32. class strided_iterator_base
  33. {
  34. public:
  35. typedef ::boost::iterator_adaptor<
  36. ::boost::compute::strided_iterator<Iterator>,
  37. Iterator,
  38. typename std::iterator_traits<Iterator>::value_type,
  39. typename std::iterator_traits<Iterator>::iterator_category
  40. > type;
  41. };
  42. // helper class for including stride value in index expression
  43. template<class IndexExpr, class Stride>
  44. struct stride_expr
  45. {
  46. stride_expr(const IndexExpr &expr, const Stride &stride)
  47. : m_index_expr(expr),
  48. m_stride(stride)
  49. {
  50. }
  51. const IndexExpr m_index_expr;
  52. const Stride m_stride;
  53. };
  54. template<class IndexExpr, class Stride>
  55. inline stride_expr<IndexExpr, Stride> make_stride_expr(const IndexExpr &expr,
  56. const Stride &stride)
  57. {
  58. return stride_expr<IndexExpr, Stride>(expr, stride);
  59. }
  60. template<class IndexExpr, class Stride>
  61. inline meta_kernel& operator<<(meta_kernel &kernel,
  62. const stride_expr<IndexExpr, Stride> &expr)
  63. {
  64. // (expr.m_stride * (expr.m_index_expr))
  65. return kernel << "(" << static_cast<ulong_>(expr.m_stride)
  66. << " * (" << expr.m_index_expr << "))";
  67. }
  68. template<class Iterator, class Stride, class IndexExpr>
  69. struct strided_iterator_index_expr
  70. {
  71. typedef typename std::iterator_traits<Iterator>::value_type result_type;
  72. strided_iterator_index_expr(const Iterator &input_iter,
  73. const Stride &stride,
  74. const IndexExpr &index_expr)
  75. : m_input_iter(input_iter),
  76. m_stride(stride),
  77. m_index_expr(index_expr)
  78. {
  79. }
  80. const Iterator m_input_iter;
  81. const Stride m_stride;
  82. const IndexExpr m_index_expr;
  83. };
  84. template<class Iterator, class Stride, class IndexExpr>
  85. inline meta_kernel& operator<<(meta_kernel &kernel,
  86. const strided_iterator_index_expr<Iterator,
  87. Stride,
  88. IndexExpr> &expr)
  89. {
  90. return kernel << expr.m_input_iter[make_stride_expr(expr.m_index_expr, expr.m_stride)];
  91. }
  92. } // end detail namespace
  93. /// \class strided_iterator
  94. /// \brief An iterator adaptor with adjustable iteration step.
  95. ///
  96. /// The strided iterator adaptor skips over multiple elements each time
  97. /// it is incremented or decremented.
  98. ///
  99. /// \see buffer_iterator, make_strided_iterator(), make_strided_iterator_end()
  100. template<class Iterator>
  101. class strided_iterator :
  102. public detail::strided_iterator_base<Iterator>::type
  103. {
  104. public:
  105. typedef typename
  106. detail::strided_iterator_base<Iterator>::type super_type;
  107. typedef typename super_type::value_type value_type;
  108. typedef typename super_type::reference reference;
  109. typedef typename super_type::base_type base_type;
  110. typedef typename super_type::difference_type difference_type;
  111. strided_iterator(Iterator iterator, difference_type stride)
  112. : super_type(iterator),
  113. m_stride(static_cast<difference_type>(stride))
  114. {
  115. // stride must be greater than zero
  116. BOOST_ASSERT_MSG(stride > 0, "Stride must be greater than zero");
  117. }
  118. strided_iterator(const strided_iterator<Iterator> &other)
  119. : super_type(other.base()),
  120. m_stride(other.m_stride)
  121. {
  122. }
  123. strided_iterator<Iterator>&
  124. operator=(const strided_iterator<Iterator> &other)
  125. {
  126. if(this != &other){
  127. super_type::operator=(other);
  128. m_stride = other.m_stride;
  129. }
  130. return *this;
  131. }
  132. ~strided_iterator()
  133. {
  134. }
  135. size_t get_index() const
  136. {
  137. return super_type::base().get_index();
  138. }
  139. const buffer& get_buffer() const
  140. {
  141. return detail::get_base_iterator_buffer(*this);
  142. }
  143. template<class IndexExpression>
  144. detail::strided_iterator_index_expr<Iterator, difference_type, IndexExpression>
  145. operator[](const IndexExpression &expr) const
  146. {
  147. typedef
  148. typename detail::strided_iterator_index_expr<Iterator,
  149. difference_type,
  150. IndexExpression>
  151. StridedIndexExprType;
  152. return StridedIndexExprType(super_type::base(),m_stride, expr);
  153. }
  154. private:
  155. friend class ::boost::iterator_core_access;
  156. reference dereference() const
  157. {
  158. return reference();
  159. }
  160. bool equal(const strided_iterator<Iterator> &other) const
  161. {
  162. return (other.m_stride == m_stride)
  163. && (other.base_reference() == this->base_reference());
  164. }
  165. void increment()
  166. {
  167. std::advance(super_type::base_reference(), m_stride);
  168. }
  169. void decrement()
  170. {
  171. std::advance(super_type::base_reference(),-m_stride);
  172. }
  173. void advance(typename super_type::difference_type n)
  174. {
  175. std::advance(super_type::base_reference(), n * m_stride);
  176. }
  177. difference_type distance_to(const strided_iterator<Iterator> &other) const
  178. {
  179. return std::distance(this->base_reference(), other.base_reference()) / m_stride;
  180. }
  181. private:
  182. difference_type m_stride;
  183. };
  184. /// Returns a strided_iterator for \p iterator with \p stride.
  185. ///
  186. /// \param iterator the underlying iterator
  187. /// \param stride the iteration step for strided_iterator
  188. ///
  189. /// \return a \c strided_iterator for \p iterator with \p stride.
  190. ///
  191. /// For example, to create an iterator which iterates over every other
  192. /// element in a \c vector<int>:
  193. /// \code
  194. /// auto strided_iterator = make_strided_iterator(vec.begin(), 2);
  195. /// \endcode
  196. template<class Iterator>
  197. inline strided_iterator<Iterator>
  198. make_strided_iterator(Iterator iterator,
  199. typename std::iterator_traits<Iterator>::difference_type stride)
  200. {
  201. return strided_iterator<Iterator>(iterator, stride);
  202. }
  203. /// Returns a strided_iterator which refers to element that would follow
  204. /// the last element accessible through strided_iterator for \p first iterator
  205. /// with \p stride.
  206. ///
  207. /// Parameter \p stride must be greater than zero.
  208. ///
  209. /// \param first the iterator referring to the first element accessible
  210. /// through strided_iterator for \p first with \p stride
  211. /// \param last the iterator referring to the last element that may be
  212. //// accessible through strided_iterator for \p first with \p stride
  213. /// \param stride the iteration step
  214. ///
  215. /// \return a \c strided_iterator referring to element that would follow
  216. /// the last element accessible through strided_iterator for \p first
  217. /// iterator with \p stride.
  218. ///
  219. /// It can be helpful when iterating over strided_iterator:
  220. /// \code
  221. /// // vec.size() may not be divisible by 3
  222. /// auto strided_iterator_begin = make_strided_iterator(vec.begin(), 3);
  223. /// auto strided_iterator_end = make_strided_iterator_end(vec.begin(), vec.end(), 3);
  224. ///
  225. /// // copy every 3rd element to result
  226. /// boost::compute::copy(
  227. /// strided_iterator_begin,
  228. /// strided_iterator_end,
  229. /// result.begin(),
  230. /// queue
  231. /// );
  232. /// \endcode
  233. template<class Iterator>
  234. strided_iterator<Iterator>
  235. make_strided_iterator_end(Iterator first,
  236. Iterator last,
  237. typename std::iterator_traits<Iterator>::difference_type stride)
  238. {
  239. typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
  240. // calculate distance from end to the last element that would be
  241. // accessible through strided_iterator.
  242. difference_type range = std::distance(first, last);
  243. difference_type d = (range - 1) / stride;
  244. d *= stride;
  245. d -= range;
  246. // advance from end to the element that would follow the last
  247. // accessible element
  248. Iterator end_for_strided_iterator = last;
  249. std::advance(end_for_strided_iterator, d + stride);
  250. return strided_iterator<Iterator>(end_for_strided_iterator, stride);
  251. }
  252. /// \internal_ (is_device_iterator specialization for strided_iterator)
  253. template<class Iterator>
  254. struct is_device_iterator<strided_iterator<Iterator> > : boost::true_type {};
  255. } // end compute namespace
  256. } // end boost namespace
  257. #endif // BOOST_COMPUTE_ITERATOR_STRIDED_ITERATOR_HPP