• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 int32_t IncStrongRef() = 0;
30     virtual int32_t DecStrongRef() = 0;
31     virtual int32_t TryIncStrongRef() = 0;
32     virtual int32_t StrongRefCount() const = 0;
33     virtual int32_t IncWeakRef() = 0;
34     virtual int32_t 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     int32_t Increase()
47     {
48         int32_t count = count_.fetch_add(1, std::memory_order_relaxed) + 1;
49         ACE_DCHECK(count > 0);
50         return count;
51     }
Decrease()52     int32_t Decrease()
53     {
54         int32_t count = count_.fetch_sub(1, std::memory_order_release);
55         ACE_DCHECK(count > 0);
56         return count - 1;
57     }
CurrentCount()58     int32_t CurrentCount() const
59     {
60         return count_.load(std::memory_order_relaxed);
61     }
62 
63     // Try to increase reference count while current value is not zero.
TryIncrease()64     int32_t TryIncrease()
65     {
66         int32_t count = CurrentCount();
67         do {
68             if (count == 0) {
69                 return 0;
70             }
71             ACE_DCHECK(count > 0);
72         } while (!count_.compare_exchange_weak(count, count + 1, std::memory_order_relaxed));
73         return count + 1;
74     }
75 
76 private:
77     std::atomic<int32_t> count_ { 0 };
78 
79     ACE_DISALLOW_COPY_AND_MOVE(ThreadSafeCounter);
80 };
81 
82 // Define thread-unsafe counter.
83 class ThreadUnsafeCounter final {
84 public:
ThreadUnsafeCounter(int32_t count)85     explicit ThreadUnsafeCounter(int32_t count) : count_(count) {}
86     ~ThreadUnsafeCounter() = default;
87 
Increase()88     int32_t Increase()
89     {
90         int32_t count = ++count_;
91         ACE_DCHECK(count > 0);
92         return count;
93     }
Decrease()94     int32_t Decrease()
95     {
96         int32_t count = --count_;
97         ACE_DCHECK(count >= 0);
98         return count;
99     }
CurrentCount()100     int32_t CurrentCount() const
101     {
102         return count_;
103     }
104 
105     // Try to increase count while current value is not zero.
TryIncrease()106     int32_t TryIncrease()
107     {
108         return CurrentCount() == 0 ? 0 : Increase();
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     int32_t IncStrongRef() final
126     {
127         return strongRef_.Increase();
128     }
DecStrongRef()129     int32_t DecStrongRef() final
130     {
131         return strongRef_.Decrease();
132     }
TryIncStrongRef()133     int32_t TryIncStrongRef() final
134     {
135         return strongRef_.TryIncrease();
136     }
StrongRefCount()137     int32_t StrongRefCount() const final
138     {
139         return strongRef_.CurrentCount();
140     }
141 
IncWeakRef()142     int32_t IncWeakRef() final
143     {
144         return weakRef_.Increase();
145     }
DecWeakRef()146     int32_t 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         return refCount;
154     }
155 
156 private:
157     T strongRef_ { 0 };
158     // Weak reference count should start with 1,
159     // because instance MUST hold the reference counter for itself.
160     T weakRef_ { 1 };
161 };
162 
163 using ThreadSafeRef = RefCounterImpl<ThreadSafeCounter>;
164 using ThreadUnsafeRef = RefCounterImpl<ThreadUnsafeCounter>;
165 
166 } // namespace OHOS::Ace
167 
168 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_MEMORY_REF_COUNTER_H
169