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