1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     ut_SharedPtr.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: 30202 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NW_UT_SHAREDPTR_H_
17 #define NW_UT_SHAREDPTR_H_
18 
19 #include <nw/types.h>
20 #include <nw/os/os_Memory.h>
21 #include <nw/os/os_Mutex.h>
22 #include <nw/ut/ut_Lock.h>
23 
24 namespace nw {
25 namespace ut {
26 
27 typedef nw::os::NullLockObject DefaultLockObject;
28 
29 //! @details :private
30 //---------------------------------------------------------------------------
31 //! @brief        シェアードポインタのカウンタクラスです。
32 //---------------------------------------------------------------------------
33 template <typename TLockObject = DefaultLockObject>
34 class SharedPtrCount
35 {
36 public:
37     //---------------------------------------------------------------------------
38     //! @brief        参照カウントを生成します。
39     //!
40     //! @param[out]   pAllocator メモリを確保するアロケータです。
41     //!
42     //! @return       生成した参照カウントクラスのインスタンスです。
43     //---------------------------------------------------------------------------
44     static SharedPtrCount*  Create( nw::os::IAllocator* pAllocator = NULL )
45     {
46         if ( pAllocator )
47         {
48             void* buf = pAllocator->Alloc( sizeof(SharedPtrCount) );
49             return new(buf) SharedPtrCount( pAllocator );
50         }
51         else
52         {
53             return new SharedPtrCount( NULL );
54         }
55     }
56 
57     //---------------------------------------------------------------------------
58     //! @brief        参照カウントを破棄します。
59     //---------------------------------------------------------------------------
Destroy()60     void Destroy()
61     {
62         if ( m_pAllocator )
63         {
64             this->~SharedPtrCount();
65             m_pAllocator->Free( this );
66         }
67         else
68         {
69             delete this;
70         }
71     }
72 
73     //---------------------------------------------------------------------------
74     //! @brief        参照カウントをインクリメントします。
75     //---------------------------------------------------------------------------
AddRef()76     void AddRef()
77     {
78         internal::AutoLock<TLockObject> lock(m_LockObject);
79         ++m_Use;
80     }
81 
82     //---------------------------------------------------------------------------
83     //! @brief        参照カウントが 0 でない場合に、参照カウントをインクリメントします。
84     //!
85     //! @return       インクリメントに成功した場合は true、失敗した場合は false を返します。
86     //---------------------------------------------------------------------------
TestAddRef()87     bool TestAddRef()
88     {
89         internal::AutoLock<TLockObject> lock(m_LockObject);
90 
91         if (m_Use == 0)  // 既にオブジェクトは破棄している
92         {
93             return false;
94         }
95         else
96         {
97             ++m_Use;
98             return true;
99         }
100     }
101 
102     //---------------------------------------------------------------------------
103     //! @brief        参照カウントをデクリメントします。
104     //!
105     //! @return       残りの参照カウント数です。
106     //---------------------------------------------------------------------------
Release()107     s32 Release()
108     {
109         internal::AutoLock<TLockObject> lock(m_LockObject);
110 
111         return --m_Use;
112     }
113 
114     //---------------------------------------------------------------------------
115     //! @brief        弱参照のカウントをインクリメントします。
116     //---------------------------------------------------------------------------
WeakAddRef()117     void WeakAddRef()
118     {
119         internal::AutoLock<TLockObject> lock(m_LockObject);
120 
121         ++m_Weak;
122     }
123 
124     //---------------------------------------------------------------------------
125     //! @brief        弱参照のカウントをデクリメントします。
126     //!
127     //! @return       残りの弱参照カウントです。
128     //---------------------------------------------------------------------------
WeakRelease()129     s32 WeakRelease()
130     {
131         internal::AutoLock<TLockObject> lock(m_LockObject);
132 
133         return --m_Weak;
134     }
135 
136 private:
137 
138     //---------------------------------------------------------------------------
139     //! @brief        コンストラクタです。
140     //!
141     //! @param[out]   pAllocator 破棄時に利用するアロケータです。
142     //---------------------------------------------------------------------------
SharedPtrCount(nw::os::IAllocator * pAllocator)143     /* ctor */ SharedPtrCount( nw::os::IAllocator* pAllocator )
144     :   m_Use( 0 ),
145         m_Weak( 0 ),
146         m_pAllocator( pAllocator )
147     {
148     }
149 
150     //---------------------------------------------------------------------------
151     //! @brief        デストラクタです。
152     //---------------------------------------------------------------------------
~SharedPtrCount()153     /* dtor */ ~SharedPtrCount()
154     {
155     }
156 
157     //---------------------------------------------------------------------------
158     //! @brief        参照カウントを取得します。
159     //!
160     //! @return       参照カウント数です。
161     //---------------------------------------------------------------------------
GetUseCount()162     s32 GetUseCount() const { return m_Use; }
163 
164     //---------------------------------------------------------------------------
165     //! @brief        弱参照のカウントを取得します。
166     //!
167     //! @return       弱参照のカウント数です。
168     //---------------------------------------------------------------------------
GetWeakCount()169     s32 GetWeakCount() const { return m_Weak; }
170 
171     s32                 m_Use;
172     s32                 m_Weak;
173     nw::os::IAllocator* m_pAllocator;
174 
175     TLockObject  m_LockObject;
176     template <typename U, typename ULockObject> friend class SharedPtr;
177 };
178 
179 template <typename Obj, typename TLockObject = DefaultLockObject> class WeakPtr;
180 
181 //--------------------------------------------------------------------------
182 //! @brief      参照カウント式のシェアードポインタクラスです。
183 //!
184 //! @details    このクラスを継承して使用する事は非サポートです。
185 //---------------------------------------------------------------------------
186 template <typename TObj, typename TLockObject = DefaultLockObject>
187 class SharedPtr
188 {
189 public:
SharedPtr()190     /* ctor */  SharedPtr() : m_pObj( NULL ), m_pCnt( NULL ), m_pAllocator( NULL ) {}
191 
192     //---------------------------------------------------------------------------
193     //! @brief        コンストラクタです。
194     //!
195     //! @param[out]   pObj       シェアードポインタを作成するオブジェクトのポインタです。
196     //! @param[out]   pAllocator メモリを開放するポインタです。
197     //! @param[out]   pCnt       参照カウント用オブジェクトです。
198     //---------------------------------------------------------------------------
199     /* ctor */ explicit SharedPtr(TObj* pObj, nw::os::IAllocator* pAllocator = NULL, SharedPtrCount<TLockObject>* pCnt = NULL)
m_pObj(pObj)200      : m_pObj( pObj ),
201        m_pCnt( pCnt ),
202        m_pAllocator( pAllocator )
203     {
204         if ( pObj == NULL )
205         {
206             m_pCnt = NULL;
207             return;
208         }
209 
210         if ( m_pCnt == NULL )
211         {
212             m_pCnt = SharedPtrCount<TLockObject>::Create( pAllocator );
213         }
214         m_pCnt->AddRef();
215         m_pCnt->WeakAddRef();
216     }
217 
218     //---------------------------------------------------------------------------
219     //! @brief        コピーコンストラクタです。
220     //!
221     //! @param[in]    other   コピー元のシェアードポインタです。
222     //---------------------------------------------------------------------------
SharedPtr(const SharedPtr & other)223     /* ctor */ /* implicit */ SharedPtr(const SharedPtr& other)
224      : m_pObj( other.m_pObj ),
225        m_pCnt( other.m_pCnt ),
226        m_pAllocator( other.m_pAllocator )
227     {
228         if (m_pCnt)
229         {
230             m_pCnt->AddRef();
231         }
232     }
233 
234     //---------------------------------------------------------------------------
235     //! @brief        コピーコンストラクタです。
236     //!
237     //! @param[in]    other    コピー元のシェアードポインタです。
238     //---------------------------------------------------------------------------
239     template <typename Y>
240     /* ctor */ /* implicit */ SharedPtr<TObj, TLockObject>(const SharedPtr<Y, TLockObject>& other)
241      : m_pObj( other.m_pObj ),
242        m_pCnt( other.m_pCnt ),
243        m_pAllocator( other.m_pAllocator )
244     {
245         if (m_pCnt)
246         {
247             m_pCnt->AddRef();
248         }
249     }
250 
251     //---------------------------------------------------------------------------
252     //! @brief        コピーコンストラクタです。
253     //!
254     //! @param[in]    other   コピー元のウィークポインタです。
255     //---------------------------------------------------------------------------
SharedPtr(const WeakPtr<TObj,TLockObject> & other)256     /* ctor */ explicit       SharedPtr(const WeakPtr<TObj, TLockObject>& other)
257      : m_pObj( other.m_pObj ),
258        m_pCnt( other.m_pCnt ),
259        m_pAllocator( other.m_pAllocator )
260     {
261         if (m_pCnt && m_pCnt->TestAddRef())
262         {
263         }
264         else
265         {
266             m_pCnt = NULL;
267             m_pObj = NULL;
268             m_pAllocator = NULL;
269         }
270     }
271 
272     //---------------------------------------------------------------------------
273     //! @brief        デストラクタです。
274     //---------------------------------------------------------------------------
~SharedPtr()275     /* dtor */ ~SharedPtr()
276     {
277         if ( m_pCnt )
278         {
279             if ( ! m_pCnt->Release() )
280             {
281                 if ( m_pAllocator )
282                 {
283                     m_pObj->~TObj();
284                     m_pAllocator->Free( m_pObj );
285                 }
286                 else
287                 {
288                     delete m_pObj;
289                 }
290 
291                 if ( ! m_pCnt->WeakRelease() )
292                 {
293                     m_pCnt->Destroy();
294                 }
295             }
296         }
297     }
298 
299     //---------------------------------------------------------------------------
300     //! @brief        代入演算子です。
301     //!
302     //! @param[in]    other   コピー元のシェアードポインタです。
303     //!
304     //! @return       コピー先への参照を返します。
305     //---------------------------------------------------------------------------
306     SharedPtr&   operator = (const SharedPtr& other)
307     {
308         SharedPtr(other).SwapObjPtr(*this);
309         return * this;
310     }
311 
312     //---------------------------------------------------------------------------
313     //! @brief        代入演算子です。
314     //!
315     //! @param[in]    other   コピー元のシェアードポインタです。
316     //!
317     //! @return       コピー先への参照を返します。
318     //---------------------------------------------------------------------------
319     template <typename U>
320     SharedPtr<TObj, TLockObject>&   operator = (const SharedPtr<U, TLockObject>& other)
321     {
322         SharedPtr(other).SwapObjPtr(*this);
323         return * this;
324     }
325 
326     //---------------------------------------------------------------------------
327     //! @brief        シェアードポインタの参照先をリセットします。
328     //!
329     //! @param[out]   pObj       シェアードポインタを作成するオブジェクトのポインタです。
330     //! @param[out]   pAllocator メモリを開放するポインタです。
331     //! @param[out]   pCnt       参照カウント用オブジェクトです。
332     //!
333     //! @return       リセットを実行したシェアードポインタの参照を返します。
334     //---------------------------------------------------------------------------
335     SharedPtr&         Reset(TObj* pObj = NULL, nw::os::IAllocator* pAllocator = NULL, SharedPtrCount<TLockObject>* pCnt = NULL)
336     {
337         SharedPtr(pObj, pAllocator, pCnt).SwapObjPtr(*this);
338         return *this;
339     }
340 
341     //---------------------------------------------------------------------------
342     //! @brief        参照しているオブジェクトを取得します。
343     //!
344     //! @return       参照しているオブジェクトのポインタです。
345     //---------------------------------------------------------------------------
Get()346     TObj*              Get() const { return m_pObj; }
347 
348     //---------------------------------------------------------------------------
349     //! @brief        参照しているオブジェクトを取得します。
350     //!
351     //! @return       参照しているオブジェクトのリファレンスです。
352     //---------------------------------------------------------------------------
353     TObj&              operator * () const { NW_NULL_ASSERT( m_pObj ); return  *m_pObj; }
354 
355     //---------------------------------------------------------------------------
356     //! @brief        参照しているオブジェクトを取得します。
357     //!
358     //! @return       参照しているオブジェクトのポインタです。
359     //---------------------------------------------------------------------------
360     TObj*              operator -> () const { NW_NULL_ASSERT( m_pObj ); return m_pObj; }
361 
362     //---------------------------------------------------------------------------
363     //! @brief        参照しているオブジェクトが NULL でないかどうかを取得します。
364     //!
365     //! @return       参照しているオブジェクトが NULL であれば false, それ以外の場合は true を返します。
366     //---------------------------------------------------------------------------
367     operator bool () const { return NULL != m_pObj; }
368 
369     // デバッグ用
370     //---------------------------------------------------------------------------
371     //! @brief        デバッグ用関数です。参照カウントの値を取得します。
372     //!
373     //! @return       参照カウントの値です。
374     //---------------------------------------------------------------------------
RefCount()375     s32                RefCount() const
376     {
377         if (m_pCnt == NULL) { return 0; }
378         return m_pCnt->GetUseCount();
379     }
380 
381 private:
382 
383     //---------------------------------------------------------------------------
384     //! @brief        ポインタの指す先をスワップする関数です。
385     //!
386     //! @param[out]   other   スワップ対象のシェアードポインタです。
387     //---------------------------------------------------------------------------
SwapObjPtr(SharedPtr & other)388     void                SwapObjPtr(SharedPtr& other)
389     {
390         std::swap( m_pObj, other.m_pObj );
391         std::swap( m_pCnt, other.m_pCnt );
392         std::swap( m_pAllocator, other.m_pAllocator );
393     }
394 
395     TObj*                        m_pObj;
396     SharedPtrCount<TLockObject>* m_pCnt;
397     nw::os::IAllocator*          m_pAllocator;
398 
399     template <typename U, typename ULockObject> friend class SharedPtr;
400     template <typename U, typename ULockObject> friend class WeakPtr;
401 };
402 
403 //----------------------------------------
404 //! @name スマートポインタ操作関連
405 //@{
406 
407 //---------------------------------------------------------------------------
408 //! @brief        SharedPtr が同じかどうかを判定します。
409 //!
410 //! @param[in]    a       比較対象となる1つ目のオブジェクトです。
411 //! @param[in]    b       比較対象となる2つ目のオブジェクトです。
412 //!
413 //! @return       ポインタが等しい場合は true、異なる場合は false を返します。
414 //---------------------------------------------------------------------------
415 template <class T, class U, typename TLockObject>
416 NW_INLINE bool
417 operator==(SharedPtr<T, TLockObject> const & a, SharedPtr<U, TLockObject> const & b)
418 {
419     return a.Get() == b.Get();
420 }
421 
422 //---------------------------------------------------------------------------
423 //! @brief        SharedPtr が異なるかどうかを判定します。
424 //!
425 //! @param[in]    a       比較対象となる1つ目のオブジェクトです。
426 //! @param[in]    b       比較対象となる2つ目のオブジェクトです。
427 //!
428 //! @return       ポインタが異なる場合は true、等しい場合は false を返します。
429 //---------------------------------------------------------------------------
430 template <class T, class U, typename TLockObject>
431 NW_INLINE bool
432 operator!=(SharedPtr<T, TLockObject> const & a, SharedPtr<U, TLockObject> const & b)
433 {
434     return ! (a == b);
435 }
436 
437 //@}
438 
439 //--------------------------------------------------------------------------
440 //! @brief      SharedPtr への弱参照クラスです。
441 //!
442 //! @details    このクラスを継承して使用する事は非サポートです。
443 //---------------------------------------------------------------------------
444 template <typename TObj, typename TLockObject>
445 class WeakPtr
446 {
447 public:
448     //---------------------------------------------------------------------------
449     //! @brief        コンストラクタです。
450     //---------------------------------------------------------------------------
WeakPtr()451     /* ctor */  WeakPtr()  : m_pObj( NULL ), m_pCnt( NULL ), m_pAllocator( NULL )
452     {
453     }
454 
455     //---------------------------------------------------------------------------
456     //! @brief        コピーコンストラクタです。
457     //!
458     //! @param[in]    other   コピー元のシェアードポインタです。
459     //---------------------------------------------------------------------------
460     template <class U>
WeakPtr(const SharedPtr<U,TLockObject> & other)461     /* ctor */ /* implicit */ WeakPtr(const SharedPtr<U, TLockObject>& other)
462         :   m_pObj(other.m_pObj),
463             m_pCnt(other.m_pCnt),
464             m_pAllocator(other.m_pAllocator)
465     {
466         if (m_pCnt)
467         {
468             m_pCnt->WeakAddRef();
469         }
470     }
471 
472     //---------------------------------------------------------------------------
473     //! @brief        コピーコンストラクタです。
474     //!
475     //! @param[in]    other   コピー元のウィークポインタです。
476     //---------------------------------------------------------------------------
477     template <class U>
WeakPtr(const WeakPtr<U,TLockObject> & other)478     /* ctor */ /* implicit */ WeakPtr(const WeakPtr<U, TLockObject>& other)
479         :   m_pObj(other.m_pObj),
480             m_pCnt(other.m_pCnt),
481             m_pAllocator(other.m_pAllocator)
482     {
483         if (m_pCnt)
484         {
485             m_pCnt->WeakAddRef();
486         }
487     }
488 
489     //---------------------------------------------------------------------------
490     //! @brief        デストラクタです。
491     //---------------------------------------------------------------------------
~WeakPtr()492     /* dtor */ ~WeakPtr()
493     {
494         if ( m_pCnt )
495         {
496             if ( ! m_pCnt->WeakRelease() )
497             {
498                 m_pCnt->Destroy();
499             }
500         }
501     }
502 
503     //---------------------------------------------------------------------------
504     //! @brief        ウィークポインタからシェアードポインタを取得します。
505     //!
506     //! @return       生成したシェアードポインタです。
507     //---------------------------------------------------------------------------
Lock()508     SharedPtr<TObj, TLockObject>    Lock() const
509     {
510         return SharedPtr<TObj, TLockObject>(*this);
511     }
512 
513     //---------------------------------------------------------------------------
514     //! @brief        代入演算子です。
515     //!
516     //! @return       コピー先のウィークポインタです。
517     //---------------------------------------------------------------------------
518     template <class U>
519     WeakPtr&           operator = (const SharedPtr<U, TLockObject>& rhs)
520     {
521         WeakPtr(rhs).SwapObjPtr(*this);
522         return *this;
523     }
524 
525     //---------------------------------------------------------------------------
526     //! @brief        代入演算子です。
527     //!
528     //! @param[in]    other コピー元のウィークポインタです。
529     //---------------------------------------------------------------------------
530     template <class U>
531     WeakPtr&            operator = (const WeakPtr<U, TLockObject>& other)
532     {
533         WeakPtr(other).SwapObjPtr(*this);
534         return *this;
535     }
536 
537 private:
538 
539     //---------------------------------------------------------------------------
540     //! @brief        ポインタの指す先をスワップする関数です。
541     //!
542     //! @param[out]   other   スワップ対象のウィークポインタです。
543     //---------------------------------------------------------------------------
SwapObjPtr(WeakPtr & other)544     void                SwapObjPtr(WeakPtr& other)
545     {
546         std::swap( m_pObj, other.m_pObj );
547         std::swap( m_pCnt, other.m_pCnt );
548         std::swap( m_pAllocator, other.m_pAllocator );
549     }
550 
551     TObj*                        m_pObj;
552     SharedPtrCount<TLockObject>* m_pCnt;
553     nw::os::IAllocator*          m_pAllocator;
554 
555     template <typename U, typename ULockObject> friend class SharedPtr;
556     template <typename U, typename ULockObject> friend class WeakPtr;
557 };
558 
559 } // namespace ut
560 } // namespace nw
561 
562 #endif // NW_UT_SHAREDPTR_H_
563