• 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_REFERENCED_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BASE_MEMORY_REFERENCED_H
18 
19 #include <string>
20 
21 #include "base/memory/memory_monitor.h"
22 #include "base/memory/ref_counter.h"
23 #include "base/utils/macros.h"
24 
25 #define ACE_REMOVE(...)
26 
27 namespace OHOS::Ace {
28 
29 template<class T>
30 class RefPtr;
31 template<class T>
32 class WeakPtr;
33 
34 // Inherit this class to use 'RefPtr' and 'WeakPtr' to manage pointer of instance.
35 class Referenced {
36 public:
37     // Use raw pointer to construct 'RefPtr' and 'WeakPtr'.
38     template<class T>
Claim(T * rawPtr)39     static RefPtr<T> Claim(T* rawPtr)
40     {
41         if (MemoryMonitor::IsEnable()) {
42             MemoryMonitor::GetInstance().Update(rawPtr, static_cast<Referenced*>(rawPtr));
43         }
44         return RefPtr<T>(rawPtr);
45     }
46     template<class T>
WeakClaim(T * rawPtr)47     static WeakPtr<T> WeakClaim(T* rawPtr)
48     {
49         return WeakPtr<T>(rawPtr);
50     }
51 
52     // 'Referenced::MakeRefPtr' is used to create new instance inherited from 'Referenced',
53     // and manager its pointer using 'RefPtr'.
54     template<class T, class... Args>
MakeRefPtr(Args &&...args)55     static RefPtr<T> MakeRefPtr(Args&&... args)
56     {
57         return Claim(new T(std::forward<Args>(args)...));
58     }
59 
60     // Get raw pointer from 'RefPtr'.
61     template<class T>
RawPtr(const RefPtr<T> & ptr)62     static T* RawPtr(const RefPtr<T>& ptr)
63     {
64         return ptr.rawPtr_;
65     }
66 
IncRefCount()67     int32_t IncRefCount()
68     {
69         return refCounter_->IncStrongRef();
70     }
DecRefCount()71     int32_t DecRefCount()
72     {
73         int32_t refCount = refCounter_->DecStrongRef();
74         if (refCount == 0 && MaybeRelease()) {
75             // Release this instance, while its strong reference have reduced to zero.
76             delete this;
77         }
78         return refCount;
79     }
80 
RefCount()81     int32_t RefCount() const
82     {
83         return refCounter_->StrongRefCount();
84     }
85 
86 protected:
87     explicit Referenced(bool threadSafe = true)
88         : refCounter_(threadSafe ? ThreadSafeRef::Create() : ThreadUnsafeRef::Create())
89     {
90         if (MemoryMonitor::IsEnable()) {
91             MemoryMonitor::GetInstance().Add(this);
92         }
93     }
94 
~Referenced()95     virtual ~Referenced()
96     {
97         // Decrease weak reference count held by 'Referenced' itself.
98         refCounter_->DecWeakRef();
99         refCounter_ = nullptr;
100         if (MemoryMonitor::IsEnable()) {
101             MemoryMonitor::GetInstance().Remove(this);
102         }
103     }
104 
MaybeRelease()105     virtual bool MaybeRelease()
106     {
107         return true;
108     }
109 
110 private:
111     template<class T>
112     friend class RefPtr;
113     template<class T>
114     friend class WeakPtr;
115     // Forbid getting raw pointer from rvalue 'RefPtr'.
116     template<class T>
117     static T* RawPtr(const RefPtr<T>&& ptr) = delete;
118 
119     RefCounter* refCounter_ { nullptr };
120 
121     ACE_DISALLOW_COPY_AND_MOVE(Referenced);
122 };
123 
124 // Use reference count to manager instance inherited from 'Referenced'.
125 // Implicit conversion is necessary in some cases, so remove 'explicit' from construct function.
126 template<class T>
127 class RefPtr final {
128 public:
129     // Basic constructors.
130     RefPtr() = default;
RefPtr(std::nullptr_t)131     ACE_REMOVE(explicit) RefPtr(std::nullptr_t) {}
132     // Basic copy and move constructors.
RefPtr(const RefPtr & other)133     ACE_REMOVE(explicit) RefPtr(const RefPtr& other) : RefPtr(other.rawPtr_) {}
RefPtr(RefPtr && other)134     ACE_REMOVE(explicit) RefPtr(RefPtr&& other) : rawPtr_(other.rawPtr_)
135     {
136         other.rawPtr_ = nullptr;
137     }
138     // Construct instance by other 'RefPtr' that inherited from type 'T'.
139     template<class O>
ACE_REMOVE(explicit)140     ACE_REMOVE(explicit) RefPtr(const RefPtr<O>& other) : RefPtr(other.rawPtr_) {}
141     template<class O>
ACE_REMOVE(explicit)142     ACE_REMOVE(explicit) RefPtr(RefPtr<O>&& other) : rawPtr_(other.rawPtr_)
143     {
144         other.rawPtr_ = nullptr;
145     }
146 
~RefPtr()147     ~RefPtr()
148     {
149         if (rawPtr_ != nullptr) {
150             // Decrease strong reference count.
151             rawPtr_->DecRefCount();
152             rawPtr_ = nullptr;
153         }
154     }
155 
Swap(RefPtr & other)156     void Swap(RefPtr& other)
157     {
158         std::swap(rawPtr_, other.rawPtr_);
159     }
Swap(RefPtr && other)160     void Swap(RefPtr&& other)
161     {
162         Swap(other);
163     }
Reset()164     void Reset()
165     {
166         Swap(RefPtr());
167     }
168 
169     T* operator->() const
170     {
171         return rawPtr_;
172     }
173     T& operator*() const
174     {
175         ACE_DCHECK(rawPtr_ != nullptr);
176         return *rawPtr_;
177     }
178     operator bool() const
179     {
180         return rawPtr_ != nullptr;
181     }
182 
183     // Use 'Swap' to implement overloaded operator '='.
184     // Construct a temporary 'RefPtr' by different parameters to increase strong reference count of the new instance,
185     // swap with 'this', and then decrease strong reference of the old instance while destroying the temporary 'RefPtr'.
186     RefPtr& operator=(const RefPtr& other)
187     {
188         if (this != &other) {
189             Swap(RefPtr(other));
190         }
191         return *this;
192     }
193     RefPtr& operator=(RefPtr&& other)
194     {
195         if (this != &other) {
196             Swap(RefPtr(std::move(other)));
197         }
198         return *this;
199     }
200 
201     template<class O>
202     RefPtr& operator=(O* rawPtr)
203     {
204         Swap(RefPtr(rawPtr));
205         return *this;
206     }
207     template<class O>
208     RefPtr& operator=(const RefPtr<O>& other)
209     {
210         Swap(RefPtr(other));
211         return *this;
212     }
213     template<class O>
214     RefPtr& operator=(RefPtr<O>&& other)
215     {
216         Swap(RefPtr(std::move(other)));
217         return *this;
218     }
219 
220     // Comparing pointer of reference counter to implement Overloaded operator '==' and '!='.
221     template<class O>
222     bool operator==(const O* rawPtr) const
223     {
224         if (rawPtr_ == nullptr) {
225             return rawPtr == nullptr;
226         }
227         return rawPtr != nullptr && rawPtr_->refCounter_ == rawPtr->refCounter_;
228     }
229     template<class O>
230     bool operator!=(const O* rawPtr) const
231     {
232         return !operator==(rawPtr);
233     }
234 
235     template<class O>
236     bool operator==(const RefPtr<O>& other) const
237     {
238         return *this == other.rawPtr_;
239     }
240     template<class O>
241     bool operator!=(const RefPtr<O>& other) const
242     {
243         return !operator==(other);
244     }
245 
246     template<class O>
247     bool operator==(const WeakPtr<O>& weak) const
248     {
249         return weak == *this;
250     }
251     template<class O>
252     bool operator!=(const WeakPtr<O>& weak) const
253     {
254         return !operator==(weak);
255     }
256 
257     bool operator==(std::nullptr_t) const
258     {
259         return rawPtr_ == nullptr;
260     }
261     bool operator!=(std::nullptr_t) const
262     {
263         return rawPtr_ != nullptr;
264     }
265 
266     // Overload '<' is useful for 'std::map', 'std::set' and so on.
267     template<class O>
268     bool operator<(const RefPtr<O>& other) const
269     {
270         if (rawPtr_ == nullptr) {
271             return other.rawPtr_ != nullptr;
272         }
273         return other.rawPtr_ != nullptr && rawPtr_->refCounter_ < other.rawPtr_->refCounter_;
274     }
275 
276 private:
277     // Construct instance by raw pointer.
278     // 'WeakPtr' may construct 'RefPtr' without increasing its strong reference count,
279     // because strong reference count is already increased in 'WeakPtr' while upgrading.
280     // In that case, 'forceIncRef' should be 'false'.
rawPtr_(rawPtr)281     explicit RefPtr(T* rawPtr, bool forceIncRef = true) : rawPtr_(rawPtr)
282     {
283         if (rawPtr_ != nullptr && forceIncRef) {
284             // Increase strong reference count for holding instance.
285             rawPtr_->IncRefCount();
286         }
287     }
288 
289     friend class Referenced;
290     template<class O>
291     friend class RefPtr;
292     template<class O>
293     friend class WeakPtr;
294 
295     T* rawPtr_ { nullptr };
296 };
297 
298 // Working with 'RefPtr' to resolve 'circular reference'.
299 // Implicit conversion is necessary in some cases, so remove 'explicit' from construct function.
300 template<class T>
301 class WeakPtr final {
302 public:
303     // Basic constructors.
304     WeakPtr() = default;
WeakPtr(std::nullptr_t)305     ACE_REMOVE(explicit) WeakPtr(std::nullptr_t) {}
306     // Basic copy and move constructors.
WeakPtr(const WeakPtr & other)307     ACE_REMOVE(explicit) WeakPtr(const WeakPtr& other) : WeakPtr(other.unsafeRawPtr_, other.refCounter_) {}
WeakPtr(WeakPtr && other)308     ACE_REMOVE(explicit) WeakPtr(WeakPtr&& other) : unsafeRawPtr_(other.unsafeRawPtr_), refCounter_(other.refCounter_)
309     {
310         other.unsafeRawPtr_ = nullptr;
311         other.refCounter_ = nullptr;
312     }
313     // Construct instance by other 'WeakPtr' that inherited from type 'T'.
314     template<class O>
ACE_REMOVE(explicit)315     ACE_REMOVE(explicit) WeakPtr(const WeakPtr<O>& other) : WeakPtr(other.unsafeRawPtr_, other.refCounter_) {}
316     template<class O>
ACE_REMOVE(explicit)317     ACE_REMOVE(explicit) WeakPtr(WeakPtr<O>&& other)
318         : unsafeRawPtr_(other.unsafeRawPtr_), refCounter_(other.refCounter_)
319     {
320         other.unsafeRawPtr_ = nullptr;
321         other.refCounter_ = nullptr;
322     }
323     // Construct instance by 'RefPtr' that inherited from type 'T' or 'T' itself.
324     template<class O>
ACE_REMOVE(explicit)325     ACE_REMOVE(explicit) WeakPtr(const RefPtr<O>& other) : WeakPtr(other.rawPtr_) {}
WeakPtr(const RefPtr<T> & other)326     ACE_REMOVE(explicit) WeakPtr(const RefPtr<T>& other) : WeakPtr(other.rawPtr_) {}
327 
~WeakPtr()328     ~WeakPtr()
329     {
330         // Decrease weak reference count while releasing reference counter.
331         if (refCounter_ != nullptr) {
332             refCounter_->DecWeakRef();
333             refCounter_ = nullptr;
334             unsafeRawPtr_ = nullptr;
335         }
336     }
337 
Swap(WeakPtr & other)338     void Swap(WeakPtr& other)
339     {
340         std::swap(unsafeRawPtr_, other.unsafeRawPtr_);
341         std::swap(refCounter_, other.refCounter_);
342     }
Swap(WeakPtr && other)343     void Swap(WeakPtr&& other)
344     {
345         Swap(other);
346     }
Reset()347     void Reset()
348     {
349         Swap(WeakPtr());
350     }
351 
Upgrade()352     RefPtr<T> Upgrade() const
353     {
354         // A 'WeakPtr' could upgrade to 'RefPtr' if this instance is still alive.
355         return refCounter_ != nullptr && refCounter_->TryIncStrongRef() > 0 ? RefPtr<T>(unsafeRawPtr_, false) : nullptr;
356     }
Invalid()357     bool Invalid() const
358     {
359         return refCounter_ == nullptr || refCounter_->StrongRefCount() == 0;
360     }
361 
362     // Use 'Swap' to implement overloaded operator '=', just like 'RefPtr'.
363     WeakPtr& operator=(const WeakPtr& other)
364     {
365         if (this != &other) {
366             Swap(WeakPtr(other));
367         }
368         return *this;
369     }
370     WeakPtr& operator=(WeakPtr&& other)
371     {
372         if (this != &other) {
373             Swap(WeakPtr(std::move(other)));
374         }
375         return *this;
376     }
377 
378     template<class O>
379     WeakPtr& operator=(O* rawPtr)
380     {
381         Swap(WeakPtr(rawPtr));
382         return *this;
383     }
384     template<class O>
385     WeakPtr& operator=(const WeakPtr<O>& other)
386     {
387         Swap(WeakPtr(other));
388         return *this;
389     }
390     template<class O>
391     WeakPtr& operator=(WeakPtr<O>&& other)
392     {
393         Swap(WeakPtr(std::move(other)));
394         return *this;
395     }
396     template<class O>
397     WeakPtr& operator=(const RefPtr<O>& other)
398     {
399         Swap(WeakPtr(other.rawPtr_));
400         return *this;
401     }
402 
403     // Comparing pointer of reference counter to implement Overloaded operator '==' and '!=', just like 'RefPtr'.
404     template<class O>
405     bool operator==(const O* rawPtr) const
406     {
407         if (refCounter_ == nullptr) {
408             return rawPtr == nullptr;
409         }
410         return rawPtr != nullptr && refCounter_ == rawPtr->refCounter_;
411     }
412     template<class O>
413     bool operator!=(const O* rawPtr) const
414     {
415         return !operator==(rawPtr);
416     }
417 
418     template<class O>
419     bool operator==(const WeakPtr<O>& other) const
420     {
421         return refCounter_ == other.refCounter_;
422     }
423     template<class O>
424     bool operator!=(const WeakPtr<O>& other) const
425     {
426         return !operator==(other);
427     }
428 
429     template<class O>
430     bool operator==(const RefPtr<O>& strong) const
431     {
432         return strong.rawPtr_ != nullptr ? strong.rawPtr_->refCounter_ == refCounter_ : refCounter_ == nullptr;
433     }
434     template<class O>
435     bool operator!=(const RefPtr<O>& strong) const
436     {
437         return !operator==(strong);
438     }
439 
440     // Overload '<' is useful for 'std::map', 'std::set' and so on, just like 'RefPtr'.
441     template<class O>
442     bool operator<(const WeakPtr<O>& other) const
443     {
444         return refCounter_ < other.refCounter_;
445     }
446 
447 private:
448     // Construct instance by raw pointer.
WeakPtr(T * rawPtr)449     explicit WeakPtr(T* rawPtr) : WeakPtr(rawPtr, rawPtr != nullptr ? rawPtr->refCounter_ : nullptr) {}
450     template<class O>
WeakPtr(O * rawPtr,RefCounter * aceRef)451     WeakPtr(O* rawPtr, RefCounter* aceRef) : unsafeRawPtr_(rawPtr), refCounter_(aceRef)
452     {
453         if (refCounter_) {
454             refCounter_->IncWeakRef();
455         }
456     }
457 
458     friend class Referenced;
459     template<class O>
460     friend class WeakPtr;
461 
462     // Notice: Raw pointer of instance is kept, but NEVER use it except succeed to upgrade to 'RefPtr'.
463     T* unsafeRawPtr_ { nullptr };
464     RefCounter* refCounter_ { nullptr };
465 };
466 
467 } // namespace OHOS::Ace
468 
469 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_MEMORY_REFERENCED_H
470