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