/*---------------------------------------------------------------------------* Project: NintendoWare File: ut_MovePtr.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: 27739 $ *---------------------------------------------------------------------------*/ #ifndef NW_UT_MOVEPTR_H_ #define NW_UT_MOVEPTR_H_ #include namespace nw { namespace os { class IAllocator; } // namespace os namespace ut { namespace internal { //--------------------------------------------------------------------------- //! @brief MovePtr 用デリーターの基本クラスです。 //! //! @tparam TObject 削除するオブジェクトの型です。 //--------------------------------------------------------------------------- template class MovePtrDeleterBase { public: typedef void* (*Deleter)(TObject*); //! @brief コンストラクタです。 //! //! @param[in] deleter オブジェクトを削除するためのデリータです。 //! MovePtrDeleterBase(Deleter deleter) : m_Allocator(0) { m_DeleteFunction = deleter; } //! @brief コンストラクタです。 //! //! @param[in] deleter オブジェクトを削除するためのデリータです。 //! @param[in] allocator オブジェクトを削除するためのアロケータです。 //! MovePtrDeleterBase(Deleter deleter, os::IAllocator* allocator) : m_Allocator(allocator) { m_DeleteFunction = deleter; } //! @brief 削除を実行します。 //! //! @param[in] object 削除するオブジェクトです。 //! void operator() (TObject* object) { void* memory = m_DeleteFunction(object); if (m_Allocator) { m_Allocator->Free(memory); } } static Deleter m_DeleteFunction; os::IAllocator* m_Allocator; }; template typename MovePtrDeleterBase::Deleter MovePtrDeleterBase::m_DeleteFunction; //--------------------------------------------------------------------------- //! @brief MovePtr の単数オブジェクト用デリータークラスです。 //! //! @tparam TScalar 削除するオブジェクトの型です。 //--------------------------------------------------------------------------- template class MovePtrScalarDeleter : public MovePtrDeleterBase { public: typedef MovePtrDeleterBase base; //! @brief コンストラクタです。 MovePtrScalarDeleter() : base(DoDelete) { } //! @brief コンストラクタです。 //! //! @param[in] allocator オブジェクトを削除するためのアロケータです。 //! MovePtrScalarDeleter(os::IAllocator* allocator) : base(DoDelete, allocator) { } //! @brief 削除を実行します。 //! //! @param[in] scalar 削除するオブジェクトです。 //! static void* DoDelete(TScalar* scalar) { scalar->~TScalar(); return scalar; } }; //--------------------------------------------------------------------------- //! @brief MovePtr の複数オブジェクト(配列)用デリータークラスです。 //! //! この実装方法では、配列にしている要素の型によっては要素数が //! 格納されていないことがあり、その基準はコンパイラ等に依存するので、 //! 配列用のデリーターは使用禁止とします。 //! //! @tparam TArray 削除する配列の型です。 //--------------------------------------------------------------------------- template class MovePtrArrayDeleter : public MovePtrDeleterBase::type> { public: typedef typename remove_bounds::type element_type; typedef MovePtrDeleterBase base; //! @brief コンストラクタです。 MovePtrArrayDeleter() : base(DoDelete) { } //! @brief コンストラクタです。 //! //! @param[in] allocator オブジェクトを削除するためのアロケータです。 //! MovePtrArrayDeleter(os::IAllocator* allocator) : base(DoDelete, allocator) { } //! @brief 削除を実行します。 //! //! @param[in] array 削除するオブジェクトです。 //! static void* DoDelete(element_type* array) { // 先頭アドレスより前の 4 バイトに要素数が格納されている。 size_t arraySize = *(reinterpret_cast(array) - 1); element_type* end = array + arraySize; for (element_type* i = array; i != end; ++i) { i->~element_type(); } // 解放されるべきアドレスは先頭アドレスより 4 バイト前になる。 return reinterpret_cast(array) - 4; } }; //--------------------------------------------------------------------------- //! @brief MovePtr や Move に内部的に使用されるクラスです。 //! //! @details :private //! //! @tparam TPointer 移動させるポインタです。 //--------------------------------------------------------------------------- template class MoveSource { public: //! @brief コンストラクタです。 //! //! @param[in] pointer 移動させるポインタです。 //! MoveSource(TPointer& pointer) : m_Pointer(pointer) {} //! @brief ポインタを返します。 TPointer& Ptr() const { return m_Pointer; } private: TPointer& m_Pointer; MoveSource(const TPointer&); }; } // namespace internal //---------------------------------------- //! @name スマートポインタ操作関連 //@{ //! MovePtr を移動させるための関数です。 template internal::MoveSource Move(TPointer& pointer) { return internal::MoveSource(pointer); } //@} //--------------------------------------------------------------------------- //! @brief MovePtr のデフォルトデリータークラスです。 //! //! @tparam TObject 削除するオブジェクトの型です。 //--------------------------------------------------------------------------- template class MovePtrDefaultDeleter : public If_< IsArray, internal::MovePtrArrayDeleter, internal::MovePtrScalarDeleter >::type { public: //! @brief コンストラクタです。 //! //! @param[in] allocator アロケータです。 //! MovePtrDefaultDeleter(os::IAllocator* allocator = 0) { this->m_Allocator = allocator; } //! @brief コンストラクタです。 //! //! @tparam TTObject 削除するオブジェクトの型です。 //! //! @param[in] allocator アロケータです。 //! template MovePtrDefaultDeleter(MovePtrDefaultDeleter object) { } }; //--------------------------------------------------------------------------- //! @brief 所有権移動式スマートポインタです。 //! //! 所有権を移動するように拡張した auto_ptr です。 //! 任意のデリータを指定することが可能です。 //! //! @tparam TObject オブジェクトの型です。 //! @tparam TDeleter デリーターの型です。 //--------------------------------------------------------------------------- template > class MovePtr { NW_STATIC_ASSERT(!IsArray::value); public: typedef typename remove_bounds::type element_type; //!< 要素の型です。 typedef TDeleter deleter_type; //!< オブジェクトを削除するデリータの型です。 typedef TDeleter& deleter_reference; //!< オブジェクトを削除するデリータの参照です。 typedef const TDeleter& deleter_const_reference; //!< オブジェクトを削除するデリータの const 参照です。 //! @details :private struct SafeBoolHelper { int x; }; typedef int SafeBoolHelper::* SafeBool; //!< @details :private //! @brief コンストラクタです。 MovePtr() : m_Object(0), m_Deleter() { } //! @brief コピーコンストラクタです。コピー元から要素を移動します。 //! //! @param[in] pointer コピー元の MovePtr クラスです。 //! MovePtr(const MovePtr& pointer) : m_Object(const_cast(pointer.Get())), m_Deleter(pointer.GetDeleter()) { const_cast(pointer).Release(); } //! @brief コンストラクタです。 //! //! @tparam TTObject 格納するポインタの型です。 //! //! @param[in] pointer 格納するポインタです。 //! template explicit MovePtr(TTObject* pointer) : m_Object(pointer), m_Deleter() { } //! @brief コンストラクタです。 //! //! @tparam TTObject 格納するポインタの型です。 //! //! @param[in] pointer 格納するポインタです。 //! @param[in] allocator 解放時に使用するアロケータです。 //! template MovePtr(TTObject* pointer, os::IAllocator* allocator) : m_Object(pointer), m_Deleter(allocator) { } //! @brief コンストラクタです。 //! //! @tparam TTObject 格納するポインタの型です。 //! @tparam TTDeleter 解放時に使用するデリータの型です。 //! //! @param[in] pointer 格納するポインタです。 //! @param[in] deleter 解放時に使用するデリーターです。 //! template MovePtr(TTObject* pointer, TTDeleter deleter) : m_Object(pointer), m_Deleter(deleter) { } //! @brief コンストラクタです。 //! //! @tparam TTObject 格納するポインタの型です。 //! @tparam TTDeleter 解放時に使用するデリータの型です。 //! //! @param[in] source 所有権移動元の MovePtr です。 //! template MovePtr(internal::MoveSource > source) : m_Object(source.Ptr().Get()), m_Deleter(source.Ptr().GetDeleter()) { source.Ptr().Release(); } //! @brief デストラクタです。 ~MovePtr() { if (this->Ptr()) { this->GetDeleter()(this->Ptr()); } } //! @brief MovePtr を代入します。 //! //! @param[in] rhs 代入する MovePtr です。 //! 代入元の MovePtr は破棄されます。 //! MovePtr& operator=(MovePtr rhs) { rhs.Swap(*this); return *this; } //! @brief 格納しているオブジェクトのポインタを取得します。 //! //! @return 格納しているオブジェクトのポインタです。 //! element_type* Get() const { return Ptr(); } //! @brief 格納しているオブジェクトの参照を返します。 element_type& operator*() const { NW_STATIC_ASSERT(!IsArray::value); return *Ptr(); } //! @brief 格納しているオブジェクトを操作します。 element_type* operator->() const { NW_STATIC_ASSERT(!IsArray::value); return Ptr(); } //! @brief インデックスを指定して格納している配列の要素の参照を取得します。 element_type& operator[](std::size_t i) const { NW_STATIC_ASSERT(IsArray::value); return Ptr()[i]; } //! @brief 格納しているオブジェクトの管理を放棄します。 element_type* Release() { element_type* result = Ptr(); Ptr() = 0; return result; } //! @brief 格納しているオブジェクトを削除して、状態をリセットします。 void Reset() { if (Ptr()) { GetDeleter()(Ptr()); } Ptr() = 0; } //! @brief 格納しているオブジェクトを削除して、オブジェクトを入れ替えます。 //! //! @tparam TTObject 入れ替えを行うオブジェクトの型です。 //! //! @param[in] object 入れ替えを行うオブジェクトです。 //! template void Reset(TTObject* object) { MovePtr(object).Swap(*this); } //! @brief 格納しているインスタンスを削除して、オブジェクトを入れ替えます。 //! //! @tparam TTObject 入れ替えを行うオブジェクトの型です。 //! @tparam TTDeleter オブジェクトを削除するためのデリータの型です。 //! //! @param[in] object 入れ替えを行うインスタンスです。 //! @param[in] delelter オブジェクトを削除するためのデリータです。 //! template void Reset(TTObject* object, TTDeleter deleter) { MovePtr(object, deleter).Swap(*this); } //! @brief 格納しているインスタンスを削除して、オブジェクトを入れ替えます。 //! //! @tparam TTObject 入れ替えを行うオブジェクトの型です。 //! //! @param[in] object 入れ替えを行うインスタンスです。 //! @param[in] allocator オブジェクトを解放するためのアロケータです。 //! template void Reset(TTObject* object, os::IAllocator* allocator) { MovePtr(object, TDeleter(allocator)).Swap(*this); } //! @brief オブジェクトを所有を確認します。 //! //! 望まない式評価を行われないような安全な真偽評価を行います。 //! //! @return オブジェクトを所有する場合に true を返します。 //! operator SafeBool() const { return Ptr() ? &SafeBoolHelper::x : 0; } //! @brief MovePtr を入れ替えます。 //! //! @param[in] pointer 入れ替える MovePtr です。 //! void Swap(MovePtr& pointer) { if (&pointer == this) { return; } element_type* object = this->m_Object; deleter_type deleter = this->m_Deleter; this->m_Object = pointer.m_Object; this->m_Deleter = pointer.m_Deleter; pointer.m_Object = object; pointer.m_Deleter = deleter; } //! @brief デリータを取得します。 //! //! @return オブジェクトを削除するためのデリータです。 //! deleter_reference GetDeleter() { return m_Deleter; } //! @brief デリータを取得します。 //! //! @return オブジェクトを削除するためのデリータです。 //! deleter_const_reference GetDeleter() const { return m_Deleter; } private: template struct CantMoveFromConst; template struct CantMoveFromConst > { typedef typename MovePtr::error type; }; template MovePtr(Pointer&, typename CantMoveFromConst::type = 0); //MovePtr(MovePtr&); element_type*& Ptr() { return m_Object; } element_type* Ptr() const { return m_Object; } element_type* m_Object; deleter_type m_Deleter; }; } // namespace ut } // namespace nw #endif // NW_UT_MOVEPTR_H_