summaryrefslogtreecommitdiffstats
path: root/media/webrtc/signaling/src/common/Wrapper.h
diff options
context:
space:
mode:
Diffstat (limited to 'media/webrtc/signaling/src/common/Wrapper.h')
-rw-r--r--media/webrtc/signaling/src/common/Wrapper.h175
1 files changed, 175 insertions, 0 deletions
diff --git a/media/webrtc/signaling/src/common/Wrapper.h b/media/webrtc/signaling/src/common/Wrapper.h
new file mode 100644
index 000000000..a88cbd4bf
--- /dev/null
+++ b/media/webrtc/signaling/src/common/Wrapper.h
@@ -0,0 +1,175 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#pragma once
+
+/*
+ * Wrapper - Helper class for wrapper objects.
+ *
+ * This helps to construct a shared_ptr object which wraps access to an underlying handle.
+ * (The handle could be a pointer to some low-level type, a conventional C handle, an int ID, a GUID, etc.)
+ *
+ * Usage:
+ * To obtain a FooPtr from a foo_handle_t, call FooPtr Foo::wrap(foo_handle_t);
+ *
+ * To implement Foo using Wrapper, Foo needs to include this macro in its class definition:
+ * CSF_DECLARE_WRAP(Foo, foo_handle_t);
+ * It also needs to include this in the cpp file, to provide the wrap() implementation and define the static Wrapper.
+ * CSF_IMPLEMENT_WRAP(Foo, foo_handle_t);
+ * These are all declared in common/Wrapper.h - Foo.h needs to include this too.
+ * The client needs to declare Foo(foo_handle_t) as private, and provide a suitable implementation, as well as
+ * implementing wrappers for any other functions to be exposed.
+ * The client needs to implement ~Foo() to perform any cleanup as usual.
+ *
+ * wrap() will always return the same FooPtr for a given foo_handle_t, it will not construct additional objects
+ * if a suitable one already exists.
+ * changeHandle() is used in rare cases where the underlying handle is changed, but the wrapper object is intended
+ * to remain. This is the case for the "fake" CC_DPCall generated on CC_DPLine::CreateCall(), where
+ * the correct IDPCall* is provided later.
+ * reset() is a cleanup step to wipe the handle map and allow memory to be reclaimed.
+ *
+ * Future enhancements:
+ * - For now, objects remain in the map forever. Better would be to add a releaseHandle() function which would
+ * allow the map to be emptied as underlying handles expired. While we can't force the client to give up its
+ * shared_ptr<Foo> objects, we can remove our own copy, for instance on a call ended event.
+ */
+
+#include <map>
+#include "prlock.h"
+#include "mozilla/Assertions.h"
+
+/*
+ * Wrapper has its own autolock class because the instances are declared
+ * statically and mozilla::Mutex will not work properly when instantiated
+ * in a static constructor.
+ */
+
+class LockNSPR {
+public:
+ LockNSPR() : lock_(nullptr) {
+ lock_ = PR_NewLock();
+ MOZ_ASSERT(lock_);
+ }
+ ~LockNSPR() {
+ PR_DestroyLock(lock_);
+ }
+
+ void Acquire() {
+ PR_Lock(lock_);
+ }
+
+ void Release() {
+ PR_Unlock(lock_);
+ }
+
+private:
+ PRLock *lock_;
+};
+
+class AutoLockNSPR {
+public:
+ explicit AutoLockNSPR(LockNSPR& lock) : lock_(lock) {
+ lock_.Acquire();
+ }
+ ~AutoLockNSPR() {
+ lock_.Release();
+ }
+
+private:
+ LockNSPR& lock_;
+};
+
+template <class T>
+class Wrapper
+{
+private:
+ typedef std::map<typename T::Handle, typename T::Ptr> HandleMapType;
+ HandleMapType handleMap;
+ LockNSPR handleMapMutex;
+
+public:
+ Wrapper() {}
+
+ typename T::Ptr wrap(typename T::Handle handle)
+ {
+ AutoLockNSPR lock(handleMapMutex);
+ typename HandleMapType::iterator it = handleMap.find(handle);
+ if(it != handleMap.end())
+ {
+ return it->second;
+ }
+ else
+ {
+ typename T::Ptr p(new T(handle));
+ handleMap[handle] = p;
+ return p;
+ }
+ }
+
+ bool changeHandle(typename T::Handle oldHandle, typename T::Handle newHandle)
+ {
+ AutoLockNSPR lock(handleMapMutex);
+ typename HandleMapType::iterator it = handleMap.find(oldHandle);
+ if(it != handleMap.end())
+ {
+ typename T::Ptr p = it->second;
+ handleMap.erase(it);
+ handleMap[newHandle] = p;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ bool release(typename T::Handle handle)
+ {
+ AutoLockNSPR lock(handleMapMutex);
+ typename HandleMapType::iterator it = handleMap.find(handle);
+ if(it != handleMap.end())
+ {
+ handleMap.erase(it);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ void reset()
+ {
+ AutoLockNSPR lock(handleMapMutex);
+ handleMap.clear();
+ }
+};
+
+#define CSF_DECLARE_WRAP(classname, handletype) \
+ public: \
+ static classname ## Ptr wrap(handletype handle); \
+ static void reset(); \
+ static void release(handletype handle); \
+ private: \
+ friend class Wrapper<classname>; \
+ typedef classname ## Ptr Ptr; \
+ typedef handletype Handle; \
+ static Wrapper<classname>& getWrapper() { \
+ static Wrapper<classname> wrapper; \
+ return wrapper; \
+ }
+
+#define CSF_IMPLEMENT_WRAP(classname, handletype) \
+ classname ## Ptr classname::wrap(handletype handle) \
+ { \
+ return getWrapper().wrap(handle); \
+ } \
+ void classname::reset() \
+ { \
+ getWrapper().reset(); \
+ } \
+ void classname::release(handletype handle) \
+ { \
+ getWrapper().release(handle); \
+ }