michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsTWeakRef_h__ michael@0: #define nsTWeakRef_h__ michael@0: michael@0: #ifndef nsDebug_h___ michael@0: #include "nsDebug.h" michael@0: #endif michael@0: michael@0: /** michael@0: * A weak reference class for use with generic C++ objects. NOT THREADSAFE! michael@0: * michael@0: * Example usage: michael@0: * michael@0: * class A { michael@0: * public: michael@0: * A() : mWeakSelf(this) { michael@0: * } michael@0: * ~A() { michael@0: * mWeakSelf.forget(); michael@0: * } michael@0: * void Bar() { printf("Bar!\n"); } michael@0: * const nsTWeakRef &AsWeakRef() const { return mWeakSelf; } michael@0: * private: michael@0: * nsTWeakRef mWeakSelf; michael@0: * }; michael@0: * michael@0: * class B { michael@0: * public: michael@0: * void SetA(const nsTWeakRef &a) { michael@0: * mA = a; michael@0: * } michael@0: * void Foo() { michael@0: * if (mA) michael@0: * mA->Bar(); michael@0: * } michael@0: * private: michael@0: * nsTWeakRef mA; michael@0: * }; michael@0: * michael@0: * void Test() { michael@0: * B b; michael@0: * { michael@0: * A a; michael@0: * b.SetA(a.AsWeakRef()); michael@0: * b.Foo(); // prints "Bar!" michael@0: * } michael@0: * b.Foo(); // prints nothing because |a| has already been destroyed michael@0: * } michael@0: * michael@0: * One can imagine much more complex examples, especially when asynchronous michael@0: * event processing is involved. michael@0: * michael@0: * Keep in mind that you should only ever need a class like this when you have michael@0: * multiple instances of B, such that it is not possible for A and B to simply michael@0: * have pointers to one another. michael@0: */ michael@0: template michael@0: class nsTWeakRef { michael@0: public: michael@0: ~nsTWeakRef() { michael@0: if (mRef) michael@0: mRef->Release(); michael@0: } michael@0: michael@0: /** michael@0: * Construct from an object pointer (may be null). michael@0: */ michael@0: explicit michael@0: nsTWeakRef(Type *obj = nullptr) { michael@0: if (obj) { michael@0: mRef = new Inner(obj); michael@0: } else { michael@0: mRef = nullptr; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Construct from another weak reference object. michael@0: */ michael@0: explicit michael@0: nsTWeakRef(const nsTWeakRef &other) : mRef(other.mRef) { michael@0: if (mRef) michael@0: mRef->AddRef(); michael@0: } michael@0: michael@0: /** michael@0: * Assign from an object pointer. michael@0: */ michael@0: nsTWeakRef &operator=(Type *obj) { michael@0: if (mRef) michael@0: mRef->Release(); michael@0: if (obj) { michael@0: mRef = new Inner(obj); michael@0: } else { michael@0: mRef = nullptr; michael@0: } michael@0: return *this; michael@0: } michael@0: michael@0: /** michael@0: * Assign from another weak reference object. michael@0: */ michael@0: nsTWeakRef &operator=(const nsTWeakRef &other) { michael@0: if (mRef) michael@0: mRef->Release(); michael@0: mRef = other.mRef; michael@0: if (mRef) michael@0: mRef->AddRef(); michael@0: return *this; michael@0: } michael@0: michael@0: /** michael@0: * Get the referenced object. This method may return null if the reference michael@0: * has been cleared or if an out-of-memory error occurred at assignment. michael@0: */ michael@0: Type *get() const { michael@0: return mRef ? mRef->mObj : nullptr; michael@0: } michael@0: michael@0: /** michael@0: * Called to "null out" the weak reference. Typically, the object referenced michael@0: * by this weak reference calls this method when it is being destroyed. michael@0: * @returns The former referenced object. michael@0: */ michael@0: Type *forget() { michael@0: Type *obj; michael@0: if (mRef) { michael@0: obj = mRef->mObj; michael@0: mRef->mObj = nullptr; michael@0: mRef->Release(); michael@0: mRef = nullptr; michael@0: } else { michael@0: obj = nullptr; michael@0: } michael@0: return obj; michael@0: } michael@0: michael@0: /** michael@0: * Allow |*this| to be treated as a |Type*| for convenience. michael@0: */ michael@0: operator Type *() const { michael@0: return get(); michael@0: } michael@0: michael@0: /** michael@0: * Allow |*this| to be treated as a |Type*| for convenience. Use with michael@0: * caution since this method will crash if the referenced object is null. michael@0: */ michael@0: Type *operator->() const { michael@0: NS_ASSERTION(mRef && mRef->mObj, michael@0: "You can't dereference a null weak reference with operator->()."); michael@0: return get(); michael@0: } michael@0: michael@0: private: michael@0: michael@0: struct Inner { michael@0: int mCnt; michael@0: Type *mObj; michael@0: michael@0: Inner(Type *obj) : mCnt(1), mObj(obj) {} michael@0: void AddRef() { ++mCnt; } michael@0: void Release() { if (--mCnt == 0) delete this; } michael@0: }; michael@0: michael@0: Inner *mRef; michael@0: }; michael@0: michael@0: #endif // nsTWeakRef_h__