diff options
Diffstat (limited to 'LibOVRKernel/Src/Kernel/OVR_Callbacks.h')
-rw-r--r-- | LibOVRKernel/Src/Kernel/OVR_Callbacks.h | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/LibOVRKernel/Src/Kernel/OVR_Callbacks.h b/LibOVRKernel/Src/Kernel/OVR_Callbacks.h new file mode 100644 index 0000000..b02c4ff --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Callbacks.h @@ -0,0 +1,320 @@ +/************************************************************************************ + +PublicHeader: Kernel +Filename : OVR_Callbacks.h +Content : Callback library +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_Callbacks_h +#define OVR_Callbacks_h + +#include "OVR_CallbacksInternal.h" + +#include "OVR_String.h" // For CallbackHash +#include "OVR_Hash.h" // For CallbackHash + +namespace OVR { + + +//----------------------------------------------------------------------------- +// CallbackEmitter +// +// Emitter of callbacks. +// Thread-safety: All public members may be safely called concurrently. +template<class DelegateT> +class CallbackEmitter : public NewOverrideBase +{ +public: + CallbackEmitter(); + ~CallbackEmitter(); + + // Add a listener. + bool AddListener(CallbackListener<DelegateT>* listener); + + // Get the current number of listeners. Note that this can change as other threads + // add listeners to the emitter. + int GetListenerCount() const; + + void Call() + { + Emitter->Call(); + } + template<class Param1> + void Call(Param1* p1) + { + Emitter->Call(p1); + } + template<class Param1> + void Call(Param1& p1) + { + Emitter->Call(p1); + } + template<class Param1, class Param2> + void Call(Param1* p1, Param2* p2) + { + Emitter->Call(p1, p2); + } + template<class Param1, class Param2> + void Call(Param1& p1, Param2& p2) + { + Emitter->Call(p1, p2); + } + template<class Param1, class Param2, class Param3> + void Call(Param1* p1, Param2* p2, Param3* p3) + { + Emitter->Call(p1, p2, p3); + } + template<class Param1, class Param2, class Param3> + 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< FloatingCallbackEmitter<DelegateT> > 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 DelegateT> +class CallbackListener : public NewOverrideBase +{ + friend class CallbackEmitter<DelegateT>; + +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< FloatingCallbackListener<DelegateT> > FloatingListener; + + // Reference to the associated emitter. + Ptr< FloatingCallbackEmitter<DelegateT> > FloatingEmitter; + + DelegateT Handler; +}; + + +//----------------------------------------------------------------------------- +// Template Implementation: CallbackEmitter + +template<class DelegateT> +CallbackEmitter<DelegateT>::CallbackEmitter() +{ + Emitter = *new FloatingCallbackEmitter<DelegateT>; +} + +template<class DelegateT> +CallbackEmitter<DelegateT>::~CallbackEmitter() +{ + Emitter->Shutdown(); + // Emitter goes out of scope here. +} + +template<class DelegateT> +bool CallbackEmitter<DelegateT>::AddListener(CallbackListener<DelegateT>* 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<DelegateT>(listener->Handler); + listener->FloatingEmitter = Emitter.GetPtr(); + + // The remaining input checks are performed inside. + return Emitter->AddListener(listener->FloatingListener); +} + +template<class DelegateT> +int CallbackEmitter<DelegateT>::GetListenerCount() const +{ + return Emitter->Listeners.GetSizeI(); +} + +template<class DelegateT> +void CallbackEmitter<DelegateT>::Shutdown() +{ + Emitter->Shutdown(); +} + + +//----------------------------------------------------------------------------- +// Template Implementation: CallbackListener + +template<class DelegateT> +CallbackListener<DelegateT>::CallbackListener() +{ + // Listener is null until a handler is set. +} + +template<class DelegateT> +CallbackListener<DelegateT>::~CallbackListener() +{ + Cancel(); +} + +template<class DelegateT> +void CallbackListener<DelegateT>::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<class DelegateT> +void CallbackListener<DelegateT>::SetHandler(DelegateT handler) +{ + Cancel(); + + Handler = handler; +} + +template<class DelegateT> +bool CallbackListener<DelegateT>::IsListening() const +{ + if (!FloatingListener.GetPtr()) + { + return false; + } + + return FloatingListener->IsValid(); +} + + +//----------------------------------------------------------------------------- +// CallbackHash +// +// A hash containing CallbackEmitters +template<class DelegateT> +class CallbackHash : public NewOverrideBase +{ + typedef Hash<String, CallbackEmitter<DelegateT>*, String::HashFunctor> HashTable; + +public: + ~CallbackHash() + { + Clear(); + } + + void Clear() + { + for (auto ii = Table.Begin(); ii != Table.End(); ++ii) + { + delete ii->Second; + } + + Table.Clear(); + } + + CallbackEmitter<DelegateT>* GetKey(String key) + { + CallbackEmitter<DelegateT>** emitter = Table.Get(key); + if (emitter) + { + return *emitter; + } + return nullptr; + } + + void AddListener(String key, CallbackListener<DelegateT>* listener) + { + CallbackEmitter<DelegateT>** pEmitter = Table.Get(key); + CallbackEmitter<DelegateT>* emitter = nullptr; + + if (!pEmitter) + { + emitter = new CallbackEmitter<DelegateT>; + Table.Add(key, emitter); + } + else + { + emitter = *pEmitter; + } + + emitter->AddListener(listener); + } + + void RemoveKey(String key) + { + CallbackEmitter<DelegateT>** emitter = Table.Get(key); + + if (emitter) + { + delete *emitter; + Table.Remove(key); + } + } + +protected: + HashTable Table; // Hash table +}; + + +} // namespace OVR + +#endif // OVR_Callbacks_h |