1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef FOUNDATION_ACE_FRAMEWORKS_BASE_MEMORY_REF_COUNTER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BASE_MEMORY_REF_COUNTER_H
18 
19 #include <atomic>
20 
21 #include "base/utils/macros.h"
22 #include "base/utils/noncopyable.h"
23 
24 namespace OHOS::Ace {
25 
26 // Reference counter.
27 class RefCounter {
28 public:
29     virtual void IncStrongRef() = 0;
30     virtual int32_t DecStrongRef() = 0;
31     virtual bool TryIncStrongRef() = 0;
32     virtual int32_t StrongRefCount() const = 0;
33     virtual void IncWeakRef() = 0;
34     virtual void DecWeakRef() = 0;
35 
36 protected:
37     virtual ~RefCounter() = default;
38 };
39 
40 // Define thread-safe counter using 'std::atomic' to implement Increase/Decrease count.
41 class ThreadSafeCounter final {
42 public:
ThreadSafeCounter(int32_t count)43     explicit ThreadSafeCounter(int32_t count) : count_(count) {}
44     ~ThreadSafeCounter() = default;
45 
Increase()46     void Increase()
47     {
48         count_.fetch_add(1, std::memory_order_relaxed);
49     }
Decrease()50     int32_t Decrease()
51     {
52         int32_t count = count_.fetch_sub(1, std::memory_order_release);
53         ACE_DCHECK(count > 0);
54         return count - 1;
55     }
CurrentCount()56     int32_t CurrentCount() const
57     {
58         return count_.load(std::memory_order_relaxed);
59     }
60 
61     // Try to increase reference count while current value is not zero.
TryIncrease()62     bool TryIncrease()
63     {
64         int32_t count = CurrentCount();
65         do {
66             if (count == 0) {
67                 return false;
68             }
69             ACE_DCHECK(count > 0);
70         } while (!count_.compare_exchange_weak(count, count + 1, std::memory_order_relaxed));
71         return true;
72     }
73 
74 private:
75     std::atomic<int32_t> count_ { 0 };
76 
77     ACE_DISALLOW_COPY_AND_MOVE(ThreadSafeCounter);
78 };
79 
80 // Define thread-unsafe counter.
81 class ThreadUnsafeCounter final {
82 public:
ThreadUnsafeCounter(int32_t count)83     explicit ThreadUnsafeCounter(int32_t count) : count_(count) {}
84     ~ThreadUnsafeCounter() = default;
85 
Increase()86     void Increase()
87     {
88         ++count_;
89     }
Decrease()90     int32_t Decrease()
91     {
92         int32_t count = --count_;
93         ACE_DCHECK(count >= 0);
94         return count;
95     }
CurrentCount()96     int32_t CurrentCount() const
97     {
98         return count_;
99     }
100 
101     // Try to increase count while current value is not zero.
TryIncrease()102     bool TryIncrease()
103     {
104         if (CurrentCount() == 0) {
105             return false;
106         }
107         Increase();
108         return true;
109     }
110 
111 private:
112     int32_t count_ { 0 };
113 
114     ACE_DISALLOW_COPY_AND_MOVE(ThreadUnsafeCounter);
115 };
116 
117 template<class T>
118 class RefCounterImpl final : public RefCounter {
119 public:
Create()120     static RefCounter* Create()
121     {
122         return new RefCounterImpl();
123     }
124 
IncStrongRef()125     void IncStrongRef() final
126     {
127         strongRef_.Increase();
128     }
DecStrongRef()129     int32_t DecStrongRef() final
130     {
131         return strongRef_.Decrease();
132     }
TryIncStrongRef()133     bool TryIncStrongRef() final
134     {
135         return strongRef_.TryIncrease();
136     }
StrongRefCount()137     int32_t StrongRefCount() const final
138     {
139         return strongRef_.CurrentCount();
140     }
141 
IncWeakRef()142     void IncWeakRef() final
143     {
144         weakRef_.Increase();
145     }
DecWeakRef()146     void DecWeakRef() final
147     {
148         int32_t refCount = weakRef_.Decrease();
149         if (refCount == 0) {
150             // Release this reference counter, while its weak reference have reduced to zero.
151             delete this;
152         }
153     }
154 
155 private:
156     T strongRef_ { 0 };
157     // Weak reference count should start with 1,
158     // because instance MUST hold the reference counter for itself.
159     T weakRef_ { 1 };
160 };
161 
162 using ThreadSafeRef = RefCounterImpl<ThreadSafeCounter>;
163 using ThreadUnsafeRef = RefCounterImpl<ThreadUnsafeCounter>;
164 
165 } // namespace OHOS::Ace
166 
167 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_MEMORY_REF_COUNTER_H
168