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