fix doc example typo
[boost.git] / boost / iterator / zip_iterator.hpp
blobf3896ad955176aa7328000db280d9d7b0d72b70a
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_
9 #include <stddef.h>
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>
29 namespace boost {
31 // Zip iterator forward declaration for zip_iterator_base
32 template<typename IteratorTuple>
33 class zip_iterator;
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
43 // implementation:
45 // tuple_meta_transform
46 // tuple_meta_accumulate
47 // tuple_transform
48 // tuple_for_each
50 // If the tuple implementation changes, all that needs to be
51 // replaced is the implementation of these four (meta-)algorithms.
53 namespace detail
56 // Functors to be used with tuple algorithms
58 template<typename DiffType>
59 class advance_iterator
61 public:
62 advance_iterator(DiffType step) : m_step(step) {}
64 template<typename Iterator>
65 void operator()(Iterator& it) const
66 { it += m_step; }
68 private:
69 DiffType m_step;
72 struct increment_iterator
74 template<typename Iterator>
75 void operator()(Iterator& it)
76 { ++it; }
79 struct decrement_iterator
81 template<typename Iterator>
82 void operator()(Iterator& it)
83 { --it; }
86 struct dereference_iterator
88 template<typename Iterator>
89 struct apply
91 typedef typename
92 iterator_traits<Iterator>::reference
93 type;
96 template<typename Iterator>
97 typename apply<Iterator>::type operator()(Iterator const& it)
98 { return *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
119 >::type
120 , typename tuple_meta_transform<
121 typename Tuple::tail_type
122 , UnaryMetaFun
123 >::type
124 > type;
127 template<typename Tuple, class UnaryMetaFun>
128 struct tuple_meta_transform
129 : mpl::eval_if<
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;
144 template<
145 typename Tuple
146 , class BinaryMetaFun
147 , typename StartType
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
156 , BinaryMetaFun
157 , StartType
158 >::type
159 >::type type;
162 template<
163 typename Tuple
164 , class BinaryMetaFun
165 , typename StartType
167 struct tuple_meta_accumulate
168 : mpl::eval_if<
169 #if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
170 mpl::or_<
171 #endif
172 boost::is_same<Tuple, tuples::null_type>
173 #if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
174 , boost::is_same<Tuple,int>
176 #endif
177 , mpl::identity<StartType>
178 , tuple_meta_accumulate_impl<
179 Tuple
180 , BinaryMetaFun
181 , StartType
187 #if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \
188 || ( \
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 , ...
198 #else
199 # define BOOST_TUPLE_ALGO(algo) algo
200 # define BOOST_TUPLE_ALGO_TERMINATOR
201 # define BOOST_TUPLE_ALGO_RECURSE
202 #endif
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:
209 // struct to_ptr
210 // {
211 // template <class Arg>
212 // struct apply
213 // {
214 // typedef Arg* type;
215 // }
217 // template <class Arg>
218 // Arg* operator()(Arg x);
219 // };
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<
227 Tuple
228 , Fun
229 >::type
231 BOOST_TUPLE_ALGO(tuple_transform)(
232 const Tuple& t,
233 Fun f
234 BOOST_TUPLE_ALGO_RECURSE
237 typedef typename tuple_meta_transform<
238 BOOST_DEDUCED_TYPENAME Tuple::tail_type
239 , Fun
240 >::type transformed_tail_type;
242 return tuples::cons<
243 BOOST_DEDUCED_TYPENAME mpl::apply1<
244 Fun, BOOST_DEDUCED_TYPENAME Tuple::head_type
245 >::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<
255 Tuple
256 , Fun
257 >::type
259 tuple_transform(
260 const Tuple& t,
261 Fun f
264 return tuple_transform_impl(t, f, 1);
266 #endif
268 // for_each algorithm for tuples.
270 template<typename Fun>
271 Fun BOOST_TUPLE_ALGO(tuple_for_each)(
272 tuples::null_type
273 , Fun f BOOST_TUPLE_ALGO_TERMINATOR
275 { return f; }
278 template<typename Tuple, typename Fun>
279 Fun BOOST_TUPLE_ALGO(tuple_for_each)(
280 Tuple& t
281 , Fun f BOOST_TUPLE_ALGO_RECURSE)
283 f( t.get_head() );
284 return tuple_for_each(t.get_tail(), f);
287 #ifdef BOOST_TUPLE_ALGO_DISPATCH
288 template<typename Tuple, typename Fun>
290 tuple_for_each(
291 Tuple& t,
292 Fun f
295 return tuple_for_each_impl(t, f, 1);
297 #endif
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)
305 { return true; }
307 template<typename Tuple1, typename Tuple2>
308 bool tuple_equal(
309 Tuple1 const& t1,
310 Tuple2 const& t2
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
331 // class.
332 template<>
333 struct iterator_reference<mpl::_1>
335 template <class T>
336 struct apply : iterator_reference<T> {};
338 #endif
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<
346 IteratorTuple,
347 iterator_reference<mpl::_1>
352 // Metafunction to obtain the minimal traversal tag in a tuple
353 // of iterators.
355 template<typename IteratorTuple>
356 struct minimum_traversal_category_in_iterator_tuple
358 typedef typename tuple_impl_specific::tuple_meta_transform<
359 IteratorTuple
360 , iterator_traversal<>
361 >::type tuple_of_traversal_tags;
363 typedef typename tuple_impl_specific::tuple_meta_accumulate<
364 tuple_of_traversal_tags
365 , minimum_category<>
366 , random_access_traversal_tag
367 >::type type;
370 #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) // ETI workaround
371 template <>
372 struct minimum_traversal_category_in_iterator_tuple<int>
374 typedef int type;
376 #endif
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
392 template<>
393 struct and_with_two_args<mpl::_1,mpl::_2>
395 template <class A1, class A2>
396 struct apply : mpl::and_<A1,A2>
399 # endif
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
411 private:
412 // Reference type is the type of the tuple obtained from the
413 // iterators' reference types.
414 typedef typename
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
426 // iterator tuple.
427 typedef typename
428 detail::minimum_traversal_category_in_iterator_tuple<
429 IteratorTuple
430 >::type traversal_category;
431 public:
433 // The iterator facade type from which the zip iterator will
434 // be derived.
435 typedef iterator_facade<
436 zip_iterator<IteratorTuple>,
437 value_type,
438 traversal_category,
439 reference,
440 difference_type
441 > type;
444 template <>
445 struct zip_iterator_base<int>
447 typedef int type;
451 /////////////////////////////////////////////////////////////////////
453 // zip_iterator class definition
455 template<typename IteratorTuple>
456 class zip_iterator :
457 public detail::zip_iterator_base<IteratorTuple>::type
460 // Typedef super_t as our base class.
461 typedef typename
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;
467 public:
469 // Construction
470 // ============
472 // Default constructor
473 zip_iterator() { }
475 // Constructor from iterator tuple
476 zip_iterator(IteratorTuple iterator_tuple)
477 : m_iterator_tuple(iterator_tuple)
480 // Copy constructor
481 template<typename OtherIteratorTuple>
482 zip_iterator(
483 const zip_iterator<OtherIteratorTuple>& other,
484 typename enable_if_convertible<
485 OtherIteratorTuple,
486 IteratorTuple
487 >::type* = 0
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; }
495 private:
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
512 // as
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
518 // of #ifdefs here.
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
530 // iterator tuple.
531 void advance(typename super_t::difference_type n)
533 detail::tuple_impl_specific::tuple_for_each(
534 m_iterator_tuple,
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.
540 void increment()
542 detail::tuple_impl_specific::tuple_for_each(
543 m_iterator_tuple,
544 detail::increment_iterator()
548 // Decrementing a zip iterator means to decrement all iterators in
549 // the iterator tuple.
550 void decrement()
552 detail::tuple_impl_specific::tuple_for_each(
553 m_iterator_tuple,
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
562 ) const
564 return boost::tuples::get<0>(other.get_iterator_tuple()) -
565 boost::tuples::get<0>(this->get_iterator_tuple());
568 // Data Members
569 // ============
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); }
585 #endif