| 1 | /*
 | 
|---|
| 2 |  * Cacheable.hpp
 | 
|---|
| 3 |  *
 | 
|---|
| 4 |  *  Created on: Feb 2, 2010
 | 
|---|
| 5 |  *      Author: crueger
 | 
|---|
| 6 |  */
 | 
|---|
| 7 | 
 | 
|---|
| 8 | #ifndef CACHEABLE_HPP_
 | 
|---|
| 9 | #define CACHEABLE_HPP_
 | 
|---|
| 10 | 
 | 
|---|
| 11 | #include "Patterns/Observer.hpp"
 | 
|---|
| 12 | #include <boost/function.hpp>
 | 
|---|
| 13 | 
 | 
|---|
| 14 | #ifndef NO_CACHING
 | 
|---|
| 15 | 
 | 
|---|
| 16 |   template<typename T>
 | 
|---|
| 17 |   class Cacheable : public Observer
 | 
|---|
| 18 |   {
 | 
|---|
| 19 |   public:
 | 
|---|
| 20 |     Cacheable(Observable *_owner, boost::function<T()> _recalcMethod);
 | 
|---|
| 21 |     virtual ~Cacheable();
 | 
|---|
| 22 | 
 | 
|---|
| 23 |     const bool isValid();
 | 
|---|
| 24 |     const T& operator*();
 | 
|---|
| 25 |     const bool operator==(const T&);
 | 
|---|
| 26 |     const bool operator!=(const T&);
 | 
|---|
| 27 | 
 | 
|---|
| 28 |     // methods implemented for base-class Observer
 | 
|---|
| 29 |     void update(Observable *subject);
 | 
|---|
| 30 |     void subjectKilled(Observable *subject);
 | 
|---|
| 31 |   private:
 | 
|---|
| 32 |     void checkValid();
 | 
|---|
| 33 | 
 | 
|---|
| 34 |     T content;
 | 
|---|
| 35 |     Observable *owner;
 | 
|---|
| 36 |     bool valid;
 | 
|---|
| 37 |     bool canBeUsed;
 | 
|---|
| 38 |     boost::function<T()> recalcMethod;
 | 
|---|
| 39 |   };
 | 
|---|
| 40 | 
 | 
|---|
| 41 | 
 | 
|---|
| 42 |   template<typename T>
 | 
|---|
| 43 |   Cacheable<T>::Cacheable(Observable *_owner, boost::function<T()> _recalcMethod) :
 | 
|---|
| 44 |     owner(_owner),
 | 
|---|
| 45 |     recalcMethod(_recalcMethod),
 | 
|---|
| 46 |     valid(false),
 | 
|---|
| 47 |     canBeUsed(true)
 | 
|---|
| 48 |   {
 | 
|---|
| 49 |     // we sign on with the best(=lowest) priority, so cached values are recalculated before
 | 
|---|
| 50 |     // anybody else might ask for updated values
 | 
|---|
| 51 |     owner->signOn(this,-20);
 | 
|---|
| 52 |   }
 | 
|---|
| 53 | 
 | 
|---|
| 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);
 | 
|---|
| 70 |   }
 | 
|---|
| 71 | 
 | 
|---|
| 72 |   template<typename T>
 | 
|---|
| 73 |   Cacheable<T>::~Cacheable()
 | 
|---|
| 74 |   {
 | 
|---|
| 75 |     owner->signOff(this);
 | 
|---|
| 76 |   }
 | 
|---|
| 77 | 
 | 
|---|
| 78 |   template<typename T>
 | 
|---|
| 79 |   const bool Cacheable<T>::isValid(){
 | 
|---|
| 80 |     return valid;
 | 
|---|
| 81 |   }
 | 
|---|
| 82 | 
 | 
|---|
| 83 |   template<typename T>
 | 
|---|
| 84 |   void Cacheable<T>::update(Observable *subject) {
 | 
|---|
| 85 |     valid = false;
 | 
|---|
| 86 |   }
 | 
|---|
| 87 | 
 | 
|---|
| 88 |   template<typename T>
 | 
|---|
| 89 |   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 |   }
 | 
|---|
| 101 | #else
 | 
|---|
| 102 |   template<typename T>
 | 
|---|
| 103 |   class Cacheable : public Observer
 | 
|---|
| 104 |   {
 | 
|---|
| 105 |   public:
 | 
|---|
| 106 |     Cacheable(Observable *_owner, boost::function<T()> _recalcMethod);
 | 
|---|
| 107 |     virtual ~Cacheable();
 | 
|---|
| 108 | 
 | 
|---|
| 109 |     const bool isValid();
 | 
|---|
| 110 |     const T& operator*();
 | 
|---|
| 111 |     const bool operator==(const T&);
 | 
|---|
| 112 |     const bool operator!=(const T&);
 | 
|---|
| 113 | 
 | 
|---|
| 114 |     // methods implemented for base-class Observer
 | 
|---|
| 115 |     void update(Observable *subject);
 | 
|---|
| 116 |     void subjectKilled(Observable *subject);
 | 
|---|
| 117 |   private:
 | 
|---|
| 118 | 
 | 
|---|
| 119 |     boost::function<T()> recalcMethod;
 | 
|---|
| 120 |   };
 | 
|---|
| 121 | 
 | 
|---|
| 122 |   template<typename T>
 | 
|---|
| 123 |   Cacheable<T>::Cacheable(Observable *_owner, boost::function<T()> _recalcMethod) :
 | 
|---|
| 124 |     recalcMethod(_recalcMethod)
 | 
|---|
| 125 |   {}
 | 
|---|
| 126 | 
 | 
|---|
| 127 |   template<typename T>
 | 
|---|
| 128 |   const T& Cacheable<T>::operator*(){
 | 
|---|
| 129 |     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 |   }
 | 
|---|
| 141 | 
 | 
|---|
| 142 |   template<typename T>
 | 
|---|
| 143 |   Cacheable<T>::~Cacheable()
 | 
|---|
| 144 |   {}
 | 
|---|
| 145 | 
 | 
|---|
| 146 |   template<typename T>
 | 
|---|
| 147 |   const bool Cacheable<T>::isValid(){
 | 
|---|
| 148 |     return true;
 | 
|---|
| 149 |   }
 | 
|---|
| 150 | 
 | 
|---|
| 151 |   template<typename T>
 | 
|---|
| 152 |   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");
 | 
|---|
| 159 |   }
 | 
|---|
| 160 | #endif
 | 
|---|
| 161 | 
 | 
|---|
| 162 | #endif /* CACHEABLE_HPP_ */
 | 
|---|