/*---------------------------------------------------------------------------* Project: NintendoWare File: os_Memory.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: 25820 $ *---------------------------------------------------------------------------*/ #ifndef NW_OS_MEMORY_H_ #define NW_OS_MEMORY_H_ #include #include #include #include #include #include namespace nw { namespace os { //--------------------------------------------------------------------------- //! @brief メモリアロケータのインターフェースです。 //--------------------------------------------------------------------------- class IAllocator { public: //! アライメント指定を省略した場合のデフォルト値です。 static const int DEFAULT_ALIGNMENT = 4; //! キャッシュのアライメントです。 static const int CACHE_LINE_ALIGNMENT = 32; //! @brief デストラクタです。 virtual ~IAllocator() {} //---------------------------------------- //! @name メモリの確保と解放 //@{ //! @brief メモリを確保します。 virtual void* Alloc(size_t size, u8 alignment) = 0; //! @brief メモリを解放します。 virtual void Free(void* memory) = 0; //@} //---------------------------------------- //! @name ユーティリティ //@{ //! @brief アライメント指定を省略してメモリを確保します。 //! //! 派生クラスで Alloc(size, alignment)のオーバーライドを定義するとベースクラスの //! オーバーロードが隠されるので注意してください。 //! サブクラスへの参照から直接利用するには、 using IAllocator::Alloc; を記述します。 void* Alloc(size_t size) { return this->Alloc( size, DEFAULT_ALIGNMENT ); } //! @brief メモリを確保し、指定したバイトデータでクリアします。 void* AllocAndClear(size_t size, u8 data, u8 alignment = DEFAULT_ALIGNMENT) { u8* memory = static_cast(this->Alloc(size, alignment)); if (memory != NULL) { std::fill_n(NW_CHECKED_ARRAY_ITERATOR(memory, size), size, data); } return memory; } //! @brief 指定個数分のオブジェクトに必要なメモリを確保します。 template TObject* Alloc(size_t size, u8 alignment = DEFAULT_ALIGNMENT) { return static_cast(this->Alloc(sizeof(TObject) * size, alignment)); } //! @brief 指定個数分のオブジェクトに必要なメモリを確保し、指定したバイトデータでクリアします。 template TObject* AllocAndClear(size_t size, u8 data, u8 alignment = DEFAULT_ALIGNMENT) { u8* memory = static_cast(this->Alloc(sizeof(TObject) * size, alignment)); if (memory != NULL) { std::fill_n(memory, size, data); } return static_cast(memory); } //! @brief 指定個数分のオブジェクトに必要なメモリを確保し、コンストラクタを呼び出します。 template TObject* AllocAndConstruct(size_t size, u8 alignment = DEFAULT_ALIGNMENT) { TObject* objects = static_cast(this->Alloc(sizeof(TObject) * size, alignment)); if (objects != NULL) { for (size_t i = 0; i < size; ++i) { this->Construct(&objects[i]); } } return objects; } //! @brief 指定個数分のオブジェクトに必要なメモリを確保し、指定オブジェクトをコピーします。 template TObject* AllocAndFill(size_t size, const TObject& object, u8 alignment = DEFAULT_ALIGNMENT) { TObject* objects = static_cast(this->Alloc(sizeof(TObject) * size, alignment)); if (objects != NULL) { std::fill_n(NW_CHECKED_ARRAY_ITERATOR(objects, size), size, object); } return objects; } //! @brief 指定個数分のオブジェクトのデストラクタを呼び出し、メモリを解放します。 template void DestructAndFree(TObject* objects, size_t size) { if (objects == NULL) { return; } for (size_t i = 0; i < size; ++i) { this->Destruct(&objects[i]); } Free(objects); } //@} private: //! 割当て済みの領域にコンストラクタを呼び出します。 template void Construct(TObject* object) { new(static_cast(object)) TObject; } //! 初期化済みの領域のデストラクタを呼び出します。 template void Destruct(TObject* object) { object->~TObject(); } }; //---------------------------------------- //! @name メモリ確保/解放 //@{ //--------------------------------------------------------------------------- //! @brief メモリを確保し、それを指定の値で塗りつぶします。 //! //! @tparam TObject 確保したいオブジェクトの型です。 //! //! @param[in] allocator アロケータです。 //! @param[in] value 塗りつぶす値です。 //! //! @return 確保したオブジェクトです。 //--------------------------------------------------------------------------- template NW_INLINE TObject* AllocateAndFill(os::IAllocator* allocator, u8 value) { NW_NULL_ASSERT(allocator); const size_t memorySize = sizeof(TObject); u8* memory = static_cast(allocator->Alloc(memorySize)); NW_NULL_ASSERT(memory); std::fill_n(NW_CHECKED_ARRAY_ITERATOR(memory, memorySize), memorySize, value); return reinterpret_cast(memory); } //--------------------------------------------------------------------------- //! @brief サイズを指定してメモリを確保し、指定の値で塗りつぶします。 //! //! @tparam TObject 確保したいオブジェクトの型です。 //! //! @param[in] allocator アロケータです。 //! @param[in] size 確保するサイズです。 //! @param[in] value 塗りつぶす値です。 //! //! @return 確保したオブジェクトです。 //--------------------------------------------------------------------------- template NW_INLINE TObject* AllocateAndFillN(os::IAllocator* allocator, size_t size, u8 value) { NW_NULL_ASSERT(allocator); NW_ASSERT(sizeof(TObject) <= size); u8* memory = static_cast(allocator->Alloc(size)); NW_NULL_ASSERT(memory); std::fill_n(NW_CHECKED_ARRAY_ITERATOR(memory, size), size, value); return reinterpret_cast(memory); } //--------------------------------------------------------------------------- //! @brief サイズを指定してメモリを確保し、指定の値を割り当てます。 //! //! @tparam TObject 確保したいオブジェクトの型です。 //! //! @param[in] allocator アロケータです。 //! @param[in] size 確保するサイズです。 //! @param[in] object 塗りつぶす値です。 //! //! @return 確保したオブジェクトです。 //--------------------------------------------------------------------------- template NW_INLINE TObject* AllocateAndAssignN(os::IAllocator* allocator, size_t size, TObject object) { NW_NULL_ASSERT(allocator); TObject* objects = static_cast(allocator->Alloc(sizeof(TObject) * size)); NW_NULL_ASSERT(objects); std::fill_n(objects, size, object); return objects; } //--------------------------------------------------------------------------- //! @brief 必要な分だけメモリを確保して、文字列をコピーします。 //! //! @tparam TChar 文字の型です。 //! //! @param[in] str コピーする文字列です。 //! @param[in] allocator メモリアロケータです。 //! @param[in] maxSize コピー時に制限される最大文字数です。 //! //! @return コピーした文字列を返します。 //--------------------------------------------------------------------------- template NW_INLINE TChar* AllocateAndCopyString(const TChar* str, os::IAllocator* allocator, size_t maxSize) { if (str == NULL) { return NULL; } size_t length = std::char_traits::length(str); length = (length < maxSize)? length : maxSize; size_t bufferSize = length + 1; TChar* copyStr = reinterpret_cast(allocator->Alloc(bufferSize)); NW_NULL_ASSERT(copyStr); NW_CHAR_TRAITS_COPY(TChar, copyStr, bufferSize, str, length); copyStr[length] = '\0'; return copyStr; } //--------------------------------------------------------------------------- //! @brief メモリを解放後に0を設定するためのインライン関数です。 //! //! @tparam TMemory 解放するメモリの型です。 //! //! @param[in] memory 解放するメモリです。 //! @param[in] allocator アロケータです。 //--------------------------------------------------------------------------- template inline void SafeFree( TMemory*& memory, IAllocator* allocator ) { if (memory == NULL) { return; } allocator->Free(static_cast(memory)); memory = NULL; } //--------------------------------------------------------------------------- //! @brief SafeFree でメモリを解放するためのデリーターです。 //! //! @tparam TMemory 削除するメモリの型です。 //--------------------------------------------------------------------------- template struct SafeFreeFunctor : public std::unary_function { SafeFreeFunctor(IAllocator* allocator) : m_Allocator(allocator) {} //! GfxObject を破棄します。 void operator()(TMemory& memory) const { SafeFree(memory, m_Allocator); } IAllocator* m_Allocator; }; //--------------------------------------------------------------------------- //! @brief SafeFree でコンテナ要素の全てのメモリを解放するための関数です。 //! //! @tparam TArray 解放するコンテナの型です。 //! //! @param[in] array 削除するメモリのコンテナです。 //! @param[in] allocator アロケータです。 //--------------------------------------------------------------------------- template inline void SafeFreeAll( TArray& array, IAllocator* allocator ) { std::for_each(array.begin(), array.end(), SafeFreeFunctor(allocator)); array.clear(); } //@} //--------------------------------------------------------------------------- //! @brief アドレスがデバイスメモリかどうかを判定します。 //! //! @param[in] memory メモリアドレスです。 //! //! @return デバイスメモリ用のアドレスの場合は true、 //! それ以外の場合は false を返します。 //--------------------------------------------------------------------------- inline bool IsDeviceMemory(const void* memory) { #if defined(NW_PLATFORM_CTR) if (nn::os::GetDeviceMemoryAddress() <= (uint)memory && (uint)memory < nn::os::GetDeviceMemoryAddress() + nn::os::GetDeviceMemorySize()) { return true; } else { return false; } #else return false; #endif } //--------------------------------------------------------------------------- //! @brief アラインメントを考慮したメモリサイズ計算を行います。 //! //! :private //--------------------------------------------------------------------------- class MemorySizeCalculator { public: static const size_t MAX_ALIGNMENT = IAllocator::CACHE_LINE_ALIGNMENT; MemorySizeCalculator(size_t alignment) : m_Size(0), m_Alignment(alignment), m_MaxAlignment(alignment) { NW_ASSERT(alignment <= MAX_ALIGNMENT); NW_ASSERTMSG(alignment != 0 && (alignment & alignment - 1) == 0, "alignment must be power of 2"); } MemorySizeCalculator& operator+=(size_t size) { m_MaxAlignment = ut::Max(m_MaxAlignment, m_Alignment); m_Size = ut::RoundUp(m_Size, m_Alignment) + size; return *this; } void ChangeAlignment(size_t alignment) { NW_ASSERT(alignment <= MAX_ALIGNMENT); NW_ASSERTMSG(alignment != 0 && (alignment & alignment - 1) == 0, "alignment must be power of 2"); m_Alignment = alignment; } void Add(size_t size, size_t immediateAlignment) { size_t oldAlignment = m_Alignment; ChangeAlignment(immediateAlignment); *this += size; ChangeAlignment(oldAlignment); } MemorySizeCalculator& operator*=(int operand) { m_Size = ut::RoundUp(m_Size, m_Alignment) * operand; return *this; } size_t GetAlignment() const { return m_Alignment; } size_t GetMaxAlignment() const { return m_MaxAlignment; } size_t GetSizeWithPadding(size_t alignment) const { return m_Size + m_MaxAlignment - alignment; } private: size_t m_Size; size_t m_Alignment; size_t m_MaxAlignment; }; } // namespace os } // namespace nw /* NW_OS_MEMORY_H_ */ #endif