Changeset fe3540 for molecuilder/src/Patterns/Cacheable.hpp
- Timestamp:
- Mar 25, 2010, 12:01:58 PM (16 years ago)
- Children:
- eb129c
- Parents:
- db6b872 (diff), 8d9984 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - File:
-
- 1 edited
-
molecuilder/src/Patterns/Cacheable.hpp (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
molecuilder/src/Patterns/Cacheable.hpp
rdb6b872 rfe3540 11 11 #include "Patterns/Observer.hpp" 12 12 #include <boost/function.hpp> 13 #include <boost/shared_ptr.hpp> 14 #include <iostream> 15 16 #include "Helpers/Assert.hpp" 13 17 14 18 #ifndef NO_CACHING … … 17 21 class Cacheable : public Observer 18 22 { 23 // we define the states of the cacheable so we can do very fast state-checks 24 class State{ 25 public: 26 State(Cacheable *_owner) : 27 busy(false), 28 owner(_owner) 29 {} 30 virtual T getValue()=0; 31 virtual void invalidate()=0; 32 virtual bool isValid()=0; 33 virtual void enter()=0; 34 bool isBusy(){ 35 return busy; 36 } 37 protected: 38 bool busy; 39 Cacheable *owner; 40 }; 41 42 class InvalidState : public State{ 43 public: 44 InvalidState(Cacheable *_owner): 45 State(_owner) 46 {} 47 48 virtual T getValue(){ 49 // set the state to valid 50 State::owner->switchState(State::owner->validState); 51 // get the value from the now valid state 52 return State::owner->state->getValue(); 53 } 54 55 virtual void invalidate(){ 56 // nothing to do on this message 57 } 58 59 virtual bool isValid(){ 60 return false; 61 } 62 63 virtual void enter(){ 64 // nothing to do when entering this 65 } 66 }; 67 68 class ValidState : public State{ 69 public: 70 ValidState(Cacheable *_owner) : 71 State(_owner) 72 {} 73 74 virtual T getValue(){ 75 return content; 76 } 77 78 virtual void invalidate(){ 79 State::owner->switchState(State::owner->invalidState); 80 } 81 82 virtual bool isValid(){ 83 return true; 84 } 85 86 virtual void enter(){ 87 State::busy= true; 88 // as soon as we enter the valid state we recalculate 89 content = State::owner->recalcMethod(); 90 State::busy = false; 91 } 92 private: 93 T content; 94 }; 95 96 class DestroyedState : public State { 97 public: 98 DestroyedState(Cacheable *_owner) : 99 State(_owner) 100 {} 101 102 virtual T getValue(){ 103 ASSERT(0,"Cannot get a value from a Cacheable after it's Observable has died"); 104 // we have to return a grossly invalid reference, because no value can be produced anymore 105 return *(static_cast<T*>(0)); 106 } 107 108 virtual void invalidate(){ 109 ASSERT(0,"Cannot invalidate a Cacheable after it's Observable has died"); 110 } 111 112 virtual bool isValid(){ 113 ASSERT(0,"Cannot check validity of a Cacheable after it's Observable has died"); 114 return false; 115 } 116 117 virtual void enter(){ 118 // nothing to do when entering this state 119 } 120 }; 121 122 123 typedef boost::shared_ptr<State> state_ptr; 124 19 125 public: 20 126 Cacheable(Observable *_owner, boost::function<T()> _recalcMethod); 21 127 virtual ~Cacheable(); 22 128 23 const bool isValid(); 24 const T& operator*(); 25 const bool operator==(const T&); 26 const bool operator!=(const T&); 129 const bool isValid() const; 130 const T operator*() const; 27 131 28 132 // methods implemented for base-class Observer … … 30 134 void subjectKilled(Observable *subject); 31 135 private: 32 void checkValid(); 33 34 T content; 136 137 void switchState(state_ptr newState); 138 139 mutable state_ptr state; 140 // pre-defined state so we don't have to construct to much 141 state_ptr invalidState; 142 state_ptr validState; 143 // destroyed state is not predefined, because we rarely enter that state and never leave 144 35 145 Observable *owner; 36 bool valid; 37 bool canBeUsed; 146 38 147 boost::function<T()> recalcMethod; 148 149 // de-activated copy constructor 150 Cacheable(const Cacheable&); 39 151 }; 40 152 … … 43 155 Cacheable<T>::Cacheable(Observable *_owner, boost::function<T()> _recalcMethod) : 44 156 owner(_owner), 45 valid(false),46 canBeUsed(true),47 157 recalcMethod(_recalcMethod) 48 158 { 159 // create all states needed for this object 160 invalidState = state_ptr(new InvalidState(this)); 161 validState = state_ptr(new ValidState(this)); 162 state = invalidState; 49 163 // we sign on with the best(=lowest) priority, so cached values are recalculated before 50 164 // anybody else might ask for updated values … … 52 166 } 53 167 54 template<typename T> 55 const T& Cacheable<T>::operator*(){ 56 checkValid(); 57 return content; 58 } 59 60 template<typename T> 61 const bool Cacheable<T>::operator==(const T& rval){ 62 checkValid(); 63 return (content == rval); 64 } 65 66 template<typename T> 67 const bool Cacheable<T>::operator!=(const T& rval){ 68 checkValid(); 69 return (content != rval); 168 // de-activated copy constructor 169 template<typename T> 170 Cacheable<T>::Cacheable(const Cacheable&){ 171 ASSERT(0,"Cacheables should never be copied"); 172 } 173 174 template<typename T> 175 const T Cacheable<T>::operator*() const{ 176 // we can only use the cacheable when the owner is not changing at the moment 177 if(!owner->isBlocked()){ 178 return state->getValue(); 179 } 180 else{ 181 return recalcMethod(); 182 } 70 183 } 71 184 … … 77 190 78 191 template<typename T> 79 const bool Cacheable<T>::isValid() {80 return valid;192 const bool Cacheable<T>::isValid() const{ 193 return state->isValid(); 81 194 } 82 195 83 196 template<typename T> 84 197 void Cacheable<T>::update(Observable *subject) { 85 valid = false;198 state->invalidate(); 86 199 } 87 200 88 201 template<typename T> 89 202 void Cacheable<T>::subjectKilled(Observable *subject) { 90 valid = false;91 canBeUsed = false;92 } 93 94 template<typename T> 95 void Cacheable<T>:: checkValid(){96 assert(canBeUsed && "Cacheable used after owner was deleted");97 if(!isValid()){98 content = recalcMethod();99 }100 } 203 state_ptr destroyed = state_ptr(new DestroyedState(this)); 204 switchState(destroyed); 205 } 206 207 template<typename T> 208 void Cacheable<T>::switchState(state_ptr newState){ 209 ASSERT(!state->isBusy(),"LOOP DETECTED: Cacheable state switched while recalculating.\nDid the recalculation trigger the Observable?"); 210 state = newState; 211 state->enter(); 212 } 213 101 214 #else 102 215 template<typename T> … … 107 220 virtual ~Cacheable(); 108 221 109 const bool isValid(); 110 const T& operator*(); 111 const bool operator==(const T&); 112 const bool operator!=(const T&); 222 const bool isValid() const; 223 const T operator*() const; 113 224 114 225 // methods implemented for base-class Observer … … 126 237 127 238 template<typename T> 128 const T & Cacheable<T>::operator*(){239 const T Cacheable<T>::operator*() const{ 129 240 return recalcMethod(); 130 }131 132 template<typename T>133 const bool Cacheable<T>::operator==(const T& rval){134 return (recalcMethod() == rval);135 }136 137 template<typename T>138 const bool Cacheable<T>::operator!=(const T& rval){139 return (recalcMethod() != rval);140 241 } 141 242 … … 145 246 146 247 template<typename T> 147 const bool Cacheable<T>::isValid() {248 const bool Cacheable<T>::isValid() const{ 148 249 return true; 149 250 } … … 151 252 template<typename T> 152 253 void Cacheable<T>::update(Observable *subject) { 153 assert(0 &&"Cacheable::update should never be called when caching is disabled");154 } 155 156 template<typename T> 157 void Cacheable<T>::subjectKilled(Observable *subject) {158 assert(0 &&"Cacheable::subjectKilled should never be called when caching is disabled");254 ASSERT(0, "Cacheable::update should never be called when caching is disabled"); 255 } 256 257 template<typename T> 258 void Cacheable<T>::subjectKilled(Observable *subject){ 259 ASSERT(0, "Cacheable::subjectKilled should never be called when caching is disabled"); 159 260 } 160 261 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
