SkWeakRefCnt.h revision 15e9d3e66e161ce23df30bc13f8a0c87d196b463
1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkWeakRefCnt_DEFINED
9#define SkWeakRefCnt_DEFINED
10
11#include "SkRefCnt.h"
12#include "SkThread.h"
13
14/** \class SkWeakRefCnt
15
16    SkWeakRefCnt is the base class for objects that may be shared by multiple
17    objects. When an existing strong owner wants to share a reference, it calls
18    ref(). When a strong owner wants to release its reference, it calls
19    unref(). When the shared object's strong reference count goes to zero as
20    the result of an unref() call, its (virtual) weak_dispose method is called.
21    It is an error for the destructor to be called explicitly (or via the
22    object going out of scope on the stack or calling delete) if
23    getRefCnt() > 1.
24
25    In addition to strong ownership, an owner may instead obtain a weak
26    reference by calling weak_ref(). A call to weak_ref() must be balanced my a
27    call to weak_unref(). To obtain a strong reference from a weak reference,
28    call try_ref(). If try_ref() returns true, the owner's pointer is now also
29    a strong reference on which unref() must be called. Note that this does not
30    affect the original weak reference, weak_unref() must still be called. When
31    the weak reference count goes to zero, the object is deleted. While the
32    weak reference count is positive and the strong reference count is zero the
33    object still exists, but will be in the disposed state. It is up to the
34    object to define what this means.
35
36    Note that a strong reference implicitly implies a weak reference. As a
37    result, it is allowable for the owner of a strong ref to call try_ref().
38    This will have the same effect as calling ref(), but may be more expensive.
39
40    Example:
41
42    SkWeakRefCnt myRef = strongRef.weak_ref();
43    ... // strongRef.unref() may or may not be called
44    if (myRef.try_ref()) {
45        ... // use myRef
46        myRef.unref();
47    } else {
48        // myRef is in the disposed state
49    }
50    myRef.weak_unref();
51*/
52class SK_API SkWeakRefCnt : public SkRefCnt {
53public:
54    /** Default construct, initializing the reference counts to 1.
55        The strong references collectively hold one weak reference. When the
56        strong reference count goes to zero, the collectively held weak
57        reference is released.
58    */
59    SkWeakRefCnt() : SkRefCnt(), fWeakCnt(1) {}
60
61    /** Destruct, asserting that the weak reference count is 1.
62    */
63    virtual ~SkWeakRefCnt() {
64#ifdef SK_DEBUG
65        SkASSERT(fWeakCnt == 1);
66        fWeakCnt = 0;
67#endif
68    }
69
70    /** Return the weak reference count.
71    */
72    int32_t getWeakCnt() const { return fWeakCnt; }
73
74    void validate() const {
75        SkRefCnt::validate();
76        SkASSERT(fWeakCnt > 0);
77    }
78
79    /** Creates a strong reference from a weak reference, if possible. The
80        caller must already be an owner. If try_ref() returns true the owner
81        is in posession of an additional strong reference. Both the original
82        reference and new reference must be properly unreferenced. If try_ref()
83        returns false, no strong reference could be created and the owner's
84        reference is in the same state as before the call.
85    */
86    bool SK_WARN_UNUSED_RESULT try_ref() const {
87        if (sk_atomic_conditional_inc(&fRefCnt) != 0) {
88            // Aquire barrier (L/SL), if not provided above.
89            // Prevents subsequent code from happening before the increment.
90            sk_membar_aquire__after_atomic_conditional_inc();
91            return true;
92        }
93        return false;
94    }
95
96    /** Increment the weak reference count. Must be balanced by a call to
97        weak_unref().
98    */
99    void weak_ref() const {
100        SkASSERT(fRefCnt > 0);
101        SkASSERT(fWeakCnt > 0);
102        sk_atomic_inc(&fWeakCnt);  // No barrier required.
103    }
104
105    /** Decrement the weak reference count. If the weak reference count is 1
106        before the decrement, then call delete on the object. Note that if this
107        is the case, then the object needs to have been allocated via new, and
108        not on the stack.
109    */
110    void weak_unref() const {
111        SkASSERT(fWeakCnt > 0);
112        // Release barrier (SL/S), if not provided below.
113        if (sk_atomic_dec(&fWeakCnt) == 1) {
114            // Aquire barrier (L/SL), if not provided above.
115            // Prevents code in destructor from happening before the decrement.
116            sk_membar_aquire__after_atomic_dec();
117#ifdef SK_DEBUG
118            // so our destructor won't complain
119            fWeakCnt = 1;
120#endif
121            SkRefCnt::internal_dispose();
122        }
123    }
124
125    /** Returns true if there are no strong references to the object. When this
126        is the case all future calls to try_ref() will return false.
127    */
128    bool weak_expired() const {
129        return fRefCnt == 0;
130    }
131
132protected:
133    /** Called when the strong reference count goes to zero. This allows the
134        object to free any resources it may be holding. Weak references may
135        still exist and their level of allowed access to the object is defined
136        by the object's class.
137    */
138    virtual void weak_dispose() const {
139    }
140
141private:
142    /** Called when the strong reference count goes to zero. Calls weak_dispose
143        on the object and releases the implicit weak reference held
144        collectively by the strong references.
145    */
146    virtual void internal_dispose() const SK_OVERRIDE {
147        weak_dispose();
148        weak_unref();
149    }
150
151    /* Invariant: fWeakCnt = #weak + (fRefCnt > 0 ? 1 : 0) */
152    mutable int32_t fWeakCnt;
153
154    typedef SkRefCnt INHERITED;
155};
156
157#endif
158