media/webrtc/signaling/src/common/Wrapper.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:1b3437a66759
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #pragma once
6
7 /*
8 * Wrapper - Helper class for wrapper objects.
9 *
10 * This helps to construct a shared_ptr object which wraps access to an underlying handle.
11 * (The handle could be a pointer to some low-level type, a conventional C handle, an int ID, a GUID, etc.)
12 *
13 * Usage:
14 * To obtain a FooPtr from a foo_handle_t, call FooPtr Foo::wrap(foo_handle_t);
15 *
16 * To implement Foo using Wrapper, Foo needs to include this macro in its class definition:
17 * CSF_DECLARE_WRAP(Foo, foo_handle_t);
18 * It also needs to include this in the cpp file, to provide the wrap() implementation and define the static Wrapper.
19 * CSF_IMPLEMENT_WRAP(Foo, foo_handle_t);
20 * These are all declared in common/Wrapper.h - Foo.h needs to include this too.
21 * The client needs to declare Foo(foo_handle_t) as private, and provide a suitable implementation, as well as
22 * implementing wrappers for any other functions to be exposed.
23 * The client needs to implement ~Foo() to perform any cleanup as usual.
24 *
25 * wrap() will always return the same FooPtr for a given foo_handle_t, it will not construct additional objects
26 * if a suitable one already exists.
27 * changeHandle() is used in rare cases where the underlying handle is changed, but the wrapper object is intended
28 * to remain. This is the case for the "fake" CC_DPCall generated on CC_DPLine::CreateCall(), where
29 * the correct IDPCall* is provided later.
30 * reset() is a cleanup step to wipe the handle map and allow memory to be reclaimed.
31 *
32 * Future enhancements:
33 * - For now, objects remain in the map forever. Better would be to add a releaseHandle() function which would
34 * allow the map to be emptied as underlying handles expired. While we can't force the client to give up its
35 * shared_ptr<Foo> objects, we can remove our own copy, for instance on a call ended event.
36 */
37
38 #include <map>
39 #include "prlock.h"
40 #include "mozilla/Assertions.h"
41
42 /*
43 * Wrapper has its own autolock class because the instances are declared
44 * statically and mozilla::Mutex will not work properly when instantiated
45 * in a static constructor.
46 */
47
48 class LockNSPR {
49 public:
50 LockNSPR() : lock_(nullptr) {
51 lock_ = PR_NewLock();
52 MOZ_ASSERT(lock_);
53 }
54 ~LockNSPR() {
55 PR_DestroyLock(lock_);
56 }
57
58 void Acquire() {
59 PR_Lock(lock_);
60 }
61
62 void Release() {
63 PR_Unlock(lock_);
64 }
65
66 private:
67 PRLock *lock_;
68 };
69
70 class AutoLockNSPR {
71 public:
72 AutoLockNSPR(LockNSPR& lock) : lock_(lock) {
73 lock_.Acquire();
74 }
75 ~AutoLockNSPR() {
76 lock_.Release();
77 }
78
79 private:
80 LockNSPR& lock_;
81 };
82
83 template <class T>
84 class Wrapper
85 {
86 private:
87 typedef std::map<typename T::Handle, typename T::Ptr> HandleMapType;
88 HandleMapType handleMap;
89 LockNSPR handleMapMutex;
90
91 public:
92 Wrapper() {}
93
94 typename T::Ptr wrap(typename T::Handle handle)
95 {
96 AutoLockNSPR lock(handleMapMutex);
97 typename HandleMapType::iterator it = handleMap.find(handle);
98 if(it != handleMap.end())
99 {
100 return it->second;
101 }
102 else
103 {
104 typename T::Ptr p(new T(handle));
105 handleMap[handle] = p;
106 return p;
107 }
108 }
109
110 bool changeHandle(typename T::Handle oldHandle, typename T::Handle newHandle)
111 {
112 AutoLockNSPR lock(handleMapMutex);
113 typename HandleMapType::iterator it = handleMap.find(oldHandle);
114 if(it != handleMap.end())
115 {
116 typename T::Ptr p = it->second;
117 handleMap.erase(it);
118 handleMap[newHandle] = p;
119 return true;
120 }
121 else
122 {
123 return false;
124 }
125 }
126
127 bool release(typename T::Handle handle)
128 {
129 AutoLockNSPR lock(handleMapMutex);
130 typename HandleMapType::iterator it = handleMap.find(handle);
131 if(it != handleMap.end())
132 {
133 handleMap.erase(it);
134 return true;
135 }
136 else
137 {
138 return false;
139 }
140 }
141
142 void reset()
143 {
144 AutoLockNSPR lock(handleMapMutex);
145 handleMap.clear();
146 }
147 };
148
149 #define CSF_DECLARE_WRAP(classname, handletype) \
150 public: \
151 static classname ## Ptr wrap(handletype handle); \
152 static void reset(); \
153 static void release(handletype handle); \
154 private: \
155 friend class Wrapper<classname>; \
156 typedef classname ## Ptr Ptr; \
157 typedef handletype Handle; \
158 static Wrapper<classname>& getWrapper() { \
159 static Wrapper<classname> wrapper; \
160 return wrapper; \
161 }
162
163 #define CSF_IMPLEMENT_WRAP(classname, handletype) \
164 classname ## Ptr classname::wrap(handletype handle) \
165 { \
166 return getWrapper().wrap(handle); \
167 } \
168 void classname::reset() \
169 { \
170 getWrapper().reset(); \
171 } \
172 void classname::release(handletype handle) \
173 { \
174 getWrapper().release(handle); \
175 }

mercurial