michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project 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: michael@0: #ifndef SkRefCnt_DEFINED michael@0: #define SkRefCnt_DEFINED michael@0: michael@0: #include "SkDynamicAnnotations.h" michael@0: #include "SkThread.h" michael@0: #include "SkInstCnt.h" michael@0: #include "SkTemplates.h" michael@0: michael@0: /** \class SkRefCntBase michael@0: michael@0: SkRefCntBase is the base class for objects that may be shared by multiple michael@0: objects. When an existing owner wants to share a reference, it calls ref(). michael@0: When an owner wants to release its reference, it calls unref(). When the michael@0: shared object's reference count goes to zero as the result of an unref() michael@0: call, its (virtual) destructor is called. It is an error for the michael@0: destructor to be called explicitly (or via the object going out of scope on michael@0: the stack or calling delete) if getRefCnt() > 1. michael@0: */ michael@0: class SK_API SkRefCntBase : public SkNoncopyable { michael@0: public: michael@0: SK_DECLARE_INST_COUNT_ROOT(SkRefCntBase) michael@0: michael@0: /** Default construct, initializing the reference count to 1. michael@0: */ michael@0: SkRefCntBase() : fRefCnt(1) {} michael@0: michael@0: /** Destruct, asserting that the reference count is 1. michael@0: */ michael@0: virtual ~SkRefCntBase() { michael@0: #ifdef SK_DEBUG michael@0: SkASSERT(fRefCnt == 1); michael@0: fRefCnt = 0; // illegal value, to catch us if we reuse after delete michael@0: #endif michael@0: } michael@0: michael@0: /** Return the reference count. Use only for debugging. */ michael@0: int32_t getRefCnt() const { return fRefCnt; } michael@0: michael@0: /** May return true if the caller is the only owner. michael@0: * Ensures that all previous owner's actions are complete. michael@0: */ michael@0: bool unique() const { michael@0: // We believe we're reading fRefCnt in a safe way here, so we stifle the TSAN warning about michael@0: // an unproctected read. Generally, don't read fRefCnt, and don't stifle this warning. michael@0: bool const unique = (1 == SK_ANNOTATE_UNPROTECTED_READ(fRefCnt)); michael@0: if (unique) { michael@0: // Acquire barrier (L/SL), if not provided by load of fRefCnt. michael@0: // Prevents user's 'unique' code from happening before decrements. michael@0: //TODO: issue the barrier. michael@0: } michael@0: return unique; michael@0: } michael@0: michael@0: /** Increment the reference count. Must be balanced by a call to unref(). michael@0: */ michael@0: void ref() const { michael@0: SkASSERT(fRefCnt > 0); michael@0: sk_atomic_inc(&fRefCnt); // No barrier required. michael@0: } michael@0: michael@0: /** Decrement the reference count. If the reference count is 1 before the michael@0: decrement, then delete the object. Note that if this is the case, then michael@0: the object needs to have been allocated via new, and not on the stack. michael@0: */ michael@0: void unref() const { michael@0: SkASSERT(fRefCnt > 0); michael@0: // Release barrier (SL/S), if not provided below. michael@0: if (sk_atomic_dec(&fRefCnt) == 1) { michael@0: // Acquire barrier (L/SL), if not provided above. michael@0: // Prevents code in dispose from happening before the decrement. michael@0: sk_membar_acquire__after_atomic_dec(); michael@0: internal_dispose(); michael@0: } michael@0: } michael@0: michael@0: #ifdef SK_DEBUG michael@0: void validate() const { michael@0: SkASSERT(fRefCnt > 0); michael@0: } michael@0: #endif michael@0: michael@0: protected: michael@0: /** michael@0: * Allow subclasses to call this if they've overridden internal_dispose michael@0: * so they can reset fRefCnt before the destructor is called. Should only michael@0: * be called right before calling through to inherited internal_dispose() michael@0: * or before calling the destructor. michael@0: */ michael@0: void internal_dispose_restore_refcnt_to_1() const { michael@0: #ifdef SK_DEBUG michael@0: SkASSERT(0 == fRefCnt); michael@0: fRefCnt = 1; michael@0: #endif michael@0: } michael@0: michael@0: private: michael@0: /** michael@0: * Called when the ref count goes to 0. michael@0: */ michael@0: virtual void internal_dispose() const { michael@0: this->internal_dispose_restore_refcnt_to_1(); michael@0: SkDELETE(this); michael@0: } michael@0: michael@0: // The following friends are those which override internal_dispose() michael@0: // and conditionally call SkRefCnt::internal_dispose(). michael@0: friend class GrTexture; michael@0: friend class SkWeakRefCnt; michael@0: michael@0: mutable int32_t fRefCnt; michael@0: michael@0: typedef SkNoncopyable INHERITED; michael@0: }; michael@0: michael@0: #ifdef SK_REF_CNT_MIXIN_INCLUDE michael@0: // It is the responsibility of the following include to define the type SkRefCnt. michael@0: // This SkRefCnt should normally derive from SkRefCntBase. michael@0: #include SK_REF_CNT_MIXIN_INCLUDE michael@0: #else michael@0: class SK_API SkRefCnt : public SkRefCntBase { }; michael@0: #endif michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for michael@0: null in on each side of the assignment, and ensuring that ref() is called michael@0: before unref(), in case the two pointers point to the same object. michael@0: */ michael@0: #define SkRefCnt_SafeAssign(dst, src) \ michael@0: do { \ michael@0: if (src) src->ref(); \ michael@0: if (dst) dst->unref(); \ michael@0: dst = src; \ michael@0: } while (0) michael@0: michael@0: michael@0: /** Call obj->ref() and return obj. The obj must not be NULL. michael@0: */ michael@0: template static inline T* SkRef(T* obj) { michael@0: SkASSERT(obj); michael@0: obj->ref(); michael@0: return obj; michael@0: } michael@0: michael@0: /** Check if the argument is non-null, and if so, call obj->ref() and return obj. michael@0: */ michael@0: template static inline T* SkSafeRef(T* obj) { michael@0: if (obj) { michael@0: obj->ref(); michael@0: } michael@0: return obj; michael@0: } michael@0: michael@0: /** Check if the argument is non-null, and if so, call obj->unref() michael@0: */ michael@0: template static inline void SkSafeUnref(T* obj) { michael@0: if (obj) { michael@0: obj->unref(); michael@0: } michael@0: } michael@0: michael@0: template static inline void SkSafeSetNull(T*& obj) { michael@0: if (NULL != obj) { michael@0: obj->unref(); michael@0: obj = NULL; michael@0: } michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * Utility class that simply unref's its argument in the destructor. michael@0: */ michael@0: template class SkAutoTUnref : SkNoncopyable { michael@0: public: michael@0: explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {} michael@0: ~SkAutoTUnref() { SkSafeUnref(fObj); } michael@0: michael@0: T* get() const { return fObj; } michael@0: michael@0: T* reset(T* obj) { michael@0: SkSafeUnref(fObj); michael@0: fObj = obj; michael@0: return obj; michael@0: } michael@0: michael@0: void swap(SkAutoTUnref* other) { michael@0: T* tmp = fObj; michael@0: fObj = other->fObj; michael@0: other->fObj = tmp; michael@0: } michael@0: michael@0: /** michael@0: * Return the hosted object (which may be null), transferring ownership. michael@0: * The reference count is not modified, and the internal ptr is set to NULL michael@0: * so unref() will not be called in our destructor. A subsequent call to michael@0: * detach() will do nothing and return null. michael@0: */ michael@0: T* detach() { michael@0: T* obj = fObj; michael@0: fObj = NULL; michael@0: return obj; michael@0: } michael@0: michael@0: /** michael@0: * BlockRef is a type which inherits from B, cannot be created, michael@0: * cannot be deleted, and makes ref and unref private. michael@0: */ michael@0: template class BlockRef : public B { michael@0: private: michael@0: BlockRef(); michael@0: ~BlockRef(); michael@0: void ref() const; michael@0: void unref() const; michael@0: }; michael@0: michael@0: /** If T is const, the type returned from operator-> will also be const. */ michael@0: typedef typename SkTConstType, SkTIsConst::value>::type BlockRefType; michael@0: michael@0: /** michael@0: * SkAutoTUnref assumes ownership of the ref. As a result, it is an error michael@0: * for the user to ref or unref through SkAutoTUnref. Therefore michael@0: * SkAutoTUnref::operator-> returns BlockRef*. This prevents use of michael@0: * skAutoTUnrefInstance->ref() and skAutoTUnrefInstance->unref(). michael@0: */ michael@0: BlockRefType *operator->() const { michael@0: return static_cast(fObj); michael@0: } michael@0: operator T*() { return fObj; } michael@0: michael@0: private: michael@0: T* fObj; michael@0: }; michael@0: // Can't use the #define trick below to guard a bare SkAutoTUnref(...) because it's templated. :( michael@0: michael@0: class SkAutoUnref : public SkAutoTUnref { michael@0: public: michael@0: SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref(obj) {} michael@0: }; michael@0: #define SkAutoUnref(...) SK_REQUIRE_LOCAL_VAR(SkAutoUnref) michael@0: michael@0: class SkAutoRef : SkNoncopyable { michael@0: public: michael@0: SkAutoRef(SkRefCnt* obj) : fObj(obj) { SkSafeRef(obj); } michael@0: ~SkAutoRef() { SkSafeUnref(fObj); } michael@0: private: michael@0: SkRefCnt* fObj; michael@0: }; michael@0: #define SkAutoRef(...) SK_REQUIRE_LOCAL_VAR(SkAutoRef) michael@0: michael@0: /** Wrapper class for SkRefCnt pointers. This manages ref/unref of a pointer to michael@0: a SkRefCnt (or subclass) object. michael@0: */ michael@0: template class SkRefPtr { michael@0: public: michael@0: SkRefPtr() : fObj(NULL) {} michael@0: SkRefPtr(T* obj) : fObj(obj) { SkSafeRef(fObj); } michael@0: SkRefPtr(const SkRefPtr& o) : fObj(o.fObj) { SkSafeRef(fObj); } michael@0: ~SkRefPtr() { SkSafeUnref(fObj); } michael@0: michael@0: SkRefPtr& operator=(const SkRefPtr& rp) { michael@0: SkRefCnt_SafeAssign(fObj, rp.fObj); michael@0: return *this; michael@0: } michael@0: SkRefPtr& operator=(T* obj) { michael@0: SkRefCnt_SafeAssign(fObj, obj); michael@0: return *this; michael@0: } michael@0: michael@0: T* get() const { return fObj; } michael@0: T& operator*() const { return *fObj; } michael@0: T* operator->() const { return fObj; } michael@0: michael@0: typedef T* SkRefPtr::*unspecified_bool_type; michael@0: operator unspecified_bool_type() const { michael@0: return fObj ? &SkRefPtr::fObj : NULL; michael@0: } michael@0: michael@0: private: michael@0: T* fObj; michael@0: }; michael@0: michael@0: #endif