michael@0: /* michael@0: * Copyright 2012 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef SkWeakRefCnt_DEFINED michael@0: #define SkWeakRefCnt_DEFINED michael@0: michael@0: #include "SkRefCnt.h" michael@0: #include "SkThread.h" michael@0: michael@0: /** \class SkWeakRefCnt michael@0: michael@0: SkWeakRefCnt is the base class for objects that may be shared by multiple michael@0: objects. When an existing strong owner wants to share a reference, it calls michael@0: ref(). When a strong owner wants to release its reference, it calls michael@0: unref(). When the shared object's strong reference count goes to zero as michael@0: the result of an unref() call, its (virtual) weak_dispose method is called. michael@0: It is an error for the destructor to be called explicitly (or via the michael@0: object going out of scope on the stack or calling delete) if michael@0: getRefCnt() > 1. michael@0: michael@0: In addition to strong ownership, an owner may instead obtain a weak michael@0: reference by calling weak_ref(). A call to weak_ref() must be balanced by a michael@0: call to weak_unref(). To obtain a strong reference from a weak reference, michael@0: call try_ref(). If try_ref() returns true, the owner's pointer is now also michael@0: a strong reference on which unref() must be called. Note that this does not michael@0: affect the original weak reference, weak_unref() must still be called. When michael@0: the weak reference count goes to zero, the object is deleted. While the michael@0: weak reference count is positive and the strong reference count is zero the michael@0: object still exists, but will be in the disposed state. It is up to the michael@0: object to define what this means. michael@0: michael@0: Note that a strong reference implicitly implies a weak reference. As a michael@0: result, it is allowable for the owner of a strong ref to call try_ref(). michael@0: This will have the same effect as calling ref(), but may be more expensive. michael@0: michael@0: Example: michael@0: michael@0: SkWeakRefCnt myRef = strongRef.weak_ref(); michael@0: ... // strongRef.unref() may or may not be called michael@0: if (myRef.try_ref()) { michael@0: ... // use myRef michael@0: myRef.unref(); michael@0: } else { michael@0: // myRef is in the disposed state michael@0: } michael@0: myRef.weak_unref(); michael@0: */ michael@0: class SK_API SkWeakRefCnt : public SkRefCnt { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkWeakRefCnt) michael@0: michael@0: /** Default construct, initializing the reference counts to 1. michael@0: The strong references collectively hold one weak reference. When the michael@0: strong reference count goes to zero, the collectively held weak michael@0: reference is released. michael@0: */ michael@0: SkWeakRefCnt() : SkRefCnt(), fWeakCnt(1) {} michael@0: michael@0: /** Destruct, asserting that the weak reference count is 1. michael@0: */ michael@0: virtual ~SkWeakRefCnt() { michael@0: #ifdef SK_DEBUG michael@0: SkASSERT(fWeakCnt == 1); michael@0: fWeakCnt = 0; michael@0: #endif michael@0: } michael@0: michael@0: /** Return the weak reference count. michael@0: */ michael@0: int32_t getWeakCnt() const { return fWeakCnt; } michael@0: michael@0: #ifdef SK_DEBUG michael@0: void validate() const { michael@0: this->INHERITED::validate(); michael@0: SkASSERT(fWeakCnt > 0); michael@0: } michael@0: #endif michael@0: michael@0: /** Creates a strong reference from a weak reference, if possible. The michael@0: caller must already be an owner. If try_ref() returns true the owner michael@0: is in posession of an additional strong reference. Both the original michael@0: reference and new reference must be properly unreferenced. If try_ref() michael@0: returns false, no strong reference could be created and the owner's michael@0: reference is in the same state as before the call. michael@0: */ michael@0: bool SK_WARN_UNUSED_RESULT try_ref() const { michael@0: if (sk_atomic_conditional_inc(&fRefCnt) != 0) { michael@0: // Acquire barrier (L/SL), if not provided above. michael@0: // Prevents subsequent code from happening before the increment. michael@0: sk_membar_acquire__after_atomic_conditional_inc(); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: /** Increment the weak reference count. Must be balanced by a call to michael@0: weak_unref(). michael@0: */ michael@0: void weak_ref() const { michael@0: SkASSERT(fRefCnt > 0); michael@0: SkASSERT(fWeakCnt > 0); michael@0: sk_atomic_inc(&fWeakCnt); // No barrier required. michael@0: } michael@0: michael@0: /** Decrement the weak reference count. If the weak reference count is 1 michael@0: before the decrement, then call delete on the object. Note that if this michael@0: is the case, then the object needs to have been allocated via new, and michael@0: not on the stack. michael@0: */ michael@0: void weak_unref() const { michael@0: SkASSERT(fWeakCnt > 0); michael@0: // Release barrier (SL/S), if not provided below. michael@0: if (sk_atomic_dec(&fWeakCnt) == 1) { michael@0: // Acquire barrier (L/SL), if not provided above. michael@0: // Prevents code in destructor from happening before the decrement. michael@0: sk_membar_acquire__after_atomic_dec(); michael@0: #ifdef SK_DEBUG michael@0: // so our destructor won't complain michael@0: fWeakCnt = 1; michael@0: #endif michael@0: this->INHERITED::internal_dispose(); michael@0: } michael@0: } michael@0: michael@0: /** Returns true if there are no strong references to the object. When this michael@0: is the case all future calls to try_ref() will return false. michael@0: */ michael@0: bool weak_expired() const { michael@0: return fRefCnt == 0; michael@0: } michael@0: michael@0: protected: michael@0: /** Called when the strong reference count goes to zero. This allows the michael@0: object to free any resources it may be holding. Weak references may michael@0: still exist and their level of allowed access to the object is defined michael@0: by the object's class. michael@0: */ michael@0: virtual void weak_dispose() const { michael@0: } michael@0: michael@0: private: michael@0: /** Called when the strong reference count goes to zero. Calls weak_dispose michael@0: on the object and releases the implicit weak reference held michael@0: collectively by the strong references. michael@0: */ michael@0: virtual void internal_dispose() const SK_OVERRIDE { michael@0: weak_dispose(); michael@0: weak_unref(); michael@0: } michael@0: michael@0: /* Invariant: fWeakCnt = #weak + (fRefCnt > 0 ? 1 : 0) */ michael@0: mutable int32_t fWeakCnt; michael@0: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: #endif