Simple Application Framework  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Saf/Mem/SharedPtr.h
Go to the documentation of this file.
00001 /*
00002     This file is part of Simple Application Framework (Saf) library.
00003     Copyright (C) 2010 - 2012 Ondrej Danek <ondrej.danek@gmail.com>
00004 
00005     This library is free software: you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published 
00007     by the Free Software Foundation, either version 3 of the License, or
00008     (at your option) any later version.
00009 
00010     Saf is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with Simple Application Framework library. If not, 
00017     see <http://www.gnu.org/licenses/>.
00018 */
00019 
00028 #ifndef SAF_MEM_SHAREDPTR_H
00029 #define SAF_MEM_SHAREDPTR_H
00030 
00031 #include <typeinfo>
00032 #include "../Type.h"
00033 #include "../OverflowException.h"
00034 #include "../InvalidOperationException.h"
00035 #include "../InvalidCastException.h"
00036 #include "../ArgumentNullException.h"
00037 #include "../Type/Limits.h"
00038 
00039 namespace Saf
00040 {
00041     namespace Mem
00042     {
00079         template <class T> 
00080         class SharedPtr
00081         {
00082         private:
00084             Size *m_refCounter;
00086             T *m_ptr;
00087 
00088         public:
00090             SharedPtr() 
00091                 : m_refCounter(nullptr), m_ptr(nullptr)
00092             {}
00093 
00099             explicit SharedPtr(T *ptr) 
00100                 : m_refCounter(nullptr), m_ptr(nullptr)
00101             { 
00102                 Bind(ptr);
00103             }
00104 
00106             SharedPtr(const SharedPtr<T> &p)
00107                 : m_refCounter(nullptr), m_ptr(nullptr)
00108             {
00109                 *this = p;
00110             }
00111 
00113             ~SharedPtr()
00114             {
00115                 Free();
00116             }
00117 
00119             SharedPtr<T>& operator=(const SharedPtr<T>& p)
00120             {
00121                 if (&p != this)
00122                 {
00123                     Free();
00124 
00125                     if (p.m_refCounter != nullptr)
00126                     {                    
00127                         if (*p.m_refCounter == Type::Limits<Size>::Max())
00128                         {
00129                             throw OverflowException(SAF_SOURCE_LOCATION, 
00130                                 "Reference counter overflow.");
00131                         }
00132 
00133                         m_ptr = p.m_ptr;
00134                         m_refCounter = p.m_refCounter;
00135                         (*m_refCounter)++;
00136                     }
00137                 }
00138 
00139                 return *this;
00140             }
00141 
00143             void Swap(SharedPtr<T>& p)
00144             {
00145                 if (this != &p)
00146                 {
00147                     Algo::Swap(m_ptr, p.m_ptr);
00148                     Algo::Swap(m_refCounter, p.m_refCounter);
00149                 }
00150             }
00151 
00166             SharedPtr<T>& Bind(T *ptr)
00167             {            
00168                 if (ptr == nullptr)
00169                 {
00170                     throw ArgumentNullException(SAF_SOURCE_LOCATION, "Binding a null pointer.");
00171                 }
00172 
00173                 if (m_ptr == ptr)
00174                 {
00175                     throw InvalidOperationException(SAF_SOURCE_LOCATION, 
00176                         "Binding a pointer that has been already binded.");
00177                 }
00178 
00179                 Free();
00180 
00181                 m_refCounter = SAF_NEW Size(1);
00182                 m_ptr = ptr;
00183 
00184                 return *this;
00185             }
00186 
00193             SharedPtr<T>& BindWithCounter(T *ptr, Size *counter)
00194             {            
00195                 if (ptr == nullptr)
00196                 {
00197                     throw ArgumentNullException(SAF_SOURCE_LOCATION, "Binding a null pointer.");
00198                 }
00199 
00200                 if (m_ptr == ptr)
00201                 {
00202                     throw InvalidOperationException(SAF_SOURCE_LOCATION, 
00203                         "Binding a pointer that has been already binded.");
00204                 }
00205 
00206                 if (counter == nullptr)
00207                 {
00208                     throw ArgumentNullException(SAF_SOURCE_LOCATION, "Counter is a null pointer.");
00209                 }
00210 
00211                 if (*counter == Type::Limits<Size>::Max())
00212                 {
00213                     throw OverflowException(SAF_SOURCE_LOCATION, "Reference counter overflow.");
00214                 }
00215 
00216                 Free();
00217             
00218                 m_ptr = ptr;
00219                 m_refCounter = counter;
00220                 (*m_refCounter)++;
00221 
00222                 return *this;
00223             }
00224 
00230             void Free() 
00231             { 
00232                 if (m_refCounter != nullptr)
00233                 {
00234                     if (*m_refCounter > 1)
00235                     {
00236                         (*m_refCounter)--;
00237                         m_refCounter = nullptr;
00238                         m_ptr = nullptr;
00239                     }
00240                     else
00241                     {
00242                         Mem::Delete(m_refCounter);
00243                         Mem::Delete(m_ptr);
00244                     }
00245                 }
00246             }
00247 
00254             template <class C>
00255             SharedPtr<C> Cast()
00256             {
00257                 Ptr<C> p;
00258 
00259                 if (m_refCounter != nullptr)
00260                 {
00261                     C *np = dynamic_cast<C *>(m_ptr);
00262 
00263                     if (np == nullptr)
00264                     {
00265                         throw InvalidCastException(SAF_SOURCE_LOCATION);
00266                     }
00267 
00268                     p.BindWithCounter(np, m_refCounter);
00269                 }
00270 
00271                 return p;
00272             }
00273 
00275             bool IsNull() const 
00276             { 
00277                 return m_ptr == nullptr;
00278             }
00279 
00281             T* Get()
00282             { 
00283                 return m_ptr;
00284             }
00285 
00287             const T* Get() const 
00288             { 
00289                 return m_ptr;
00290             }
00291 
00293             T *operator->()
00294             { 
00295                 return m_ptr; 
00296             }
00297 
00299             const T *operator->() const 
00300             { 
00301                 return m_ptr; 
00302             }
00303 
00305             T& operator*()
00306             {
00307                 return *m_ptr;
00308             }
00309 
00311             const T& operator*() const
00312             {
00313                 return *m_ptr;
00314             }
00315         };
00316     }
00317 
00319     namespace Algo
00320     {
00321         // Swap specialization for pointer container.
00322         template <class T>
00323         struct SwapFunc< Ptr<T> >
00324         {
00325             void operator()(Ptr<T>& x, Ptr<T>& y)
00326             {
00327                 x.Swap(y);
00328             }
00329         };
00330     }
00332 }
00333 
00334 #endif