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