Definition
An instance it of class ObserverNodeIt<Obs,Iter> is an observer iterator. Any method call of iterators will be ``observed'' by an internal object of class Obs.
Class ObserverEdgeIt and ObserverAdjIt are defined analogously, i.e. can be used for edge iterators or adjacency iterators, respectively.
Precondition: The template parameter Iter must be a node iterator.
#include < LEDA/graph/graph_iterator.h >
Creation
| ObserverNodeIt<Obs,Iter> | it | introduces a variable it of this class, not bound to an observer or iterator. |
| ObserverNodeIt<Obs,Iter> | it(Obs& obs, const Iter& base_it) | |
| introduces a variable it of this class
bound to the observer obs and base_it.
Precondition: Obs must have methods observe_constructor(), observe_forward(), observe_update(). These three methods may have arbitrary return types (incl. void). |
||
Operations
Example
First two simple observer classes. The first one is a dummy class, which ignores all notifications. The second one merely counts the number of calls to operator++ for all iterators that share the same observer object through copy construction or assignment (of course, a real implementation should apply some kind of reference counting or other garbage collection).
In this example, the counter variable _count of class SimpleCountObserver will be initialized with the counter variable _count of class DummyObserver, i.e. the variable is created only once.
template <class Iter>
class DummyObserver {
int* _count;
public:
DummyObserver() : _count(new int(0)) { }
void notify_constructor(const Iter& ) { }
void notify_forward(const Iter& ) { }
void notify_update(const Iter& ) { }
int counter() const { return *_count; }
int* counter_ptr() const { return _count; }
bool operator==(const DummyObserver& D) const {
return _count==D._count; }
};
template <class Iter, class Observer>
class SimpleCountObserver {
int* _count;
public:
SimpleCountObserver() : _count(new int(0)) { }
SimpleCountObserver(Observer& obs) :
_count(obs.counter_ptr()) { }
void notify_constructor(const Iter& ) { }
void notify_forward(const Iter& ) { ++(*_count); }
void notify_update(const Iter& ) { }
int counter() const { return *_count; }
int* counter_ptr() const { return _count; }
bool operator==(const SimpleCountObserver& S) const {
return _count==S._count; }
};
Next an exemplary application, which counts the number of calls to operator++ of all adjacency iterator objects inside dummy_algorithm. Here the dummy observer class is used only as a ``Trojan horse,'' which carries the pointer to the counter without affecting the code of the algorithm.
template<class Iter>
bool break_condition (const Iter&) { ... }
template<class ONodeIt, class OAdjIt>
void dummy_algorithm(ONodeIt& it, OAdjIt& it2) {
while (it.valid()) {
for (it2.update(it); it2.valid() && !break_condition(it2); ++it2)
++it;
}
}
int write_count(graph& G) {
typedef DummyObserver<NodeIt> DummyObs;
typedef SimpleCountObserver<AdjIt,DummyObs> CountObs;
typedef ObserverNodeIt<DummyObs,NodeIt> ONodeIt;
typedef ObserverAdjIt<CountObs,AdjIt> OAdjIt;
DummyObs observer;
ONodeIt it(observer,NodeIt(G));
CountObs observer2(observer);
OAdjIt it2(observer2,AdjIt(G));
dummy_algorithm(it,it2);
return it2.get_observer().counter();
}