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