// 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 #include #include #include #include // for enable_if_convertible #include #include #include #include #include #include #include #include #include #include #include namespace boost { // Zip iterator forward declaration for zip_iterator_base template 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 class advance_iterator { public: advance_iterator(DiffType step) : m_step(step) {} template void operator()(Iterator& it) const { it += m_step; } private: DiffType m_step; }; // struct increment_iterator { template void operator()(Iterator& it) { ++it; } }; // struct decrement_iterator { template void operator()(Iterator& it) { --it; } }; // struct dereference_iterator { template struct apply { typedef typename iterator_traits::reference type; }; template typename apply::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 struct tuple_meta_transform; template struct tuple_meta_transform_impl { typedef tuples::cons< typename mpl::apply1< typename mpl::lambda::type , typename Tuple::head_type >::type , typename tuple_meta_transform< typename Tuple::tail_type , UnaryMetaFun >::type > type; }; template struct tuple_meta_transform : mpl::eval_if< boost::is_same , mpl::identity , tuple_meta_transform_impl > { }; // Meta-accumulate algorithm for tuples. Note: The template // parameter StartType corresponds to the initial value in // ordinary accumulation. // template struct tuple_meta_accumulate; template< typename Tuple , class BinaryMetaFun , typename StartType > struct tuple_meta_accumulate_impl { typedef typename mpl::apply2< typename mpl::lambda::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 #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) , boost::is_same > #endif , mpl::identity , 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 // struct apply // { // typedef Arg* type; // } // // template // Arg* operator()(Arg x); // }; template tuples::null_type BOOST_TUPLE_ALGO(tuple_transform) (tuples::null_type const&, Fun BOOST_TUPLE_ALGO_TERMINATOR) { return tuples::null_type(); } template 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_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 Fun BOOST_TUPLE_ALGO(tuple_for_each)( tuples::null_type , Fun f BOOST_TUPLE_ALGO_TERMINATOR ) { return f; } template 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 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 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 struct iterator_reference { typedef typename iterator_traits::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 { template struct apply : iterator_reference {}; }; #endif // Metafunction to obtain the type of the tuple whose element types // are the reference types of an iterator tuple. // template struct tuple_of_references : tuple_impl_specific::tuple_meta_transform< IteratorTuple, iterator_reference > { }; // Metafunction to obtain the minimal traversal tag in a tuple // of iterators. // template 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 { 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 struct and_with_two_args : mpl::and_ { }; # 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 { template struct apply : mpl::and_ {}; }; # endif /////////////////////////////////////////////////////////////////// // // Class zip_iterator_base // // Builds and exposes the iterator facade type from which the zip // iterator will be derived. // template 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::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, value_type, traversal_category, reference, difference_type > type; }; template <> struct zip_iterator_base { typedef int type; }; } ///////////////////////////////////////////////////////////////////// // // zip_iterator class definition // template class zip_iterator : public detail::zip_iterator_base::type { // Typedef super_t as our base class. typedef typename detail::zip_iterator_base::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 zip_iterator( const zip_iterator& 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 bool equal(const zip_iterator& 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(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 super_t::difference_type distance_to( const zip_iterator& 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 zip_iterator make_zip_iterator(IteratorTuple t) { return zip_iterator(t); } } #endif