/************************************************************************************ PublicHeader: Kernel Filename : OVR_Observer.h Content : Observer pattern Created : June 20, 2014 Author : Chris Taylor Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ************************************************************************************/ #ifndef OVR_Observer_h #define OVR_Observer_h #include "OVR_Types.h" #include "OVR_Atomic.h" #include "OVR_RefCount.h" #include "OVR_Delegates.h" #include "OVR_Array.h" #include "OVR_String.h" #include "OVR_Hash.h" namespace OVR { template class Observer; template class ObserverScope; template class ObserverHash; //----------------------------------------------------------------------------- // Observer pattern // An Observer will observe a Subject. The Subject can emit callbacks that get // serviced by the Observers. // The trickiest part of this is the shutdown code. // To simplify shutdown, the Observer is a reference-counted object divorced // from the handler that is called. To avoid misuse, the ObserverScope object // is provided to ensure that the Shutdown() method is called when it goes out // of scope. // The Observer<> class doubles as the subject class. // To avoid misuse, assertions are added if a subject tries to observe, or if // an observer tries to be watched. /* Usage example: Say we want to invoke a handler with the signature: void MyHandler(int i, bool b); The corresponding delegate type is: typedef Delegate2 Handler; Note: The return value will be ignored for the Observer pattern. For this example there are two classes, one that emits events and another that listens for events: */ /* Event emitter example: class MyEmitter { ObserverScope TheSubject; public: void ClearAllListeners() { TheSubject.ReleaseAll(); } void CallListeners(int x, bool y) { TheSubject->Call(x, y); } Observer* GetSubject() { return TheSubject; } }; */ /* Event listener example: class MyListener { ObserverScope TheObserver; void OnEvent(int x, bool y) { // Handle event here } public: MyListener() { TheObserver.SetHandler( Handler::FromMember(this) ); } void ClearListener() { TheObserver.ReleaseAll(); } void ListenTo(Observer* emitter) { TheObserver->Observe(emitter); } }; */ /* Usage example: MyListener listener; MyEmitter emitter; // To listen to an emitter, listener.ListenTo(emitter.GetSubject()); // To call the listeners, emitter.CallListeners(22, true); */ template class Observer : public RefCountBase< Observer > { friend class ObserverScope; friend class ObserverHash; public: typedef Observer ThisType; typedef DelegateT Handler; protected: bool IsShutdown; // Flag to indicate that the object went out of scope mutable Lock TheLock; // Lock to synchronize calls and shutdown Array< Ptr< ThisType > > References; // List of observed or observing objects Handler TheHandler; // Observer-only: Handler for callbacks Observer() : IsShutdown(false) { TheHandler.Invalidate(); } Observer(Handler handler) : IsShutdown(false), TheHandler(handler) { } ~Observer() { OVR_ASSERT(References.GetSizeI() == 0); } public: void SetHandler(Handler handler) { OVR_ASSERT(References.GetSizeI() == 0); TheHandler = handler; } // Release references and prevent further actions void Shutdown() { Lock::Locker locker(&TheLock); IsShutdown = true; References.ClearAndRelease(); } // Get count of references held int GetSizeI() const { Lock::Locker locker(&TheLock); return References.GetSizeI(); } // Observe a subject bool Observe(ThisType *subject) { OVR_ASSERT(TheHandler.IsValid()); if (!subject) { return false; } Lock::Locker locker(&TheLock); if (IsShutdown) { return false; } if (!subject->SubjectAddObserver(this)) { return false; } References.PushBack(subject); return true; } protected: // Subject function: AddObserver() // Returns true if the observer was added bool SubjectAddObserver(ThisType* observer) { OVR_ASSERT(!TheHandler.IsValid()); if (!observer) { return true; } Lock::Locker locker(&TheLock); if (IsShutdown) { return false; } const int count = References.GetSizeI(); for (int i = 0; i < count; ++i) { if (References[i] == observer) { // Already watched return true; } } References.PushBack(observer); return true; } public: // Subject function: Call() #define OVR_OBSERVER_CALL_BODY(params) \ bool callSuccess = false; \ Lock::Locker locker(&TheLock); \ int count = References.GetSizeI(); \ for (int i = 0; i < count; ++i) \ { \ if (!References[i]->IsShutdown) \ { \ OVR_ASSERT(References[i]->TheHandler.IsValid()); \ References[i]->TheHandler params; \ callSuccess = true; \ } \ if (References[i]->IsShutdown) \ { \ References.RemoveAt(i); \ --i; --count; \ } \ } \ return callSuccess; // Call: Various parameter counts // Returns true if a call was made bool Call() { OVR_OBSERVER_CALL_BODY(()) } template bool Call(Param1& p1) { OVR_OBSERVER_CALL_BODY((p1)) } template bool Call(Param1* p1) { OVR_OBSERVER_CALL_BODY((p1)) } template bool Call(Param1& p1, Param2& p2) { OVR_OBSERVER_CALL_BODY((p1, p2)) } template bool Call(Param1* p1, Param2* p2) { OVR_OBSERVER_CALL_BODY((p1, p2)) } template bool Call(Param1& p1, Param2& p2, Param3& p3) { OVR_OBSERVER_CALL_BODY((p1, p2, p3)) } template bool Call(Param1* p1, Param2* p2, Param3* p3) { OVR_OBSERVER_CALL_BODY((p1, p2, p3)) } #undef OVR_OBSERVER_CALL_BODY }; //----------------------------------------------------------------------------- // ObserverScope // Scoped shutdown of the Observer object template class ObserverScope : public NewOverrideBase { Ptr< Observer > TheObserver; DelegateT TheHandler; void Shutdown() { if (TheObserver) { TheObserver->Shutdown(); TheObserver.Clear(); } } public: ObserverScope() { TheObserver = *new Observer; } ~ObserverScope() { Shutdown(); } // Release all references and recreate it void ReleaseAll() { Shutdown(); TheObserver = *new Observer; if (TheHandler.IsValid()) { TheObserver->SetHandler(TheHandler); } } void SetHandler(DelegateT handler) { TheHandler = handler; TheObserver->SetHandler(handler); } Observer* GetPtr() { return TheObserver.GetPtr(); } Observer* operator->() { return TheObserver.GetPtr(); } const Observer* operator->() const { return TheObserver.GetPtr(); } operator Observer*() { return TheObserver.GetPtr(); } }; //----------------------------------------------------------------------------- // ObserverHash // A hash containing Observers template class ObserverHash : public NewOverrideBase { public: ObserverHash() {} ~ObserverHash() {Clear();} void Clear() { Lock::Locker locker(&TheLock); typename OVR::Hash< String, Ptr >, OVR::String::HashFunctor >::Iterator it = _Hash.Begin(); for( it = _Hash.Begin(); it != _Hash.End(); ++it ) { Ptr > o = it->Second; o->Shutdown(); } } Ptr > GetSubject(OVR::String key) { Lock::Locker locker(&TheLock); Ptr > *o = _Hash.Get(key); if (o) return (*o); return NULL; } // Add handler to new observer with implicit creation of subject. void AddObserverToSubject(OVR::String key, Observer *observer) { Lock::Locker locker(&TheLock); Ptr > *subjectPtr = _Hash.Get(key); if (subjectPtr==NULL) { Ptr > subject = *new Observer(); _Hash.Add(key, subject); observer->Observe(subject); } else { observer->Observe(*subjectPtr); } } void RemoveSubject(OVR::String key) { Lock::Locker locker(&TheLock); Ptr > *subjectPtr = _Hash.Get(key); if (subjectPtr!=NULL) { (*subjectPtr)->Shutdown(); _Hash.Remove(key); } } protected: OVR::Hash< OVR::String, Ptr >, OVR::String::HashFunctor > _Hash; Lock TheLock; // Lock to synchronize calls and shutdown }; } // namespace OVR #endif // OVR_Observer_h