mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
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:
parent
0f92e4019f
commit
ac8fdf1333
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
139
mfbt/WeakPtr.h
Normal 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_ */
|
@ -31,4 +31,5 @@ EXPORTS_mozilla += \
|
||||
TypeTraits.h \
|
||||
Types.h \
|
||||
Util.h \
|
||||
WeakPtr.h \
|
||||
$(NULL)
|
||||
|
@ -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
|
||||
|
76
mfbt/tests/TestWeakPtr.cpp
Normal file
76
mfbt/tests/TestWeakPtr.cpp
Normal 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;
|
||||
}
|
@ -9,6 +9,8 @@
|
||||
|
||||
// nsWeakReference.h
|
||||
|
||||
// See mfbt/WeakPtr.h for a more typesafe C++ implementation of weak references
|
||||
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
|
||||
class nsWeakReference;
|
||||
|
Loading…
Reference in New Issue
Block a user