zip_iterator.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013 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_ITERATOR_ZIP_ITERATOR_HPP
  11. #define BOOST_COMPUTE_ITERATOR_ZIP_ITERATOR_HPP
  12. #include <cstddef>
  13. #include <iterator>
  14. #include <boost/config.hpp>
  15. #include <boost/fusion/algorithm/iteration/for_each.hpp>
  16. #include <boost/iterator/iterator_facade.hpp>
  17. #include <boost/mpl/back_inserter.hpp>
  18. #include <boost/mpl/transform.hpp>
  19. #include <boost/mpl/vector.hpp>
  20. #include <boost/preprocessor/repetition.hpp>
  21. #include <boost/tuple/tuple.hpp>
  22. #include <boost/tuple/tuple_comparison.hpp>
  23. #include <boost/compute/config.hpp>
  24. #include <boost/compute/functional.hpp>
  25. #include <boost/compute/detail/meta_kernel.hpp>
  26. #include <boost/compute/detail/mpl_vector_to_tuple.hpp>
  27. #include <boost/compute/types/tuple.hpp>
  28. #include <boost/compute/type_traits/is_device_iterator.hpp>
  29. #include <boost/compute/type_traits/type_name.hpp>
  30. namespace boost {
  31. namespace compute {
  32. // forward declaration for zip_iterator
  33. template<class IteratorTuple>
  34. class zip_iterator;
  35. namespace detail {
  36. namespace mpl = boost::mpl;
  37. // meta-function returning the value_type for an iterator
  38. template<class Iterator>
  39. struct make_iterator_value_type
  40. {
  41. typedef typename std::iterator_traits<Iterator>::value_type type;
  42. };
  43. // meta-function returning the value_type for a zip_iterator
  44. template<class IteratorTuple>
  45. struct make_zip_iterator_value_type
  46. {
  47. typedef typename
  48. detail::mpl_vector_to_tuple<
  49. typename mpl::transform<
  50. IteratorTuple,
  51. make_iterator_value_type<mpl::_1>,
  52. mpl::back_inserter<mpl::vector<> >
  53. >::type
  54. >::type type;
  55. };
  56. // helper class which defines the iterator_facade super-class
  57. // type for zip_iterator
  58. template<class IteratorTuple>
  59. class zip_iterator_base
  60. {
  61. public:
  62. typedef ::boost::iterator_facade<
  63. ::boost::compute::zip_iterator<IteratorTuple>,
  64. typename make_zip_iterator_value_type<IteratorTuple>::type,
  65. ::std::random_access_iterator_tag,
  66. typename make_zip_iterator_value_type<IteratorTuple>::type
  67. > type;
  68. };
  69. template<class IteratorTuple, class IndexExpr>
  70. struct zip_iterator_index_expr
  71. {
  72. typedef typename
  73. make_zip_iterator_value_type<IteratorTuple>::type
  74. result_type;
  75. zip_iterator_index_expr(const IteratorTuple &iterators,
  76. const IndexExpr &index_expr)
  77. : m_iterators(iterators),
  78. m_index_expr(index_expr)
  79. {
  80. }
  81. const IteratorTuple m_iterators;
  82. const IndexExpr m_index_expr;
  83. };
  84. /// \internal_
  85. #define BOOST_COMPUTE_PRINT_ELEM(z, n, unused) \
  86. BOOST_PP_EXPR_IF(n, << ", ") \
  87. << boost::get<n>(expr.m_iterators)[expr.m_index_expr]
  88. /// \internal_
  89. #define BOOST_COMPUTE_PRINT_ZIP_IDX(z, n, unused) \
  90. template<BOOST_PP_ENUM_PARAMS(n, class Iterator), class IndexExpr> \
  91. inline meta_kernel& operator<<( \
  92. meta_kernel &kernel, \
  93. const zip_iterator_index_expr< \
  94. boost::tuple<BOOST_PP_ENUM_PARAMS(n, Iterator)>, \
  95. IndexExpr \
  96. > &expr) \
  97. { \
  98. typedef typename \
  99. boost::tuple<BOOST_PP_ENUM_PARAMS(n, Iterator)> \
  100. tuple_type; \
  101. typedef typename \
  102. make_zip_iterator_value_type<tuple_type>::type \
  103. value_type; \
  104. kernel.inject_type<value_type>(); \
  105. return kernel \
  106. << "(" << type_name<value_type>() << ")" \
  107. << "{ " \
  108. BOOST_PP_REPEAT(n, BOOST_COMPUTE_PRINT_ELEM, ~) \
  109. << "}"; \
  110. }
  111. BOOST_PP_REPEAT_FROM_TO(1, BOOST_COMPUTE_MAX_ARITY, BOOST_COMPUTE_PRINT_ZIP_IDX, ~)
  112. #undef BOOST_COMPUTE_PRINT_ZIP_IDX
  113. #undef BOOST_COMPUTE_PRINT_ELEM
  114. struct iterator_advancer
  115. {
  116. iterator_advancer(size_t n)
  117. : m_distance(n)
  118. {
  119. }
  120. template<class Iterator>
  121. void operator()(Iterator &i) const
  122. {
  123. std::advance(i, m_distance);
  124. }
  125. size_t m_distance;
  126. };
  127. template<class Iterator>
  128. void increment_iterator(Iterator &i)
  129. {
  130. i++;
  131. }
  132. template<class Iterator>
  133. void decrement_iterator(Iterator &i)
  134. {
  135. i--;
  136. }
  137. } // end detail namespace
  138. /// \class zip_iterator
  139. /// \brief A zip iterator adaptor.
  140. ///
  141. /// The zip_iterator class combines values from multiple input iterators. When
  142. /// dereferenced it returns a tuple containing each value at the current
  143. /// position in each input range.
  144. ///
  145. /// \see make_zip_iterator()
  146. template<class IteratorTuple>
  147. class zip_iterator : public detail::zip_iterator_base<IteratorTuple>::type
  148. {
  149. public:
  150. typedef typename
  151. detail::zip_iterator_base<IteratorTuple>::type
  152. super_type;
  153. typedef typename super_type::value_type value_type;
  154. typedef typename super_type::reference reference;
  155. typedef typename super_type::difference_type difference_type;
  156. typedef IteratorTuple iterator_tuple;
  157. zip_iterator(IteratorTuple iterators)
  158. : m_iterators(iterators)
  159. {
  160. }
  161. zip_iterator(const zip_iterator<IteratorTuple> &other)
  162. : m_iterators(other.m_iterators)
  163. {
  164. }
  165. zip_iterator<IteratorTuple>&
  166. operator=(const zip_iterator<IteratorTuple> &other)
  167. {
  168. if(this != &other){
  169. super_type::operator=(other);
  170. m_iterators = other.m_iterators;
  171. }
  172. return *this;
  173. }
  174. ~zip_iterator()
  175. {
  176. }
  177. const IteratorTuple& get_iterator_tuple() const
  178. {
  179. return m_iterators;
  180. }
  181. template<class IndexExpression>
  182. detail::zip_iterator_index_expr<IteratorTuple, IndexExpression>
  183. operator[](const IndexExpression &expr) const
  184. {
  185. return detail::zip_iterator_index_expr<IteratorTuple,
  186. IndexExpression>(m_iterators,
  187. expr);
  188. }
  189. private:
  190. friend class ::boost::iterator_core_access;
  191. reference dereference() const
  192. {
  193. return reference();
  194. }
  195. bool equal(const zip_iterator<IteratorTuple> &other) const
  196. {
  197. return m_iterators == other.m_iterators;
  198. }
  199. void increment()
  200. {
  201. boost::fusion::for_each(m_iterators, detail::increment_iterator);
  202. }
  203. void decrement()
  204. {
  205. boost::fusion::for_each(m_iterators, detail::decrement_iterator);
  206. }
  207. void advance(difference_type n)
  208. {
  209. boost::fusion::for_each(m_iterators, detail::iterator_advancer(n));
  210. }
  211. difference_type distance_to(const zip_iterator<IteratorTuple> &other) const
  212. {
  213. return std::distance(boost::get<0>(m_iterators),
  214. boost::get<0>(other.m_iterators));
  215. }
  216. private:
  217. IteratorTuple m_iterators;
  218. };
  219. /// Creates a zip_iterator for \p iterators.
  220. ///
  221. /// \param iterators a tuple of input iterators to zip together
  222. ///
  223. /// \return a \c zip_iterator for \p iterators
  224. ///
  225. /// For example, to zip together iterators from three vectors (\c a, \c b, and
  226. /// \p c):
  227. /// \code
  228. /// auto zipped = boost::compute::make_zip_iterator(
  229. /// boost::make_tuple(a.begin(), b.begin(), c.begin())
  230. /// );
  231. /// \endcode
  232. template<class IteratorTuple>
  233. inline zip_iterator<IteratorTuple>
  234. make_zip_iterator(IteratorTuple iterators)
  235. {
  236. return zip_iterator<IteratorTuple>(iterators);
  237. }
  238. /// \internal_ (is_device_iterator specialization for zip_iterator)
  239. template<class IteratorTuple>
  240. struct is_device_iterator<zip_iterator<IteratorTuple> > : boost::true_type {};
  241. namespace detail {
  242. // get<N>() specialization for zip_iterator
  243. /// \internal_
  244. #define BOOST_COMPUTE_ZIP_GET_N(z, n, unused) \
  245. template<size_t N, class IteratorTuple, class IndexExpr, \
  246. BOOST_PP_ENUM_PARAMS(n, class T)> \
  247. inline meta_kernel& \
  248. operator<<(meta_kernel &kernel, \
  249. const invoked_get< \
  250. N, \
  251. zip_iterator_index_expr<IteratorTuple, IndexExpr>, \
  252. boost::tuple<BOOST_PP_ENUM_PARAMS(n, T)> \
  253. > &expr) \
  254. { \
  255. typedef typename boost::tuple<BOOST_PP_ENUM_PARAMS(n, T)> Tuple; \
  256. typedef typename boost::tuples::element<N, Tuple>::type T; \
  257. BOOST_STATIC_ASSERT(N < size_t(boost::tuples::length<Tuple>::value)); \
  258. kernel.inject_type<T>(); \
  259. return kernel \
  260. << boost::get<N>(expr.m_arg.m_iterators)[expr.m_arg.m_index_expr]; \
  261. }
  262. BOOST_PP_REPEAT_FROM_TO(1, BOOST_COMPUTE_MAX_ARITY, BOOST_COMPUTE_ZIP_GET_N, ~)
  263. #undef BOOST_COMPUTE_ZIP_GET_N
  264. } // end detail namespace
  265. } // end compute namespace
  266. } // end boost namespace
  267. #endif // BOOST_COMPUTE_ITERATOR_ZIP_ITERATOR_HPP