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