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