All of the one dimensional collection types we use are derived from the Collection class. The elements contained in a collection can be examined via the creation of an iterator - different collections will have different kinds of iterators, all of which are derived from class Iterator . Any collection must be able to allocate (via new ) the appropriate type of iterator. The iterator can be dereferenced (via operator * ) to access the current element or incremented (via operator ++ ) to move to the next element. If an iterator is used where a boolean is required (e.g. in the conditional expression of a for loop), the operator bool() function will return true iff there are more elements to be iterated over. The class declarations include the following lines:
template<class T> class Collection {
public:
Iterator<T> *new_iterator();
Any_Iterator<T> any_iterator();
int size() const;
};
template<class T> class Iterator {
public:
T & operator*();
void operator++();
operator bool() const;
};
We can therefore enumerate the elements of any collection as follows:
int sum(Collection<int> &c)
{
Iterator<int> *i;
int s = 0;
for (i = c.new_iterator(); (*i); (*i)++)
s += *(*i);
delete i;
return s;
}
As it is easy to forget that the new_iterator must later be delete d, we have provided the type Any_Iterator , which handles this issue automatically.
int sum(Collection<int> &c)
{
int s = 0;
for (Any_Iterator i = c.any_iterator(); i; i++)
s += *i;
return s;
}
If a collection is changed (elements are added or removed), all the behavior of any iterators on that collection is, in general, not defined.
Both the new_iterator and any_iterator functions cause heap allocation. If we know what kind of collection we are working with, we can avoid the overhead inherent in this allocation by using a specialized iterator for that type of collection (such as a List_Iterator
for a List , as in Section 3.3).
Note that iterators can also be manipulated via an alternate set of functions: live() , curr() , and next() . These are particularly useful in a debugger, where the other syntax can be difficult to use.
Many classes in the Presburger library have iterators to walk through the structure -- iterators over conjunctions in a formula in disjunctive normal form, iterators over constraints in a conjunction, or iterators over variables in a constraint. These will be discussed in more detail later.