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