1 /*---------------------------------------------------------------------------* 2 Project: NintendoWare 3 File: ut_SharedPtr.h 4 5 Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain proprietary 8 information of Nintendo and/or its licensed developers and are protected by 9 national and international copyright laws. They may not be disclosed to third 10 parties or copied or duplicated in any form, in whole or in part, without the 11 prior written consent of Nintendo. 12 13 The content herein is highly confidential and should be handled accordingly. 14 15 $Revision: 31311 $ 16 *---------------------------------------------------------------------------*/ 17 18 #ifndef NW_UT_SHAREDPTR_H_ 19 #define NW_UT_SHAREDPTR_H_ 20 21 #include <nw/types.h> 22 #include <nw/os/os_Memory.h> 23 #include <nw/os/os_Mutex.h> 24 #include <nw/ut/ut_Lock.h> 25 26 namespace nw { 27 namespace ut { 28 29 typedef nw::os::NullLockObject DefaultLockObject; 30 31 //! @details :private 32 //--------------------------------------------------------------------------- 33 //! @brief シェアードポインタのカウンタクラスです。 34 //--------------------------------------------------------------------------- 35 template <typename TLockObject = DefaultLockObject> 36 class SharedPtrCount 37 { 38 public: 39 //--------------------------------------------------------------------------- 40 //! @brief 参照カウントを生成します。 41 //! 42 //! @param[out] pAllocator メモリを確保するアロケータです。 43 //! 44 //! @return 生成した参照カウントクラスのインスタンスです。 45 //--------------------------------------------------------------------------- 46 static SharedPtrCount* Create( nw::os::IAllocator* pAllocator = NULL ) 47 { 48 if ( pAllocator ) 49 { 50 void* buf = pAllocator->Alloc( sizeof(SharedPtrCount) ); 51 return new(buf) SharedPtrCount( pAllocator ); 52 } 53 else 54 { 55 return new SharedPtrCount( NULL ); 56 } 57 } 58 59 //--------------------------------------------------------------------------- 60 //! @brief 参照カウントを破棄します。 61 //--------------------------------------------------------------------------- Destroy()62 void Destroy() 63 { 64 if ( m_pAllocator ) 65 { 66 this->~SharedPtrCount(); 67 m_pAllocator->Free( this ); 68 } 69 else 70 { 71 delete this; 72 } 73 } 74 75 //--------------------------------------------------------------------------- 76 //! @brief 参照カウントをインクリメントします。 77 //--------------------------------------------------------------------------- AddRef()78 void AddRef() 79 { 80 internal::AutoLock<TLockObject> lock(m_LockObject); 81 ++m_Use; 82 } 83 84 //--------------------------------------------------------------------------- 85 //! @brief 参照カウントが 0 でない場合に、参照カウントをインクリメントします。 86 //! 87 //! @return インクリメントに成功した場合は true、失敗した場合は false を返します。 88 //--------------------------------------------------------------------------- TestAddRef()89 bool TestAddRef() 90 { 91 internal::AutoLock<TLockObject> lock(m_LockObject); 92 93 if (m_Use == 0) // 既にオブジェクトは破棄している 94 { 95 return false; 96 } 97 else 98 { 99 ++m_Use; 100 return true; 101 } 102 } 103 104 //--------------------------------------------------------------------------- 105 //! @brief 参照カウントをデクリメントします。 106 //! 107 //! @return 残りの参照カウント数です。 108 //--------------------------------------------------------------------------- Release()109 s32 Release() 110 { 111 internal::AutoLock<TLockObject> lock(m_LockObject); 112 113 return --m_Use; 114 } 115 116 //--------------------------------------------------------------------------- 117 //! @brief 弱参照のカウントをインクリメントします。 118 //--------------------------------------------------------------------------- WeakAddRef()119 void WeakAddRef() 120 { 121 internal::AutoLock<TLockObject> lock(m_LockObject); 122 123 ++m_Weak; 124 } 125 126 //--------------------------------------------------------------------------- 127 //! @brief 弱参照のカウントをデクリメントします。 128 //! 129 //! @return 残りの弱参照カウントです。 130 //--------------------------------------------------------------------------- WeakRelease()131 s32 WeakRelease() 132 { 133 internal::AutoLock<TLockObject> lock(m_LockObject); 134 135 return --m_Weak; 136 } 137 138 private: 139 140 //--------------------------------------------------------------------------- 141 //! @brief コンストラクタです。 142 //! 143 //! @param[out] pAllocator 破棄時に利用するアロケータです。 144 //--------------------------------------------------------------------------- SharedPtrCount(nw::os::IAllocator * pAllocator)145 /* ctor */ SharedPtrCount( nw::os::IAllocator* pAllocator ) 146 : m_Use( 0 ), 147 m_Weak( 0 ), 148 m_pAllocator( pAllocator ) 149 { 150 } 151 152 //--------------------------------------------------------------------------- 153 //! @brief デストラクタです。 154 //--------------------------------------------------------------------------- ~SharedPtrCount()155 /* dtor */ ~SharedPtrCount() 156 { 157 } 158 159 //--------------------------------------------------------------------------- 160 //! @brief 参照カウントを取得します。 161 //! 162 //! @return 参照カウント数です。 163 //--------------------------------------------------------------------------- GetUseCount()164 s32 GetUseCount() const { return m_Use; } 165 166 //--------------------------------------------------------------------------- 167 //! @brief 弱参照のカウントを取得します。 168 //! 169 //! @return 弱参照のカウント数です。 170 //--------------------------------------------------------------------------- GetWeakCount()171 s32 GetWeakCount() const { return m_Weak; } 172 173 s32 m_Use; 174 s32 m_Weak; 175 nw::os::IAllocator* m_pAllocator; 176 177 TLockObject m_LockObject; 178 template <typename U, typename ULockObject> friend class SharedPtr; 179 }; 180 181 template <typename Obj, typename TLockObject = DefaultLockObject> class WeakPtr; 182 183 //-------------------------------------------------------------------------- 184 //! @brief 参照カウント式のシェアードポインタクラスです。 185 //! 186 //! @details このクラスを継承して使用する事は非サポートです。 187 //--------------------------------------------------------------------------- 188 template <typename TObj, typename TLockObject = DefaultLockObject> 189 class SharedPtr 190 { 191 public: SharedPtr()192 /* ctor */ SharedPtr() : m_pObj( NULL ), m_pCnt( NULL ), m_pAllocator( NULL ) {} 193 194 //--------------------------------------------------------------------------- 195 //! @brief コンストラクタです。 196 //! 197 //! @param[out] pObj シェアードポインタを作成するオブジェクトのポインタです。 198 //! @param[out] pAllocator メモリを開放するポインタです。 199 //! @param[out] pCnt 参照カウント用オブジェクトです。 200 //--------------------------------------------------------------------------- 201 /* ctor */ explicit SharedPtr(TObj* pObj, nw::os::IAllocator* pAllocator = NULL, SharedPtrCount<TLockObject>* pCnt = NULL) m_pObj(pObj)202 : m_pObj( pObj ), 203 m_pCnt( pCnt ), 204 m_pAllocator( pAllocator ) 205 { 206 if ( pObj == NULL ) 207 { 208 m_pCnt = NULL; 209 return; 210 } 211 212 if ( m_pCnt == NULL ) 213 { 214 m_pCnt = SharedPtrCount<TLockObject>::Create( pAllocator ); 215 } 216 m_pCnt->AddRef(); 217 m_pCnt->WeakAddRef(); 218 } 219 220 //--------------------------------------------------------------------------- 221 //! @brief コピーコンストラクタです。 222 //! 223 //! @param[in] other コピー元のシェアードポインタです。 224 //--------------------------------------------------------------------------- SharedPtr(const SharedPtr & other)225 /* ctor */ /* implicit */ SharedPtr(const SharedPtr& other) 226 : m_pObj( other.m_pObj ), 227 m_pCnt( other.m_pCnt ), 228 m_pAllocator( other.m_pAllocator ) 229 { 230 if (m_pCnt) 231 { 232 m_pCnt->AddRef(); 233 } 234 } 235 236 //--------------------------------------------------------------------------- 237 //! @brief コピーコンストラクタです。 238 //! 239 //! @param[in] other コピー元のシェアードポインタです。 240 //--------------------------------------------------------------------------- 241 template <typename Y> 242 /* ctor */ /* implicit */ SharedPtr<TObj, TLockObject>(const SharedPtr<Y, TLockObject>& other) 243 : m_pObj( other.m_pObj ), 244 m_pCnt( other.m_pCnt ), 245 m_pAllocator( other.m_pAllocator ) 246 { 247 if (m_pCnt) 248 { 249 m_pCnt->AddRef(); 250 } 251 } 252 253 //--------------------------------------------------------------------------- 254 //! @brief コピーコンストラクタです。 255 //! 256 //! @param[in] other コピー元のウィークポインタです。 257 //--------------------------------------------------------------------------- SharedPtr(const WeakPtr<TObj,TLockObject> & other)258 /* ctor */ explicit SharedPtr(const WeakPtr<TObj, TLockObject>& other) 259 : m_pObj( other.m_pObj ), 260 m_pCnt( other.m_pCnt ), 261 m_pAllocator( other.m_pAllocator ) 262 { 263 if (m_pCnt && m_pCnt->TestAddRef()) 264 { 265 } 266 else 267 { 268 m_pCnt = NULL; 269 m_pObj = NULL; 270 m_pAllocator = NULL; 271 } 272 } 273 274 //--------------------------------------------------------------------------- 275 //! @brief デストラクタです。 276 //--------------------------------------------------------------------------- ~SharedPtr()277 /* dtor */ ~SharedPtr() 278 { 279 if ( m_pCnt ) 280 { 281 if ( ! m_pCnt->Release() ) 282 { 283 if ( m_pAllocator ) 284 { 285 m_pObj->~TObj(); 286 m_pAllocator->Free( m_pObj ); 287 } 288 else 289 { 290 delete m_pObj; 291 } 292 293 if ( ! m_pCnt->WeakRelease() ) 294 { 295 m_pCnt->Destroy(); 296 } 297 } 298 } 299 } 300 301 //--------------------------------------------------------------------------- 302 //! @brief 代入演算子です。 303 //! 304 //! @param[in] other コピー元のシェアードポインタです。 305 //! 306 //! @return コピー先への参照を返します。 307 //--------------------------------------------------------------------------- 308 SharedPtr& operator = (const SharedPtr& other) 309 { 310 SharedPtr(other).SwapObjPtr(*this); 311 return * this; 312 } 313 314 //--------------------------------------------------------------------------- 315 //! @brief 代入演算子です。 316 //! 317 //! @param[in] other コピー元のシェアードポインタです。 318 //! 319 //! @return コピー先への参照を返します。 320 //--------------------------------------------------------------------------- 321 template <typename U> 322 SharedPtr<TObj, TLockObject>& operator = (const SharedPtr<U, TLockObject>& other) 323 { 324 SharedPtr(other).SwapObjPtr(*this); 325 return * this; 326 } 327 328 //--------------------------------------------------------------------------- 329 //! @brief シェアードポインタの参照先をリセットします。 330 //! 331 //! @param[out] pObj シェアードポインタを作成するオブジェクトのポインタです。 332 //! @param[out] pAllocator メモリを開放するポインタです。 333 //! @param[out] pCnt 参照カウント用オブジェクトです。 334 //! 335 //! @return リセットを実行したシェアードポインタの参照を返します。 336 //--------------------------------------------------------------------------- 337 SharedPtr& Reset(TObj* pObj = NULL, nw::os::IAllocator* pAllocator = NULL, SharedPtrCount<TLockObject>* pCnt = NULL) 338 { 339 SharedPtr(pObj, pAllocator, pCnt).SwapObjPtr(*this); 340 return *this; 341 } 342 343 //--------------------------------------------------------------------------- 344 //! @brief 参照しているオブジェクトを取得します。 345 //! 346 //! @return 参照しているオブジェクトのポインタです。 347 //--------------------------------------------------------------------------- Get()348 TObj* Get() const { return m_pObj; } 349 350 //--------------------------------------------------------------------------- 351 //! @brief 参照しているオブジェクトを取得します。 352 //! 353 //! @return 参照しているオブジェクトのリファレンスです。 354 //--------------------------------------------------------------------------- 355 TObj& operator * () const { NW_NULL_ASSERT( m_pObj ); return *m_pObj; } 356 357 //--------------------------------------------------------------------------- 358 //! @brief 参照しているオブジェクトを取得します。 359 //! 360 //! @return 参照しているオブジェクトのポインタです。 361 //--------------------------------------------------------------------------- 362 TObj* operator -> () const { NW_NULL_ASSERT( m_pObj ); return m_pObj; } 363 364 //--------------------------------------------------------------------------- 365 //! @brief 参照しているオブジェクトが NULL でないかどうかを取得します。 366 //! 367 //! @return 参照しているオブジェクトが NULL であれば false, それ以外の場合は true を返します。 368 //--------------------------------------------------------------------------- 369 operator bool () const { return NULL != m_pObj; } 370 371 // デバッグ用 372 //--------------------------------------------------------------------------- 373 //! @brief デバッグ用関数です。参照カウントの値を取得します。 374 //! 375 //! @return 参照カウントの値です。 376 //--------------------------------------------------------------------------- RefCount()377 s32 RefCount() const 378 { 379 if (m_pCnt == NULL) { return 0; } 380 return m_pCnt->GetUseCount(); 381 } 382 383 private: 384 385 //--------------------------------------------------------------------------- 386 //! @brief ポインタの指す先をスワップする関数です。 387 //! 388 //! @param[out] other スワップ対象のシェアードポインタです。 389 //--------------------------------------------------------------------------- SwapObjPtr(SharedPtr & other)390 void SwapObjPtr(SharedPtr& other) 391 { 392 std::swap( m_pObj, other.m_pObj ); 393 std::swap( m_pCnt, other.m_pCnt ); 394 std::swap( m_pAllocator, other.m_pAllocator ); 395 } 396 397 TObj* m_pObj; 398 SharedPtrCount<TLockObject>* m_pCnt; 399 nw::os::IAllocator* m_pAllocator; 400 401 template <typename U, typename ULockObject> friend class SharedPtr; 402 template <typename U, typename ULockObject> friend class WeakPtr; 403 }; 404 405 //---------------------------------------- 406 //! @name スマートポインタ操作関連 407 //@{ 408 409 //--------------------------------------------------------------------------- 410 //! @brief SharedPtr が同じかどうかを判定します。 411 //! 412 //! @param[in] a 比較対象となる1つ目のオブジェクトです。 413 //! @param[in] b 比較対象となる2つ目のオブジェクトです。 414 //! 415 //! @return ポインタが等しい場合は true、異なる場合は false を返します。 416 //--------------------------------------------------------------------------- 417 template <class T, class U, typename TLockObject> 418 NW_INLINE bool 419 operator==(SharedPtr<T, TLockObject> const & a, SharedPtr<U, TLockObject> const & b) 420 { 421 return a.Get() == b.Get(); 422 } 423 424 //--------------------------------------------------------------------------- 425 //! @brief SharedPtr が異なるかどうかを判定します。 426 //! 427 //! @param[in] a 比較対象となる1つ目のオブジェクトです。 428 //! @param[in] b 比較対象となる2つ目のオブジェクトです。 429 //! 430 //! @return ポインタが異なる場合は true、等しい場合は false を返します。 431 //--------------------------------------------------------------------------- 432 template <class T, class U, typename TLockObject> 433 NW_INLINE bool 434 operator!=(SharedPtr<T, TLockObject> const & a, SharedPtr<U, TLockObject> const & b) 435 { 436 return ! (a == b); 437 } 438 439 //@} 440 441 //-------------------------------------------------------------------------- 442 //! @brief SharedPtr への弱参照クラスです。 443 //! 444 //! @details このクラスを継承して使用する事は非サポートです。 445 //--------------------------------------------------------------------------- 446 template <typename TObj, typename TLockObject> 447 class WeakPtr 448 { 449 public: 450 //--------------------------------------------------------------------------- 451 //! @brief コンストラクタです。 452 //--------------------------------------------------------------------------- WeakPtr()453 /* ctor */ WeakPtr() : m_pObj( NULL ), m_pCnt( NULL ), m_pAllocator( NULL ) 454 { 455 } 456 457 //--------------------------------------------------------------------------- 458 //! @brief コピーコンストラクタです。 459 //! 460 //! @param[in] other コピー元のシェアードポインタです。 461 //--------------------------------------------------------------------------- 462 template <typename U> 463 /* ctor */ /* implicit */ WeakPtr<TObj, TLockObject>(const SharedPtr<U, TLockObject>& other) 464 : m_pObj( other.m_pObj ), 465 m_pCnt( other.m_pCnt ), 466 m_pAllocator( other.m_pAllocator ) 467 { 468 if (m_pCnt) 469 { 470 m_pCnt->WeakAddRef(); 471 } 472 } 473 474 //--------------------------------------------------------------------------- 475 //! @brief コピーコンストラクタです。 476 //! 477 //! @param[in] other コピー元のウィークポインタです。 478 //--------------------------------------------------------------------------- WeakPtr(const WeakPtr & other)479 /* ctor */ /* implicit */ WeakPtr(const WeakPtr& other) 480 : m_pObj( other.m_pObj ), 481 m_pCnt( other.m_pCnt ), 482 m_pAllocator( other.m_pAllocator ) 483 { 484 if (m_pCnt) 485 { 486 m_pCnt->WeakAddRef(); 487 } 488 } 489 490 //--------------------------------------------------------------------------- 491 //! @brief コピーコンストラクタです。 492 //! 493 //! @param[in] other コピー元のウィークポインタです。 494 //--------------------------------------------------------------------------- 495 template <typename U> 496 /* ctor */ /* implicit */ WeakPtr<TObj, TLockObject>(const WeakPtr<U, TLockObject>& other) 497 : m_pObj( other.m_pObj ), 498 m_pCnt( other.m_pCnt ), 499 m_pAllocator( other.m_pAllocator ) 500 { 501 if (m_pCnt) 502 { 503 m_pCnt->WeakAddRef(); 504 } 505 } 506 507 //--------------------------------------------------------------------------- 508 //! @brief デストラクタです。 509 //--------------------------------------------------------------------------- ~WeakPtr()510 /* dtor */ ~WeakPtr() 511 { 512 if ( m_pCnt ) 513 { 514 if ( ! m_pCnt->WeakRelease() ) 515 { 516 m_pCnt->Destroy(); 517 } 518 } 519 } 520 521 //--------------------------------------------------------------------------- 522 //! @brief ウィークポインタからシェアードポインタを取得します。 523 //! 524 //! @return 生成したシェアードポインタです。 525 //--------------------------------------------------------------------------- Lock()526 SharedPtr<TObj, TLockObject> Lock() const 527 { 528 return SharedPtr<TObj, TLockObject>(*this); 529 } 530 531 //--------------------------------------------------------------------------- 532 //! @brief ウィークポインタの参照先をリセットします。 533 //! 534 //! @return リセットを実行したウィークポインタを返します。 535 //--------------------------------------------------------------------------- Reset()536 WeakPtr& Reset() 537 { 538 WeakPtr().SwapObjPtr(*this); 539 return *this; 540 } 541 542 //--------------------------------------------------------------------------- 543 //! @brief 代入演算子です。 544 //! 545 //! @return コピー先のウィークポインタです。 546 //--------------------------------------------------------------------------- 547 template <class U> 548 WeakPtr& operator = (const SharedPtr<U, TLockObject>& rhs) 549 { 550 WeakPtr(rhs).SwapObjPtr(*this); 551 return *this; 552 } 553 554 //--------------------------------------------------------------------------- 555 //! @brief 代入演算子です。 556 //! 557 //! @param[in] other コピー元のウィークポインタです。 558 //--------------------------------------------------------------------------- 559 WeakPtr& operator = (const WeakPtr& other) 560 { 561 WeakPtr(other).SwapObjPtr(*this); 562 return *this; 563 } 564 565 //--------------------------------------------------------------------------- 566 //! @brief 代入演算子です。 567 //! 568 //! @param[in] other コピー元のウィークポインタです。 569 //--------------------------------------------------------------------------- 570 template <class U> 571 WeakPtr& operator = (const WeakPtr<U, TLockObject>& other) 572 { 573 WeakPtr(other).SwapObjPtr(*this); 574 return *this; 575 } 576 577 private: 578 579 //--------------------------------------------------------------------------- 580 //! @brief ポインタの指す先をスワップする関数です。 581 //! 582 //! @param[out] other スワップ対象のウィークポインタです。 583 //--------------------------------------------------------------------------- SwapObjPtr(WeakPtr & other)584 void SwapObjPtr(WeakPtr& other) 585 { 586 std::swap( m_pObj, other.m_pObj ); 587 std::swap( m_pCnt, other.m_pCnt ); 588 std::swap( m_pAllocator, other.m_pAllocator ); 589 } 590 591 TObj* m_pObj; 592 SharedPtrCount<TLockObject>* m_pCnt; 593 nw::os::IAllocator* m_pAllocator; 594 595 template <typename U, typename ULockObject> friend class SharedPtr; 596 template <typename U, typename ULockObject> friend class WeakPtr; 597 }; 598 599 } // namespace ut 600 } // namespace nw 601 602 #endif // NW_UT_SHAREDPTR_H_ 603