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