Bug 792954. Add a WeakPtr implementation to use instead of nsISupportsWeakReference. r=joe,ehsan,Waldo

This patch also replaces the usage of nsISupportsWeakReference in RasterImage as an example.

--HG--
extra : rebase_source : ac6a039dcc3227a04ac4c2221f38856bb308c695
This commit is contained in:
Jeff Muizelaar 2012-10-04 15:45:07 -04:00
parent 0f92e4019f
commit ac8fdf1333
7 changed files with 230 additions and 12 deletions

View File

@ -204,11 +204,10 @@ namespace image {
static nsCOMPtr<nsIThread> sScaleWorkerThread = nullptr;
#ifndef DEBUG
NS_IMPL_ISUPPORTS3(RasterImage, imgIContainer, nsIProperties,
nsISupportsWeakReference)
NS_IMPL_ISUPPORTS2(RasterImage, imgIContainer, nsIProperties)
#else
NS_IMPL_ISUPPORTS4(RasterImage, imgIContainer, nsIProperties,
imgIContainerDebug, nsISupportsWeakReference)
NS_IMPL_ISUPPORTS3(RasterImage, imgIContainer, nsIProperties,
imgIContainerDebug)
#endif
//******************************************************************************
@ -2557,7 +2556,7 @@ RasterImage::RequestDecode()
// RequestDecode() is an asynchronous function this works fine (though it's
// a little slower).
if (mInDecoder) {
nsRefPtr<imgDecodeRequestor> requestor = new imgDecodeRequestor(this);
nsRefPtr<imgDecodeRequestor> requestor = new imgDecodeRequestor(*this);
return NS_DispatchToCurrentThread(requestor);
}

View File

@ -33,6 +33,7 @@
#include "mozilla/Telemetry.h"
#include "mozilla/LinkedList.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/WeakPtr.h"
#ifdef DEBUG
#include "imgIContainerDebug.h"
#endif
@ -136,7 +137,7 @@ class Decoder;
class RasterImage : public Image
, public nsIProperties
, public nsSupportsWeakReference
, public SupportsWeakPtr<RasterImage>
#ifdef DEBUG
, public imgIContainerDebug
#endif
@ -811,18 +812,17 @@ protected:
class imgDecodeRequestor : public nsRunnable
{
public:
imgDecodeRequestor(imgIContainer *aContainer) {
mContainer = do_GetWeakReference(aContainer);
imgDecodeRequestor(RasterImage &aContainer) {
mContainer = aContainer.asWeakPtr();
}
NS_IMETHOD Run() {
nsCOMPtr<imgIContainer> con = do_QueryReferent(mContainer);
if (con)
con->RequestDecode();
if (mContainer)
mContainer->RequestDecode();
return NS_OK;
}
private:
nsWeakPtr mContainer;
WeakPtr<RasterImage> mContainer;
};
} // namespace image

139
mfbt/WeakPtr.h Normal file
View File

@ -0,0 +1,139 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/* Weak pointer functionality, implemented as a mixin for use with any class. */
/**
* SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting
* its lifetime. It works by creating a single shared reference counted object
* (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo'
* clear the pointer in the WeakReference without having to know about all of
* the WeakPtrs to it and allows the WeakReference to live beyond the lifetime
* of 'Foo'.
*
* The overhead of WeakPtr is that accesses to 'Foo' becomes an additional
* dereference, and an additional heap allocated pointer sized object shared
* between all of the WeakPtrs.
*
* Example of usage:
*
* // To have a class C support weak pointers, inherit from SupportsWeakPtr<C>.
* class C : public SupportsWeakPtr<C>
* {
* public:
* int num;
* void act();
* };
*
* C* ptr = new C();
*
* // Get weak pointers to ptr. The first time asWeakPtr is called
* // a reference counted WeakReference object is created that
* // can live beyond the lifetime of 'ptr'. The WeakReference
* // object will be notified of 'ptr's destruction.
* WeakPtr<C> weak = ptr->asWeakPtr();
* WeakPtr<C> other = ptr->asWeakPtr();
*
* // Test a weak pointer for validity before using it.
* if (weak) {
* weak->num = 17;
* weak->act();
* }
*
* // Destroying the underlying object clears weak pointers to it.
* delete ptr;
*
* MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
* MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
*
* WeakPtr is typesafe and may be used with any class. It is not required that
* the class be reference-counted or allocated in any particular way.
*
* The API was loosely inspired by Chromium's weak_ptr.h:
* http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h
*/
#ifndef mozilla_WeakPtr_h_
#define mozilla_WeakPtr_h_
#include "mozilla/Assertions.h"
#include "mozilla/NullPtr.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
template <typename T> class WeakPtr;
template <typename T>
class SupportsWeakPtr
{
public:
WeakPtr<T> asWeakPtr() {
if (!weakRef)
weakRef = new WeakReference(static_cast<T*>(this));
return WeakPtr<T>(weakRef);
}
protected:
~SupportsWeakPtr() {
MOZ_STATIC_ASSERT((IsBaseOf<SupportsWeakPtr<T>, T>::value), "T must derive from SupportsWeakPtr<T>");
if (weakRef)
weakRef->detach();
}
private:
friend class WeakPtr<T>;
// This can live beyond the lifetime of the class derived from SupportsWeakPtr.
class WeakReference : public RefCounted<WeakReference>
{
public:
explicit WeakReference(T* ptr) : ptr(ptr) {}
T* get() const {
return ptr;
}
private:
friend class WeakPtr<T>;
friend class SupportsWeakPtr<T>;
void detach() {
ptr = nullptr;
}
T* ptr;
};
RefPtr<WeakReference> weakRef;
};
template <typename T>
class WeakPtr
{
public:
WeakPtr(const WeakPtr<T>& o) : ref(o.ref) {}
WeakPtr() : ref(nullptr) {}
operator T*() const {
return ref->get();
}
T& operator*() const {
return *ref->get();
}
T* operator->() const {
return ref->get();
}
private:
friend class SupportsWeakPtr<T>;
explicit WeakPtr(const RefPtr<typename SupportsWeakPtr<T>::WeakReference> &o) : ref(o) {}
RefPtr<typename SupportsWeakPtr<T>::WeakReference> ref;
};
} // namespace mozilla
#endif /* ifdef mozilla_WeakPtr_h_ */

View File

@ -31,4 +31,5 @@ EXPORTS_mozilla += \
TypeTraits.h \
Types.h \
Util.h \
WeakPtr.h \
$(NULL)

View File

@ -15,6 +15,7 @@ CPP_UNIT_TESTS = \
TestCheckedInt.cpp \
TestTypeTraits.cpp \
TestSHA1.cpp \
TestWeakPtr.cpp \
$(NULL)
# in order to prevent rules.mk from trying to link to libraries that are

View File

@ -0,0 +1,76 @@
/* 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/. */
#include "mozilla/WeakPtr.h"
using mozilla::SupportsWeakPtr;
using mozilla::WeakPtr;
// To have a class C support weak pointers, inherit from SupportsWeakPtr<C>.
class C : public SupportsWeakPtr<C>
{
public:
int num;
void act() {}
};
static void
example()
{
C* ptr = new C();
// Get weak pointers to ptr. The first time asWeakPtr is called
// a reference counted WeakReference object is created that
// can live beyond the lifetime of 'ptr'. The WeakReference
// object will be notified of 'ptr's destruction.
WeakPtr<C> weak = ptr->asWeakPtr();
WeakPtr<C> other = ptr->asWeakPtr();
// Test a weak pointer for validity before using it.
if (weak) {
weak->num = 17;
weak->act();
}
// Destroying the underlying object clears weak pointers to it.
delete ptr;
MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
}
struct A : public SupportsWeakPtr<A>
{
int data;
};
int main()
{
A* a = new A;
// a2 is unused to test the case when we haven't initialized
// the internal WeakReference pointer.
A* a2 = new A;
a->data = 5;
WeakPtr<A> ptr = a->asWeakPtr();
{
WeakPtr<A> ptr2 = a->asWeakPtr();
MOZ_ASSERT(ptr->data == 5);
WeakPtr<A> ptr3 = a->asWeakPtr();
MOZ_ASSERT(ptr->data == 5);
}
delete a;
MOZ_ASSERT(!ptr);
delete a2;
example();
return 0;
}

View File

@ -9,6 +9,8 @@
// nsWeakReference.h
// See mfbt/WeakPtr.h for a more typesafe C++ implementation of weak references
#include "nsIWeakReferenceUtils.h"
class nsWeakReference;