ovr_sdk
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/LibOVR/Src/Kernel/OVR_Observer.h Wed Jan 14 06:51:16 2015 +0200 1.3 @@ -0,0 +1,457 @@ 1.4 +/************************************************************************************ 1.5 + 1.6 +PublicHeader: Kernel 1.7 +Filename : OVR_Observer.h 1.8 +Content : Observer pattern 1.9 +Created : June 20, 2014 1.10 +Author : Chris Taylor 1.11 + 1.12 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. 1.13 + 1.14 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 1.15 +you may not use the Oculus VR Rift SDK except in compliance with the License, 1.16 +which is provided at the time of installation or download, or which 1.17 +otherwise accompanies this software in either electronic or hard copy form. 1.18 + 1.19 +You may obtain a copy of the License at 1.20 + 1.21 +http://www.oculusvr.com/licenses/LICENSE-3.2 1.22 + 1.23 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 1.24 +distributed under the License is distributed on an "AS IS" BASIS, 1.25 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.26 +See the License for the specific language governing permissions and 1.27 +limitations under the License. 1.28 + 1.29 +************************************************************************************/ 1.30 + 1.31 +#ifndef OVR_Observer_h 1.32 +#define OVR_Observer_h 1.33 + 1.34 +#include "OVR_Types.h" 1.35 +#include "OVR_Atomic.h" 1.36 +#include "OVR_RefCount.h" 1.37 +#include "OVR_Delegates.h" 1.38 +#include "OVR_Array.h" 1.39 +#include "OVR_String.h" 1.40 +#include "OVR_Hash.h" 1.41 + 1.42 +namespace OVR { 1.43 + 1.44 +template<class DelegateT> class Observer; 1.45 +template<class DelegateT> class ObserverScope; 1.46 +template<class DelegateT> class ObserverHash; 1.47 + 1.48 + 1.49 +//----------------------------------------------------------------------------- 1.50 +// Observer pattern 1.51 + 1.52 +// An Observer will observe a Subject. The Subject can emit callbacks that get 1.53 +// serviced by the Observers. 1.54 + 1.55 +// The trickiest part of this is the shutdown code. 1.56 +// To simplify shutdown, the Observer is a reference-counted object divorced 1.57 +// from the handler that is called. To avoid misuse, the ObserverScope object 1.58 +// is provided to ensure that the Shutdown() method is called when it goes out 1.59 +// of scope. 1.60 + 1.61 +// The Observer<> class doubles as the subject class. 1.62 +// To avoid misuse, assertions are added if a subject tries to observe, or if 1.63 +// an observer tries to be watched. 1.64 + 1.65 +/* 1.66 + Usage example: 1.67 + 1.68 + Say we want to invoke a handler with the signature: 1.69 + 1.70 + void MyHandler(int i, bool b); 1.71 + 1.72 + The corresponding delegate type is: 1.73 + 1.74 + typedef Delegate2<void, int, bool> Handler; 1.75 + 1.76 + Note: The return value will be ignored for the Observer pattern. 1.77 + 1.78 + For this example there are two classes, one that emits events and another 1.79 + that listens for events: 1.80 +*/ 1.81 + 1.82 +/* 1.83 + Event emitter example: 1.84 + 1.85 + class MyEmitter 1.86 + { 1.87 + ObserverScope<Handler> TheSubject; 1.88 + 1.89 + public: 1.90 + void ClearAllListeners() 1.91 + { 1.92 + TheSubject.ReleaseAll(); 1.93 + } 1.94 + 1.95 + void CallListeners(int x, bool y) 1.96 + { 1.97 + TheSubject->Call(x, y); 1.98 + } 1.99 + 1.100 + Observer<Handler>* GetSubject() 1.101 + { 1.102 + return TheSubject; 1.103 + } 1.104 + }; 1.105 +*/ 1.106 + 1.107 +/* 1.108 + Event listener example: 1.109 + 1.110 + class MyListener 1.111 + { 1.112 + ObserverScope<Handler> TheObserver; 1.113 + 1.114 + void OnEvent(int x, bool y) 1.115 + { 1.116 + // Handle event here 1.117 + } 1.118 + 1.119 + public: 1.120 + MyListener() 1.121 + { 1.122 + TheObserver.SetHandler( 1.123 + Handler::FromMember<MyListener, &MyListener::OnEvent>(this) 1.124 + ); 1.125 + } 1.126 + 1.127 + void ClearListener() 1.128 + { 1.129 + TheObserver.ReleaseAll(); 1.130 + } 1.131 + 1.132 + void ListenTo(Observer<Handler>* emitter) 1.133 + { 1.134 + TheObserver->Observe(emitter); 1.135 + } 1.136 + }; 1.137 +*/ 1.138 + 1.139 +/* 1.140 + Usage example: 1.141 + 1.142 + MyListener listener; 1.143 + MyEmitter emitter; 1.144 + 1.145 + // To listen to an emitter, 1.146 + listener.ListenTo(emitter.GetSubject()); 1.147 + 1.148 + // To call the listeners, 1.149 + emitter.CallListeners(22, true); 1.150 +*/ 1.151 + 1.152 +template<class DelegateT> 1.153 +class Observer : public RefCountBase< Observer<DelegateT> > 1.154 +{ 1.155 + friend class ObserverScope<DelegateT>; 1.156 + friend class ObserverHash<DelegateT>; 1.157 + 1.158 +public: 1.159 + typedef Observer<DelegateT> ThisType; 1.160 + typedef DelegateT Handler; 1.161 + 1.162 +protected: 1.163 + bool IsShutdown; // Flag to indicate that the object went out of scope 1.164 + mutable Lock TheLock; // Lock to synchronize calls and shutdown 1.165 + Array< Ptr< ThisType > > References; // List of observed or observing objects 1.166 + Handler TheHandler; // Observer-only: Handler for callbacks 1.167 + 1.168 + Observer() : 1.169 + IsShutdown(false) 1.170 + { 1.171 + TheHandler.Invalidate(); 1.172 + } 1.173 + Observer(Handler handler) : 1.174 + IsShutdown(false), 1.175 + TheHandler(handler) 1.176 + { 1.177 + } 1.178 + ~Observer() 1.179 + { 1.180 + OVR_ASSERT(References.GetSizeI() == 0); 1.181 + } 1.182 + 1.183 +public: 1.184 + void SetHandler(Handler handler) 1.185 + { 1.186 + OVR_ASSERT(References.GetSizeI() == 0); 1.187 + TheHandler = handler; 1.188 + } 1.189 + 1.190 + // Release references and prevent further actions 1.191 + void Shutdown() 1.192 + { 1.193 + Lock::Locker locker(&TheLock); 1.194 + IsShutdown = true; 1.195 + References.ClearAndRelease(); 1.196 + } 1.197 + 1.198 + // Get count of references held 1.199 + int GetSizeI() const 1.200 + { 1.201 + Lock::Locker locker(&TheLock); 1.202 + return References.GetSizeI(); 1.203 + } 1.204 + 1.205 + // Observe a subject 1.206 + bool Observe(ThisType *subject) 1.207 + { 1.208 + OVR_ASSERT(TheHandler.IsValid()); 1.209 + 1.210 + if (!subject) 1.211 + { 1.212 + return false; 1.213 + } 1.214 + 1.215 + Lock::Locker locker(&TheLock); 1.216 + 1.217 + if (IsShutdown) 1.218 + { 1.219 + return false; 1.220 + } 1.221 + 1.222 + if (!subject->SubjectAddObserver(this)) 1.223 + { 1.224 + return false; 1.225 + } 1.226 + 1.227 + References.PushBack(subject); 1.228 + return true; 1.229 + } 1.230 + 1.231 +protected: 1.232 + // Subject function: AddObserver() 1.233 + // Returns true if the observer was added 1.234 + bool SubjectAddObserver(ThisType* observer) 1.235 + { 1.236 + OVR_ASSERT(!TheHandler.IsValid()); 1.237 + 1.238 + if (!observer) 1.239 + { 1.240 + return true; 1.241 + } 1.242 + 1.243 + Lock::Locker locker(&TheLock); 1.244 + 1.245 + if (IsShutdown) 1.246 + { 1.247 + return false; 1.248 + } 1.249 + 1.250 + const int count = References.GetSizeI(); 1.251 + for (int i = 0; i < count; ++i) 1.252 + { 1.253 + if (References[i] == observer) 1.254 + { 1.255 + // Already watched 1.256 + return true; 1.257 + } 1.258 + } 1.259 + 1.260 + References.PushBack(observer); 1.261 + 1.262 + return true; 1.263 + } 1.264 + 1.265 +public: 1.266 + // Subject function: Call() 1.267 +#define OVR_OBSERVER_CALL_BODY(params) \ 1.268 + bool callSuccess = false; \ 1.269 + Lock::Locker locker(&TheLock); \ 1.270 + int count = References.GetSizeI(); \ 1.271 + for (int i = 0; i < count; ++i) \ 1.272 + { \ 1.273 + if (!References[i]->IsShutdown) \ 1.274 + { \ 1.275 + OVR_ASSERT(References[i]->TheHandler.IsValid()); \ 1.276 + References[i]->TheHandler params; \ 1.277 + callSuccess = true; \ 1.278 + } \ 1.279 + if (References[i]->IsShutdown) \ 1.280 + { \ 1.281 + References.RemoveAt(i); \ 1.282 + --i; --count; \ 1.283 + } \ 1.284 + } \ 1.285 + return callSuccess; 1.286 + 1.287 + // Call: Various parameter counts 1.288 + // Returns true if a call was made 1.289 + bool Call() 1.290 + { 1.291 + OVR_OBSERVER_CALL_BODY(()) 1.292 + } 1.293 + template<class Param1> 1.294 + bool Call(Param1& p1) 1.295 + { 1.296 + OVR_OBSERVER_CALL_BODY((p1)) 1.297 + } 1.298 + template<class Param1> 1.299 + bool Call(Param1* p1) 1.300 + { 1.301 + OVR_OBSERVER_CALL_BODY((p1)) 1.302 + } 1.303 + template<class Param1, class Param2> 1.304 + bool Call(Param1& p1, Param2& p2) 1.305 + { 1.306 + OVR_OBSERVER_CALL_BODY((p1, p2)) 1.307 + } 1.308 + template<class Param1, class Param2> 1.309 + bool Call(Param1* p1, Param2* p2) 1.310 + { 1.311 + OVR_OBSERVER_CALL_BODY((p1, p2)) 1.312 + } 1.313 + template<class Param1, class Param2, class Param3> 1.314 + bool Call(Param1& p1, Param2& p2, Param3& p3) 1.315 + { 1.316 + OVR_OBSERVER_CALL_BODY((p1, p2, p3)) 1.317 + } 1.318 + template<class Param1, class Param2, class Param3> 1.319 + bool Call(Param1* p1, Param2* p2, Param3* p3) 1.320 + { 1.321 + OVR_OBSERVER_CALL_BODY((p1, p2, p3)) 1.322 + } 1.323 + 1.324 +#undef OVR_OBSERVER_CALL_BODY 1.325 +}; 1.326 + 1.327 + 1.328 +//----------------------------------------------------------------------------- 1.329 +// ObserverScope 1.330 + 1.331 +// Scoped shutdown of the Observer object 1.332 +template<class DelegateT> 1.333 +class ObserverScope : public NewOverrideBase 1.334 +{ 1.335 + Ptr< Observer<DelegateT> > TheObserver; 1.336 + DelegateT TheHandler; 1.337 + 1.338 + void Shutdown() 1.339 + { 1.340 + if (TheObserver) 1.341 + { 1.342 + TheObserver->Shutdown(); 1.343 + TheObserver.Clear(); 1.344 + } 1.345 + } 1.346 + 1.347 +public: 1.348 + ObserverScope() 1.349 + { 1.350 + TheObserver = *new Observer<DelegateT>; 1.351 + } 1.352 + ~ObserverScope() 1.353 + { 1.354 + Shutdown(); 1.355 + } 1.356 + 1.357 + // Release all references and recreate it 1.358 + void ReleaseAll() 1.359 + { 1.360 + Shutdown(); 1.361 + TheObserver = *new Observer<DelegateT>; 1.362 + if (TheHandler.IsValid()) 1.363 + { 1.364 + TheObserver->SetHandler(TheHandler); 1.365 + } 1.366 + } 1.367 + 1.368 + void SetHandler(DelegateT handler) 1.369 + { 1.370 + TheHandler = handler; 1.371 + TheObserver->SetHandler(handler); 1.372 + } 1.373 + 1.374 + Observer<DelegateT>* GetPtr() 1.375 + { 1.376 + return TheObserver.GetPtr(); 1.377 + } 1.378 + Observer<DelegateT>* operator->() 1.379 + { 1.380 + return TheObserver.GetPtr(); 1.381 + } 1.382 + const Observer<DelegateT>* operator->() const 1.383 + { 1.384 + return TheObserver.GetPtr(); 1.385 + } 1.386 + operator Observer<DelegateT>*() 1.387 + { 1.388 + return TheObserver.GetPtr(); 1.389 + } 1.390 +}; 1.391 + 1.392 + 1.393 +//----------------------------------------------------------------------------- 1.394 +// ObserverHash 1.395 + 1.396 +// A hash containing Observers 1.397 +template<class DelegateT> 1.398 +class ObserverHash : public NewOverrideBase 1.399 +{ 1.400 +public: 1.401 + ObserverHash() {} 1.402 + ~ObserverHash() {Clear();} 1.403 + void Clear() 1.404 + { 1.405 + Lock::Locker locker(&TheLock); 1.406 + typename OVR::Hash< String, Ptr<Observer<DelegateT> >, OVR::String::HashFunctor >::Iterator it = _Hash.Begin(); 1.407 + for( it = _Hash.Begin(); it != _Hash.End(); ++it ) 1.408 + { 1.409 + Ptr<Observer<DelegateT> > o = it->Second; 1.410 + o->Shutdown(); 1.411 + } 1.412 + } 1.413 + 1.414 + Ptr<Observer<DelegateT> > GetSubject(OVR::String key) 1.415 + { 1.416 + Lock::Locker locker(&TheLock); 1.417 + Ptr<Observer<DelegateT> > *o = _Hash.Get(key); 1.418 + if (o) 1.419 + return (*o); 1.420 + return NULL; 1.421 + } 1.422 + 1.423 + // Add handler to new observer with implicit creation of subject. 1.424 + void AddObserverToSubject(OVR::String key, Observer<DelegateT> *observer) 1.425 + { 1.426 + Lock::Locker locker(&TheLock); 1.427 + Ptr<Observer<DelegateT> > *subjectPtr = _Hash.Get(key); 1.428 + 1.429 + if (subjectPtr==NULL) 1.430 + { 1.431 + Ptr<Observer<DelegateT> > subject = *new Observer<DelegateT>(); 1.432 + _Hash.Add(key, subject); 1.433 + observer->Observe(subject); 1.434 + } 1.435 + else 1.436 + { 1.437 + observer->Observe(*subjectPtr); 1.438 + } 1.439 + } 1.440 + 1.441 + void RemoveSubject(OVR::String key) 1.442 + { 1.443 + Lock::Locker locker(&TheLock); 1.444 + Ptr<Observer<DelegateT> > *subjectPtr = _Hash.Get(key); 1.445 + if (subjectPtr!=NULL) 1.446 + { 1.447 + (*subjectPtr)->Shutdown(); 1.448 + _Hash.Remove(key); 1.449 + } 1.450 + } 1.451 + 1.452 +protected: 1.453 + OVR::Hash< OVR::String, Ptr<Observer<DelegateT> >, OVR::String::HashFunctor > _Hash; 1.454 + Lock TheLock; // Lock to synchronize calls and shutdown 1.455 +}; 1.456 + 1.457 + 1.458 +} // namespace OVR 1.459 + 1.460 +#endif // OVR_Observer_h