SkRefCnt.h revision 40528743dbb9ce7f39f093e0cdc47849ac8887cf
10910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*
20910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
30910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *
40910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
50910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * you may not use this file except in compliance with the License.
60910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * You may obtain a copy of the License at
70910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *
80910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * See the License for the specific language governing permissions and
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * limitations under the License.
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */
160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifndef SkRefCnt_DEFINED
180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define SkRefCnt_DEFINED
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkThread.h"
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/** \class SkRefCnt
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkRefCnt is the base class for objects that may be shared by multiple
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    objects. When a new owner wants a reference, it calls ref(). When an owner
260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    wants to release its reference, it calls unref(). When the shared object's
270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    reference count goes to zero as the result of an unref() call, its (virtual)
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    destructor is called. It is an error for the destructor to be called
290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    explicitly (or via the object going out of scope on the stack or calling
300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    delete) if getRefCnt() > 1.
310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkRefCnt : SkNoncopyable {
330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /** Default construct, initializing the reference count to 1.
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkRefCnt() : fRefCnt(1) {}
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /**  Destruct, asserting that the reference count is 1.
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    virtual ~SkRefCnt() { SkASSERT(fRefCnt == 1); }
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /** Return the reference count.
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int32_t getRefCnt() const { return fRefCnt; }
450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /** Increment the reference count. Must be balanced by a call to unref().
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void ref() const {
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(fRefCnt > 0);
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        sk_atomic_inc(&fRefCnt);
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /** Decrement the reference count. If the reference count is 1 before the
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        decrement, then call delete on the object. Note that if this is the
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case, then the object needs to have been allocated via new, and not on
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        the stack.
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void unref() const {
590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(fRefCnt > 0);
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (sk_atomic_dec(&fRefCnt) == 1) {
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fRefCnt = 1;    // so our destructor won't complain
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkDELETE(this);
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate:
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    mutable int32_t fRefCnt;
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/** \class SkAutoUnref
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoUnref is a stack-helper class that will automatically call unref() on
730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    the object it points to when the SkAutoUnref object goes out of scope.
740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    If obj is null, do nothing.
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkAutoUnref : SkNoncopyable {
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoUnref(SkRefCnt* obj) : fObj(obj) {}
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    ~SkAutoUnref();
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkRefCnt*   get() const { return fObj; }
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /** If the hosted object is null, do nothing and return false, else call
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        ref() on it and return true
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool        ref();
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /** If the hosted object is null, do nothing and return false, else call
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unref() on it, set its reference to null, and return true
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool        unref();
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /** If the hosted object is null, do nothing and return NULL, else call
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unref() on it, set its reference to null, and return the object
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkRefCnt*   detach();
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate:
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkRefCnt*   fObj;
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    null in on each side of the assignment, and ensuring that ref() is called
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    before unref(), in case the two pointers point to the same object.
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define SkRefCnt_SafeAssign(dst, src)   \
1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    do {                                \
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (src) src->ref();            \
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (dst) dst->unref();          \
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst = src;                      \
1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } while (0)
1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
115dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed
116dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed/** Check if the argument is non-null, and if so, call obj->ref()
117dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed */
118dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reedtemplate <typename T> static inline void SkSafeRef(T* obj) {
119dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed    if (obj) {
120dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed        obj->ref();
121dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed    }
122dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed}
123dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed
124dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed/** Check if the argument is non-null, and if so, call obj->unref()
125dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed */
126dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reedtemplate <typename T> static inline void SkSafeUnref(T* obj) {
127dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed    if (obj) {
128dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed        obj->unref();
129dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed    }
130dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed}
131dab163f0b2658c2dba48839e72f81d3d8ee0ae8bMike Reed
13240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger/** Wrapper class for SkRefCnt pointers. This manages ref/unref of a pointer to
13340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    a SkRefCnt (or subclass) object.
13440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger */
13540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergertemplate <typename T> class SkRefPtr {
13640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergerpublic:
13740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkRefPtr() : fObj(NULL) {}
13840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkRefPtr(T* obj) : fObj(obj) { SkSafeRef(fObj); }
13940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkRefPtr(const SkRefPtr& o) : fObj(o.fObj) { SkSafeRef(fObj); }
14040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    ~SkRefPtr() { SkSafeUnref(fObj); }
14140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
14240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkRefPtr& operator=(const SkRefPtr& rp) {
14340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        SkRefCnt_SafeAssign(fObj, rp.fObj);
14440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        return *this;
14540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
14640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkRefPtr& operator=(T* obj) {
14740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        SkRefCnt_SafeAssign(fObj, obj);
14840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        return *this;
14940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
15040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
15140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    bool operator==(const SkRefPtr& rp) const { return fObj == rp.fObj; }
15240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    bool operator==(const T* obj) const { return fObj == obj; }
15340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    bool operator!=(const SkRefPtr& rp) const { return fObj != rp.fObj; }
15440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    bool operator!=(const T* obj) const { return fObj != obj; }
15540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
15640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    T* get() const { return fObj; }
15740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    T& operator*() const { return *fObj; }
15840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    T* operator->() const { return fObj; }
15940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    bool operator!() const { return !fObj; }
16040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
16140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    typedef T* SkRefPtr::*unspecified_bool_type;
16240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    operator unspecified_bool_type() const { return fObj ? &SkRefPtr::fObj : NULL; }
16340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
16440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergerprivate:
16540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    T* fObj;
16640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger};
16740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
16840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergertemplate <typename T>
16940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergerinline bool operator==(T* obj, const SkRefPtr<T>& rp) {
17040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    return obj == rp.get();
17140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger}
17240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
17340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergertemplate <typename T>
17440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergerinline bool operator!=(T* obj, const SkRefPtr<T>& rp) {
17540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    return obj != rp.get();
17640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger}
17740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
180