0% found this document useful (0 votes)
9 views5 pages

Zip - Iterator Synopsis

The document describes a zip iterator, which allows parallel iteration over multiple sequences. A zip iterator is constructed from a tuple of iterators and dereferencing it returns a tuple of the dereferenced values. The zip iterator models readable iterator and supports common iterator operations like increment and dereference.

Uploaded by

Alex Mercan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views5 pages

Zip - Iterator Synopsis

The document describes a zip iterator, which allows parallel iteration over multiple sequences. A zip iterator is constructed from a tuple of iterators and dereferencing it returns a tuple of the dereferenced values. The zip iterator models readable iterator and supports common iterator operations like increment and dereference.

Uploaded by

Alex Mercan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Zip Iterator

Author: David Abrahams, Thomas Becker


Contact: dave@[Link], thomas@[Link]
Organization: Boost Consulting, Zephyr Associates, Inc.
Date: 2004-11-01
Copyright: Copyright David Abrahams and Thomas Becker 2003.

abstract: The zip iterator provides the ability to parallel-iterate over several controlled se-
quences simultaneously. A zip iterator is constructed from a tuple of iterators. Moving
the zip iterator moves all the iterators in parallel. Dereferencing the zip iterator returns
a tuple that contains the results of dereferencing the individual iterators.

Table of Contents
zip_iterator synopsis
zip_iterator requirements
zip_iterator models
zip_iterator operations
Examples

zip_iterator synopsis
template<typename IteratorTuple>
class zip_iterator
{

public:
typedef /* see below */ reference;
typedef reference value_type;
typedef value_type* pointer;
typedef /* see below */ difference_type;
typedef /* see below */ iterator_category;

zip_iterator();
zip_iterator(IteratorTuple iterator_tuple);

template<typename OtherIteratorTuple>
zip_iterator(
const zip_iterator<OtherIteratorTuple>& other
, typename enable_if_convertible<
OtherIteratorTuple

1
, IteratorTuple>::type* = 0 // exposition only
);

const IteratorTuple& get_iterator_tuple() const;

private:
IteratorTuple m_iterator_tuple; // exposition only
};

template<typename IteratorTuple>
zip_iterator<IteratorTuple>
make_zip_iterator(IteratorTuple t);

The reference member of zip_iterator is the type of the tuple made of the reference types of
the iterator types in the IteratorTuple argument.
The difference_type member of zip_iterator is the difference_type of the first of the iterator
types in the IteratorTuple argument.
The iterator_category member of zip_iterator is convertible to the minimum of the traversal
categories of the iterator types in the IteratorTuple argument. For example, if the zip_iterator holds
only vector iterators, then iterator_category is convertible to boost::random_access_traversal_tag.
If you add a list iterator, then iterator_category will be convertible to boost::bidirectional_traversal_tag,
but no longer to boost::random_access_traversal_tag.

zip_iterator requirements
All iterator types in the argument IteratorTuple shall model Readable Iterator.

zip_iterator models
The resulting zip_iterator models Readable Iterator.
The fact that the zip_iterator models only Readable Iterator does not prevent you from modifying
the values that the individual iterators point to. The tuple returned by the zip_iterator’s operator* is
a tuple constructed from the reference types of the individual iterators, not their value types. For exam-
ple, if zip_it is a zip_iterator whose first member iterator is an std::vector<double>::iterator,
then the following line will modify the value which the first member iterator of zip_it currently points
to:

zip_it->get<0>() = 42.0;

Consider the set of standard traversal concepts obtained by taking the most refined standard traversal
concept modeled by each individual iterator type in the IteratorTuple [Link] zip_iterator
models the least refined standard traversal concept in this set.
zip_iterator<IteratorTuple1> is interoperable with zip_iterator<IteratorTuple2> if and only
if IteratorTuple1 is interoperable with IteratorTuple2.

zip_iterator operations
In addition to the operations required by the concepts modeled by zip_iterator, zip_iterator pro-
vides the following operations.
zip_iterator();

Returns: An instance of zip_iterator with m_iterator_tuple default constructed.

2
zip_iterator(IteratorTuple iterator_tuple);
Returns: An instance of zip_iterator with m_iterator_tuple initialized to itera-
tor_tuple.

template<typename OtherIteratorTuple>
zip_iterator(
const zip_iterator<OtherIteratorTuple>& other
, typename enable_if_convertible<
OtherIteratorTuple
, IteratorTuple>::type* = 0 // exposition only
);

Returns: An instance of zip_iterator that is a copy of other.


Requires: OtherIteratorTuple is implicitly convertible to IteratorTuple.

const IteratorTuple& get_iterator_tuple() const;


Returns: m_iterator_tuple
reference operator*() const;
Returns: A tuple consisting of the results of dereferencing all iterators in m_iterator_tuple.
zip_iterator& operator++();
Effects: Increments each iterator in m_iterator_tuple.
Returns: *this
zip_iterator& operator--();
Effects: Decrements each iterator in m_iterator_tuple.
Returns: *this

template<typename IteratorTuple>
zip_iterator<IteratorTuple>
make_zip_iterator(IteratorTuple t);

Returns: An instance of zip_iterator<IteratorTuple> with m_iterator_tuple initial-


ized to t.

template<typename IteratorTuple>
zip_iterator<IteratorTuple>
make_zip_iterator(IteratorTuple t);

Returns: An instance of zip_iterator<IteratorTuple> with m_iterator_tuple initial-


ized to t.

Examples
There are two main types of applications of the zip_iterator. The first one concerns runtime efficiency:
If one has several controlled sequences of the same length that must be somehow processed, e.g., with
the for_each algorithm, then it is more efficient to perform just one parallel-iteration rather than
several individual iterations. For an example, assume that vect_of_doubles and vect_of_ints are
two vectors of equal length containing doubles and ints, respectively, and consider the following two
iterations:

3
std::vector<double>::const_iterator beg1 = vect_of_doubles.begin();
std::vector<double>::const_iterator end1 = vect_of_doubles.end();
std::vector<int>::const_iterator beg2 = vect_of_ints.begin();
std::vector<int>::const_iterator end2 = vect_of_ints.end();

std::for_each(beg1, end1, func_0());


std::for_each(beg2, end2, func_1());

These two iterations can now be replaced with a single one as follows:

std::for_each(
boost::make_zip_iterator(
boost::make_tuple(beg1, beg2)
),
boost::make_zip_iterator(
boost::make_tuple(end1, end2)
),
zip_func()
);

A non-generic implementation of zip_func could look as follows:

struct zip_func :
public std::unary_function<const boost::tuple<const dou-
ble&, const int&>&, void>
{
void operator()(const boost::tuple<const double&, const int&>& t) const
{
m_f0([Link]<0>());
m_f1([Link]<1>());
}

private:
func_0 m_f0;
func_1 m_f1;
};

The second important application of the zip_iterator is as a building block to make combining
iterators. A combining iterator is an iterator that parallel-iterates over several controlled sequences
and, upon dereferencing, returns the result of applying a functor to the values of the sequences at the
respective positions. This can now be achieved by using the zip_iterator in conjunction with the
transform_iterator.
Suppose, for example, that you have two vectors of doubles, say vect_1 and vect_2, and you need
to expose to a client a controlled sequence containing the products of the elements of vect_1 and
vect_2. Rather than placing these products in a third vector, you can use a combining iterator that
calculates the products on the fly. Let us assume that tuple_multiplies is a functor that works
like std::multiplies, except that it takes its two arguments packaged in a tuple. Then the two
iterators it_begin and it_end defined below delimit a controlled sequence containing the products of
the elements of vect_1 and vect_2:

typedef boost::tuple<
std::vector<double>::const_iterator,
std::vector<double>::const_iterator
> the_iterator_tuple;

4
typedef boost::zip_iterator<
the_iterator_tuple
> the_zip_iterator;

typedef boost::transform_iterator<
tuple_multiplies<double>,
the_zip_iterator
> the_transform_iterator;

the_transform_iterator it_begin(
the_zip_iterator(
the_iterator_tuple(
vect_1.begin(),
vect_2.begin()
)
),
tuple_multiplies<double>()
);

the_transform_iterator it_end(
the_zip_iterator(
the_iterator_tuple(
vect_1.end(),
vect_2.end()
)
),
tuple_multiplies<double>()
);

You might also like