//---------------------------------------------------------------------------// // Copyright (c) 2013 Kyle Lutz // // Distributed under the Boost Software License, Version 1.0 // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt // // See http://boostorg.github.com/compute for more information. //---------------------------------------------------------------------------// #ifndef BOOST_COMPUTE_ITERATOR_ZIP_ITERATOR_HPP #define BOOST_COMPUTE_ITERATOR_ZIP_ITERATOR_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace compute { // forward declaration for zip_iterator template class zip_iterator; namespace detail { namespace mpl = boost::mpl; // meta-function returning the value_type for an iterator template struct make_iterator_value_type { typedef typename std::iterator_traits::value_type type; }; // meta-function returning the value_type for a zip_iterator template struct make_zip_iterator_value_type { typedef typename detail::mpl_vector_to_tuple< typename mpl::transform< IteratorTuple, make_iterator_value_type, mpl::back_inserter > >::type >::type type; }; // helper class which defines the iterator_facade super-class // type for zip_iterator template class zip_iterator_base { public: typedef ::boost::iterator_facade< ::boost::compute::zip_iterator, typename make_zip_iterator_value_type::type, ::std::random_access_iterator_tag, typename make_zip_iterator_value_type::type > type; }; template struct zip_iterator_index_expr { typedef typename make_zip_iterator_value_type::type result_type; zip_iterator_index_expr(const IteratorTuple &iterators, const IndexExpr &index_expr) : m_iterators(iterators), m_index_expr(index_expr) { } const IteratorTuple m_iterators; const IndexExpr m_index_expr; }; /// \internal_ #define BOOST_COMPUTE_PRINT_ELEM(z, n, unused) \ BOOST_PP_EXPR_IF(n, << ", ") \ << boost::get(expr.m_iterators)[expr.m_index_expr] /// \internal_ #define BOOST_COMPUTE_PRINT_ZIP_IDX(z, n, unused) \ template \ inline meta_kernel& operator<<( \ meta_kernel &kernel, \ const zip_iterator_index_expr< \ boost::tuple, \ IndexExpr \ > &expr) \ { \ typedef typename \ boost::tuple \ tuple_type; \ typedef typename \ make_zip_iterator_value_type::type \ value_type; \ kernel.inject_type(); \ return kernel \ << "(" << type_name() << ")" \ << "{ " \ BOOST_PP_REPEAT(n, BOOST_COMPUTE_PRINT_ELEM, ~) \ << "}"; \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_COMPUTE_MAX_ARITY, BOOST_COMPUTE_PRINT_ZIP_IDX, ~) #undef BOOST_COMPUTE_PRINT_ZIP_IDX #undef BOOST_COMPUTE_PRINT_ELEM struct iterator_advancer { iterator_advancer(size_t n) : m_distance(n) { } template void operator()(Iterator &i) const { std::advance(i, m_distance); } size_t m_distance; }; template void increment_iterator(Iterator &i) { i++; } template void decrement_iterator(Iterator &i) { i--; } } // end detail namespace /// \class zip_iterator /// \brief A zip iterator adaptor. /// /// The zip_iterator class combines values from multiple input iterators. When /// dereferenced it returns a tuple containing each value at the current /// position in each input range. /// /// \see make_zip_iterator() template class zip_iterator : public detail::zip_iterator_base::type { public: typedef typename detail::zip_iterator_base::type super_type; typedef typename super_type::value_type value_type; typedef typename super_type::reference reference; typedef typename super_type::difference_type difference_type; typedef IteratorTuple iterator_tuple; zip_iterator(IteratorTuple iterators) : m_iterators(iterators) { } zip_iterator(const zip_iterator &other) : m_iterators(other.m_iterators) { } zip_iterator& operator=(const zip_iterator &other) { if(this != &other){ super_type::operator=(other); m_iterators = other.m_iterators; } return *this; } ~zip_iterator() { } const IteratorTuple& get_iterator_tuple() const { return m_iterators; } template detail::zip_iterator_index_expr operator[](const IndexExpression &expr) const { return detail::zip_iterator_index_expr(m_iterators, expr); } private: friend class ::boost::iterator_core_access; reference dereference() const { return reference(); } bool equal(const zip_iterator &other) const { return m_iterators == other.m_iterators; } void increment() { boost::fusion::for_each(m_iterators, detail::increment_iterator); } void decrement() { boost::fusion::for_each(m_iterators, detail::decrement_iterator); } void advance(difference_type n) { boost::fusion::for_each(m_iterators, detail::iterator_advancer(n)); } difference_type distance_to(const zip_iterator &other) const { return std::distance(boost::get<0>(m_iterators), boost::get<0>(other.m_iterators)); } private: IteratorTuple m_iterators; }; /// Creates a zip_iterator for \p iterators. /// /// \param iterators a tuple of input iterators to zip together /// /// \return a \c zip_iterator for \p iterators /// /// For example, to zip together iterators from three vectors (\c a, \c b, and /// \p c): /// \code /// auto zipped = boost::compute::make_zip_iterator( /// boost::make_tuple(a.begin(), b.begin(), c.begin()) /// ); /// \endcode template inline zip_iterator make_zip_iterator(IteratorTuple iterators) { return zip_iterator(iterators); } /// \internal_ (is_device_iterator specialization for zip_iterator) template struct is_device_iterator > : boost::true_type {}; namespace detail { // get() specialization for zip_iterator /// \internal_ #define BOOST_COMPUTE_ZIP_GET_N(z, n, unused) \ template \ inline meta_kernel& \ operator<<(meta_kernel &kernel, \ const invoked_get< \ N, \ zip_iterator_index_expr, \ boost::tuple \ > &expr) \ { \ typedef typename boost::tuple Tuple; \ typedef typename boost::tuples::element::type T; \ BOOST_STATIC_ASSERT(N < size_t(boost::tuples::length::value)); \ kernel.inject_type(); \ return kernel \ << boost::get(expr.m_arg.m_iterators)[expr.m_arg.m_index_expr]; \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_COMPUTE_MAX_ARITY, BOOST_COMPUTE_ZIP_GET_N, ~) #undef BOOST_COMPUTE_ZIP_GET_N } // end detail namespace } // end compute namespace } // end boost namespace #endif // BOOST_COMPUTE_ITERATOR_ZIP_ITERATOR_HPP