1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     os_Memory.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: 25820 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NW_OS_MEMORY_H_
17 #define NW_OS_MEMORY_H_
18 
19 #include <nw/types.h>
20 #include <nw/assert.h>
21 #include <nw/ut/ut_Inlines.h>
22 #include <nn/os.h>
23 
24 #include <functional>
25 #include <algorithm>
26 
27 namespace nw {
28 namespace os {
29 
30 //---------------------------------------------------------------------------
31 //! @brief        メモリアロケータのインターフェースです。
32 //---------------------------------------------------------------------------
33 class IAllocator
34 {
35 public:
36     //! アライメント指定を省略した場合のデフォルト値です。
37     static const int DEFAULT_ALIGNMENT = 4;
38 
39     //! キャッシュのアライメントです。
40     static const int CACHE_LINE_ALIGNMENT = 32;
41 
42 
43     //! @brief デストラクタです。
~IAllocator()44     virtual ~IAllocator() {}
45 
46     //----------------------------------------
47     //! @name メモリの確保と解放
48     //@{
49 
50     //! @brief メモリを確保します。
51     virtual void* Alloc(size_t size, u8 alignment) = 0;
52 
53     //! @brief メモリを解放します。
54     virtual void  Free(void* memory) = 0;
55 
56     //@}
57 
58     //----------------------------------------
59     //! @name ユーティリティ
60     //@{
61 
62     //! @brief アライメント指定を省略してメモリを確保します。
63     //!
64     //! 派生クラスで Alloc(size, alignment)のオーバーライドを定義するとベースクラスの
65     //! オーバーロードが隠されるので注意してください。
66     //! サブクラスへの参照から直接利用するには、 using IAllocator::Alloc; を記述します。
Alloc(size_t size)67     void* Alloc(size_t size) { return this->Alloc( size, DEFAULT_ALIGNMENT ); }
68 
69     //! @brief メモリを確保し、指定したバイトデータでクリアします。
70     void* AllocAndClear(size_t size, u8 data, u8 alignment = DEFAULT_ALIGNMENT)
71     {
72         u8* memory = static_cast<u8*>(this->Alloc(size, alignment));
73 
74         if (memory != NULL)
75         {
76             std::fill_n(NW_CHECKED_ARRAY_ITERATOR(memory, size), size,  data);
77         }
78         return memory;
79     }
80 
81     //! @brief 指定個数分のオブジェクトに必要なメモリを確保します。
82     template<typename TObject>
83     TObject* Alloc(size_t size, u8 alignment = DEFAULT_ALIGNMENT)
84     {
85         return static_cast<TObject*>(this->Alloc(sizeof(TObject) * size, alignment));
86     }
87 
88     //! @brief 指定個数分のオブジェクトに必要なメモリを確保し、指定したバイトデータでクリアします。
89     template<typename TObject>
90     TObject* AllocAndClear(size_t size, u8 data, u8 alignment = DEFAULT_ALIGNMENT)
91     {
92         u8* memory = static_cast<u8*>(this->Alloc(sizeof(TObject) * size, alignment));
93 
94         if (memory != NULL)
95         {
96             std::fill_n(memory, size, data);
97         }
98 
99         return static_cast<TObject*>(memory);
100     }
101 
102     //! @brief 指定個数分のオブジェクトに必要なメモリを確保し、コンストラクタを呼び出します。
103     template<typename TObject>
104     TObject* AllocAndConstruct(size_t size, u8 alignment = DEFAULT_ALIGNMENT)
105     {
106         TObject* objects = static_cast<TObject*>(this->Alloc(sizeof(TObject) * size, alignment));
107 
108         if (objects != NULL)
109         {
110             for (size_t i = 0; i < size; ++i)
111             {
112                 this->Construct(&objects[i]);
113             }
114         }
115 
116         return objects;
117     }
118 
119     //! @brief 指定個数分のオブジェクトに必要なメモリを確保し、指定オブジェクトをコピーします。
120     template<typename TObject>
121     TObject* AllocAndFill(size_t size, const TObject& object, u8 alignment = DEFAULT_ALIGNMENT)
122     {
123         TObject* objects = static_cast<TObject*>(this->Alloc(sizeof(TObject) * size, alignment));
124 
125         if (objects != NULL)
126         {
127             std::fill_n(NW_CHECKED_ARRAY_ITERATOR(objects, size), size, object);
128         }
129 
130         return objects;
131     }
132 
133     //! @brief 指定個数分のオブジェクトのデストラクタを呼び出し、メモリを解放します。
134     template<typename TObject>
DestructAndFree(TObject * objects,size_t size)135     void DestructAndFree(TObject* objects, size_t size)
136     {
137         if (objects == NULL) { return; }
138 
139         for (size_t i = 0; i < size; ++i)
140         {
141             this->Destruct(&objects[i]);
142         }
143         Free(objects);
144     }
145 
146     //@}
147 
148 private:
149     //! 割当て済みの領域にコンストラクタを呼び出します。
150     template<typename TObject>
Construct(TObject * object)151     void Construct(TObject* object)
152     {
153         new(static_cast<void*>(object)) TObject;
154     }
155 
156     //! 初期化済みの領域のデストラクタを呼び出します。
157     template<typename TObject>
Destruct(TObject * object)158     void Destruct(TObject* object)
159     {
160         object->~TObject();
161     }
162 };
163 
164 //----------------------------------------
165 //! @name メモリ確保/解放
166 //@{
167 
168 //---------------------------------------------------------------------------
169 //! @brief        メモリを確保し、それを指定の値で塗りつぶします。
170 //!
171 //! @tparam       TObject 確保したいオブジェクトの型です。
172 //!
173 //! @param[in]    allocator アロケータです。
174 //! @param[in]    value 塗りつぶす値です。
175 //!
176 //! @return       確保したオブジェクトです。
177 //---------------------------------------------------------------------------
178 template<typename TObject>
179 NW_INLINE TObject*
AllocateAndFill(os::IAllocator * allocator,u8 value)180 AllocateAndFill(os::IAllocator* allocator, u8 value)
181 {
182     NW_NULL_ASSERT(allocator);
183     const size_t memorySize = sizeof(TObject);
184     u8* memory = static_cast<u8*>(allocator->Alloc(memorySize));
185     NW_NULL_ASSERT(memory);
186 
187     std::fill_n(NW_CHECKED_ARRAY_ITERATOR(memory, memorySize), memorySize, value);
188 
189     return reinterpret_cast<TObject*>(memory);
190 }
191 
192 //---------------------------------------------------------------------------
193 //! @brief        サイズを指定してメモリを確保し、指定の値で塗りつぶします。
194 //!
195 //! @tparam       TObject 確保したいオブジェクトの型です。
196 //!
197 //! @param[in]    allocator アロケータです。
198 //! @param[in]    size 確保するサイズです。
199 //! @param[in]    value 塗りつぶす値です。
200 //!
201 //! @return       確保したオブジェクトです。
202 //---------------------------------------------------------------------------
203 template<typename TObject>
204 NW_INLINE TObject*
AllocateAndFillN(os::IAllocator * allocator,size_t size,u8 value)205 AllocateAndFillN(os::IAllocator* allocator, size_t size, u8 value)
206 {
207     NW_NULL_ASSERT(allocator);
208     NW_ASSERT(sizeof(TObject) <= size);
209     u8* memory = static_cast<u8*>(allocator->Alloc(size));
210     NW_NULL_ASSERT(memory);
211 
212     std::fill_n(NW_CHECKED_ARRAY_ITERATOR(memory, size), size, value);
213 
214     return reinterpret_cast<TObject*>(memory);
215 }
216 
217 //---------------------------------------------------------------------------
218 //! @brief        サイズを指定してメモリを確保し、指定の値を割り当てます。
219 //!
220 //! @tparam       TObject 確保したいオブジェクトの型です。
221 //!
222 //! @param[in]    allocator アロケータです。
223 //! @param[in]    size 確保するサイズです。
224 //! @param[in]    object 塗りつぶす値です。
225 //!
226 //! @return       確保したオブジェクトです。
227 //---------------------------------------------------------------------------
228 template<typename TObject>
229 NW_INLINE TObject*
AllocateAndAssignN(os::IAllocator * allocator,size_t size,TObject object)230 AllocateAndAssignN(os::IAllocator* allocator, size_t size, TObject object)
231 {
232     NW_NULL_ASSERT(allocator);
233     TObject* objects = static_cast<TObject*>(allocator->Alloc(sizeof(TObject) * size));
234     NW_NULL_ASSERT(objects);
235 
236     std::fill_n(objects, size, object);
237 
238     return objects;
239 }
240 
241 //---------------------------------------------------------------------------
242 //! @brief        必要な分だけメモリを確保して、文字列をコピーします。
243 //!
244 //! @tparam       TChar 文字の型です。
245 //!
246 //! @param[in]    str コピーする文字列です。
247 //! @param[in]    allocator メモリアロケータです。
248 //! @param[in]    maxSize コピー時に制限される最大文字数です。
249 //!
250 //! @return       コピーした文字列を返します。
251 //---------------------------------------------------------------------------
252 template<typename TChar>
253 NW_INLINE TChar*
AllocateAndCopyString(const TChar * str,os::IAllocator * allocator,size_t maxSize)254 AllocateAndCopyString(const TChar* str, os::IAllocator* allocator, size_t maxSize)
255 {
256     if (str == NULL) { return NULL; }
257 
258     size_t length = std::char_traits<TChar>::length(str);
259     length = (length < maxSize)? length : maxSize;
260 
261     size_t bufferSize = length + 1;
262     TChar* copyStr = reinterpret_cast<char*>(allocator->Alloc(bufferSize));
263     NW_NULL_ASSERT(copyStr);
264     NW_CHAR_TRAITS_COPY(TChar, copyStr, bufferSize, str, length);
265     copyStr[length] = '\0';
266 
267     return copyStr;
268 }
269 
270 //---------------------------------------------------------------------------
271 //! @brief        メモリを解放後に0を設定するためのインライン関数です。
272 //!
273 //! @tparam       TMemory 解放するメモリの型です。
274 //!
275 //! @param[in]    memory 解放するメモリです。
276 //! @param[in]    allocator アロケータです。
277 //---------------------------------------------------------------------------
278 template<typename TMemory>
279 inline void
SafeFree(TMemory * & memory,IAllocator * allocator)280 SafeFree(
281     TMemory*& memory, IAllocator* allocator
282 )
283 {
284     if (memory == NULL)
285     {
286         return;
287     }
288     allocator->Free(static_cast<void*>(memory));
289     memory = NULL;
290 }
291 
292 //---------------------------------------------------------------------------
293 //! @brief        SafeFree でメモリを解放するためのデリーターです。
294 //!
295 //! @tparam       TMemory 削除するメモリの型です。
296 //---------------------------------------------------------------------------
297 template<typename TMemory>
298 struct SafeFreeFunctor : public std::unary_function<TMemory&, void>
299 {
SafeFreeFunctorSafeFreeFunctor300     SafeFreeFunctor(IAllocator* allocator) : m_Allocator(allocator) {}
301 
302     //! GfxObject を破棄します。
operatorSafeFreeFunctor303     void operator()(TMemory& memory) const
304     {
305         SafeFree(memory, m_Allocator);
306     }
307 
308     IAllocator* m_Allocator;
309 };
310 
311 //---------------------------------------------------------------------------
312 //! @brief        SafeFree でコンテナ要素の全てのメモリを解放するための関数です。
313 //!
314 //! @tparam       TArray 解放するコンテナの型です。
315 //!
316 //! @param[in]    array 削除するメモリのコンテナです。
317 //! @param[in]    allocator アロケータです。
318 //---------------------------------------------------------------------------
319 template<typename TArray>
320 inline void
SafeFreeAll(TArray & array,IAllocator * allocator)321 SafeFreeAll(
322     TArray& array, IAllocator* allocator
323 )
324 {
325     std::for_each(array.begin(), array.end(),
326                   SafeFreeFunctor<typename TArray::value_type>(allocator));
327     array.clear();
328 }
329 
330 //@}
331 
332 //---------------------------------------------------------------------------
333 //! @brief        アドレスがデバイスメモリかどうかを判定します。
334 //!
335 //! @param[in]    memory  メモリアドレスです。
336 //!
337 //! @return       デバイスメモリ用のアドレスの場合は true、
338 //!               それ以外の場合は false を返します。
339 //---------------------------------------------------------------------------
340 inline bool
IsDeviceMemory(const void * memory)341 IsDeviceMemory(const void* memory)
342 {
343 #if defined(NW_PLATFORM_CTR)
344     if (nn::os::GetDeviceMemoryAddress() <= (uint)memory &&
345         (uint)memory < nn::os::GetDeviceMemoryAddress() + nn::os::GetDeviceMemorySize())
346     {
347         return true;
348     }
349     else
350     {
351         return false;
352     }
353 #else
354     return false;
355 #endif
356 }
357 
358 //---------------------------------------------------------------------------
359 //! @brief        アラインメントを考慮したメモリサイズ計算を行います。
360 //!
361 //! :private
362 //---------------------------------------------------------------------------
363 class MemorySizeCalculator
364 {
365 public:
366     static const size_t MAX_ALIGNMENT = IAllocator::CACHE_LINE_ALIGNMENT;
367 
MemorySizeCalculator(size_t alignment)368     MemorySizeCalculator(size_t alignment)
369     : m_Size(0),
370       m_Alignment(alignment),
371       m_MaxAlignment(alignment)
372     {
373         NW_ASSERT(alignment <= MAX_ALIGNMENT);
374         NW_ASSERTMSG(alignment != 0 && (alignment & alignment - 1) == 0, "alignment must be power of 2");
375     }
376 
377     MemorySizeCalculator& operator+=(size_t size)
378     {
379         m_MaxAlignment = ut::Max(m_MaxAlignment, m_Alignment);
380         m_Size = ut::RoundUp(m_Size, m_Alignment) + size;
381         return *this;
382     }
383 
ChangeAlignment(size_t alignment)384     void ChangeAlignment(size_t alignment)
385     {
386         NW_ASSERT(alignment <= MAX_ALIGNMENT);
387         NW_ASSERTMSG(alignment != 0 && (alignment & alignment - 1) == 0, "alignment must be power of 2");
388         m_Alignment = alignment;
389     }
390 
Add(size_t size,size_t immediateAlignment)391     void Add(size_t size, size_t immediateAlignment)
392     {
393         size_t oldAlignment = m_Alignment;
394 
395         ChangeAlignment(immediateAlignment);
396         *this += size;
397         ChangeAlignment(oldAlignment);
398     }
399 
400     MemorySizeCalculator& operator*=(int operand)
401     {
402         m_Size = ut::RoundUp(m_Size, m_Alignment) * operand;
403         return *this;
404     }
405 
406     size_t GetAlignment() const {
407         return m_Alignment;
408     }
409 
410     size_t GetMaxAlignment() const {
411         return m_MaxAlignment;
412     }
413 
414     size_t GetSizeWithPadding(size_t alignment) const {
415         return m_Size + m_MaxAlignment - alignment;
416     }
417 
418 private:
419     size_t m_Size;
420     size_t m_Alignment;
421 
422     size_t m_MaxAlignment;
423 };
424 
425 } // namespace os
426 } // namespace nw
427 
428 
429 /* NW_OS_MEMORY_H_ */
430 #endif
431