| [a80f419] | 1 | /* | 
|---|
|  | 2 | * ObservedIterator.hpp | 
|---|
|  | 3 | * | 
|---|
|  | 4 | *  Created on: Mar 4, 2010 | 
|---|
|  | 5 | *      Author: crueger | 
|---|
|  | 6 | */ | 
|---|
|  | 7 |  | 
|---|
|  | 8 | #ifndef OBSERVEDITERATOR_HPP_ | 
|---|
|  | 9 | #define OBSERVEDITERATOR_HPP_ | 
|---|
|  | 10 |  | 
|---|
| [70672e3] | 11 | // include config.h | 
|---|
|  | 12 | #ifdef HAVE_CONFIG_H | 
|---|
|  | 13 | #include <config.h> | 
|---|
|  | 14 | #endif | 
|---|
|  | 15 |  | 
|---|
| [9098f9] | 16 | #include "Observer.hpp" | 
|---|
| [a80f419] | 17 |  | 
|---|
|  | 18 | #include <iterator> | 
|---|
|  | 19 |  | 
|---|
|  | 20 | // we build an iterator that observes traversion of some kind of Data structure conforming to STL | 
|---|
|  | 21 | template<class _Set> | 
|---|
|  | 22 | class ObservedIterator | 
|---|
|  | 23 | : public std::iterator<typename std::iterator_traits<typename _Set::iterator>::iterator_category, | 
|---|
|  | 24 | typename std::iterator_traits<typename _Set::iterator>::value_type, | 
|---|
|  | 25 | typename std::iterator_traits<typename _Set::iterator>::difference_type, | 
|---|
|  | 26 | typename std::iterator_traits<typename _Set::iterator>::pointer, | 
|---|
|  | 27 | typename std::iterator_traits<typename _Set::iterator>::reference> | 
|---|
|  | 28 | { | 
|---|
|  | 29 | public: | 
|---|
|  | 30 | // Some typedefs to conform to STL-Iterator structure | 
|---|
|  | 31 | typedef typename _Set::iterator _Iter; | 
|---|
|  | 32 | typedef typename _Iter::value_type value_type; | 
|---|
|  | 33 | typedef typename _Iter::difference_type difference_type; | 
|---|
|  | 34 | typedef typename _Iter::pointer pointer; | 
|---|
|  | 35 | typedef typename _Iter::reference reference; | 
|---|
|  | 36 | typedef typename _Iter::iterator_category iterator_category; | 
|---|
|  | 37 |  | 
|---|
|  | 38 | ObservedIterator() : | 
|---|
|  | 39 | protector(0) | 
|---|
|  | 40 | {} | 
|---|
|  | 41 |  | 
|---|
|  | 42 | ObservedIterator(_Iter iter,Observable *obs) : | 
|---|
|  | 43 | iter(iter), | 
|---|
|  | 44 | collection(obs), | 
|---|
|  | 45 | protector(0) | 
|---|
|  | 46 | {} | 
|---|
|  | 47 |  | 
|---|
|  | 48 | ObservedIterator(const ObservedIterator &dest) : | 
|---|
|  | 49 | iter(dest.iter), | 
|---|
|  | 50 | collection(dest.collection), | 
|---|
|  | 51 | protector(dest.copyLock()) | 
|---|
|  | 52 | {} | 
|---|
|  | 53 |  | 
|---|
|  | 54 | ~ObservedIterator(){ | 
|---|
|  | 55 | if(protector) | 
|---|
|  | 56 | delete protector; | 
|---|
|  | 57 | } | 
|---|
|  | 58 |  | 
|---|
|  | 59 | // standard Iterator methods | 
|---|
|  | 60 | ObservedIterator& operator=(const ObservedIterator& dest){ | 
|---|
|  | 61 | if(&dest !=this){ | 
|---|
|  | 62 | // get the new lock first, in case the two locks point to the same observable | 
|---|
|  | 63 | Observable::_Observable_protector *newLock = dest.copyLock(); | 
|---|
|  | 64 | if(protector) | 
|---|
|  | 65 | delete protector; | 
|---|
|  | 66 | protector = newLock; | 
|---|
|  | 67 | // After the new lock is aquired we can safely set the iterator | 
|---|
|  | 68 | iter = dest.iter; | 
|---|
|  | 69 | // we need to know the collection, in case we still have to set the lock | 
|---|
|  | 70 | collection = dest.collection; | 
|---|
|  | 71 | } | 
|---|
|  | 72 | return *this; | 
|---|
|  | 73 | } | 
|---|
|  | 74 |  | 
|---|
|  | 75 | ObservedIterator& operator++()   // prefix | 
|---|
|  | 76 | { | 
|---|
|  | 77 | ++iter; | 
|---|
|  | 78 | return *this; | 
|---|
|  | 79 | } | 
|---|
|  | 80 |  | 
|---|
|  | 81 | ObservedIterator operator++(int) // postfix with the dummy int parameter | 
|---|
|  | 82 | { | 
|---|
|  | 83 | ObservedIterator ret(*this); | 
|---|
|  | 84 | ++(*this); | 
|---|
|  | 85 | return ret; | 
|---|
|  | 86 | } | 
|---|
|  | 87 |  | 
|---|
|  | 88 | ObservedIterator& operator--()   // prefix | 
|---|
|  | 89 | { | 
|---|
|  | 90 | --iter; | 
|---|
|  | 91 | return *this; | 
|---|
|  | 92 | } | 
|---|
|  | 93 |  | 
|---|
|  | 94 | ObservedIterator  operator--(int) // postfix with the dummy int parameter | 
|---|
|  | 95 | { | 
|---|
|  | 96 | ObservedIterator ret(*this); | 
|---|
|  | 97 | --(*this); | 
|---|
|  | 98 | return ret; | 
|---|
|  | 99 | } | 
|---|
|  | 100 |  | 
|---|
| [178da0] | 101 | bool operator==(const ObservedIterator &rhs) const | 
|---|
|  | 102 | { | 
|---|
| [a80f419] | 103 | return iter==rhs.iter; | 
|---|
|  | 104 | } | 
|---|
|  | 105 |  | 
|---|
| [178da0] | 106 | bool operator!=(const ObservedIterator &rhs) const | 
|---|
|  | 107 | { | 
|---|
| [a80f419] | 108 | return iter!=rhs.iter; | 
|---|
|  | 109 | } | 
|---|
|  | 110 |  | 
|---|
| [4fb16c] | 111 | /** Returns the value_type this iterator represents. | 
|---|
|  | 112 | * Activates a lock. | 
|---|
|  | 113 | * | 
|---|
|  | 114 | * \note In order to be conforming, dereference must be const member. | 
|---|
|  | 115 | * | 
|---|
|  | 116 | * @return value_type of iterator | 
|---|
|  | 117 | */ | 
|---|
|  | 118 | value_type operator*() const { | 
|---|
| [a80f419] | 119 | // access is requested... time to get the lock | 
|---|
|  | 120 | acquireLock(); | 
|---|
|  | 121 | return (*iter); | 
|---|
|  | 122 | } | 
|---|
|  | 123 |  | 
|---|
| [4fb16c] | 124 | /** Returns pointer to value_type this iterator represents. | 
|---|
|  | 125 | * Activates a lock. | 
|---|
|  | 126 | * | 
|---|
|  | 127 | * \note In order to be conforming, dereference must be const member. | 
|---|
|  | 128 | * | 
|---|
|  | 129 | * @return pointer to value_type of iterator | 
|---|
|  | 130 | */ | 
|---|
|  | 131 | value_type *operator->() const { | 
|---|
| [a80f419] | 132 | acquireLock(); | 
|---|
|  | 133 | return &(*iter); | 
|---|
|  | 134 | } | 
|---|
|  | 135 |  | 
|---|
|  | 136 | // when we turn into a const iterator we can loose our lock | 
|---|
|  | 137 | operator typename _Set::const_iterator() { | 
|---|
|  | 138 | // typecast will be handled by the typecast method of the original iterator | 
|---|
|  | 139 | return iter; | 
|---|
|  | 140 | } | 
|---|
|  | 141 |  | 
|---|
|  | 142 | private: | 
|---|
|  | 143 |  | 
|---|
|  | 144 | /** | 
|---|
|  | 145 | * gets the lock for the collection when needed | 
|---|
|  | 146 | * | 
|---|
|  | 147 | * The lock is only acquired when the first change is done, so we can be free to do | 
|---|
|  | 148 | * anything with the iterator before that. I.e. step forward, turn into a const_iterator | 
|---|
|  | 149 | * etc. | 
|---|
|  | 150 | */ | 
|---|
| [4fb16c] | 151 | void acquireLock() const { | 
|---|
| [a80f419] | 152 | if(!protector) | 
|---|
|  | 153 | protector = new Observable::_Observable_protector(collection); | 
|---|
|  | 154 | } | 
|---|
|  | 155 |  | 
|---|
|  | 156 | Observable::_Observable_protector *copyLock() const{ | 
|---|
|  | 157 | // we only copy if we actually carry a lock | 
|---|
|  | 158 | if(protector){ | 
|---|
|  | 159 | return new Observable::_Observable_protector(*protector); | 
|---|
|  | 160 | } | 
|---|
|  | 161 | else{ | 
|---|
|  | 162 | return 0; | 
|---|
|  | 163 | } | 
|---|
|  | 164 | } | 
|---|
|  | 165 |  | 
|---|
|  | 166 | _Iter iter; | 
|---|
|  | 167 | Observable *collection; | 
|---|
| [4fb16c] | 168 | mutable Observable::_Observable_protector *protector; | 
|---|
| [a80f419] | 169 | }; | 
|---|
|  | 170 |  | 
|---|
|  | 171 | #endif /* OBSERVEDITERATOR_HPP_ */ | 
|---|