/*---------------------------------------------------------------------------* Project: NintendoWare File: ut_SharedPtr.h Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 30202 $ *---------------------------------------------------------------------------*/ #ifndef NW_UT_SHAREDPTR_H_ #define NW_UT_SHAREDPTR_H_ #include #include #include #include namespace nw { namespace ut { typedef nw::os::NullLockObject DefaultLockObject; //! @details :private //--------------------------------------------------------------------------- //! @brief シェアードポインタのカウンタクラスです。 //--------------------------------------------------------------------------- template class SharedPtrCount { public: //--------------------------------------------------------------------------- //! @brief 参照カウントを生成します。 //! //! @param[out] pAllocator メモリを確保するアロケータです。 //! //! @return 生成した参照カウントクラスのインスタンスです。 //--------------------------------------------------------------------------- static SharedPtrCount* Create( nw::os::IAllocator* pAllocator = NULL ) { if ( pAllocator ) { void* buf = pAllocator->Alloc( sizeof(SharedPtrCount) ); return new(buf) SharedPtrCount( pAllocator ); } else { return new SharedPtrCount( NULL ); } } //--------------------------------------------------------------------------- //! @brief 参照カウントを破棄します。 //--------------------------------------------------------------------------- void Destroy() { if ( m_pAllocator ) { this->~SharedPtrCount(); m_pAllocator->Free( this ); } else { delete this; } } //--------------------------------------------------------------------------- //! @brief 参照カウントをインクリメントします。 //--------------------------------------------------------------------------- void AddRef() { internal::AutoLock lock(m_LockObject); ++m_Use; } //--------------------------------------------------------------------------- //! @brief 参照カウントが 0 でない場合に、参照カウントをインクリメントします。 //! //! @return インクリメントに成功した場合は true、失敗した場合は false を返します。 //--------------------------------------------------------------------------- bool TestAddRef() { internal::AutoLock lock(m_LockObject); if (m_Use == 0) // 既にオブジェクトは破棄している { return false; } else { ++m_Use; return true; } } //--------------------------------------------------------------------------- //! @brief 参照カウントをデクリメントします。 //! //! @return 残りの参照カウント数です。 //--------------------------------------------------------------------------- s32 Release() { internal::AutoLock lock(m_LockObject); return --m_Use; } //--------------------------------------------------------------------------- //! @brief 弱参照のカウントをインクリメントします。 //--------------------------------------------------------------------------- void WeakAddRef() { internal::AutoLock lock(m_LockObject); ++m_Weak; } //--------------------------------------------------------------------------- //! @brief 弱参照のカウントをデクリメントします。 //! //! @return 残りの弱参照カウントです。 //--------------------------------------------------------------------------- s32 WeakRelease() { internal::AutoLock lock(m_LockObject); return --m_Weak; } private: //--------------------------------------------------------------------------- //! @brief コンストラクタです。 //! //! @param[out] pAllocator 破棄時に利用するアロケータです。 //--------------------------------------------------------------------------- /* ctor */ SharedPtrCount( nw::os::IAllocator* pAllocator ) : m_Use( 0 ), m_Weak( 0 ), m_pAllocator( pAllocator ) { } //--------------------------------------------------------------------------- //! @brief デストラクタです。 //--------------------------------------------------------------------------- /* dtor */ ~SharedPtrCount() { } //--------------------------------------------------------------------------- //! @brief 参照カウントを取得します。 //! //! @return 参照カウント数です。 //--------------------------------------------------------------------------- s32 GetUseCount() const { return m_Use; } //--------------------------------------------------------------------------- //! @brief 弱参照のカウントを取得します。 //! //! @return 弱参照のカウント数です。 //--------------------------------------------------------------------------- s32 GetWeakCount() const { return m_Weak; } s32 m_Use; s32 m_Weak; nw::os::IAllocator* m_pAllocator; TLockObject m_LockObject; template friend class SharedPtr; }; template class WeakPtr; //-------------------------------------------------------------------------- //! @brief 参照カウント式のシェアードポインタクラスです。 //! //! @details このクラスを継承して使用する事は非サポートです。 //--------------------------------------------------------------------------- template class SharedPtr { public: /* ctor */ SharedPtr() : m_pObj( NULL ), m_pCnt( NULL ), m_pAllocator( NULL ) {} //--------------------------------------------------------------------------- //! @brief コンストラクタです。 //! //! @param[out] pObj シェアードポインタを作成するオブジェクトのポインタです。 //! @param[out] pAllocator メモリを開放するポインタです。 //! @param[out] pCnt 参照カウント用オブジェクトです。 //--------------------------------------------------------------------------- /* ctor */ explicit SharedPtr(TObj* pObj, nw::os::IAllocator* pAllocator = NULL, SharedPtrCount* pCnt = NULL) : m_pObj( pObj ), m_pCnt( pCnt ), m_pAllocator( pAllocator ) { if ( pObj == NULL ) { m_pCnt = NULL; return; } if ( m_pCnt == NULL ) { m_pCnt = SharedPtrCount::Create( pAllocator ); } m_pCnt->AddRef(); m_pCnt->WeakAddRef(); } //--------------------------------------------------------------------------- //! @brief コピーコンストラクタです。 //! //! @param[in] other コピー元のシェアードポインタです。 //--------------------------------------------------------------------------- /* ctor */ /* implicit */ SharedPtr(const SharedPtr& other) : m_pObj( other.m_pObj ), m_pCnt( other.m_pCnt ), m_pAllocator( other.m_pAllocator ) { if (m_pCnt) { m_pCnt->AddRef(); } } //--------------------------------------------------------------------------- //! @brief コピーコンストラクタです。 //! //! @param[in] other コピー元のシェアードポインタです。 //--------------------------------------------------------------------------- template /* ctor */ /* implicit */ SharedPtr(const SharedPtr& other) : m_pObj( other.m_pObj ), m_pCnt( other.m_pCnt ), m_pAllocator( other.m_pAllocator ) { if (m_pCnt) { m_pCnt->AddRef(); } } //--------------------------------------------------------------------------- //! @brief コピーコンストラクタです。 //! //! @param[in] other コピー元のウィークポインタです。 //--------------------------------------------------------------------------- /* ctor */ explicit SharedPtr(const WeakPtr& other) : m_pObj( other.m_pObj ), m_pCnt( other.m_pCnt ), m_pAllocator( other.m_pAllocator ) { if (m_pCnt && m_pCnt->TestAddRef()) { } else { m_pCnt = NULL; m_pObj = NULL; m_pAllocator = NULL; } } //--------------------------------------------------------------------------- //! @brief デストラクタです。 //--------------------------------------------------------------------------- /* dtor */ ~SharedPtr() { if ( m_pCnt ) { if ( ! m_pCnt->Release() ) { if ( m_pAllocator ) { m_pObj->~TObj(); m_pAllocator->Free( m_pObj ); } else { delete m_pObj; } if ( ! m_pCnt->WeakRelease() ) { m_pCnt->Destroy(); } } } } //--------------------------------------------------------------------------- //! @brief 代入演算子です。 //! //! @param[in] other コピー元のシェアードポインタです。 //! //! @return コピー先への参照を返します。 //--------------------------------------------------------------------------- SharedPtr& operator = (const SharedPtr& other) { SharedPtr(other).SwapObjPtr(*this); return * this; } //--------------------------------------------------------------------------- //! @brief 代入演算子です。 //! //! @param[in] other コピー元のシェアードポインタです。 //! //! @return コピー先への参照を返します。 //--------------------------------------------------------------------------- template SharedPtr& operator = (const SharedPtr& other) { SharedPtr(other).SwapObjPtr(*this); return * this; } //--------------------------------------------------------------------------- //! @brief シェアードポインタの参照先をリセットします。 //! //! @param[out] pObj シェアードポインタを作成するオブジェクトのポインタです。 //! @param[out] pAllocator メモリを開放するポインタです。 //! @param[out] pCnt 参照カウント用オブジェクトです。 //! //! @return リセットを実行したシェアードポインタの参照を返します。 //--------------------------------------------------------------------------- SharedPtr& Reset(TObj* pObj = NULL, nw::os::IAllocator* pAllocator = NULL, SharedPtrCount* pCnt = NULL) { SharedPtr(pObj, pAllocator, pCnt).SwapObjPtr(*this); return *this; } //--------------------------------------------------------------------------- //! @brief 参照しているオブジェクトを取得します。 //! //! @return 参照しているオブジェクトのポインタです。 //--------------------------------------------------------------------------- TObj* Get() const { return m_pObj; } //--------------------------------------------------------------------------- //! @brief 参照しているオブジェクトを取得します。 //! //! @return 参照しているオブジェクトのリファレンスです。 //--------------------------------------------------------------------------- TObj& operator * () const { NW_NULL_ASSERT( m_pObj ); return *m_pObj; } //--------------------------------------------------------------------------- //! @brief 参照しているオブジェクトを取得します。 //! //! @return 参照しているオブジェクトのポインタです。 //--------------------------------------------------------------------------- TObj* operator -> () const { NW_NULL_ASSERT( m_pObj ); return m_pObj; } //--------------------------------------------------------------------------- //! @brief 参照しているオブジェクトが NULL でないかどうかを取得します。 //! //! @return 参照しているオブジェクトが NULL であれば false, それ以外の場合は true を返します。 //--------------------------------------------------------------------------- operator bool () const { return NULL != m_pObj; } // デバッグ用 //--------------------------------------------------------------------------- //! @brief デバッグ用関数です。参照カウントの値を取得します。 //! //! @return 参照カウントの値です。 //--------------------------------------------------------------------------- s32 RefCount() const { if (m_pCnt == NULL) { return 0; } return m_pCnt->GetUseCount(); } private: //--------------------------------------------------------------------------- //! @brief ポインタの指す先をスワップする関数です。 //! //! @param[out] other スワップ対象のシェアードポインタです。 //--------------------------------------------------------------------------- void SwapObjPtr(SharedPtr& other) { std::swap( m_pObj, other.m_pObj ); std::swap( m_pCnt, other.m_pCnt ); std::swap( m_pAllocator, other.m_pAllocator ); } TObj* m_pObj; SharedPtrCount* m_pCnt; nw::os::IAllocator* m_pAllocator; template friend class SharedPtr; template friend class WeakPtr; }; //---------------------------------------- //! @name スマートポインタ操作関連 //@{ //--------------------------------------------------------------------------- //! @brief SharedPtr が同じかどうかを判定します。 //! //! @param[in] a 比較対象となる1つ目のオブジェクトです。 //! @param[in] b 比較対象となる2つ目のオブジェクトです。 //! //! @return ポインタが等しい場合は true、異なる場合は false を返します。 //--------------------------------------------------------------------------- template NW_INLINE bool operator==(SharedPtr const & a, SharedPtr const & b) { return a.Get() == b.Get(); } //--------------------------------------------------------------------------- //! @brief SharedPtr が異なるかどうかを判定します。 //! //! @param[in] a 比較対象となる1つ目のオブジェクトです。 //! @param[in] b 比較対象となる2つ目のオブジェクトです。 //! //! @return ポインタが異なる場合は true、等しい場合は false を返します。 //--------------------------------------------------------------------------- template NW_INLINE bool operator!=(SharedPtr const & a, SharedPtr const & b) { return ! (a == b); } //@} //-------------------------------------------------------------------------- //! @brief SharedPtr への弱参照クラスです。 //! //! @details このクラスを継承して使用する事は非サポートです。 //--------------------------------------------------------------------------- template class WeakPtr { public: //--------------------------------------------------------------------------- //! @brief コンストラクタです。 //--------------------------------------------------------------------------- /* ctor */ WeakPtr() : m_pObj( NULL ), m_pCnt( NULL ), m_pAllocator( NULL ) { } //--------------------------------------------------------------------------- //! @brief コピーコンストラクタです。 //! //! @param[in] other コピー元のシェアードポインタです。 //--------------------------------------------------------------------------- template /* ctor */ /* implicit */ WeakPtr(const SharedPtr& other) : m_pObj(other.m_pObj), m_pCnt(other.m_pCnt), m_pAllocator(other.m_pAllocator) { if (m_pCnt) { m_pCnt->WeakAddRef(); } } //--------------------------------------------------------------------------- //! @brief コピーコンストラクタです。 //! //! @param[in] other コピー元のウィークポインタです。 //--------------------------------------------------------------------------- template /* ctor */ /* implicit */ WeakPtr(const WeakPtr& other) : m_pObj(other.m_pObj), m_pCnt(other.m_pCnt), m_pAllocator(other.m_pAllocator) { if (m_pCnt) { m_pCnt->WeakAddRef(); } } //--------------------------------------------------------------------------- //! @brief デストラクタです。 //--------------------------------------------------------------------------- /* dtor */ ~WeakPtr() { if ( m_pCnt ) { if ( ! m_pCnt->WeakRelease() ) { m_pCnt->Destroy(); } } } //--------------------------------------------------------------------------- //! @brief ウィークポインタからシェアードポインタを取得します。 //! //! @return 生成したシェアードポインタです。 //--------------------------------------------------------------------------- SharedPtr Lock() const { return SharedPtr(*this); } //--------------------------------------------------------------------------- //! @brief 代入演算子です。 //! //! @return コピー先のウィークポインタです。 //--------------------------------------------------------------------------- template WeakPtr& operator = (const SharedPtr& rhs) { WeakPtr(rhs).SwapObjPtr(*this); return *this; } //--------------------------------------------------------------------------- //! @brief 代入演算子です。 //! //! @param[in] other コピー元のウィークポインタです。 //--------------------------------------------------------------------------- template WeakPtr& operator = (const WeakPtr& other) { WeakPtr(other).SwapObjPtr(*this); return *this; } private: //--------------------------------------------------------------------------- //! @brief ポインタの指す先をスワップする関数です。 //! //! @param[out] other スワップ対象のウィークポインタです。 //--------------------------------------------------------------------------- void SwapObjPtr(WeakPtr& other) { std::swap( m_pObj, other.m_pObj ); std::swap( m_pCnt, other.m_pCnt ); std::swap( m_pAllocator, other.m_pAllocator ); } TObj* m_pObj; SharedPtrCount* m_pCnt; nw::os::IAllocator* m_pAllocator; template friend class SharedPtr; template friend class WeakPtr; }; } // namespace ut } // namespace nw #endif // NW_UT_SHAREDPTR_H_