/************************************************************************************ PublicHeader: Kernel Filename : OVR_Callbacks.h Content : Callback library Created : June 20, 2014 Author : Chris Taylor Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved. Licensed under the Oculus Master SDK License Version 1.0 (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 https://developer.oculus.com/licenses/oculusmastersdk-1.0 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_Callbacks_h #define OVR_Callbacks_h #include "OVR_CallbacksInternal.h" #include "OVR_Hash.h" // For CallbackHash #include "OVR_String.h" // For CallbackHash namespace OVR { //----------------------------------------------------------------------------- // CallbackEmitter // // Emitter of callbacks. // Thread-safety: All public members may be safely called concurrently. template class CallbackEmitter : public NewOverrideBase { public: CallbackEmitter(); ~CallbackEmitter(); // Add a listener. bool AddListener(CallbackListener* listener); // Get the current number of listeners. Note that this can change as other threads // add listeners to the emitter. int GetListenerCount() const; bool HasListeners() const { return Emitter->HasListeners(); } void Call() { Emitter->Call(); } template void Call(Param1* p1) { Emitter->Call(p1); } template void Call(Param1& p1) { Emitter->Call(p1); } template void Call(Param1* p1, Param2* p2) { Emitter->Call(p1, p2); } template void Call(Param1& p1, Param2& p2) { Emitter->Call(p1, p2); } template void Call(Param1* p1, Param2* p2, Param3* p3) { Emitter->Call(p1, p2, p3); } template void Call(Param1& p1, Param2& p2, Param3& p3) { Emitter->Call(p1, p2, p3); } // Remove all listeners and prevent further listeners from being added. void Shutdown(); protected: Ptr> Emitter; }; //----------------------------------------------------------------------------- // CallbackListener // // Listener for callbacks. // Thread-safety: Operations on a listener are not thread-safe. // The listener may only listen to *one emitter* at a time. template class CallbackListener : public NewOverrideBase { friend class CallbackEmitter; public: CallbackListener(); ~CallbackListener(); // Stop listening to callbacks. // And set a new handler for callbacks. void SetHandler(DelegateT handler); // Is listening to an emitter at this instant? // If the Emitter has shutdown, then this may inaccurately return true. bool IsListening() const; // Stops listening to callbacks. void Cancel(); protected: /// Internal data: // Reference to the associated listener. Ptr> FloatingListener; // Reference to the associated emitter. Ptr> FloatingEmitter; DelegateT Handler; }; //----------------------------------------------------------------------------- // Template Implementation: CallbackEmitter template CallbackEmitter::CallbackEmitter() { Emitter = *new FloatingCallbackEmitter; } template CallbackEmitter::~CallbackEmitter() { Emitter->Shutdown(); // Emitter goes out of scope here. } template bool CallbackEmitter::AddListener(CallbackListener* listener) { // The listener object can only be attached to one emitter at a time. // The caller should explicitly Cancel() a listener before listening // to a new emitter, even if it is the same emitter. OVR_ASSERT(!listener->FloatingEmitter && !listener->FloatingListener); if (listener->FloatingEmitter || listener->FloatingListener) { // Cancel any previous listening listener->Cancel(); } // Set the floating listener and emitter listener->FloatingListener = *new FloatingCallbackListener(listener->Handler); listener->FloatingEmitter = Emitter.GetPtr(); // The remaining input checks are performed inside. return Emitter->AddListener(listener->FloatingListener); } template int CallbackEmitter::GetListenerCount() const { return Emitter->Listeners.GetSizeI(); } template void CallbackEmitter::Shutdown() { Emitter->Shutdown(); } //----------------------------------------------------------------------------- // Template Implementation: CallbackListener template CallbackListener::CallbackListener() { // Listener is null until a handler is set. } template CallbackListener::~CallbackListener() { Cancel(); } template void CallbackListener::Cancel() { if (FloatingListener) { FloatingListener->EnterCancelState(); } if (FloatingEmitter) { if (FloatingListener) { FloatingEmitter->OnListenerCancel(FloatingListener); } } // FloatingEmitter goes out of scope here. FloatingEmitter = nullptr; // FloatingListener goes out of scope here. FloatingListener = nullptr; } template void CallbackListener::SetHandler(DelegateT handler) { Cancel(); Handler = handler; } template bool CallbackListener::IsListening() const { if (!FloatingListener.GetPtr()) { return false; } return FloatingListener->IsValid(); } //----------------------------------------------------------------------------- // CallbackHash // // A hash containing CallbackEmitters template class CallbackHash : public NewOverrideBase { typedef Hash*, String::HashFunctor> HashTable; public: ~CallbackHash() { Clear(); } void Clear() { for (auto ii = Table.Begin(); ii != Table.End(); ++ii) { delete ii->Second; } Table.Clear(); } CallbackEmitter* GetKey(String key) { CallbackEmitter** emitter = Table.Get(key); if (emitter) { return *emitter; } return nullptr; } void AddListener(String key, CallbackListener* listener) { CallbackEmitter** pEmitter = Table.Get(key); CallbackEmitter* emitter = nullptr; if (!pEmitter) { emitter = new CallbackEmitter; Table.Add(key, emitter); } else { emitter = *pEmitter; } emitter->AddListener(listener); } void RemoveKey(String key) { CallbackEmitter** emitter = Table.Get(key); if (emitter) { delete *emitter; Table.Remove(key); } } protected: HashTable Table; // Hash table }; } // namespace OVR #endif // OVR_Callbacks_h