| // Copyright David Abrahams and Thomas Becker 2000-2006. 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) |
| |
| #ifndef BOOST_ZIP_ITERATOR_TMB_07_13_2003_HPP_ |
| # define BOOST_ZIP_ITERATOR_TMB_07_13_2003_HPP_ |
| |
| #include <stddef.h> |
| #include <boost/iterator.hpp> |
| #include <boost/iterator/iterator_traits.hpp> |
| #include <boost/iterator/iterator_facade.hpp> |
| #include <boost/iterator/iterator_adaptor.hpp> // for enable_if_convertible |
| #include <boost/iterator/iterator_categories.hpp> |
| #include <boost/detail/iterator.hpp> |
| |
| #include <boost/iterator/detail/minimum_category.hpp> |
| |
| #include <boost/tuple/tuple.hpp> |
| |
| #include <boost/type_traits/is_same.hpp> |
| #include <boost/mpl/and.hpp> |
| #include <boost/mpl/apply.hpp> |
| #include <boost/mpl/eval_if.hpp> |
| #include <boost/mpl/lambda.hpp> |
| #include <boost/mpl/placeholders.hpp> |
| #include <boost/mpl/aux_/lambda_support.hpp> |
| |
| namespace boost { |
| |
| // Zip iterator forward declaration for zip_iterator_base |
| template<typename IteratorTuple> |
| class zip_iterator; |
| |
| // One important design goal of the zip_iterator is to isolate all |
| // functionality whose implementation relies on the current tuple |
| // implementation. This goal has been achieved as follows: Inside |
| // the namespace detail there is a namespace tuple_impl_specific. |
| // This namespace encapsulates all functionality that is specific |
| // to the current Boost tuple implementation. More precisely, the |
| // namespace tuple_impl_specific provides the following tuple |
| // algorithms and meta-algorithms for the current Boost tuple |
| // implementation: |
| // |
| // tuple_meta_transform |
| // tuple_meta_accumulate |
| // tuple_transform |
| // tuple_for_each |
| // |
| // If the tuple implementation changes, all that needs to be |
| // replaced is the implementation of these four (meta-)algorithms. |
| |
| namespace detail |
| { |
| |
| // Functors to be used with tuple algorithms |
| // |
| template<typename DiffType> |
| class advance_iterator |
| { |
| public: |
| advance_iterator(DiffType step) : m_step(step) {} |
| |
| template<typename Iterator> |
| void operator()(Iterator& it) const |
| { it += m_step; } |
| |
| private: |
| DiffType m_step; |
| }; |
| // |
| struct increment_iterator |
| { |
| template<typename Iterator> |
| void operator()(Iterator& it) |
| { ++it; } |
| }; |
| // |
| struct decrement_iterator |
| { |
| template<typename Iterator> |
| void operator()(Iterator& it) |
| { --it; } |
| }; |
| // |
| struct dereference_iterator |
| { |
| template<typename Iterator> |
| struct apply |
| { |
| typedef typename |
| iterator_traits<Iterator>::reference |
| type; |
| }; |
| |
| template<typename Iterator> |
| typename apply<Iterator>::type operator()(Iterator const& it) |
| { return *it; } |
| }; |
| |
| |
| // The namespace tuple_impl_specific provides two meta- |
| // algorithms and two algorithms for tuples. |
| // |
| namespace tuple_impl_specific |
| { |
| // Meta-transform algorithm for tuples |
| // |
| template<typename Tuple, class UnaryMetaFun> |
| struct tuple_meta_transform; |
| |
| template<typename Tuple, class UnaryMetaFun> |
| struct tuple_meta_transform_impl |
| { |
| typedef tuples::cons< |
| typename mpl::apply1< |
| typename mpl::lambda<UnaryMetaFun>::type |
| , typename Tuple::head_type |
| >::type |
| , typename tuple_meta_transform< |
| typename Tuple::tail_type |
| , UnaryMetaFun |
| >::type |
| > type; |
| }; |
| |
| template<typename Tuple, class UnaryMetaFun> |
| struct tuple_meta_transform |
| : mpl::eval_if< |
| boost::is_same<Tuple, tuples::null_type> |
| , mpl::identity<tuples::null_type> |
| , tuple_meta_transform_impl<Tuple, UnaryMetaFun> |
| > |
| { |
| }; |
| |
| // Meta-accumulate algorithm for tuples. Note: The template |
| // parameter StartType corresponds to the initial value in |
| // ordinary accumulation. |
| // |
| template<class Tuple, class BinaryMetaFun, class StartType> |
| struct tuple_meta_accumulate; |
| |
| template< |
| typename Tuple |
| , class BinaryMetaFun |
| , typename StartType |
| > |
| struct tuple_meta_accumulate_impl |
| { |
| typedef typename mpl::apply2< |
| typename mpl::lambda<BinaryMetaFun>::type |
| , typename Tuple::head_type |
| , typename tuple_meta_accumulate< |
| typename Tuple::tail_type |
| , BinaryMetaFun |
| , StartType |
| >::type |
| >::type type; |
| }; |
| |
| template< |
| typename Tuple |
| , class BinaryMetaFun |
| , typename StartType |
| > |
| struct tuple_meta_accumulate |
| : mpl::eval_if< |
| #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) |
| mpl::or_< |
| #endif |
| boost::is_same<Tuple, tuples::null_type> |
| #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) |
| , boost::is_same<Tuple,int> |
| > |
| #endif |
| , mpl::identity<StartType> |
| , tuple_meta_accumulate_impl< |
| Tuple |
| , BinaryMetaFun |
| , StartType |
| > |
| > |
| { |
| }; |
| |
| #if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ |
| || ( \ |
| BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, != 0) && defined(_MSC_VER) \ |
| ) |
| // Not sure why intel's partial ordering fails in this case, but I'm |
| // assuming int's an MSVC bug-compatibility feature. |
| |
| # define BOOST_TUPLE_ALGO_DISPATCH |
| # define BOOST_TUPLE_ALGO(algo) algo##_impl |
| # define BOOST_TUPLE_ALGO_TERMINATOR , int |
| # define BOOST_TUPLE_ALGO_RECURSE , ... |
| #else |
| # define BOOST_TUPLE_ALGO(algo) algo |
| # define BOOST_TUPLE_ALGO_TERMINATOR |
| # define BOOST_TUPLE_ALGO_RECURSE |
| #endif |
| |
| // transform algorithm for tuples. The template parameter Fun |
| // must be a unary functor which is also a unary metafunction |
| // class that computes its return type based on its argument |
| // type. For example: |
| // |
| // struct to_ptr |
| // { |
| // template <class Arg> |
| // struct apply |
| // { |
| // typedef Arg* type; |
| // } |
| // |
| // template <class Arg> |
| // Arg* operator()(Arg x); |
| // }; |
| template<typename Fun> |
| tuples::null_type BOOST_TUPLE_ALGO(tuple_transform) |
| (tuples::null_type const&, Fun BOOST_TUPLE_ALGO_TERMINATOR) |
| { return tuples::null_type(); } |
| |
| template<typename Tuple, typename Fun> |
| typename tuple_meta_transform< |
| Tuple |
| , Fun |
| >::type |
| |
| BOOST_TUPLE_ALGO(tuple_transform)( |
| const Tuple& t, |
| Fun f |
| BOOST_TUPLE_ALGO_RECURSE |
| ) |
| { |
| typedef typename tuple_meta_transform< |
| BOOST_DEDUCED_TYPENAME Tuple::tail_type |
| , Fun |
| >::type transformed_tail_type; |
| |
| return tuples::cons< |
| BOOST_DEDUCED_TYPENAME mpl::apply1< |
| Fun, BOOST_DEDUCED_TYPENAME Tuple::head_type |
| >::type |
| , transformed_tail_type |
| >( |
| f(boost::tuples::get<0>(t)), tuple_transform(t.get_tail(), f) |
| ); |
| } |
| |
| #ifdef BOOST_TUPLE_ALGO_DISPATCH |
| template<typename Tuple, typename Fun> |
| typename tuple_meta_transform< |
| Tuple |
| , Fun |
| >::type |
| |
| tuple_transform( |
| const Tuple& t, |
| Fun f |
| ) |
| { |
| return tuple_transform_impl(t, f, 1); |
| } |
| #endif |
| |
| // for_each algorithm for tuples. |
| // |
| template<typename Fun> |
| Fun BOOST_TUPLE_ALGO(tuple_for_each)( |
| tuples::null_type |
| , Fun f BOOST_TUPLE_ALGO_TERMINATOR |
| ) |
| { return f; } |
| |
| |
| template<typename Tuple, typename Fun> |
| Fun BOOST_TUPLE_ALGO(tuple_for_each)( |
| Tuple& t |
| , Fun f BOOST_TUPLE_ALGO_RECURSE) |
| { |
| f( t.get_head() ); |
| return tuple_for_each(t.get_tail(), f); |
| } |
| |
| #ifdef BOOST_TUPLE_ALGO_DISPATCH |
| template<typename Tuple, typename Fun> |
| Fun |
| tuple_for_each( |
| Tuple& t, |
| Fun f |
| ) |
| { |
| return tuple_for_each_impl(t, f, 1); |
| } |
| #endif |
| |
| // Equality of tuples. NOTE: "==" for tuples currently (7/2003) |
| // has problems under some compilers, so I just do my own. |
| // No point in bringing in a bunch of #ifdefs here. This is |
| // going to go away with the next tuple implementation anyway. |
| // |
| inline bool tuple_equal(tuples::null_type, tuples::null_type) |
| { return true; } |
| |
| template<typename Tuple1, typename Tuple2> |
| bool tuple_equal( |
| Tuple1 const& t1, |
| Tuple2 const& t2 |
| ) |
| { |
| return t1.get_head() == t2.get_head() && |
| tuple_equal(t1.get_tail(), t2.get_tail()); |
| } |
| } |
| // |
| // end namespace tuple_impl_specific |
| |
| template<typename Iterator> |
| struct iterator_reference |
| { |
| typedef typename iterator_traits<Iterator>::reference type; |
| }; |
| |
| #ifdef BOOST_MPL_CFG_NO_FULL_LAMBDA_SUPPORT |
| // Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work |
| // out well. Instantiating the nested apply template also |
| // requires instantiating iterator_traits on the |
| // placeholder. Instead we just specialize it as a metafunction |
| // class. |
| template<> |
| struct iterator_reference<mpl::_1> |
| { |
| template <class T> |
| struct apply : iterator_reference<T> {}; |
| }; |
| #endif |
| |
| // Metafunction to obtain the type of the tuple whose element types |
| // are the reference types of an iterator tuple. |
| // |
| template<typename IteratorTuple> |
| struct tuple_of_references |
| : tuple_impl_specific::tuple_meta_transform< |
| IteratorTuple, |
| iterator_reference<mpl::_1> |
| > |
| { |
| }; |
| |
| // Metafunction to obtain the minimal traversal tag in a tuple |
| // of iterators. |
| // |
| template<typename IteratorTuple> |
| struct minimum_traversal_category_in_iterator_tuple |
| { |
| typedef typename tuple_impl_specific::tuple_meta_transform< |
| IteratorTuple |
| , iterator_traversal<> |
| >::type tuple_of_traversal_tags; |
| |
| typedef typename tuple_impl_specific::tuple_meta_accumulate< |
| tuple_of_traversal_tags |
| , minimum_category<> |
| , random_access_traversal_tag |
| >::type type; |
| }; |
| |
| #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) // ETI workaround |
| template <> |
| struct minimum_traversal_category_in_iterator_tuple<int> |
| { |
| typedef int type; |
| }; |
| #endif |
| |
| // We need to call tuple_meta_accumulate with mpl::and_ as the |
| // accumulating functor. To this end, we need to wrap it into |
| // a struct that has exactly two arguments (that is, template |
| // parameters) and not five, like mpl::and_ does. |
| // |
| template<typename Arg1, typename Arg2> |
| struct and_with_two_args |
| : mpl::and_<Arg1, Arg2> |
| { |
| }; |
| |
| # ifdef BOOST_MPL_CFG_NO_FULL_LAMBDA_SUPPORT |
| // Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work |
| // out well. In this case I think it's an MPL bug |
| template<> |
| struct and_with_two_args<mpl::_1,mpl::_2> |
| { |
| template <class A1, class A2> |
| struct apply : mpl::and_<A1,A2> |
| {}; |
| }; |
| # endif |
| |
| /////////////////////////////////////////////////////////////////// |
| // |
| // Class zip_iterator_base |
| // |
| // Builds and exposes the iterator facade type from which the zip |
| // iterator will be derived. |
| // |
| template<typename IteratorTuple> |
| struct zip_iterator_base |
| { |
| private: |
| // Reference type is the type of the tuple obtained from the |
| // iterators' reference types. |
| typedef typename |
| detail::tuple_of_references<IteratorTuple>::type reference; |
| |
| // Value type is the same as reference type. |
| typedef reference value_type; |
| |
| // Difference type is the first iterator's difference type |
| typedef typename iterator_traits< |
| typename tuples::element<0, IteratorTuple>::type |
| >::difference_type difference_type; |
| |
| // Traversal catetgory is the minimum traversal category in the |
| // iterator tuple. |
| typedef typename |
| detail::minimum_traversal_category_in_iterator_tuple< |
| IteratorTuple |
| >::type traversal_category; |
| public: |
| |
| // The iterator facade type from which the zip iterator will |
| // be derived. |
| typedef iterator_facade< |
| zip_iterator<IteratorTuple>, |
| value_type, |
| traversal_category, |
| reference, |
| difference_type |
| > type; |
| }; |
| |
| template <> |
| struct zip_iterator_base<int> |
| { |
| typedef int type; |
| }; |
| } |
| |
| ///////////////////////////////////////////////////////////////////// |
| // |
| // zip_iterator class definition |
| // |
| template<typename IteratorTuple> |
| class zip_iterator : |
| public detail::zip_iterator_base<IteratorTuple>::type |
| { |
| |
| // Typedef super_t as our base class. |
| typedef typename |
| detail::zip_iterator_base<IteratorTuple>::type super_t; |
| |
| // iterator_core_access is the iterator's best friend. |
| friend class iterator_core_access; |
| |
| public: |
| |
| // Construction |
| // ============ |
| |
| // Default constructor |
| zip_iterator() { } |
| |
| // Constructor from iterator tuple |
| zip_iterator(IteratorTuple iterator_tuple) |
| : m_iterator_tuple(iterator_tuple) |
| { } |
| |
| // Copy constructor |
| template<typename OtherIteratorTuple> |
| zip_iterator( |
| const zip_iterator<OtherIteratorTuple>& other, |
| typename enable_if_convertible< |
| OtherIteratorTuple, |
| IteratorTuple |
| >::type* = 0 |
| ) : m_iterator_tuple(other.get_iterator_tuple()) |
| {} |
| |
| // Get method for the iterator tuple. |
| const IteratorTuple& get_iterator_tuple() const |
| { return m_iterator_tuple; } |
| |
| private: |
| |
| // Implementation of Iterator Operations |
| // ===================================== |
| |
| // Dereferencing returns a tuple built from the dereferenced |
| // iterators in the iterator tuple. |
| typename super_t::reference dereference() const |
| { |
| return detail::tuple_impl_specific::tuple_transform( |
| get_iterator_tuple(), |
| detail::dereference_iterator() |
| ); |
| } |
| |
| // Two zip iterators are equal if all iterators in the iterator |
| // tuple are equal. NOTE: It should be possible to implement this |
| // as |
| // |
| // return get_iterator_tuple() == other.get_iterator_tuple(); |
| // |
| // but equality of tuples currently (7/2003) does not compile |
| // under several compilers. No point in bringing in a bunch |
| // of #ifdefs here. |
| // |
| template<typename OtherIteratorTuple> |
| bool equal(const zip_iterator<OtherIteratorTuple>& other) const |
| { |
| return detail::tuple_impl_specific::tuple_equal( |
| get_iterator_tuple(), |
| other.get_iterator_tuple() |
| ); |
| } |
| |
| // Advancing a zip iterator means to advance all iterators in the |
| // iterator tuple. |
| void advance(typename super_t::difference_type n) |
| { |
| detail::tuple_impl_specific::tuple_for_each( |
| m_iterator_tuple, |
| detail::advance_iterator<BOOST_DEDUCED_TYPENAME super_t::difference_type>(n) |
| ); |
| } |
| // Incrementing a zip iterator means to increment all iterators in |
| // the iterator tuple. |
| void increment() |
| { |
| detail::tuple_impl_specific::tuple_for_each( |
| m_iterator_tuple, |
| detail::increment_iterator() |
| ); |
| } |
| |
| // Decrementing a zip iterator means to decrement all iterators in |
| // the iterator tuple. |
| void decrement() |
| { |
| detail::tuple_impl_specific::tuple_for_each( |
| m_iterator_tuple, |
| detail::decrement_iterator() |
| ); |
| } |
| |
| // Distance is calculated using the first iterator in the tuple. |
| template<typename OtherIteratorTuple> |
| typename super_t::difference_type distance_to( |
| const zip_iterator<OtherIteratorTuple>& other |
| ) const |
| { |
| return boost::tuples::get<0>(other.get_iterator_tuple()) - |
| boost::tuples::get<0>(this->get_iterator_tuple()); |
| } |
| |
| // Data Members |
| // ============ |
| |
| // The iterator tuple. |
| IteratorTuple m_iterator_tuple; |
| |
| }; |
| |
| // Make function for zip iterator |
| // |
| template<typename IteratorTuple> |
| zip_iterator<IteratorTuple> |
| make_zip_iterator(IteratorTuple t) |
| { return zip_iterator<IteratorTuple>(t); } |
| |
| } |
| |
| #endif |