1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/signaling/src/common/Wrapper.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,175 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#pragma once 1.9 + 1.10 +/* 1.11 + * Wrapper - Helper class for wrapper objects. 1.12 + * 1.13 + * This helps to construct a shared_ptr object which wraps access to an underlying handle. 1.14 + * (The handle could be a pointer to some low-level type, a conventional C handle, an int ID, a GUID, etc.) 1.15 + * 1.16 + * Usage: 1.17 + * To obtain a FooPtr from a foo_handle_t, call FooPtr Foo::wrap(foo_handle_t); 1.18 + * 1.19 + * To implement Foo using Wrapper, Foo needs to include this macro in its class definition: 1.20 + * CSF_DECLARE_WRAP(Foo, foo_handle_t); 1.21 + * It also needs to include this in the cpp file, to provide the wrap() implementation and define the static Wrapper. 1.22 + * CSF_IMPLEMENT_WRAP(Foo, foo_handle_t); 1.23 + * These are all declared in common/Wrapper.h - Foo.h needs to include this too. 1.24 + * The client needs to declare Foo(foo_handle_t) as private, and provide a suitable implementation, as well as 1.25 + * implementing wrappers for any other functions to be exposed. 1.26 + * The client needs to implement ~Foo() to perform any cleanup as usual. 1.27 + * 1.28 + * wrap() will always return the same FooPtr for a given foo_handle_t, it will not construct additional objects 1.29 + * if a suitable one already exists. 1.30 + * changeHandle() is used in rare cases where the underlying handle is changed, but the wrapper object is intended 1.31 + * to remain. This is the case for the "fake" CC_DPCall generated on CC_DPLine::CreateCall(), where 1.32 + * the correct IDPCall* is provided later. 1.33 + * reset() is a cleanup step to wipe the handle map and allow memory to be reclaimed. 1.34 + * 1.35 + * Future enhancements: 1.36 + * - For now, objects remain in the map forever. Better would be to add a releaseHandle() function which would 1.37 + * allow the map to be emptied as underlying handles expired. While we can't force the client to give up its 1.38 + * shared_ptr<Foo> objects, we can remove our own copy, for instance on a call ended event. 1.39 + */ 1.40 + 1.41 +#include <map> 1.42 +#include "prlock.h" 1.43 +#include "mozilla/Assertions.h" 1.44 + 1.45 +/* 1.46 + * Wrapper has its own autolock class because the instances are declared 1.47 + * statically and mozilla::Mutex will not work properly when instantiated 1.48 + * in a static constructor. 1.49 + */ 1.50 + 1.51 +class LockNSPR { 1.52 +public: 1.53 + LockNSPR() : lock_(nullptr) { 1.54 + lock_ = PR_NewLock(); 1.55 + MOZ_ASSERT(lock_); 1.56 + } 1.57 + ~LockNSPR() { 1.58 + PR_DestroyLock(lock_); 1.59 + } 1.60 + 1.61 + void Acquire() { 1.62 + PR_Lock(lock_); 1.63 + } 1.64 + 1.65 + void Release() { 1.66 + PR_Unlock(lock_); 1.67 + } 1.68 + 1.69 +private: 1.70 + PRLock *lock_; 1.71 +}; 1.72 + 1.73 +class AutoLockNSPR { 1.74 +public: 1.75 + AutoLockNSPR(LockNSPR& lock) : lock_(lock) { 1.76 + lock_.Acquire(); 1.77 + } 1.78 + ~AutoLockNSPR() { 1.79 + lock_.Release(); 1.80 + } 1.81 + 1.82 +private: 1.83 + LockNSPR& lock_; 1.84 +}; 1.85 + 1.86 +template <class T> 1.87 +class Wrapper 1.88 +{ 1.89 +private: 1.90 + typedef std::map<typename T::Handle, typename T::Ptr> HandleMapType; 1.91 + HandleMapType handleMap; 1.92 + LockNSPR handleMapMutex; 1.93 + 1.94 +public: 1.95 + Wrapper() {} 1.96 + 1.97 + typename T::Ptr wrap(typename T::Handle handle) 1.98 + { 1.99 + AutoLockNSPR lock(handleMapMutex); 1.100 + typename HandleMapType::iterator it = handleMap.find(handle); 1.101 + if(it != handleMap.end()) 1.102 + { 1.103 + return it->second; 1.104 + } 1.105 + else 1.106 + { 1.107 + typename T::Ptr p(new T(handle)); 1.108 + handleMap[handle] = p; 1.109 + return p; 1.110 + } 1.111 + } 1.112 + 1.113 + bool changeHandle(typename T::Handle oldHandle, typename T::Handle newHandle) 1.114 + { 1.115 + AutoLockNSPR lock(handleMapMutex); 1.116 + typename HandleMapType::iterator it = handleMap.find(oldHandle); 1.117 + if(it != handleMap.end()) 1.118 + { 1.119 + typename T::Ptr p = it->second; 1.120 + handleMap.erase(it); 1.121 + handleMap[newHandle] = p; 1.122 + return true; 1.123 + } 1.124 + else 1.125 + { 1.126 + return false; 1.127 + } 1.128 + } 1.129 + 1.130 + bool release(typename T::Handle handle) 1.131 + { 1.132 + AutoLockNSPR lock(handleMapMutex); 1.133 + typename HandleMapType::iterator it = handleMap.find(handle); 1.134 + if(it != handleMap.end()) 1.135 + { 1.136 + handleMap.erase(it); 1.137 + return true; 1.138 + } 1.139 + else 1.140 + { 1.141 + return false; 1.142 + } 1.143 + } 1.144 + 1.145 + void reset() 1.146 + { 1.147 + AutoLockNSPR lock(handleMapMutex); 1.148 + handleMap.clear(); 1.149 + } 1.150 +}; 1.151 + 1.152 +#define CSF_DECLARE_WRAP(classname, handletype) \ 1.153 + public: \ 1.154 + static classname ## Ptr wrap(handletype handle); \ 1.155 + static void reset(); \ 1.156 + static void release(handletype handle); \ 1.157 + private: \ 1.158 + friend class Wrapper<classname>; \ 1.159 + typedef classname ## Ptr Ptr; \ 1.160 + typedef handletype Handle; \ 1.161 + static Wrapper<classname>& getWrapper() { \ 1.162 + static Wrapper<classname> wrapper; \ 1.163 + return wrapper; \ 1.164 + } 1.165 + 1.166 +#define CSF_IMPLEMENT_WRAP(classname, handletype) \ 1.167 + classname ## Ptr classname::wrap(handletype handle) \ 1.168 + { \ 1.169 + return getWrapper().wrap(handle); \ 1.170 + } \ 1.171 + void classname::reset() \ 1.172 + { \ 1.173 + getWrapper().reset(); \ 1.174 + } \ 1.175 + void classname::release(handletype handle) \ 1.176 + { \ 1.177 + getWrapper().release(handle); \ 1.178 + }