rev |
line source |
nuclear@0
|
1 /************************************************************************************
|
nuclear@0
|
2
|
nuclear@0
|
3 PublicHeader: Kernel
|
nuclear@0
|
4 Filename : OVR_Observer.h
|
nuclear@0
|
5 Content : Observer pattern
|
nuclear@0
|
6 Created : June 20, 2014
|
nuclear@0
|
7 Author : Chris Taylor
|
nuclear@0
|
8
|
nuclear@0
|
9 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
|
nuclear@0
|
10
|
nuclear@0
|
11 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
|
nuclear@0
|
12 you may not use the Oculus VR Rift SDK except in compliance with the License,
|
nuclear@0
|
13 which is provided at the time of installation or download, or which
|
nuclear@0
|
14 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@0
|
15
|
nuclear@0
|
16 You may obtain a copy of the License at
|
nuclear@0
|
17
|
nuclear@0
|
18 http://www.oculusvr.com/licenses/LICENSE-3.2
|
nuclear@0
|
19
|
nuclear@0
|
20 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
|
nuclear@0
|
21 distributed under the License is distributed on an "AS IS" BASIS,
|
nuclear@0
|
22 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
nuclear@0
|
23 See the License for the specific language governing permissions and
|
nuclear@0
|
24 limitations under the License.
|
nuclear@0
|
25
|
nuclear@0
|
26 ************************************************************************************/
|
nuclear@0
|
27
|
nuclear@0
|
28 #ifndef OVR_Observer_h
|
nuclear@0
|
29 #define OVR_Observer_h
|
nuclear@0
|
30
|
nuclear@0
|
31 #include "OVR_Types.h"
|
nuclear@0
|
32 #include "OVR_Atomic.h"
|
nuclear@0
|
33 #include "OVR_RefCount.h"
|
nuclear@0
|
34 #include "OVR_Delegates.h"
|
nuclear@0
|
35 #include "OVR_Array.h"
|
nuclear@0
|
36 #include "OVR_String.h"
|
nuclear@0
|
37 #include "OVR_Hash.h"
|
nuclear@0
|
38
|
nuclear@0
|
39 namespace OVR {
|
nuclear@0
|
40
|
nuclear@0
|
41 template<class DelegateT> class Observer;
|
nuclear@0
|
42 template<class DelegateT> class ObserverScope;
|
nuclear@0
|
43 template<class DelegateT> class ObserverHash;
|
nuclear@0
|
44
|
nuclear@0
|
45
|
nuclear@0
|
46 //-----------------------------------------------------------------------------
|
nuclear@0
|
47 // Observer pattern
|
nuclear@0
|
48
|
nuclear@0
|
49 // An Observer will observe a Subject. The Subject can emit callbacks that get
|
nuclear@0
|
50 // serviced by the Observers.
|
nuclear@0
|
51
|
nuclear@0
|
52 // The trickiest part of this is the shutdown code.
|
nuclear@0
|
53 // To simplify shutdown, the Observer is a reference-counted object divorced
|
nuclear@0
|
54 // from the handler that is called. To avoid misuse, the ObserverScope object
|
nuclear@0
|
55 // is provided to ensure that the Shutdown() method is called when it goes out
|
nuclear@0
|
56 // of scope.
|
nuclear@0
|
57
|
nuclear@0
|
58 // The Observer<> class doubles as the subject class.
|
nuclear@0
|
59 // To avoid misuse, assertions are added if a subject tries to observe, or if
|
nuclear@0
|
60 // an observer tries to be watched.
|
nuclear@0
|
61
|
nuclear@0
|
62 /*
|
nuclear@0
|
63 Usage example:
|
nuclear@0
|
64
|
nuclear@0
|
65 Say we want to invoke a handler with the signature:
|
nuclear@0
|
66
|
nuclear@0
|
67 void MyHandler(int i, bool b);
|
nuclear@0
|
68
|
nuclear@0
|
69 The corresponding delegate type is:
|
nuclear@0
|
70
|
nuclear@0
|
71 typedef Delegate2<void, int, bool> Handler;
|
nuclear@0
|
72
|
nuclear@0
|
73 Note: The return value will be ignored for the Observer pattern.
|
nuclear@0
|
74
|
nuclear@0
|
75 For this example there are two classes, one that emits events and another
|
nuclear@0
|
76 that listens for events:
|
nuclear@0
|
77 */
|
nuclear@0
|
78
|
nuclear@0
|
79 /*
|
nuclear@0
|
80 Event emitter example:
|
nuclear@0
|
81
|
nuclear@0
|
82 class MyEmitter
|
nuclear@0
|
83 {
|
nuclear@0
|
84 ObserverScope<Handler> TheSubject;
|
nuclear@0
|
85
|
nuclear@0
|
86 public:
|
nuclear@0
|
87 void ClearAllListeners()
|
nuclear@0
|
88 {
|
nuclear@0
|
89 TheSubject.ReleaseAll();
|
nuclear@0
|
90 }
|
nuclear@0
|
91
|
nuclear@0
|
92 void CallListeners(int x, bool y)
|
nuclear@0
|
93 {
|
nuclear@0
|
94 TheSubject->Call(x, y);
|
nuclear@0
|
95 }
|
nuclear@0
|
96
|
nuclear@0
|
97 Observer<Handler>* GetSubject()
|
nuclear@0
|
98 {
|
nuclear@0
|
99 return TheSubject;
|
nuclear@0
|
100 }
|
nuclear@0
|
101 };
|
nuclear@0
|
102 */
|
nuclear@0
|
103
|
nuclear@0
|
104 /*
|
nuclear@0
|
105 Event listener example:
|
nuclear@0
|
106
|
nuclear@0
|
107 class MyListener
|
nuclear@0
|
108 {
|
nuclear@0
|
109 ObserverScope<Handler> TheObserver;
|
nuclear@0
|
110
|
nuclear@0
|
111 void OnEvent(int x, bool y)
|
nuclear@0
|
112 {
|
nuclear@0
|
113 // Handle event here
|
nuclear@0
|
114 }
|
nuclear@0
|
115
|
nuclear@0
|
116 public:
|
nuclear@0
|
117 MyListener()
|
nuclear@0
|
118 {
|
nuclear@0
|
119 TheObserver.SetHandler(
|
nuclear@0
|
120 Handler::FromMember<MyListener, &MyListener::OnEvent>(this)
|
nuclear@0
|
121 );
|
nuclear@0
|
122 }
|
nuclear@0
|
123
|
nuclear@0
|
124 void ClearListener()
|
nuclear@0
|
125 {
|
nuclear@0
|
126 TheObserver.ReleaseAll();
|
nuclear@0
|
127 }
|
nuclear@0
|
128
|
nuclear@0
|
129 void ListenTo(Observer<Handler>* emitter)
|
nuclear@0
|
130 {
|
nuclear@0
|
131 TheObserver->Observe(emitter);
|
nuclear@0
|
132 }
|
nuclear@0
|
133 };
|
nuclear@0
|
134 */
|
nuclear@0
|
135
|
nuclear@0
|
136 /*
|
nuclear@0
|
137 Usage example:
|
nuclear@0
|
138
|
nuclear@0
|
139 MyListener listener;
|
nuclear@0
|
140 MyEmitter emitter;
|
nuclear@0
|
141
|
nuclear@0
|
142 // To listen to an emitter,
|
nuclear@0
|
143 listener.ListenTo(emitter.GetSubject());
|
nuclear@0
|
144
|
nuclear@0
|
145 // To call the listeners,
|
nuclear@0
|
146 emitter.CallListeners(22, true);
|
nuclear@0
|
147 */
|
nuclear@0
|
148
|
nuclear@0
|
149 template<class DelegateT>
|
nuclear@0
|
150 class Observer : public RefCountBase< Observer<DelegateT> >
|
nuclear@0
|
151 {
|
nuclear@0
|
152 friend class ObserverScope<DelegateT>;
|
nuclear@0
|
153 friend class ObserverHash<DelegateT>;
|
nuclear@0
|
154
|
nuclear@0
|
155 public:
|
nuclear@0
|
156 typedef Observer<DelegateT> ThisType;
|
nuclear@0
|
157 typedef DelegateT Handler;
|
nuclear@0
|
158
|
nuclear@0
|
159 protected:
|
nuclear@0
|
160 bool IsShutdown; // Flag to indicate that the object went out of scope
|
nuclear@0
|
161 mutable Lock TheLock; // Lock to synchronize calls and shutdown
|
nuclear@0
|
162 Array< Ptr< ThisType > > References; // List of observed or observing objects
|
nuclear@0
|
163 Handler TheHandler; // Observer-only: Handler for callbacks
|
nuclear@0
|
164
|
nuclear@0
|
165 Observer() :
|
nuclear@0
|
166 IsShutdown(false)
|
nuclear@0
|
167 {
|
nuclear@0
|
168 TheHandler.Invalidate();
|
nuclear@0
|
169 }
|
nuclear@0
|
170 Observer(Handler handler) :
|
nuclear@0
|
171 IsShutdown(false),
|
nuclear@0
|
172 TheHandler(handler)
|
nuclear@0
|
173 {
|
nuclear@0
|
174 }
|
nuclear@0
|
175 ~Observer()
|
nuclear@0
|
176 {
|
nuclear@0
|
177 OVR_ASSERT(References.GetSizeI() == 0);
|
nuclear@0
|
178 }
|
nuclear@0
|
179
|
nuclear@0
|
180 public:
|
nuclear@0
|
181 void SetHandler(Handler handler)
|
nuclear@0
|
182 {
|
nuclear@0
|
183 OVR_ASSERT(References.GetSizeI() == 0);
|
nuclear@0
|
184 TheHandler = handler;
|
nuclear@0
|
185 }
|
nuclear@0
|
186
|
nuclear@0
|
187 // Release references and prevent further actions
|
nuclear@0
|
188 void Shutdown()
|
nuclear@0
|
189 {
|
nuclear@0
|
190 Lock::Locker locker(&TheLock);
|
nuclear@0
|
191 IsShutdown = true;
|
nuclear@0
|
192 References.ClearAndRelease();
|
nuclear@0
|
193 }
|
nuclear@0
|
194
|
nuclear@0
|
195 // Get count of references held
|
nuclear@0
|
196 int GetSizeI() const
|
nuclear@0
|
197 {
|
nuclear@0
|
198 Lock::Locker locker(&TheLock);
|
nuclear@0
|
199 return References.GetSizeI();
|
nuclear@0
|
200 }
|
nuclear@0
|
201
|
nuclear@0
|
202 // Observe a subject
|
nuclear@0
|
203 bool Observe(ThisType *subject)
|
nuclear@0
|
204 {
|
nuclear@0
|
205 OVR_ASSERT(TheHandler.IsValid());
|
nuclear@0
|
206
|
nuclear@0
|
207 if (!subject)
|
nuclear@0
|
208 {
|
nuclear@0
|
209 return false;
|
nuclear@0
|
210 }
|
nuclear@0
|
211
|
nuclear@0
|
212 Lock::Locker locker(&TheLock);
|
nuclear@0
|
213
|
nuclear@0
|
214 if (IsShutdown)
|
nuclear@0
|
215 {
|
nuclear@0
|
216 return false;
|
nuclear@0
|
217 }
|
nuclear@0
|
218
|
nuclear@0
|
219 if (!subject->SubjectAddObserver(this))
|
nuclear@0
|
220 {
|
nuclear@0
|
221 return false;
|
nuclear@0
|
222 }
|
nuclear@0
|
223
|
nuclear@0
|
224 References.PushBack(subject);
|
nuclear@0
|
225 return true;
|
nuclear@0
|
226 }
|
nuclear@0
|
227
|
nuclear@0
|
228 protected:
|
nuclear@0
|
229 // Subject function: AddObserver()
|
nuclear@0
|
230 // Returns true if the observer was added
|
nuclear@0
|
231 bool SubjectAddObserver(ThisType* observer)
|
nuclear@0
|
232 {
|
nuclear@0
|
233 OVR_ASSERT(!TheHandler.IsValid());
|
nuclear@0
|
234
|
nuclear@0
|
235 if (!observer)
|
nuclear@0
|
236 {
|
nuclear@0
|
237 return true;
|
nuclear@0
|
238 }
|
nuclear@0
|
239
|
nuclear@0
|
240 Lock::Locker locker(&TheLock);
|
nuclear@0
|
241
|
nuclear@0
|
242 if (IsShutdown)
|
nuclear@0
|
243 {
|
nuclear@0
|
244 return false;
|
nuclear@0
|
245 }
|
nuclear@0
|
246
|
nuclear@0
|
247 const int count = References.GetSizeI();
|
nuclear@0
|
248 for (int i = 0; i < count; ++i)
|
nuclear@0
|
249 {
|
nuclear@0
|
250 if (References[i] == observer)
|
nuclear@0
|
251 {
|
nuclear@0
|
252 // Already watched
|
nuclear@0
|
253 return true;
|
nuclear@0
|
254 }
|
nuclear@0
|
255 }
|
nuclear@0
|
256
|
nuclear@0
|
257 References.PushBack(observer);
|
nuclear@0
|
258
|
nuclear@0
|
259 return true;
|
nuclear@0
|
260 }
|
nuclear@0
|
261
|
nuclear@0
|
262 public:
|
nuclear@0
|
263 // Subject function: Call()
|
nuclear@0
|
264 #define OVR_OBSERVER_CALL_BODY(params) \
|
nuclear@0
|
265 bool callSuccess = false; \
|
nuclear@0
|
266 Lock::Locker locker(&TheLock); \
|
nuclear@0
|
267 int count = References.GetSizeI(); \
|
nuclear@0
|
268 for (int i = 0; i < count; ++i) \
|
nuclear@0
|
269 { \
|
nuclear@0
|
270 if (!References[i]->IsShutdown) \
|
nuclear@0
|
271 { \
|
nuclear@0
|
272 OVR_ASSERT(References[i]->TheHandler.IsValid()); \
|
nuclear@0
|
273 References[i]->TheHandler params; \
|
nuclear@0
|
274 callSuccess = true; \
|
nuclear@0
|
275 } \
|
nuclear@0
|
276 if (References[i]->IsShutdown) \
|
nuclear@0
|
277 { \
|
nuclear@0
|
278 References.RemoveAt(i); \
|
nuclear@0
|
279 --i; --count; \
|
nuclear@0
|
280 } \
|
nuclear@0
|
281 } \
|
nuclear@0
|
282 return callSuccess;
|
nuclear@0
|
283
|
nuclear@0
|
284 // Call: Various parameter counts
|
nuclear@0
|
285 // Returns true if a call was made
|
nuclear@0
|
286 bool Call()
|
nuclear@0
|
287 {
|
nuclear@0
|
288 OVR_OBSERVER_CALL_BODY(())
|
nuclear@0
|
289 }
|
nuclear@0
|
290 template<class Param1>
|
nuclear@0
|
291 bool Call(Param1& p1)
|
nuclear@0
|
292 {
|
nuclear@0
|
293 OVR_OBSERVER_CALL_BODY((p1))
|
nuclear@0
|
294 }
|
nuclear@0
|
295 template<class Param1>
|
nuclear@0
|
296 bool Call(Param1* p1)
|
nuclear@0
|
297 {
|
nuclear@0
|
298 OVR_OBSERVER_CALL_BODY((p1))
|
nuclear@0
|
299 }
|
nuclear@0
|
300 template<class Param1, class Param2>
|
nuclear@0
|
301 bool Call(Param1& p1, Param2& p2)
|
nuclear@0
|
302 {
|
nuclear@0
|
303 OVR_OBSERVER_CALL_BODY((p1, p2))
|
nuclear@0
|
304 }
|
nuclear@0
|
305 template<class Param1, class Param2>
|
nuclear@0
|
306 bool Call(Param1* p1, Param2* p2)
|
nuclear@0
|
307 {
|
nuclear@0
|
308 OVR_OBSERVER_CALL_BODY((p1, p2))
|
nuclear@0
|
309 }
|
nuclear@0
|
310 template<class Param1, class Param2, class Param3>
|
nuclear@0
|
311 bool Call(Param1& p1, Param2& p2, Param3& p3)
|
nuclear@0
|
312 {
|
nuclear@0
|
313 OVR_OBSERVER_CALL_BODY((p1, p2, p3))
|
nuclear@0
|
314 }
|
nuclear@0
|
315 template<class Param1, class Param2, class Param3>
|
nuclear@0
|
316 bool Call(Param1* p1, Param2* p2, Param3* p3)
|
nuclear@0
|
317 {
|
nuclear@0
|
318 OVR_OBSERVER_CALL_BODY((p1, p2, p3))
|
nuclear@0
|
319 }
|
nuclear@0
|
320
|
nuclear@0
|
321 #undef OVR_OBSERVER_CALL_BODY
|
nuclear@0
|
322 };
|
nuclear@0
|
323
|
nuclear@0
|
324
|
nuclear@0
|
325 //-----------------------------------------------------------------------------
|
nuclear@0
|
326 // ObserverScope
|
nuclear@0
|
327
|
nuclear@0
|
328 // Scoped shutdown of the Observer object
|
nuclear@0
|
329 template<class DelegateT>
|
nuclear@0
|
330 class ObserverScope : public NewOverrideBase
|
nuclear@0
|
331 {
|
nuclear@0
|
332 Ptr< Observer<DelegateT> > TheObserver;
|
nuclear@0
|
333 DelegateT TheHandler;
|
nuclear@0
|
334
|
nuclear@0
|
335 void Shutdown()
|
nuclear@0
|
336 {
|
nuclear@0
|
337 if (TheObserver)
|
nuclear@0
|
338 {
|
nuclear@0
|
339 TheObserver->Shutdown();
|
nuclear@0
|
340 TheObserver.Clear();
|
nuclear@0
|
341 }
|
nuclear@0
|
342 }
|
nuclear@0
|
343
|
nuclear@0
|
344 public:
|
nuclear@0
|
345 ObserverScope()
|
nuclear@0
|
346 {
|
nuclear@0
|
347 TheObserver = *new Observer<DelegateT>;
|
nuclear@0
|
348 }
|
nuclear@0
|
349 ~ObserverScope()
|
nuclear@0
|
350 {
|
nuclear@0
|
351 Shutdown();
|
nuclear@0
|
352 }
|
nuclear@0
|
353
|
nuclear@0
|
354 // Release all references and recreate it
|
nuclear@0
|
355 void ReleaseAll()
|
nuclear@0
|
356 {
|
nuclear@0
|
357 Shutdown();
|
nuclear@0
|
358 TheObserver = *new Observer<DelegateT>;
|
nuclear@0
|
359 if (TheHandler.IsValid())
|
nuclear@0
|
360 {
|
nuclear@0
|
361 TheObserver->SetHandler(TheHandler);
|
nuclear@0
|
362 }
|
nuclear@0
|
363 }
|
nuclear@0
|
364
|
nuclear@0
|
365 void SetHandler(DelegateT handler)
|
nuclear@0
|
366 {
|
nuclear@0
|
367 TheHandler = handler;
|
nuclear@0
|
368 TheObserver->SetHandler(handler);
|
nuclear@0
|
369 }
|
nuclear@0
|
370
|
nuclear@0
|
371 Observer<DelegateT>* GetPtr()
|
nuclear@0
|
372 {
|
nuclear@0
|
373 return TheObserver.GetPtr();
|
nuclear@0
|
374 }
|
nuclear@0
|
375 Observer<DelegateT>* operator->()
|
nuclear@0
|
376 {
|
nuclear@0
|
377 return TheObserver.GetPtr();
|
nuclear@0
|
378 }
|
nuclear@0
|
379 const Observer<DelegateT>* operator->() const
|
nuclear@0
|
380 {
|
nuclear@0
|
381 return TheObserver.GetPtr();
|
nuclear@0
|
382 }
|
nuclear@0
|
383 operator Observer<DelegateT>*()
|
nuclear@0
|
384 {
|
nuclear@0
|
385 return TheObserver.GetPtr();
|
nuclear@0
|
386 }
|
nuclear@0
|
387 };
|
nuclear@0
|
388
|
nuclear@0
|
389
|
nuclear@0
|
390 //-----------------------------------------------------------------------------
|
nuclear@0
|
391 // ObserverHash
|
nuclear@0
|
392
|
nuclear@0
|
393 // A hash containing Observers
|
nuclear@0
|
394 template<class DelegateT>
|
nuclear@0
|
395 class ObserverHash : public NewOverrideBase
|
nuclear@0
|
396 {
|
nuclear@0
|
397 public:
|
nuclear@0
|
398 ObserverHash() {}
|
nuclear@0
|
399 ~ObserverHash() {Clear();}
|
nuclear@0
|
400 void Clear()
|
nuclear@0
|
401 {
|
nuclear@0
|
402 Lock::Locker locker(&TheLock);
|
nuclear@0
|
403 typename OVR::Hash< String, Ptr<Observer<DelegateT> >, OVR::String::HashFunctor >::Iterator it = _Hash.Begin();
|
nuclear@0
|
404 for( it = _Hash.Begin(); it != _Hash.End(); ++it )
|
nuclear@0
|
405 {
|
nuclear@0
|
406 Ptr<Observer<DelegateT> > o = it->Second;
|
nuclear@0
|
407 o->Shutdown();
|
nuclear@0
|
408 }
|
nuclear@0
|
409 }
|
nuclear@0
|
410
|
nuclear@0
|
411 Ptr<Observer<DelegateT> > GetSubject(OVR::String key)
|
nuclear@0
|
412 {
|
nuclear@0
|
413 Lock::Locker locker(&TheLock);
|
nuclear@0
|
414 Ptr<Observer<DelegateT> > *o = _Hash.Get(key);
|
nuclear@0
|
415 if (o)
|
nuclear@0
|
416 return (*o);
|
nuclear@0
|
417 return NULL;
|
nuclear@0
|
418 }
|
nuclear@0
|
419
|
nuclear@0
|
420 // Add handler to new observer with implicit creation of subject.
|
nuclear@0
|
421 void AddObserverToSubject(OVR::String key, Observer<DelegateT> *observer)
|
nuclear@0
|
422 {
|
nuclear@0
|
423 Lock::Locker locker(&TheLock);
|
nuclear@0
|
424 Ptr<Observer<DelegateT> > *subjectPtr = _Hash.Get(key);
|
nuclear@0
|
425
|
nuclear@0
|
426 if (subjectPtr==NULL)
|
nuclear@0
|
427 {
|
nuclear@0
|
428 Ptr<Observer<DelegateT> > subject = *new Observer<DelegateT>();
|
nuclear@0
|
429 _Hash.Add(key, subject);
|
nuclear@0
|
430 observer->Observe(subject);
|
nuclear@0
|
431 }
|
nuclear@0
|
432 else
|
nuclear@0
|
433 {
|
nuclear@0
|
434 observer->Observe(*subjectPtr);
|
nuclear@0
|
435 }
|
nuclear@0
|
436 }
|
nuclear@0
|
437
|
nuclear@0
|
438 void RemoveSubject(OVR::String key)
|
nuclear@0
|
439 {
|
nuclear@0
|
440 Lock::Locker locker(&TheLock);
|
nuclear@0
|
441 Ptr<Observer<DelegateT> > *subjectPtr = _Hash.Get(key);
|
nuclear@0
|
442 if (subjectPtr!=NULL)
|
nuclear@0
|
443 {
|
nuclear@0
|
444 (*subjectPtr)->Shutdown();
|
nuclear@0
|
445 _Hash.Remove(key);
|
nuclear@0
|
446 }
|
nuclear@0
|
447 }
|
nuclear@0
|
448
|
nuclear@0
|
449 protected:
|
nuclear@0
|
450 OVR::Hash< OVR::String, Ptr<Observer<DelegateT> >, OVR::String::HashFunctor > _Hash;
|
nuclear@0
|
451 Lock TheLock; // Lock to synchronize calls and shutdown
|
nuclear@0
|
452 };
|
nuclear@0
|
453
|
nuclear@0
|
454
|
nuclear@0
|
455 } // namespace OVR
|
nuclear@0
|
456
|
nuclear@0
|
457 #endif // OVR_Observer_h
|