// 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 |