1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: ut_MovePtr.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: 27739 $
14 *---------------------------------------------------------------------------*/
15
16 #ifndef NW_UT_MOVEPTR_H_
17 #define NW_UT_MOVEPTR_H_
18
19 #include <nw/ut/ut_TypeTraits.h>
20
21 namespace nw
22 {
23 namespace os
24 {
25 class IAllocator;
26 } // namespace os
27
28 namespace ut
29 {
30
31 namespace internal
32 {
33
34 //---------------------------------------------------------------------------
35 //! @brief MovePtr 用デリーターの基本クラスです。
36 //!
37 //! @tparam TObject 削除するオブジェクトの型です。
38 //---------------------------------------------------------------------------
39 template<typename TObject>
40 class MovePtrDeleterBase
41 {
42 public:
43 typedef void* (*Deleter)(TObject*);
44
45 //! @brief コンストラクタです。
46 //!
47 //! @param[in] deleter オブジェクトを削除するためのデリータです。
48 //!
MovePtrDeleterBase(Deleter deleter)49 MovePtrDeleterBase(Deleter deleter)
50 : m_Allocator(0)
51 { m_DeleteFunction = deleter; }
52
53 //! @brief コンストラクタです。
54 //!
55 //! @param[in] deleter オブジェクトを削除するためのデリータです。
56 //! @param[in] allocator オブジェクトを削除するためのアロケータです。
57 //!
MovePtrDeleterBase(Deleter deleter,os::IAllocator * allocator)58 MovePtrDeleterBase(Deleter deleter, os::IAllocator* allocator)
59 : m_Allocator(allocator)
60 { m_DeleteFunction = deleter; }
61
62 //! @brief 削除を実行します。
63 //!
64 //! @param[in] object 削除するオブジェクトです。
65 //!
operator()66 void operator() (TObject* object)
67 {
68 void* memory = m_DeleteFunction(object);
69 if (m_Allocator)
70 {
71 m_Allocator->Free(memory);
72 }
73 }
74
75 static Deleter m_DeleteFunction;
76 os::IAllocator* m_Allocator;
77 };
78
79 template<class TObject>
80 typename MovePtrDeleterBase<TObject>::Deleter MovePtrDeleterBase<TObject>::m_DeleteFunction;
81
82 //---------------------------------------------------------------------------
83 //! @brief MovePtr の単数オブジェクト用デリータークラスです。
84 //!
85 //! @tparam TScalar 削除するオブジェクトの型です。
86 //---------------------------------------------------------------------------
87 template<typename TScalar>
88 class MovePtrScalarDeleter : public MovePtrDeleterBase<TScalar>
89 {
90 public:
91 typedef MovePtrDeleterBase<TScalar> base;
92
93 //! @brief コンストラクタです。
MovePtrScalarDeleter()94 MovePtrScalarDeleter() : base(DoDelete) { }
95
96 //! @brief コンストラクタです。
97 //!
98 //! @param[in] allocator オブジェクトを削除するためのアロケータです。
99 //!
MovePtrScalarDeleter(os::IAllocator * allocator)100 MovePtrScalarDeleter(os::IAllocator* allocator) : base(DoDelete, allocator) { }
101
102 //! @brief 削除を実行します。
103 //!
104 //! @param[in] scalar 削除するオブジェクトです。
105 //!
DoDelete(TScalar * scalar)106 static void* DoDelete(TScalar* scalar)
107 {
108 scalar->~TScalar();
109 return scalar;
110 }
111 };
112
113 //---------------------------------------------------------------------------
114 //! @brief MovePtr の複数オブジェクト(配列)用デリータークラスです。
115 //!
116 //! この実装方法では、配列にしている要素の型によっては要素数が
117 //! 格納されていないことがあり、その基準はコンパイラ等に依存するので、
118 //! 配列用のデリーターは使用禁止とします。
119 //!
120 //! @tparam TArray 削除する配列の型です。
121 //---------------------------------------------------------------------------
122 template<typename TArray>
123 class MovePtrArrayDeleter
124 : public MovePtrDeleterBase<typename remove_bounds<TArray>::type>
125 {
126 public:
127 typedef typename remove_bounds<TArray>::type element_type;
128 typedef MovePtrDeleterBase<element_type> base;
129
130 //! @brief コンストラクタです。
MovePtrArrayDeleter()131 MovePtrArrayDeleter() : base(DoDelete) { }
132
133 //! @brief コンストラクタです。
134 //!
135 //! @param[in] allocator オブジェクトを削除するためのアロケータです。
136 //!
MovePtrArrayDeleter(os::IAllocator * allocator)137 MovePtrArrayDeleter(os::IAllocator* allocator) : base(DoDelete, allocator) { }
138
139 //! @brief 削除を実行します。
140 //!
141 //! @param[in] array 削除するオブジェクトです。
142 //!
DoDelete(element_type * array)143 static void* DoDelete(element_type* array)
144 {
145 // 先頭アドレスより前の 4 バイトに要素数が格納されている。
146 size_t arraySize = *(reinterpret_cast<int*>(array) - 1);
147
148 element_type* end = array + arraySize;
149 for (element_type* i = array; i != end; ++i)
150 {
151 i->~element_type();
152 }
153
154 // 解放されるべきアドレスは先頭アドレスより 4 バイト前になる。
155 return reinterpret_cast<char*>(array) - 4;
156 }
157 };
158
159 //---------------------------------------------------------------------------
160 //! @brief MovePtr や Move に内部的に使用されるクラスです。
161 //!
162 //! @details :private
163 //!
164 //! @tparam TPointer 移動させるポインタです。
165 //---------------------------------------------------------------------------
166 template<typename TPointer>
167 class MoveSource
168 {
169 public:
170 //! @brief コンストラクタです。
171 //!
172 //! @param[in] pointer 移動させるポインタです。
173 //!
MoveSource(TPointer & pointer)174 MoveSource(TPointer& pointer) : m_Pointer(pointer) {}
175
176 //! @brief ポインタを返します。
Ptr()177 TPointer& Ptr() const { return m_Pointer; }
178
179 private:
180 TPointer& m_Pointer;
181 MoveSource(const TPointer&);
182 };
183
184 } // namespace internal
185
186 //----------------------------------------
187 //! @name スマートポインタ操作関連
188 //@{
189
190 //! MovePtr を移動させるための関数です。
191 template<typename TPointer>
Move(TPointer & pointer)192 internal::MoveSource<TPointer> Move(TPointer& pointer)
193 {
194 return internal::MoveSource<TPointer>(pointer);
195 }
196
197 //@}
198
199 //---------------------------------------------------------------------------
200 //! @brief MovePtr のデフォルトデリータークラスです。
201 //!
202 //! @tparam TObject 削除するオブジェクトの型です。
203 //---------------------------------------------------------------------------
204 template<typename TObject>
205 class MovePtrDefaultDeleter : public If_< IsArray<TObject>,
206 internal::MovePtrArrayDeleter<TObject>,
207 internal::MovePtrScalarDeleter<TObject>
208 >::type
209 {
210 public:
211 //! @brief コンストラクタです。
212 //!
213 //! @param[in] allocator アロケータです。
214 //!
215 MovePtrDefaultDeleter(os::IAllocator* allocator = 0) { this->m_Allocator = allocator; }
216
217 //! @brief コンストラクタです。
218 //!
219 //! @tparam TTObject 削除するオブジェクトの型です。
220 //!
221 //! @param[in] allocator アロケータです。
222 //!
223 template<typename TTObject>
MovePtrDefaultDeleter(MovePtrDefaultDeleter<TTObject> object)224 MovePtrDefaultDeleter(MovePtrDefaultDeleter<TTObject> object) { }
225 };
226
227 //---------------------------------------------------------------------------
228 //! @brief 所有権移動式スマートポインタです。
229 //!
230 //! 所有権を移動するように拡張した auto_ptr です。
231 //! 任意のデリータを指定することが可能です。
232 //!
233 //! @tparam TObject オブジェクトの型です。
234 //! @tparam TDeleter デリーターの型です。
235 //---------------------------------------------------------------------------
236 template<typename TObject, typename TDeleter = MovePtrDefaultDeleter<TObject> >
237 class MovePtr
238 {
239 NW_STATIC_ASSERT(!IsArray<TObject>::value);
240
241 public:
242 typedef typename remove_bounds<TObject>::type element_type; //!< 要素の型です。
243 typedef TDeleter deleter_type; //!< オブジェクトを削除するデリータの型です。
244 typedef TDeleter& deleter_reference; //!< オブジェクトを削除するデリータの参照です。
245 typedef const TDeleter& deleter_const_reference; //!< オブジェクトを削除するデリータの const 参照です。
246
247 //! @details :private
248 struct SafeBoolHelper { int x; };
249 typedef int SafeBoolHelper::* SafeBool; //!< @details :private
250
251 //! @brief コンストラクタです。
MovePtr()252 MovePtr() : m_Object(0), m_Deleter()
253 {
254 }
255
256 //! @brief コピーコンストラクタです。コピー元から要素を移動します。
257 //!
258 //! @param[in] pointer コピー元の MovePtr クラスです。
259 //!
MovePtr(const MovePtr & pointer)260 MovePtr(const MovePtr& pointer)
261 : m_Object(const_cast<element_type*>(pointer.Get())), m_Deleter(pointer.GetDeleter())
262 {
263 const_cast<MovePtr&>(pointer).Release();
264 }
265
266 //! @brief コンストラクタです。
267 //!
268 //! @tparam TTObject 格納するポインタの型です。
269 //!
270 //! @param[in] pointer 格納するポインタです。
271 //!
272 template<typename TTObject>
MovePtr(TTObject * pointer)273 explicit MovePtr(TTObject* pointer)
274 : m_Object(pointer), m_Deleter()
275 {
276 }
277
278 //! @brief コンストラクタです。
279 //!
280 //! @tparam TTObject 格納するポインタの型です。
281 //!
282 //! @param[in] pointer 格納するポインタです。
283 //! @param[in] allocator 解放時に使用するアロケータです。
284 //!
285 template<typename TTObject>
MovePtr(TTObject * pointer,os::IAllocator * allocator)286 MovePtr(TTObject* pointer, os::IAllocator* allocator)
287 : m_Object(pointer), m_Deleter(allocator)
288 {
289 }
290
291 //! @brief コンストラクタです。
292 //!
293 //! @tparam TTObject 格納するポインタの型です。
294 //! @tparam TTDeleter 解放時に使用するデリータの型です。
295 //!
296 //! @param[in] pointer 格納するポインタです。
297 //! @param[in] deleter 解放時に使用するデリーターです。
298 //!
299 template<typename TTObject, typename TTDeleter>
MovePtr(TTObject * pointer,TTDeleter deleter)300 MovePtr(TTObject* pointer, TTDeleter deleter)
301 : m_Object(pointer), m_Deleter(deleter)
302 {
303 }
304
305 //! @brief コンストラクタです。
306 //!
307 //! @tparam TTObject 格納するポインタの型です。
308 //! @tparam TTDeleter 解放時に使用するデリータの型です。
309 //!
310 //! @param[in] source 所有権移動元の MovePtr です。
311 //!
312 template<typename TTObject, typename TTDeleter>
MovePtr(internal::MoveSource<MovePtr<TTObject,TTDeleter>> source)313 MovePtr(internal::MoveSource<MovePtr<TTObject, TTDeleter> > source)
314 : m_Object(source.Ptr().Get()), m_Deleter(source.Ptr().GetDeleter())
315 {
316 source.Ptr().Release();
317 }
318
319 //! @brief デストラクタです。
~MovePtr()320 ~MovePtr()
321 {
322 if (this->Ptr())
323 {
324 this->GetDeleter()(this->Ptr());
325 }
326 }
327
328 //! @brief MovePtr を代入します。
329 //!
330 //! @param[in] rhs 代入する MovePtr です。
331 //! 代入元の MovePtr は破棄されます。
332 //!
333 MovePtr& operator=(MovePtr rhs)
334 {
335 rhs.Swap(*this);
336 return *this;
337 }
338
339 //! @brief 格納しているオブジェクトのポインタを取得します。
340 //!
341 //! @return 格納しているオブジェクトのポインタです。
342 //!
Get()343 element_type* Get() const { return Ptr(); }
344
345 //! @brief 格納しているオブジェクトの参照を返します。
346 element_type& operator*() const
347 {
348 NW_STATIC_ASSERT(!IsArray<TObject>::value);
349 return *Ptr();
350 }
351
352 //! @brief 格納しているオブジェクトを操作します。
353 element_type* operator->() const
354 {
355 NW_STATIC_ASSERT(!IsArray<TObject>::value);
356 return Ptr();
357 }
358
359 //! @brief インデックスを指定して格納している配列の要素の参照を取得します。
360 element_type& operator[](std::size_t i) const
361 {
362 NW_STATIC_ASSERT(IsArray<TObject>::value);
363 return Ptr()[i];
364 }
365
366 //! @brief 格納しているオブジェクトの管理を放棄します。
Release()367 element_type* Release()
368 {
369 element_type* result = Ptr();
370 Ptr() = 0;
371 return result;
372 }
373
374 //! @brief 格納しているオブジェクトを削除して、状態をリセットします。
Reset()375 void Reset()
376 {
377 if (Ptr())
378 {
379 GetDeleter()(Ptr());
380 }
381 Ptr() = 0;
382 }
383
384 //! @brief 格納しているオブジェクトを削除して、オブジェクトを入れ替えます。
385 //!
386 //! @tparam TTObject 入れ替えを行うオブジェクトの型です。
387 //!
388 //! @param[in] object 入れ替えを行うオブジェクトです。
389 //!
390 template<typename TTObject>
Reset(TTObject * object)391 void Reset(TTObject* object)
392 {
393 MovePtr(object).Swap(*this);
394 }
395
396 //! @brief 格納しているインスタンスを削除して、オブジェクトを入れ替えます。
397 //!
398 //! @tparam TTObject 入れ替えを行うオブジェクトの型です。
399 //! @tparam TTDeleter オブジェクトを削除するためのデリータの型です。
400 //!
401 //! @param[in] object 入れ替えを行うインスタンスです。
402 //! @param[in] delelter オブジェクトを削除するためのデリータです。
403 //!
404 template<typename TTObject, typename TTDeleter>
Reset(TTObject * object,TTDeleter deleter)405 void Reset(TTObject* object, TTDeleter deleter)
406 {
407 MovePtr(object, deleter).Swap(*this);
408 }
409
410 //! @brief 格納しているインスタンスを削除して、オブジェクトを入れ替えます。
411 //!
412 //! @tparam TTObject 入れ替えを行うオブジェクトの型です。
413 //!
414 //! @param[in] object 入れ替えを行うインスタンスです。
415 //! @param[in] allocator オブジェクトを解放するためのアロケータです。
416 //!
417 template<typename TTObject>
Reset(TTObject * object,os::IAllocator * allocator)418 void Reset(TTObject* object, os::IAllocator* allocator)
419 {
420 MovePtr(object, TDeleter(allocator)).Swap(*this);
421 }
422
423 //! @brief オブジェクトを所有を確認します。
424 //!
425 //! 望まない式評価を行われないような安全な真偽評価を行います。
426 //!
427 //! @return オブジェクトを所有する場合に true を返します。
428 //!
SafeBool()429 operator SafeBool() const { return Ptr() ? &SafeBoolHelper::x : 0; }
430
431 //! @brief MovePtr を入れ替えます。
432 //!
433 //! @param[in] pointer 入れ替える MovePtr です。
434 //!
Swap(MovePtr & pointer)435 void Swap(MovePtr& pointer)
436 {
437 if (&pointer == this)
438 {
439 return;
440 }
441
442 element_type* object = this->m_Object;
443 deleter_type deleter = this->m_Deleter;
444
445 this->m_Object = pointer.m_Object;
446 this->m_Deleter = pointer.m_Deleter;
447
448 pointer.m_Object = object;
449 pointer.m_Deleter = deleter;
450 }
451
452 //! @brief デリータを取得します。
453 //!
454 //! @return オブジェクトを削除するためのデリータです。
455 //!
GetDeleter()456 deleter_reference GetDeleter() { return m_Deleter; }
457
458 //! @brief デリータを取得します。
459 //!
460 //! @return オブジェクトを削除するためのデリータです。
461 //!
GetDeleter()462 deleter_const_reference GetDeleter() const { return m_Deleter; }
463
464 private:
465 template<typename Pointer> struct CantMoveFromConst;
466 template<typename TTObject, typename TTDeleter>
467 struct CantMoveFromConst<const MovePtr<TTObject, TTDeleter> >
468 {
469 typedef typename MovePtr<TTObject, TTDeleter>::error type;
470 };
471
472 template<typename Pointer>
473 MovePtr(Pointer&, typename CantMoveFromConst<Pointer>::type = 0);
474
475 //MovePtr(MovePtr&);
476
477 element_type*& Ptr() { return m_Object; }
478 element_type* Ptr() const { return m_Object; }
479
480 element_type* m_Object;
481 deleter_type m_Deleter;
482 };
483
484 } // namespace ut
485 } // namespace nw
486
487 #endif // NW_UT_MOVEPTR_H_
488