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