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