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