ovr_sdk

view LibOVR/Src/Kernel/OVR_Observer.h @ 0:1b39a1b46319

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