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