#ifndef BOOST_RANGE_COMBINE_HPP #define BOOST_RANGE_COMBINE_HPP #include #include #include #include #include #include #include #include #include #include namespace boost { namespace detail { struct void_ { typedef void_ type; }; } template<> struct range_iterator { typedef tuples::null_type type; }; namespace detail { inline tuples::null_type range_begin( void_& ) { return tuples::null_type(); } inline tuples::null_type range_end( void_& ) { return tuples::null_type(); } template< class T > struct tuple_iter { typedef typename mpl::eval_if_c< is_same::value, mpl::identity, range_iterator >::type type; }; template< class Rng1, class Rng2 > struct tuple_range { typedef typename mpl::eval_if_c< is_same::value, void_, mpl::identity >::type type; }; template < class R1, class R2, class R3, class R4, class R5, class R6 > struct generate_tuple { typedef boost::tuple< typename tuple_iter::type, typename tuple_iter::type, typename tuple_iter::type, typename tuple_iter::type, typename tuple_iter::type, typename tuple_iter::type > type; static type begin( R1& r1, R2& r2, R3& r3, R4& r4, R5& r5, R6& r6 ) { return make_tuple( boost::begin(r1), boost::begin(r2), boost::begin(r3), boost::begin(r4), boost::begin(r5), boost::begin(r6) ); } static type end( R1& r1, R2& r2, R3& r3, R4& r4, R5& r5, R6& r6 ) { return make_tuple( boost::end(r1), boost::end(r2), boost::end(r3), boost::end(r4), boost::end(r5), boost::end(r6) ); } }; template < class R1, class R2 = void_, class R3 = void_, class R4 = void_, class R5 = void_, class R6 = void_ > struct zip_rng : iterator_range< zip_iterator< typename generate_tuple::type > > { private: typedef generate_tuple generator; typedef typename generator::type tuple; typedef zip_iterator zip_iter; typedef iterator_range base; public: zip_rng( R1& r1, R2& r2, R3& r3, R4& r4, R5& r5, R6& r6 ) : base( zip_iter( generator::begin(r1,r2,r3,r4,r5,r6) ), zip_iter( generator::end(r1,r2,r3,r4,r5,r6) ) ) { BOOST_ASSERT(boost::distance(r1) <= boost::distance(r2)); BOOST_ASSERT(boost::distance(r1) <= boost::distance(r3)); BOOST_ASSERT(boost::distance(r1) <= boost::distance(r4)); BOOST_ASSERT(boost::distance(r1) <= boost::distance(r5)); BOOST_ASSERT(boost::distance(r1) <= boost::distance(r6)); } template< class Zip, class Rng > zip_rng( Zip& z, Rng& r ) : base( zip_iter( generator::begin( z, r ) ), zip_iter( generator::end( z, r ) ) ) { // @todo: tuple::begin( should be overloaded for this situation } struct tuple_length : tuples::length { }; template< unsigned N > struct get { template< class Z, class R > static typename tuples::element::type begin( Z& z, R& ) { return get( z.begin().get_iterator_tuple() ); } template< class Z, class R > static typename tuples::element::type end( Z& z, R& r ) { return get( z.end().get_iterator_tuple() ); } }; }; template< class Rng1, class Rng2 > struct zip_range : iterator_range< zip_iterator< tuple< typename range_iterator::type, typename range_iterator::type > > > { private: typedef zip_iterator< tuple< typename range_iterator::type, typename range_iterator::type > > zip_iter; typedef iterator_range base; public: zip_range( Rng1& r1, Rng2& r2 ) : base( zip_iter( make_tuple(boost::begin(r1), boost::begin(r2)) ), zip_iter( make_tuple(boost::end(r1), boost::end(r2)) ) ) { BOOST_ASSERT(boost::distance(r1) <= boost::distance(r2)); } }; template< class Rng1, class Rng2, class Rng3 > struct zip_range3 : iterator_range< zip_iterator< tuple< typename range_iterator::type, typename range_iterator::type, typename range_iterator::type > > > { private: typedef zip_iterator< tuple< typename range_iterator::type, typename range_iterator::type, typename range_iterator::type > > zip_iter; typedef iterator_range base; public: zip_range3( Rng1& r1, Rng2& r2, Rng3& r3 ) : base( zip_iter( make_tuple(boost::begin(r1), boost::begin(r2), boost::begin(r3)) ), zip_iter( make_tuple(boost::end(r1), boost::end(r2), boost::end(r3)) ) ) { BOOST_ASSERT(distance(r1) <= distance(r2)); BOOST_ASSERT(distance(r1) <= distance(r3)); } }; struct combine_tag {}; template< class Rng > inline zip_rng operator&( combine_tag, Rng& r ) { return zip_rng(r); } template< class Rng > inline iterator_range operator&( combine_tag, const Rng& r ) { return iterator_range(r); } template < class R1, class R2, class R3, class R4, class R5, class Rng > inline typename zip_rng::next operator&( const zip_rng& zip, Rng& r ) { return zip_rng::next( zip, r ); } // // This one should be able to be made generic // // template // < // class R1, // class R2 = void, // class R3 = void, // class R4 = void, // class R5 = void, // class R6 = void // > // inline zip_range::type // x // // /* template< class Rng1, class Rng2, class Rng3 > inline zip_range3 operator&( const zip_range& r1, const Rng3& r3 ) { return zip_range3( }*/ } // namespace 'detail' template< class Rng1, class Rng2 > inline detail::zip_range combine( Rng1& r1, Rng2& r2 ) { return detail::zip_range(r1,r2); } template< class Rng1, class Rng2 > inline detail::zip_range combine( const Rng1& r1, Rng2& r2 ) { return detail::zip_range(r1,r2); } template< class Rng1, class Rng2 > inline detail::zip_range combine( Rng1& r1, const Rng2& r2 ) { return detail::zip_range(r1,r2); } template< class Rng1, class Rng2 > inline detail::zip_range combine( const Rng1& r1, const Rng2& r2 ) { return detail::zip_range(r1,r2); } // // @todo: find a solution that scales better // instead of adding 6 overloads! // } #endif