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

changeset 0
6474c204b198
     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 +        }

mercurial