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