gecko-dev/layout/style/HandleRefPtr.h

108 lines
2.4 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=2 sw=2 et tw=78:
* 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/.
*/
/* smart pointer for strong references to objects through pointer-like
* "handle" objects */
#include <algorithm>
#include "mozilla/Assertions.h"
#ifndef mozilla_HandleRefPtr_h
#define mozilla_HandleRefPtr_h
namespace mozilla {
/**
* A class for holding strong references to handle-managed objects.
*
* This is intended for use with objects like StyleSheetHandle, where
* the handle type is not a pointer but which can still have ->AddRef()
* and ->Release() called on it.
*/
template<typename T>
class HandleRefPtr
{
public:
HandleRefPtr() {}
HandleRefPtr(HandleRefPtr<T>& aRhs)
{
assign(aRhs.mHandle);
}
HandleRefPtr(HandleRefPtr<T>&& aRhs)
{
std::swap(mHandle, aRhs.mHandle);
}
MOZ_IMPLICIT HandleRefPtr(T aRhs)
{
assign(aRhs);
}
HandleRefPtr<T>& operator=(HandleRefPtr<T>& aRhs)
{
assign(aRhs.mHandle);
return *this;
}
HandleRefPtr<T>& operator=(T aRhs)
{
assign(aRhs);
return *this;
}
~HandleRefPtr() { assign(nullptr); }
explicit operator bool() const { return !!mHandle; }
bool operator!() const { return !mHandle; }
operator T() const { return mHandle; }
T operator->() const { return mHandle; }
bool operator==(const HandleRefPtr<T>& aOther) const
{
return mHandle == aOther.mHandle;
}
bool operator!=(const HandleRefPtr<T>& aOther) const
{
return !(*this == aOther);
}
void swap(HandleRefPtr<T>& aOther)
{
std::swap(mHandle, aOther.mHandle);
}
private:
void assign(T aPtr)
{
// AddRef early so |aPtr| can't disappear underneath us.
if (aPtr) {
aPtr->AddRef();
}
// Don't release |mHandle| yet: if |mHandle| indirectly owns |this|,
// releasing would invalidate |this|. Swap |aPtr| for |mHandle| so that
// |aPtr| lives as long as |this|, then release the new |aPtr| (really the
// original |mHandle|) so that if |this| is invalidated, we're not using it
// any more.
std::swap(mHandle, aPtr);
if (aPtr) {
aPtr->Release();
}
}
T mHandle;
};
} // namespace mozilla
#endif // mozilla_HandleRefPtr_h