You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
585 lines
16 KiB
585 lines
16 KiB
// 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 |
|
, pure_traversal_tag<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
|
|
|