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