1 /*
2  * Copyright (c) 2022 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 UTILS_BASE_REFBASE_H
17 #define UTILS_BASE_REFBASE_H
18 
19 #include <atomic>
20 #include <functional>
21 
22 namespace OHOS {
23 #define INITIAL_PRIMARY_VALUE (1 << 28)
24 class RefBase;
25 class RefCounter {
26 public:
27     using RefPtrCallback = std::function<void()>;
28 
29     RefCounter();
30 
31     explicit RefCounter(RefCounter *counter);
32 
33     RefCounter &operator=(const RefCounter &counter);
34 
35     virtual ~RefCounter();
36 
37     void SetCallback(const RefPtrCallback &callback);
38 
39     void RemoveCallback();
40 
41     int GetRefCount();
42 
43     void IncRefCount();
44 
45     void DecRefCount();
46 
47     bool IsRefPtrValid();
48 
49     int IncStrongRefCount(const void *objectId);
50 
51     int DecStrongRefCount(const void *objectId);
52 
53     int GetStrongRefCount();
54 
55     int IncWeakRefCount(const void *objectId);
56 
57     int DecWeakRefCount(const void *objectId);
58 
59     int GetWeakRefCount();
60 
61     void SetAttemptAcquire();
62 
63     bool IsAttemptAcquireSet();
64 
65     void ClearAttemptAcquire();
66 
67     bool AttemptIncStrongRef(const void *objectId, int &outCount);
68 
69     bool IsLifeTimeExtended();
70 
71     void ExtendObjectLifetime();
72 
73 private:
74     std::atomic<int> atomicStrong_;
75     std::atomic<int> atomicWeak_;
76     std::atomic<int> atomicRefCount_;
77     std::atomic<unsigned int> atomicFlags_;
78     std::atomic<int> atomicAttempt_;
79     RefPtrCallback callback_ = nullptr;
80     static constexpr unsigned int FLAG_EXTEND_LIFE_TIME = 0x00000002;
81 };
82 
83 class WeakRefCounter {
84 public:
85     WeakRefCounter(RefCounter *counter, void *cookie);
86 
87     virtual ~WeakRefCounter();
88 
89     void *GetRefPtr();
90 
91     void IncWeakRefCount(const void *objectId);
92 
93     void DecWeakRefCount(const void *objectId);
94 
95     bool AttemptIncStrongRef(const void *objectId);
96 
97 private:
98     std::atomic<int> atomicWeak_;
99     RefCounter *refCounter_ = nullptr;
100     void *cookie_ = nullptr;
101 };
102 
103 class RefBase {
104 public:
105     RefBase();
106 
107     RefBase(const RefBase &other);
108 
109     RefBase &operator=(const RefBase &other);
110 
111     RefBase(RefBase &&other) noexcept;
112 
113     RefBase &operator=(RefBase &&other) noexcept;
114 
115     virtual ~RefBase();
116 
117     virtual void RefPtrCallback();
118 
119     void ExtendObjectLifetime();
120 
121     void IncStrongRef(const void *objectId);
122 
123     void DecStrongRef(const void *objectId);
124 
125     int GetSptrRefCount();
126 
127     WeakRefCounter *CreateWeakRef(void *cookie);
128 
129     void IncWeakRef(const void *objectId);
130 
131     void DecWeakRef(const void *objectId);
132 
133     int GetWptrRefCount();
134 
135     bool AttemptAcquire(const void *objectId);
136 
137     bool AttemptIncStrongRef(const void *objectId);
138 
139     bool IsAttemptAcquireSet();
140 
141     bool IsExtendLifeTimeSet();
142 
143     virtual void OnFirstStrongRef(const void *objectId);
144 
145     virtual void OnLastStrongRef(const void *objectId);
146 
147     virtual void OnLastWeakRef(const void *objectId);
148 
149     virtual bool OnAttemptPromoted(const void *objectId);
150 
151 private:
152     RefCounter *refs_ = nullptr;
153 };
154 
155 template<typename T> class wptr;
156 
157 template<typename T>
158 
159 class sptr {
160     friend class wptr<T>;
161 
162 public:
163     sptr();
164 
165     ~sptr();
166 
167     sptr(T *other);
168 
169     sptr(const sptr<T> &other);
170 
171     sptr(sptr<T> &&other);
172 
173     sptr<T> &operator=(sptr<T> &&other);
174 
175     template<typename O> sptr(const sptr<O> &other);
176 
177     inline sptr(WeakRefCounter *p, bool force);
178 
GetRefPtr()179     inline T *GetRefPtr() const
180     {
181         return refs_;
182     }
183 
184     inline void ForceSetRefPtr(T *other);
185 
186     void clear();
187 
188     inline operator T *() const
189     {
190         return refs_;
191     }
192 
193     inline T &operator*() const
194     {
195         return *refs_;
196     }
197 
198     inline T *operator->() const
199     {
200         return refs_;
201     }
202 
203     inline bool operator!() const
204     {
205         return refs_ == nullptr;
206     }
207 
208     sptr<T> &operator=(T *other);
209 
210     sptr<T> &operator=(const sptr<T> &other);
211 
212     sptr<T> &operator=(const wptr<T> &other);
213 
214     template<typename O> sptr<T> &operator=(const sptr<O> &other);
215 
216     bool operator==(const T *other) const;
217 
218     inline bool operator!=(const T *other) const
219     {
220         return !operator==(other);
221     }
222 
223     bool operator==(const wptr<T> &other) const;
224 
225     inline bool operator!=(const wptr<T> &other) const
226     {
227         return !operator==(other);
228     }
229 
230     bool operator==(const sptr<T> &other) const;
231 
232     inline bool operator!=(const sptr<T> &other) const
233     {
234         return !operator==(other);
235     }
236 
237 private:
238     T *refs_ = nullptr;
239 };
240 
ForceSetRefPtr(T * other)241 template<typename T> inline void sptr<T>::ForceSetRefPtr(T *other)
242 {
243     refs_ = other;
244 }
245 
sptr()246 template<typename T> inline sptr<T>::sptr()
247 {
248     refs_ = nullptr;
249 }
250 
sptr(T * other)251 template<typename T> inline sptr<T>::sptr(T *other)
252 {
253     refs_ = other;
254 }
255 
sptr(const sptr<T> & other)256 template<typename T> inline sptr<T>::sptr(const sptr<T> &other)
257 {
258     refs_ = other.GetRefPtr();
259     if (refs_ != nullptr) {
260         refs_->IncStrongRef(this);
261     }
262 }
263 
sptr(sptr<T> && other)264 template<typename T> sptr<T>::sptr(sptr<T> &&other)
265 {
266     refs_ = other.GetRefPtr();
267     other.ForceSetRefPtr(nullptr);
268 }
269 
270 template<typename T> sptr<T> &sptr<T>::operator=(sptr<T> &&other)
271 {
272     if (refs_ != nullptr) {
273         refs_->DecStrongRef(this);
274     }
275     refs_ = other.GetRefPtr();
276     other.ForceSetRefPtr(nullptr);
277     return *this;
278 }
279 
sptr(const sptr<O> & other)280 template<typename T> template<typename O> sptr<T>::sptr(const sptr<O> &other) : refs_(other.GetRefPtr())
281 {
282     if (refs_ != nullptr) {
283         refs_->IncStrongRef(this);
284     }
285 }
286 
287 template<typename T> inline sptr<T> &sptr<T>::operator=(T *other)
288 {
289     if (other != nullptr) {
290         other->IncStrongRef(this);
291     }
292 
293     if (refs_ != nullptr) {
294         refs_->DecStrongRef(this);
295     }
296 
297     refs_ = other;
298     return *this;
299 }
300 
301 template<typename T> inline sptr<T> &sptr<T>::operator=(const sptr<T> &other)
302 {
303     T *otherRef(other.GetRefPtr());
304     if (otherRef != nullptr) {
305         otherRef->IncStrongRef(this);
306     }
307 
308     if (refs_ != nullptr) {
309         refs_->DecStrongRef(this);
310     }
311 
312     refs_ = otherRef;
313     return *this;
314 }
315 
316 template<typename T> inline sptr<T> &sptr<T>::operator=(const wptr<T> &other)
317 {
318     if ((other != nullptr) && other.AttemptIncStrongRef(this)) {
319         refs_ = other.GetRefPtr();
320     } else {
321         refs_ = nullptr;
322     }
323 
324     return *this;
325 }
326 
327 template<typename T> template<typename O> sptr<T> &sptr<T>::operator=(const sptr<O> &other)
328 {
329     T *otherRef(other.GetRefPtr());
330     if (otherRef != nullptr) {
331         otherRef->IncStrongRef(this);
332     }
333 
334     if (refs_ != nullptr) {
335         refs_->DecStrongRef(this);
336     }
337 
338     refs_ = otherRef;
339     return *this;
340 }
341 
342 template<typename T> inline bool sptr<T>::operator==(const T *other) const
343 {
344     return other == refs_;
345 }
346 
347 template<typename T> inline bool sptr<T>::operator==(const wptr<T> &other) const
348 {
349     return refs_ == other.GetRefPtr();
350 }
351 
352 template<typename T> inline bool sptr<T>::operator==(const sptr<T> &other) const
353 {
354     return refs_ == other.GetRefPtr();
355 }
356 
clear()357 template<typename T> void sptr<T>::clear()
358 {
359     if (refs_) {
360         refs_->DecStrongRef(this);
361         refs_ = 0;
362     }
363 }
364 
~sptr()365 template<typename T> inline sptr<T>::~sptr()
366 {
367     if (refs_ != nullptr) {
368         refs_->DecStrongRef(this);
369     }
370 }
371 
sptr(WeakRefCounter * p,bool)372 template<typename T> inline sptr<T>::sptr(WeakRefCounter *p, bool /* force */)
373 {
374     if ((p != nullptr) && p->AttemptIncStrongRef(this)) {
375         refs_ = reinterpret_cast<T *>(p->GetRefPtr());
376     } else {
377         refs_ = nullptr;
378     }
379 }
380 
381 template<typename T> class wptr {
382     template<typename O> friend class wptr;
383 
384 public:
385     wptr();
386 
387     wptr(T *other);
388 
389     wptr(const wptr<T> &other);
390 
391     wptr(const sptr<T> &other);
392 
393     template<typename O> wptr(const wptr<O> &other);
394 
395     template<typename O> wptr(const sptr<O> &other);
396 
397     wptr<T> &operator=(T *other);
398 
399     template<typename O> wptr<T> &operator=(O *other);
400 
401     wptr<T> &operator=(const wptr<T> &other);
402 
403     wptr<T> &operator=(const sptr<T> &other);
404 
405     template<typename O> wptr<T> &operator=(const wptr<O> &other);
406 
407     template<typename O> wptr<T> &operator=(const sptr<O> &other);
408 
409     inline T *operator*() const
410     {
411         return *refs_;
412     }
413     inline T *operator->() const
414     {
415         return reinterpret_cast<T *>(refs_->GetRefPtr());
416     }
417 
418     bool operator==(const T *other) const;
419 
420     inline bool operator!=(const T *other) const
421     {
422         return !operator==(other);
423     };
424 
425     bool operator==(const wptr<T> &other) const;
426 
427     inline bool operator!=(const wptr<T> &other) const
428     {
429         return !operator==(other);
430     }
431 
432     bool operator==(const sptr<T> &other) const;
433 
434     inline bool operator!=(const sptr<T> &other) const
435     {
436         return !operator==(other);
437     }
438 
439     T *GetRefPtr() const;
440 
AttemptIncStrongRef(const void * objectId)441     inline bool AttemptIncStrongRef(const void *objectId) const
442     {
443         return refs_->AttemptIncStrongRef(objectId);
444     }
445 
446     const sptr<T> promote() const;
447 
448     ~wptr();
449 
450 private:
451     WeakRefCounter *refs_ = nullptr;
452 };
453 
GetRefPtr()454 template<typename T> inline T *wptr<T>::GetRefPtr() const
455 {
456     return (refs_ != nullptr) ? reinterpret_cast<T *>(refs_->GetRefPtr()) : nullptr;
457 }
458 
wptr()459 template<typename T> wptr<T>::wptr()
460 {
461     refs_ = nullptr;
462 }
463 
wptr(T * other)464 template<typename T> wptr<T>::wptr(T *other)
465 {
466     if (other != nullptr) {
467         refs_ = other->CreateWeakRef(other);
468         if (refs_ != nullptr) {
469             refs_->IncWeakRefCount(this);
470         }
471     } else {
472         refs_ = nullptr;
473     }
474 }
475 
wptr(const wptr<T> & other)476 template<typename T> wptr<T>::wptr(const wptr<T> &other)
477 {
478     refs_ = other.refs_;
479     if (refs_ != nullptr) {
480         refs_->IncWeakRefCount(this);
481     }
482 }
483 
wptr(const sptr<T> & other)484 template<typename T> wptr<T>::wptr(const sptr<T> &other)
485 {
486     if (other.GetRefPtr() != nullptr) {
487         refs_ = other->CreateWeakRef(other.GetRefPtr());
488         if (refs_ != nullptr) {
489             refs_->IncWeakRefCount(this);
490         }
491     }
492 }
493 
wptr(const wptr<O> & other)494 template<typename T> template<typename O> wptr<T>::wptr(const wptr<O> &other)
495 {
496     refs_ = other.refs_;
497     if (refs_ != nullptr) {
498         refs_->IncWeakRefCount(this);
499     }
500 }
501 
wptr(const sptr<O> & other)502 template<typename T> template<typename O> wptr<T>::wptr(const sptr<O> &other)
503 {
504     if (other.GetRefPtr() != nullptr) {
505         refs_ = other->CreateWeakRef(other.GetRefPtr());
506         if (refs_ != nullptr) {
507             refs_->IncWeakRefCount(this);
508         }
509     }
510 }
511 
512 template<typename T> wptr<T> &wptr<T>::operator=(T *other)
513 {
514     WeakRefCounter *newWeakRef = nullptr;
515     if (other != nullptr) {
516         newWeakRef = other->CreateWeakRef(other);
517         if (newWeakRef != nullptr) {
518             newWeakRef->IncWeakRefCount(this);
519         }
520     }
521 
522     if (refs_ != nullptr) {
523         refs_->DecWeakRefCount(this);
524     }
525 
526     refs_ = newWeakRef;
527     return *this;
528 }
529 
530 template<typename T> template<typename O> wptr<T> &wptr<T>::operator=(O *other)
531 {
532     T *object = reinterpret_cast<T *>(other);
533     WeakRefCounter *newWeakRef = nullptr;
534     if (object != nullptr) {
535         newWeakRef = object->CreateWeakRef(object);
536         if (newWeakRef != nullptr) {
537             newWeakRef->IncWeakRefCount(this);
538         }
539     }
540 
541     if (refs_ != nullptr) {
542         refs_->DecWeakRefCount(this);
543     }
544 
545     refs_ = newWeakRef;
546     return *this;
547 }
548 
549 template<typename T> inline wptr<T> &wptr<T>::operator=(const wptr<T> &other)
550 {
551     if (other.refs_ != nullptr) {
552         other.refs_->IncWeakRefCount(this);
553     }
554 
555     if (refs_ != nullptr) {
556         refs_->DecWeakRefCount(this);
557     }
558 
559     refs_ = other.refs_;
560     return *this;
561 }
562 
563 template<typename T> inline wptr<T> &wptr<T>::operator=(const sptr<T> &other)
564 {
565     WeakRefCounter *newWeakRef = nullptr;
566     if (other.GetRefPtr() != nullptr) {
567         newWeakRef = other->CreateWeakRef(other.GetRefPtr());
568         if (newWeakRef != nullptr) {
569             newWeakRef->IncWeakRefCount(this);
570         }
571     }
572 
573     if (refs_ != nullptr) {
574         refs_->DecWeakRefCount(this);
575     }
576 
577     refs_ = newWeakRef;
578     return *this;
579 }
580 
581 template<typename T> template<typename O> wptr<T> &wptr<T>::operator=(const wptr<O> &other)
582 {
583     if (other.refs_ != nullptr) {
584         other.refs_->IncWeakRefCount(this);
585     }
586 
587     if (refs_ != nullptr) {
588         refs_->DecWeakRefCount(this);
589     }
590 
591     refs_ = other.refs_;
592     return *this;
593 }
594 
595 template<typename T> template<typename O> wptr<T> &wptr<T>::operator=(const sptr<O> &other)
596 {
597     WeakRefCounter *newWeakRef = nullptr;
598     if (other.GetRefPtr() != nullptr) {
599         newWeakRef = other->CreateWeakRef(other->GetRefPtr());
600         if (newWeakRef != nullptr) {
601             newWeakRef->IncWeakRefCount(this);
602         }
603     }
604 
605     if (refs_ != nullptr) {
606         refs_->DecWeakRefCount(this);
607     }
608 
609     refs_ = newWeakRef;
610     return *this;
611 }
612 
613 template<typename T> inline bool wptr<T>::operator==(const T *other) const
614 {
615     return GetRefPtr() == other;
616 }
617 
618 template<typename T> inline bool wptr<T>::operator==(const wptr<T> &other) const
619 {
620     return GetRefPtr() == other.GetRefPtr();
621 }
622 
623 template<typename T> inline bool wptr<T>::operator==(const sptr<T> &other) const
624 {
625     return GetRefPtr() == other.GetRefPtr();
626 }
627 
promote()628 template<typename T> inline const sptr<T> wptr<T>::promote() const
629 {
630     return sptr<T>(refs_, true);
631 }
632 
~wptr()633 template<typename T> inline wptr<T>::~wptr()
634 {
635     if (refs_ != nullptr) {
636         refs_->DecWeakRefCount(this);
637     }
638 }
639 } // namespace OHOS
640 #endif
641