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