1 // Copyright David Abrahams and Thomas Becker 2000-2006. Distributed
2 // under the Boost Software License, Version 1.0. (See accompanying
3 // file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
6 #ifndef BOOST_ZIP_ITERATOR_TMB_07_13_2003_HPP_
7 # define BOOST_ZIP_ITERATOR_TMB_07_13_2003_HPP_
10 #include <boost/iterator.hpp>
11 #include <boost/iterator/iterator_traits.hpp>
12 #include <boost/iterator/iterator_facade.hpp>
13 #include <boost/iterator/iterator_adaptor.hpp> // for enable_if_convertible
14 #include <boost/iterator/iterator_categories.hpp>
15 #include <boost/detail/iterator.hpp>
17 #include <boost/iterator/detail/minimum_category.hpp>
19 #include <boost/tuple/tuple.hpp>
21 #include <boost/type_traits/is_same.hpp>
22 #include <boost/mpl/and.hpp>
23 #include <boost/mpl/apply.hpp>
24 #include <boost/mpl/eval_if.hpp>
25 #include <boost/mpl/lambda.hpp>
26 #include <boost/mpl/placeholders.hpp>
27 #include <boost/mpl/aux_/lambda_support.hpp>
31 // Zip iterator forward declaration for zip_iterator_base
32 template<typename IteratorTuple
>
35 // One important design goal of the zip_iterator is to isolate all
36 // functionality whose implementation relies on the current tuple
37 // implementation. This goal has been achieved as follows: Inside
38 // the namespace detail there is a namespace tuple_impl_specific.
39 // This namespace encapsulates all functionality that is specific
40 // to the current Boost tuple implementation. More precisely, the
41 // namespace tuple_impl_specific provides the following tuple
42 // algorithms and meta-algorithms for the current Boost tuple
45 // tuple_meta_transform
46 // tuple_meta_accumulate
50 // If the tuple implementation changes, all that needs to be
51 // replaced is the implementation of these four (meta-)algorithms.
56 // Functors to be used with tuple algorithms
58 template<typename DiffType
>
59 class advance_iterator
62 advance_iterator(DiffType step
) : m_step(step
) {}
64 template<typename Iterator
>
65 void operator()(Iterator
& it
) const
72 struct increment_iterator
74 template<typename Iterator
>
75 void operator()(Iterator
& it
)
79 struct decrement_iterator
81 template<typename Iterator
>
82 void operator()(Iterator
& it
)
86 struct dereference_iterator
88 template<typename Iterator
>
92 iterator_traits
<Iterator
>::reference
96 template<typename Iterator
>
97 typename apply
<Iterator
>::type
operator()(Iterator
const& it
)
102 // The namespace tuple_impl_specific provides two meta-
103 // algorithms and two algorithms for tuples.
105 namespace tuple_impl_specific
107 // Meta-transform algorithm for tuples
109 template<typename Tuple
, class UnaryMetaFun
>
110 struct tuple_meta_transform
;
112 template<typename Tuple
, class UnaryMetaFun
>
113 struct tuple_meta_transform_impl
115 typedef tuples::cons
<
116 typename
mpl::apply1
<
117 typename
mpl::lambda
<UnaryMetaFun
>::type
118 , typename
Tuple::head_type
120 , typename tuple_meta_transform
<
121 typename
Tuple::tail_type
127 template<typename Tuple
, class UnaryMetaFun
>
128 struct tuple_meta_transform
130 boost::is_same
<Tuple
, tuples::null_type
>
131 , mpl::identity
<tuples::null_type
>
132 , tuple_meta_transform_impl
<Tuple
, UnaryMetaFun
>
137 // Meta-accumulate algorithm for tuples. Note: The template
138 // parameter StartType corresponds to the initial value in
139 // ordinary accumulation.
141 template<class Tuple
, class BinaryMetaFun
, class StartType
>
142 struct tuple_meta_accumulate
;
146 , class BinaryMetaFun
149 struct tuple_meta_accumulate_impl
151 typedef typename
mpl::apply2
<
152 typename
mpl::lambda
<BinaryMetaFun
>::type
153 , typename
Tuple::head_type
154 , typename tuple_meta_accumulate
<
155 typename
Tuple::tail_type
164 , class BinaryMetaFun
167 struct tuple_meta_accumulate
169 #if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
172 boost::is_same
<Tuple
, tuples::null_type
>
173 #if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
174 , boost::is_same
<Tuple
,int>
177 , mpl::identity
<StartType
>
178 , tuple_meta_accumulate_impl
<
187 #if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \
189 BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, != 0) && defined(_MSC_VER) \
191 // Not sure why intel's partial ordering fails in this case, but I'm
192 // assuming int's an MSVC bug-compatibility feature.
194 # define BOOST_TUPLE_ALGO_DISPATCH
195 # define BOOST_TUPLE_ALGO(algo) algo##_impl
196 # define BOOST_TUPLE_ALGO_TERMINATOR , int
197 # define BOOST_TUPLE_ALGO_RECURSE , ...
199 # define BOOST_TUPLE_ALGO(algo) algo
200 # define BOOST_TUPLE_ALGO_TERMINATOR
201 # define BOOST_TUPLE_ALGO_RECURSE
204 // transform algorithm for tuples. The template parameter Fun
205 // must be a unary functor which is also a unary metafunction
206 // class that computes its return type based on its argument
207 // type. For example:
211 // template <class Arg>
214 // typedef Arg* type;
217 // template <class Arg>
218 // Arg* operator()(Arg x);
220 template<typename Fun
>
221 tuples::null_type
BOOST_TUPLE_ALGO(tuple_transform
)
222 (tuples::null_type
const&, Fun BOOST_TUPLE_ALGO_TERMINATOR
)
223 { return tuples::null_type(); }
225 template<typename Tuple
, typename Fun
>
226 typename tuple_meta_transform
<
231 BOOST_TUPLE_ALGO(tuple_transform
)(
234 BOOST_TUPLE_ALGO_RECURSE
237 typedef typename tuple_meta_transform
<
238 BOOST_DEDUCED_TYPENAME
Tuple::tail_type
240 >::type transformed_tail_type
;
243 BOOST_DEDUCED_TYPENAME
mpl::apply1
<
244 Fun
, BOOST_DEDUCED_TYPENAME
Tuple::head_type
246 , transformed_tail_type
248 f(boost::tuples::get
<0>(t
)), tuple_transform(t
.get_tail(), f
)
252 #ifdef BOOST_TUPLE_ALGO_DISPATCH
253 template<typename Tuple
, typename Fun
>
254 typename tuple_meta_transform
<
264 return tuple_transform_impl(t
, f
, 1);
268 // for_each algorithm for tuples.
270 template<typename Fun
>
271 Fun
BOOST_TUPLE_ALGO(tuple_for_each
)(
273 , Fun f BOOST_TUPLE_ALGO_TERMINATOR
278 template<typename Tuple
, typename Fun
>
279 Fun
BOOST_TUPLE_ALGO(tuple_for_each
)(
281 , Fun f BOOST_TUPLE_ALGO_RECURSE
)
284 return tuple_for_each(t
.get_tail(), f
);
287 #ifdef BOOST_TUPLE_ALGO_DISPATCH
288 template<typename Tuple
, typename Fun
>
295 return tuple_for_each_impl(t
, f
, 1);
299 // Equality of tuples. NOTE: "==" for tuples currently (7/2003)
300 // has problems under some compilers, so I just do my own.
301 // No point in bringing in a bunch of #ifdefs here. This is
302 // going to go away with the next tuple implementation anyway.
304 inline bool tuple_equal(tuples::null_type
, tuples::null_type
)
307 template<typename Tuple1
, typename Tuple2
>
313 return t1
.get_head() == t2
.get_head() &&
314 tuple_equal(t1
.get_tail(), t2
.get_tail());
318 // end namespace tuple_impl_specific
320 template<typename Iterator
>
321 struct iterator_reference
323 typedef typename iterator_traits
<Iterator
>::reference type
;
326 #ifdef BOOST_MPL_CFG_NO_FULL_LAMBDA_SUPPORT
327 // Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work
328 // out well. Instantiating the nested apply template also
329 // requires instantiating iterator_traits on the
330 // placeholder. Instead we just specialize it as a metafunction
333 struct iterator_reference
<mpl::_1
>
336 struct apply
: iterator_reference
<T
> {};
340 // Metafunction to obtain the type of the tuple whose element types
341 // are the reference types of an iterator tuple.
343 template<typename IteratorTuple
>
344 struct tuple_of_references
345 : tuple_impl_specific::tuple_meta_transform
<
347 iterator_reference
<mpl::_1
>
352 // Metafunction to obtain the minimal traversal tag in a tuple
355 template<typename IteratorTuple
>
356 struct minimum_traversal_category_in_iterator_tuple
358 typedef typename
tuple_impl_specific::tuple_meta_transform
<
360 , iterator_traversal
<>
361 >::type tuple_of_traversal_tags
;
363 typedef typename
tuple_impl_specific::tuple_meta_accumulate
<
364 tuple_of_traversal_tags
366 , random_access_traversal_tag
370 #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) // ETI workaround
372 struct minimum_traversal_category_in_iterator_tuple
<int>
378 // We need to call tuple_meta_accumulate with mpl::and_ as the
379 // accumulating functor. To this end, we need to wrap it into
380 // a struct that has exactly two arguments (that is, template
381 // parameters) and not five, like mpl::and_ does.
383 template<typename Arg1
, typename Arg2
>
384 struct and_with_two_args
385 : mpl::and_
<Arg1
, Arg2
>
389 # ifdef BOOST_MPL_CFG_NO_FULL_LAMBDA_SUPPORT
390 // Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work
391 // out well. In this case I think it's an MPL bug
393 struct and_with_two_args
<mpl::_1
,mpl::_2
>
395 template <class A1
, class A2
>
396 struct apply
: mpl::and_
<A1
,A2
>
401 ///////////////////////////////////////////////////////////////////
403 // Class zip_iterator_base
405 // Builds and exposes the iterator facade type from which the zip
406 // iterator will be derived.
408 template<typename IteratorTuple
>
409 struct zip_iterator_base
412 // Reference type is the type of the tuple obtained from the
413 // iterators' reference types.
415 detail::tuple_of_references
<IteratorTuple
>::type reference
;
417 // Value type is the same as reference type.
418 typedef reference value_type
;
420 // Difference type is the first iterator's difference type
421 typedef typename iterator_traits
<
422 typename
tuples::element
<0, IteratorTuple
>::type
423 >::difference_type difference_type
;
425 // Traversal catetgory is the minimum traversal category in the
428 detail::minimum_traversal_category_in_iterator_tuple
<
430 >::type traversal_category
;
433 // The iterator facade type from which the zip iterator will
435 typedef iterator_facade
<
436 zip_iterator
<IteratorTuple
>,
445 struct zip_iterator_base
<int>
451 /////////////////////////////////////////////////////////////////////
453 // zip_iterator class definition
455 template<typename IteratorTuple
>
457 public detail::zip_iterator_base
<IteratorTuple
>::type
460 // Typedef super_t as our base class.
462 detail::zip_iterator_base
<IteratorTuple
>::type super_t
;
464 // iterator_core_access is the iterator's best friend.
465 friend class iterator_core_access
;
472 // Default constructor
475 // Constructor from iterator tuple
476 zip_iterator(IteratorTuple iterator_tuple
)
477 : m_iterator_tuple(iterator_tuple
)
481 template<typename OtherIteratorTuple
>
483 const zip_iterator
<OtherIteratorTuple
>& other
,
484 typename enable_if_convertible
<
488 ) : m_iterator_tuple(other
.get_iterator_tuple())
491 // Get method for the iterator tuple.
492 const IteratorTuple
& get_iterator_tuple() const
493 { return m_iterator_tuple
; }
497 // Implementation of Iterator Operations
498 // =====================================
500 // Dereferencing returns a tuple built from the dereferenced
501 // iterators in the iterator tuple.
502 typename
super_t::reference
dereference() const
504 return detail::tuple_impl_specific::tuple_transform(
505 get_iterator_tuple(),
506 detail::dereference_iterator()
510 // Two zip iterators are equal if all iterators in the iterator
511 // tuple are equal. NOTE: It should be possible to implement this
514 // return get_iterator_tuple() == other.get_iterator_tuple();
516 // but equality of tuples currently (7/2003) does not compile
517 // under several compilers. No point in bringing in a bunch
520 template<typename OtherIteratorTuple
>
521 bool equal(const zip_iterator
<OtherIteratorTuple
>& other
) const
523 return detail::tuple_impl_specific::tuple_equal(
524 get_iterator_tuple(),
525 other
.get_iterator_tuple()
529 // Advancing a zip iterator means to advance all iterators in the
531 void advance(typename
super_t::difference_type n
)
533 detail::tuple_impl_specific::tuple_for_each(
535 detail::advance_iterator
<BOOST_DEDUCED_TYPENAME
super_t::difference_type
>(n
)
538 // Incrementing a zip iterator means to increment all iterators in
539 // the iterator tuple.
542 detail::tuple_impl_specific::tuple_for_each(
544 detail::increment_iterator()
548 // Decrementing a zip iterator means to decrement all iterators in
549 // the iterator tuple.
552 detail::tuple_impl_specific::tuple_for_each(
554 detail::decrement_iterator()
558 // Distance is calculated using the first iterator in the tuple.
559 template<typename OtherIteratorTuple
>
560 typename
super_t::difference_type
distance_to(
561 const zip_iterator
<OtherIteratorTuple
>& other
564 return boost::tuples::get
<0>(other
.get_iterator_tuple()) -
565 boost::tuples::get
<0>(this->get_iterator_tuple());
571 // The iterator tuple.
572 IteratorTuple m_iterator_tuple
;
576 // Make function for zip iterator
578 template<typename IteratorTuple
>
579 zip_iterator
<IteratorTuple
>
580 make_zip_iterator(IteratorTuple t
)
581 { return zip_iterator
<IteratorTuple
>(t
); }