source: src/CodePatterns/Cacheable.hpp@ f1df08

Last change on this file since f1df08 was 9b8fa4, checked in by Frederik Heber <heber@…>, 14 years ago

Huge update of file structure to place installation header files into right folder.

  • The problem ist that we desire use as include "CodePatterns/...". For this to work, especially with the new Observer subfolder structure, it has been necessary to place all header files away from their source files into a distinct folder called CodePatterns. This emulates the later, after make install present structure.
  • essentially all source and header files had to be changed to adapt the include.
  • all Makefile.am's had to be changed.
  • nobase_ ... was removed such that header files are installed flat and not creating their subfolder along the process.
  • We placed Observer into its own convenience library and own folder Observer away from Patterns.

Some other changes:

  • FIX: MemDebug.hpp inclusion has been removed in all stubs.
  • Property mode set to 100644
File size: 6.9 KB
Line 
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 config.h
12#ifdef HAVE_CONFIG_H
13#include <config.h>
14#endif
15
16#include "Observer/Observable.hpp"
17#include "Observer/Observer.hpp"
18#include <boost/function.hpp>
19#include <boost/shared_ptr.hpp>
20
21#include "CodePatterns/Assert.hpp"
22
23#ifndef NO_CACHING
24
25 template<typename T>
26 class Cacheable : public Observer
27 {
28 // we define the states of the cacheable so we can do very fast state-checks
29 class State{
30 public:
31 State(Cacheable *_owner) :
32 busy(false),
33 owner(_owner)
34 {}
35 virtual T& getValue()=0;
36 virtual void invalidate()=0;
37 virtual bool isValid()=0;
38 virtual void enter()=0;
39 bool isBusy(){
40 return busy;
41 }
42 virtual std::string getName()=0;
43 protected:
44 bool busy;
45 Cacheable *owner;
46 };
47
48 class InvalidState : public State{
49 public:
50 InvalidState(Cacheable *_owner):
51 State(_owner)
52 {}
53
54 virtual T& getValue(){
55 // set the state to valid
56 State::owner->switchState(State::owner->validState);
57 // get the value from the now valid state
58 return State::owner->state->getValue();
59 }
60
61 virtual void invalidate(){
62 // nothing to do on this message
63 }
64
65 virtual bool isValid(){
66 return false;
67 }
68
69 virtual void enter(){
70 // nothing to do when entering this
71 }
72
73 virtual std::string getName(){
74 return "invalid";
75 }
76 };
77
78 class ValidState : public State{
79 public:
80 ValidState(Cacheable *_owner) :
81 State(_owner)
82 {}
83
84 virtual T& getValue(){
85 return content;
86 }
87
88 virtual void invalidate(){
89 State::owner->switchState(State::owner->invalidState);
90 }
91
92 virtual bool isValid(){
93 return true;
94 }
95
96 virtual void enter(){
97 State::busy= true;
98 // as soon as we enter the valid state we recalculate
99 content = State::owner->recalcMethod();
100 State::busy = false;
101 }
102
103 virtual std::string getName(){
104 return "valid";
105 }
106 private:
107 T content;
108 };
109
110 class DestroyedState : public State {
111 public:
112 DestroyedState(Cacheable *_owner) :
113 State(_owner)
114 {}
115
116 virtual T& getValue(){
117 ASSERT(0,"Cannot get a value from a Cacheable after it's Observable has died");
118 // we have to return a grossly invalid reference, because no value can be produced anymore
119 return *(static_cast<T*>(0));
120 }
121
122 virtual void invalidate(){
123 ASSERT(0,"Cannot invalidate a Cacheable after it's Observable has died");
124 }
125
126 virtual bool isValid(){
127 ASSERT(0,"Cannot check validity of a Cacheable after it's Observable has died");
128 return false;
129 }
130
131 virtual void enter(){
132 // nothing to do when entering this state
133 }
134
135 virtual std::string getName(){
136 return "destroyed";
137 }
138 };
139
140
141 typedef boost::shared_ptr<State> state_ptr;
142
143 public:
144 Cacheable(Observable *_owner, boost::function<T()> _recalcMethod, std::string name);
145 virtual ~Cacheable();
146
147 const bool isValid() const;
148 const T operator*() const;
149
150 // methods implemented for base-class Observer
151 void update(Observable *subject);
152 void subjectKilled(Observable *subject);
153 private:
154 void switchState(state_ptr newState);
155
156 mutable state_ptr state;
157 // pre-defined state so we don't have to construct to much
158 state_ptr invalidState;
159 state_ptr validState;
160 // destroyed state is not predefined, because we rarely enter that state and never leave
161
162 Observable *owner;
163 boost::function<T()> recalcMethod;
164
165 // de-activated copy constructor
166 Cacheable(const Cacheable&);
167 };
168
169
170 template<typename T>
171 Cacheable<T>::Cacheable(Observable *_owner, boost::function<T()> _recalcMethod, std::string name) :
172 Observer(name + "(Cached)"),
173 owner(_owner),
174 recalcMethod(_recalcMethod)
175 {
176 // create all states needed for this object
177 invalidState = state_ptr(new InvalidState(this));
178 validState = state_ptr(new ValidState(this));
179 state = invalidState;
180 // we sign on with the best(=lowest) priority, so cached values are recalculated before
181 // anybody else might ask for updated values
182 owner->signOn(this,Observable::PriorityLevel(int(-20)));
183 }
184
185 // de-activated copy constructor
186 template<typename T>
187 Cacheable<T>::Cacheable(const Cacheable&){
188 ASSERT(0,"Cacheables should never be copied");
189 }
190
191 template<typename T>
192 const T Cacheable<T>::operator*() const{
193 // we can only use the cacheable when the owner is not changing at the moment
194 if(!owner->isBlocked()){
195 return state->getValue();
196 }
197 else{
198 return recalcMethod();
199 }
200 }
201
202 template<typename T>
203 Cacheable<T>::~Cacheable()
204 {
205 owner->signOff(this);
206 }
207
208 template<typename T>
209 const bool Cacheable<T>::isValid() const{
210 return state->isValid();
211 }
212
213 template<typename T>
214 void Cacheable<T>::update(Observable *subject) {
215 state->invalidate();
216 }
217
218 template<typename T>
219 void Cacheable<T>::subjectKilled(Observable *subject) {
220 state_ptr destroyed = state_ptr(new DestroyedState(this));
221 switchState(destroyed);
222 }
223
224 template<typename T>
225 void Cacheable<T>::switchState(state_ptr newState){
226 ASSERT(!state->isBusy(),"LOOP DETECTED: Cacheable state switched while recalculating.\nDid the recalculation trigger the Observable?");
227#ifdef LOG_OBSERVER
228 observerLog().addMessage() << "## Cacheable " << observerLog().getName(this) << " changed state (" << state->getName()
229 << "->" << newState->getName() << ")";
230#endif
231 state = newState;
232 state->enter();
233 }
234
235#else
236 template<typename T>
237 class Cacheable : public Observer
238 {
239 public:
240 Cacheable(Observable *_owner, boost::function<T()> _recalcMethod,std::string name);
241 virtual ~Cacheable();
242
243 const bool isValid() const;
244 const T operator*() const;
245
246 // methods implemented for base-class Observer
247 void update(Observable *subject);
248 void subjectKilled(Observable *subject);
249 private:
250
251 boost::function<T()> recalcMethod;
252 };
253
254 template<typename T>
255 Cacheable<T>::Cacheable(Observable *_owner, boost::function<T()> _recalcMethod, std::string name) :
256 Observer(name),
257 recalcMethod(_recalcMethod)
258 {}
259
260 template<typename T>
261 const T Cacheable<T>::operator*() const{
262 return recalcMethod();
263 }
264
265 template<typename T>
266 Cacheable<T>::~Cacheable()
267 {}
268
269 template<typename T>
270 const bool Cacheable<T>::isValid() const{
271 return true;
272 }
273
274 template<typename T>
275 void Cacheable<T>::update(Observable *subject) {
276 ASSERT(0, "Cacheable::update should never be called when caching is disabled");
277 }
278
279 template<typename T>
280 void Cacheable<T>::subjectKilled(Observable *subject){
281 ASSERT(0, "Cacheable::subjectKilled should never be called when caching is disabled");
282 }
283#endif
284
285#endif /* CACHEABLE_HPP_ */
Note: See TracBrowser for help on using the repository browser.