• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

spl/RefCountPtr.h

00001 /*
00002  *   This file is part of the Standard Portable Library (SPL).
00003  *
00004  *   SPL is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   SPL is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with SPL.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 #ifndef _refcountptr_h
00018 #define _refcountptr_h
00019 
00020 #include <spl/types.h>
00021 #include <spl/Debug.h>
00022 #include <spl/Exception.h>
00023 #include <spl/threading/InterlockCounter.h>
00024 #include <spl/Memory.h>
00025 
00033 template<class Y>
00034 struct _PtrHolder
00035 {
00036 private:
00037         bool m_threadSafe;
00038         mutable volatile short m_icount;
00039         mutable InterlockCounter m_tcount;
00040 
00041 public:
00042         mutable Y* ptr;
00043 
00044         inline _PtrHolder (Y* rhs, bool threadSafe)
00045         : ptr(rhs), m_icount(1), m_tcount(1), m_threadSafe(threadSafe)
00046         {
00047         }
00048 
00049         inline void SetThreadSafeOn()
00050         {
00051                 m_threadSafe = true;
00052         }
00053 
00054         inline void ValidateThis() const
00055         {
00056                 ASSERT_MEM(this, sizeof(_PtrHolder<Y>));
00057         }
00058 
00059         inline int Count() const
00060         {
00061                 if (m_threadSafe)
00062                 {
00063                         return (int)m_tcount;
00064                 }
00065                 return m_icount;
00066         }
00067 
00068         inline void Inc()
00069         {
00070                 if (m_threadSafe)
00071                 {
00072                         m_tcount++;
00073                 }
00074                 else
00075                 {
00076                         m_icount++;
00077                 }
00078         }
00079 
00080         inline int Dec()
00081         {
00082                 if (m_threadSafe)
00083                 {
00084                         m_tcount--;
00085                         return (int)m_tcount;
00086                 }
00087                 m_icount--;
00088                 return m_icount;
00089         }
00090         
00091         inline bool IsThreadSafe() const
00092         {
00093                 return m_threadSafe;
00094         }
00095 };
00096 
00097 template<class T>
00098 class RefCountPtr : public IMemoryValidate
00099 {
00100 private:
00101         mutable _PtrHolder<T> *m_ptr;
00102 
00103         inline void _Dec()
00104         {
00105                 if (NULL != m_ptr)
00106                 {
00107                         ASSERT(m_ptr->Count() > 0);
00108                         if (0 == m_ptr->Dec())
00109                         {
00110                                 delete m_ptr->ptr;
00111                                 delete m_ptr;
00112                         }
00113                 }
00114         }
00115 
00116 public:
00117     typedef T element_type;
00118 
00119     // constructor
00120     explicit RefCountPtr (T* ptr, bool threadSafe = false)
00121         {
00122                 if (NULL == ptr)
00123                 {
00124                         m_ptr = NULL;
00125                         return;
00126                 }
00127                 ASSERT_PTR(ptr);
00128                 m_ptr = new _PtrHolder<T>(ptr, threadSafe);
00129         }
00130 
00131     // copy constructors (with implicit conversion)
00132     // - note: nonconstant parameter
00133     RefCountPtr (const RefCountPtr<T>& rhs) 
00134         : m_ptr(rhs.m_ptr)
00135         {
00136                 if (NULL != m_ptr)
00137                 {
00138                         ASSERT(m_ptr->Count() > 0);
00139                         m_ptr->ValidateThis();
00140                         m_ptr->Inc();
00141                 }
00142         }
00143 
00144     RefCountPtr ()
00145         : m_ptr(NULL)
00146         {
00147         }
00148 
00149         RefCountPtr(_PtrHolder<T> *ptr)
00150         : m_ptr(ptr)
00151         {
00152                 if(NULL != ptr)
00153                 {
00154                         m_ptr->Inc();
00155                 }
00156         }
00157 
00158   //  // assignments (with implicit conversion)
00159   //  // - note: nonconstant parameter
00160     RefCountPtr<T>& operator =(const RefCountPtr<T>& rhs)
00161     {
00162                 _Dec();
00163                 
00164                 if (NULL != (m_ptr = rhs.m_ptr))
00165                 {
00166                         ASSERT_MEM(m_ptr, sizeof(_PtrHolder<T>));
00167                         m_ptr->Inc();
00168                 }
00169 
00170         return *this;
00171     }
00172     
00173     RefCountPtr<T>& operator =(T *p)
00174     {
00175                 _Dec();
00176                 if (NULL == p)
00177                 {
00178                         m_ptr = NULL;
00179                         return *this;
00180                 }
00181                 ASSERT_PTR(p);
00182                 m_ptr = new _PtrHolder<T>(p, NULL == m_ptr ? false : m_ptr->IsThreadSafe());
00183                 
00184                 return *this;
00185     }
00186 
00187 #ifndef _WINDOWS
00188         // gnu has stricter definition of const.
00189     // assignments (with implicit conversion)
00190     // - note: nonconstant parameter
00191     RefCountPtr<T>& operator= (RefCountPtr<T>& rhs)
00192     {
00193                 return *this = (const RefCountPtr<T>&)rhs;
00194     }
00195 #endif
00196 
00197     // destructor
00198     virtual ~RefCountPtr()
00199     {
00200                 Release();
00201     }
00202 
00203         inline void SetThreadSafeOn()
00204         {
00205                 ASSERT(NULL != m_ptr);
00206                 m_ptr->SetThreadSafeOn();
00207         }
00208 
00209         inline int ReferenceCount() const
00210         {
00211                 return NULL == m_ptr ? 0 : m_ptr->Count();
00212         }
00213 
00214         inline bool IsNull() const
00215         {
00216                 return NULL == m_ptr || NULL == m_ptr->ptr;
00217         }
00218 
00219         inline bool IsNotNull() const
00220         {
00221                 return !IsNull();
00222         }
00223 
00224         void Release()
00225         {
00226                 if (NULL != m_ptr)
00227                 {                       
00228                         m_ptr->ValidateThis();
00229                         ASSERT(m_ptr->Count() > 0);
00230 
00231                         if (0 == m_ptr->Dec())
00232                         {
00233                                 delete m_ptr->ptr;
00234                                 delete m_ptr;
00235                         }
00236                         m_ptr = NULL;
00237                 }
00238         }
00239 
00240         T* Detach()
00241         {
00242                 if(m_ptr == NULL)
00243                 {
00244                         return NULL;
00245                 }
00246                 ASSERT(m_ptr->Count() == 1);
00247                 T* ret = m_ptr->ptr;
00248                 delete m_ptr;
00249                 m_ptr = NULL;
00250                 return ret;
00251         }
00252 
00253     // value access
00254     inline T* Get() const
00255     {
00256                 if (NULL == m_ptr)
00257                 {
00258                         return NULL;
00259                 }
00260                 ASSERT(m_ptr->Count() > 0);
00261         return m_ptr->ptr;
00262     }
00263 
00264         // This is for casting of pointers
00265         inline _PtrHolder<T> *GetHolder() const
00266         {
00267                 ASSERT(NULL == m_ptr || m_ptr->Count() > 0);
00268                 return m_ptr;
00269         }
00270 
00271     inline T& operator*() const
00272     {
00273                 ASSERT(NULL != m_ptr);
00274                 ASSERT(m_ptr->Count() > 0);
00275         return *m_ptr->ptr;
00276     }
00277 
00278     inline T* operator->() const
00279     {
00280                 ASSERT(NULL != m_ptr);
00281                 ASSERT(m_ptr->Count() > 0);
00282         return m_ptr->ptr;
00283     }
00284 
00285         inline operator T&() const
00286         {
00287                 if (NULL == m_ptr)
00288                 {
00289                         throw new Exception("NULL pointer");
00290                 }
00291                 ASSERT(m_ptr->Count() > 0);
00292         return *m_ptr->ptr;
00293         }
00294 
00295 #if defined(DEBUG) || defined(_DEBUG)
00296         void CheckMem() const
00297         {
00298                 if (NULL != m_ptr)
00299                 {
00300                         DEBUG_NOTE_MEM(m_ptr);
00301                         DEBUG_NOTE_MEM(m_ptr->ptr);
00302                         ValidateType( m_ptr->ptr );
00303                 }
00304         }
00305 
00306         void ValidateMem() const
00307         {
00308                 if (NULL != m_ptr)
00309                 {
00310                         m_ptr->ValidateThis();
00311                         ASSERT_MEM(m_ptr->ptr, sizeof(T));
00312                         ValidateType( m_ptr->ptr );
00313                 }
00314         }
00315 #endif
00316 };
00317 
00320 #endif