mirror of https://github.com/CGAL/cgal
444 lines
13 KiB
TeX
444 lines
13 KiB
TeX
|
|
|
|
\cleardoublepage
|
|
\chapter{Iterators}
|
|
\label{chapterIterators}
|
|
|
|
Iterators are a generalization of pointers that allow a programmer to
|
|
work with different data structures (containers) in a uniform manner.
|
|
An iterator is the glue that allows to write a single implementation of
|
|
an algorithm that will work for data contained in an array, a list or
|
|
some other container -- even a container that did not yet exist when the
|
|
algorithm was implemented.
|
|
|
|
An iterator is a concept, not a programming language construct. It can
|
|
be seen as a set of requirements. A type is an iterator if it satisfies
|
|
those requirements. So, for instance, a pointer to an element of an
|
|
array is an iterator. We will check this later.
|
|
|
|
Depending on the operations defined for an iterator, there are five
|
|
categories: {\em input, output, forward, bidirectional} and {\em
|
|
random access iterators}. We first have to introduce some terminology.
|
|
|
|
{\bf Mutable versus constant:}
|
|
There is an additional attribute that forward, bidirectional and
|
|
random access iterators might have, that is, they can be {\em mutable}
|
|
or {\em constant} depending on whether the result of the
|
|
\ccTexHtml{{\tt operator }\raisebox{-1mm}{*}}{<TT>operator *</TT>}
|
|
behaves as a reference or as a reference to a constant.
|
|
|
|
{\bf Past-the-end value:}
|
|
Just as a regular pointer to an array guarantees that there is a
|
|
pointer value pointing past the last element of the array, so for any
|
|
iterator type there is an iterator value that points past the last
|
|
element of a corresponding container. These values are called {\em
|
|
past-the-end} values. Values of the iterator for which the
|
|
\ccTexHtml{{\tt operator }\raisebox{-1mm}{*}}{<TT>operator *</TT>}
|
|
is defined are called {\em dereferenceable}.
|
|
The library never assumes that past-the-end values are
|
|
dereferenceable.
|
|
|
|
{\bf Reachability} An iterator $j$ is called {\em reachable} from an
|
|
iterator $i$ if and only if there is a finite sequence of applications
|
|
of \ccStyle{operator}$\!+\!+$ to $i$ that makes $i == j$. If $i$ and
|
|
$j$ refer to the same container, then either $j$ is reachable from
|
|
$i$, or $i$ is reachable from $j$, or both ($i == j$).
|
|
|
|
{\bf Range:}
|
|
Most of the library's algorithmic templates that operate on data
|
|
structures have interfaces that use {\em ranges}. A range is a pair of
|
|
iterators that designate the beginning and end of the computation. A
|
|
range $\left[i, i\right)$ is an {\em empty range}; in general, a range
|
|
$\left[i, j\right)$ refers to the elements in the data structure
|
|
starting with the one pointed to by $i$ and up to but not including the
|
|
one pointed to by $j$. Range $\left[i, j\right)$ is valid if and only if $j$
|
|
is reachable from $i$. The result of the application of the
|
|
algorithms in the library to invalid ranges is undefined.
|
|
|
|
\medskip
|
|
|
|
As we mentioned in the introduction we are a little bit sloppy in the
|
|
presentation of \stl, in order to make it easier to understand. A
|
|
class is said to be an iterator if it fulfills a set of requirements.
|
|
In the following sections we do not present the requirements, but we
|
|
state properties that are true, if the requirements are fulfilled.
|
|
The difference is best seen by an example: we write that the return
|
|
value of the test for equality returns a \ccStyle{bool}, but the
|
|
requirement is only that the return value is convertible to \ccStyle{bool}.
|
|
|
|
\newpage
|
|
|
|
|
|
|
|
|
|
\begin{ccClass}{forward_iterator}
|
|
|
|
\ccSection{Forward Iterator}
|
|
|
|
\ccDefinition
|
|
|
|
A class \ccClassName\ that satisfies the requirements of a forward iterator
|
|
for the value type \ccStyle{T}, supports the following operations.
|
|
|
|
\ccCreation
|
|
\ccCreationVariable{it}
|
|
|
|
\ccConstructor{iterator();}
|
|
{}
|
|
|
|
\ccConstructor{iterator(const iterator& it1);}
|
|
{}
|
|
|
|
\ccOperations
|
|
|
|
\ccMethod{iterator& operator=(const iterator &it1);}
|
|
{Assignment.}
|
|
|
|
\ccMethod{bool operator==(const iterator &it1) const;}
|
|
{Test for equality: Two iterators are equal if they refer to the same item.}
|
|
|
|
\ccMethod{bool operator!=(const iterator &it1) const;}
|
|
{Test for inequality. The result is the same as \ccStyle{!(it == it1)}.}
|
|
|
|
\ccMethod{T& operator*();}
|
|
{Returns the value of the iterator.
|
|
If \ccClassName\ is mutable \ccStyle{*it = t} is valid.
|
|
\ccPrecond \ccVar\ is dereferenceable.}
|
|
|
|
\ccMethod{iterator& operator++();}
|
|
{Prefix increment operation.
|
|
\ccPrecond \ccVar\ is dereferenceable.}
|
|
|
|
\ccMethod{const iterator& operator++(int);}
|
|
{Postfix increment operation. The result is the same as that of
|
|
\ccStyle{iterator tmp = it; ++it; return tmp;}.
|
|
\ccPrecond \ccVar\ is dereferenceable.}
|
|
|
|
\end{ccClass}
|
|
|
|
|
|
\begin{ccClass}{bidirectional_iterator}
|
|
|
|
\ccSection{Bidirectional Iterator}
|
|
|
|
\ccDefinition
|
|
|
|
A class \ccClassName\ that satisfies the requirements of a bidirectional
|
|
iterator for the value type \ccStyle{T}, supports the following operations
|
|
in addition to the operations supported by a forward iterator.
|
|
|
|
\ccCreationVariable{it}
|
|
\ccOperations
|
|
|
|
\ccMethod{iterator& operator--();}
|
|
{Prefix decrement operation.
|
|
\ccPrecond \ccVar\ is dereferenceable.}
|
|
|
|
\ccMethod{const iterator& operator--(int);}
|
|
{Postfix decrement operation. The result is the same as that of
|
|
\ccStyle{iterator tmp = it; --it; return tmp;}.
|
|
\ccPrecond \ccVar\ is dereferenceable.}
|
|
|
|
\end{ccClass}
|
|
|
|
\newpage
|
|
|
|
|
|
\begin{ccClass}{random_access_iterator}
|
|
|
|
\ccSection{Random Access Iterator}
|
|
|
|
\ccDefinition
|
|
|
|
A class \ccClassName\ that satisfies the requirements of a random access
|
|
iterator for the value type \ccStyle{T}, supports the following operations
|
|
in addition to the operations supported by a bidirectional iterator.
|
|
|
|
\ccCreationVariable{it}
|
|
|
|
\vfill
|
|
|
|
\ccOperations
|
|
|
|
\ccMethod{iterator& operator+=(int n);}
|
|
{The result is the same as if the prefix increment operation
|
|
was applied $n$ times, but it is computed in constant time.}
|
|
|
|
\ccMethod{iterator operator+(int n);}
|
|
{Same as above, but returns a new iterator.}
|
|
|
|
\ccFunction{iterator operator+(int n, iterator it);}
|
|
{Same as above.}
|
|
|
|
\ccMethod{iterator& operator-=(int n);}
|
|
{The result is the same as if the prefix decrement operation
|
|
was applied $n$ times, but it is computed in constant time.}
|
|
|
|
\ccMethod{iterator operator-(int n);}
|
|
{Same as above, but returns a new iterator.}
|
|
|
|
\ccMethod{int operator-(const iterator &it1);}
|
|
{The result \ccStyle{n} is such that \ccStyle{it1 + n ==} \ccVar.
|
|
\ccPrecond \ccVar\ is reachable from \ccStyle{it1}.}
|
|
|
|
\ccMethod{T& operator[](int n);}
|
|
{Returns \ccStyle{*(it + n)}.
|
|
\ccPrecond \ccStyle{*(it + n)} is dereferenceable}
|
|
|
|
|
|
\ccMethod{bool operator<(iterator it1);}
|
|
{$<$ is a total ordering relation.}
|
|
|
|
\ccMethod{bool operator>(iterator it1);}
|
|
{$>$ is a total ordering relation opposite to \ccStyle{<}.}
|
|
|
|
\ccMethod{bool operator<=(iterator it1);}
|
|
{Result is the same as \ccStyle{! it > it1}.}
|
|
|
|
\ccMethod{bool operator>=(iterator it1);}
|
|
{Result is the same as \ccStyle{! it < it1}.}
|
|
|
|
\vfill
|
|
\ccExample
|
|
|
|
We promised to show why a pointer (in this case \ccStyle{V*}) is a random access
|
|
iterator. In order to show that it supports the required operations, we
|
|
give a program that uses them. Not all operations are used --- so it is not a
|
|
complete proof --- but hopefully enough to convince the reader.
|
|
|
|
Notice that the program is nothing special. It was valid \CC\ (with minor
|
|
changes even valid C), long before the iterator concept was invented!
|
|
The comments point to the requirements.
|
|
|
|
\newpage
|
|
|
|
\begin{cprog}
|
|
|
|
const int N = 10;
|
|
|
|
struct V {
|
|
float val;
|
|
};
|
|
|
|
float fill_and_add(V *b, V *e)
|
|
{
|
|
V *c; /* creation, first way (ForwardIterator) */
|
|
float sum;
|
|
for (int i=0; i<e-b; i++) /* subtraction (RandomAccessIterator) */
|
|
b[i].val = i*i/2.0; /* indexing (RandomAccessIterator) */
|
|
for (c=b; c != e; ++c) /* assignment, inequality test, increment (ForwardIterator) */
|
|
sum += (*c).val; /* dereference (ForwardIterator) */
|
|
return sum;
|
|
}
|
|
|
|
float foo()
|
|
{
|
|
V a[N];
|
|
V *e(a+N); /* creation, second way (ForwardIterator) and */
|
|
/* integer adding (RandomAccessIterator) */
|
|
return fill_and_add(a,e);
|
|
}
|
|
\end{cprog}
|
|
|
|
\ccExample
|
|
|
|
We give a second example for the more advanced \stl\ user. We stated
|
|
that iterators allow us to work with different data structures in a
|
|
unform manner. But the function \ccStyle{fill_and_add} in the
|
|
previous example only takes pointers as argument. Here we rewrite it
|
|
so that it takes any random access iterator as argument, provided it
|
|
has the right value type (\ccStyle{V}).
|
|
|
|
\begin{cprog}
|
|
|
|
template <class RandomAccessIterator>
|
|
float fill_and_add(RandomAccessIterator b, RandomAccessIterator e)
|
|
{
|
|
RandomAccessIterator c;
|
|
float sum;
|
|
for (int i=0; i<e-b; i++)
|
|
b[i].val = i*i/2.0;
|
|
for (c=b; c != e; ++c)
|
|
sum += (*c).val;
|
|
return sum;
|
|
}
|
|
\end{cprog}
|
|
\end{ccClass}
|
|
|
|
|
|
|
|
\begin{ccClass}{input_iterator}
|
|
|
|
\ccSection{Input Iterator}
|
|
|
|
|
|
\ccDefinition
|
|
|
|
A class \ccClassName\ that satisfies the requirements of an input iterator
|
|
for the value type \ccStyle{T}, supports the following operations.
|
|
|
|
Algorithms on input iterators should never attempt to pass through the
|
|
same iterator twice. They should be single pass algorithms.
|
|
|
|
\ccCreation
|
|
\ccCreationVariable{it}
|
|
|
|
\ccConstructor{iterator(const iterator& it1);}
|
|
{}
|
|
|
|
\ccOperations
|
|
|
|
\ccMethod{iterator& operator=(const iterator &it1);}
|
|
{Assignment.}
|
|
|
|
|
|
\ccMethod{T operator*();}
|
|
{Returns the value of the iterator.
|
|
\ccPrecond \ccVar\ is dereferenceable.}
|
|
|
|
\ccMethod{iterator& operator++();}
|
|
{Prefix increment operation.
|
|
\ccPrecond \ccVar\ is dereferenceable.}
|
|
|
|
\ccMethod{iterator operator++(int);}
|
|
{Postfix increment operation. The result is the same as that of
|
|
\ccStyle{(void)++it;}.
|
|
\ccPrecond \ccVar\ is dereferenceable.}
|
|
|
|
|
|
\ccExample
|
|
|
|
The following code fragment reads numbers of the type \ccc{double}
|
|
from \ccc{cin} and computes their sum. The {\sc Stl} provides an
|
|
\ccc{istream_iterator} that fulfills the input iterator requirements.
|
|
As the iterator is a kind of file pointer it should be clear
|
|
why only single pass algorithms can be applied on this iterator.
|
|
|
|
\begin{cprog}
|
|
{
|
|
istream_iterator<double> it(cin),
|
|
end();
|
|
double sum = 0.0;
|
|
while(it != end){
|
|
sum += *it;
|
|
++it;
|
|
}
|
|
cout << sum << endl;
|
|
}
|
|
\end{cprog}
|
|
|
|
|
|
\end{ccClass}
|
|
|
|
|
|
|
|
\begin{ccClass}{output_iterator}
|
|
|
|
\ccSection{Output Iterator}
|
|
|
|
|
|
\ccDefinition
|
|
|
|
A class \ccClassName\ that satisfies the requirements of an output iterator
|
|
for the value type \ccStyle{T}, supports the following operations.
|
|
|
|
Algorithms on input iterators should never attempt to pass through the
|
|
same iterator twice. They should be single pass algorithms.
|
|
|
|
\ccCreation
|
|
\ccCreationVariable{it}
|
|
|
|
\ccConstructor{iterator();}
|
|
{}
|
|
|
|
\ccConstructor{iterator(const iterator& it1);}
|
|
{}
|
|
|
|
\ccOperations
|
|
|
|
\ccMethod{iterator& operator=(const iterator &it1);}
|
|
{Assignment.}
|
|
|
|
\ccMethod{bool operator==(const iterator &it1) const;}
|
|
{Test for equality: Two iterators are equal if they refer to the same item.}
|
|
|
|
\ccMethod{bool operator!=(const iterator &it1) const;}
|
|
{Test for inequality. The result is the same as \ccStyle{!(it == it1)}.}
|
|
|
|
\ccMethod{T& operator*();}
|
|
{Returns a reference to the value of the iterator. This operator can
|
|
only be used in order to assign a value to this reference.}
|
|
|
|
\ccMethod{iterator& operator++();}
|
|
{Prefix increment operation.
|
|
\ccPrecond \ccVar\ is dereferenceable.}
|
|
|
|
\ccMethod{void operator++(int);}
|
|
{Postfix increment operation. The result is the same as that of
|
|
\ccStyle{iterator tmp = it; ++it; return tmp;}.
|
|
\ccPrecond \ccVar\ is dereferenceable.}
|
|
|
|
|
|
\ccExample
|
|
|
|
The following code fragment reads numbers of the type \ccc{double}
|
|
from \ccc{cin} and computes their sum. The {\sc Stl} provides an
|
|
\ccc{ostream_iterator} that fulfills the output iterator requirements.
|
|
As the iterator is a kind of file pointer it should be clear
|
|
why only single pass algorithms can be applied on this iterator.
|
|
|
|
\begin{cprog}
|
|
{
|
|
ostream_iterator<double> it(cout);
|
|
for(int r = 0; r < 10; r++){
|
|
*it = 3.1415 * r * r;
|
|
++it;
|
|
}
|
|
}
|
|
\end{cprog}
|
|
|
|
The above code fragment is equivalent to:
|
|
|
|
\begin{cprog}
|
|
{
|
|
for(int r = 0; r < 10; r++){
|
|
cout << 3.1415 * r * r;
|
|
}
|
|
}
|
|
\end{cprog}
|
|
|
|
The use of output iterators is better illustrated with a function
|
|
that can write into arbitrary containers:
|
|
|
|
\begin{cprog}
|
|
template < class OutputIterator >
|
|
void
|
|
generator(OutputIterator it)
|
|
{
|
|
for(int r = 0; r < 10; r++){
|
|
*it = 3.1415 * r * r;
|
|
++it;
|
|
}
|
|
}
|
|
\end{cprog}
|
|
|
|
and here comes its usage.
|
|
|
|
\begin{cprog}
|
|
{
|
|
ostream_iterator<double> it(cout);
|
|
generator(it);
|
|
double R[10];
|
|
generator(R);
|
|
}
|
|
\end{cprog}
|
|
|
|
Note that the memory where the function \ccc{generator} writes to
|
|
must be allocated. If you want to insert the generated doubles at the end
|
|
of a list you have to use a \ccc{back_insert_iterator}. To explain
|
|
this is out of the scope of this introduction to the {\sc Stl}. Please
|
|
refer to the {\sc Stl} reference manuals.
|
|
|
|
\end{ccClass}
|
|
|