gc_ptr.hh

00001 //********************************************************************
00002 //*** mm/gc_ptr.hh
00003 //*** Copyright (c) 2002-2004 by Markus Winand <mws@fatalmind.com>
00004 //*** $Id: gc_ptr.hh,v 1.30 2009-05-04 13:20:43 mws Exp $
00005 //********************************************************************
00006 /*
00007 This file is part of ResourcePool.
00008 
00009 ResourcePool is free software; you can redistribute it
00010 and/or modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2 of 
00012 the License, or (at your option) any later version.
00013 
00014 ResourcePool is distributed in the hope that it will be
00015 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00016 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with ResourcePool; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00022 02111-1307  USA */
00023 
00024 #ifndef INCLUDED_GC_PTR_HH
00025 #define INCLUDED_GC_PTR_HH
00026 
00027 #ifndef INCLUDED_THREAD_LOCK_HH
00028 #include "Thread/Lock.hh"
00029 #endif
00030 
00031 #ifndef INCLUDED_THREAD_SYNCHRONIZE_HH
00032 #include "Thread/Synchronize.hh"
00033 #endif
00034 
00035 namespace fatalmind {
00036 
00037 // fwd decl
00038 template<class T, class TM> class gc_ptr;
00039 
00040 // See Alexandrescu, Modern C++ Design, par 2.7
00041 
00042 // TODO, seperated version's to also work with fwd declared classes
00043 template<class T, class U>
00044 class Conversion
00045 {
00046         typedef char Small;
00047         class Big {char dummy[2]; };
00048 
00049         static Small Test(U&);
00050         static Big   Test(...);
00051         static T&    MakeT();
00052     public:
00053         enum {exists = sizeof(Test(MakeT())) == sizeof(Small) };
00054 };
00055 
00056 template<class TM>
00057 class usg_cnt_t {
00058         typedef typename TM::FastLock lock_t;
00059         typedef fatalmind::Synchronize<lock_t> sync;
00060     public:
00061         inline usg_cnt_t(): d_cnt(1) {};
00062         inline ~usg_cnt_t() {};
00063 
00064     private:
00065         inline int inc() {sync s(_lk); return ++d_cnt;};
00066         inline int dec() {sync s(_lk); return --d_cnt;};
00067         inline void reset() {sync s(_lk); d_cnt = 1;};
00068 
00069         int d_cnt;
00070         lock_t _lk;
00071 
00072         // hidden stuff
00073         // cctor
00074         usg_cnt_t(const usg_cnt_t&);
00075 
00076         template<class T, class TM2>
00077         friend
00078         class gc_ptr;
00079 };
00080 
00081 template<class T, class TM>
00082 class gc_ptr_ref {
00083     public:
00084         gc_ptr_ref(T* ptr, usg_cnt_t<TM>* usg) 
00085         : d_ptr(ptr)
00086         , d_usg(usg)
00087         {
00088         }
00089         
00090         typedef usg_cnt_t<TM> usg_cnt;
00091         T* d_ptr;
00092         usg_cnt* d_usg;
00093 };
00094 
00099 // when the pointed type derives from usg_cnt_t, it works better ;)
00100 // TODO, in that case it would be even possible to optimize d_usg (the member, which is a pointer) away completley ;)
00101 template<class T, class TM = fatalmind::DefaultThreadedModel>
00102 class gc_ptr {
00103         typedef usg_cnt_t<TM> usg_cnt;
00104     public:
00105         // need default constructor to work with STL
00106         explicit gc_ptr(T* p=0)
00107         : d_ptr(p)
00108         , d_usg( newUsageCounter(p))
00109         {
00110         };
00111 
00120         void resetFromExisting(T* ptr) 
00121         {
00122             if (d_ptr != ptr) {
00123                 dispose();
00124                 d_ptr = ptr;
00125                 d_usg = ptr;
00126                 d_usg->inc();
00127             }   
00128         }
00129 
00130         inline gc_ptr(const gc_ptr<T, TM>&p) throw()
00131         :   d_ptr(p.get()), d_usg(p.d_usg) 
00132         {
00133             if (d_usg) {
00134                 d_usg->inc();
00135             }
00136         }
00137 
00138         inline gc_ptr(const gc_ptr_ref<T, TM>&p) throw()
00139         :   d_ptr(p.d_ptr), d_usg(p.d_usg) 
00140         {
00141             if (d_usg) {
00142                 d_usg->inc();
00143             }
00144         }
00145 
00146         ~gc_ptr() throw() {
00147             dispose();
00148         }
00149     
00150         inline gc_ptr<T, TM>& operator= (const gc_ptr<T, TM>& p) throw()
00151         {
00152             if (this != &p) {
00153                 dispose();
00154                 d_ptr = p.d_ptr;
00155                 d_usg = p.d_usg;
00156                 if (d_usg) {
00157                     d_usg->inc();
00158                 }
00159             }
00160             return *this;
00161         }
00162 
00163         inline T& operator*() const throw()
00164         {
00165             return *d_ptr;
00166         }
00167         
00168         inline T* operator->() const throw()
00169         {
00170             return d_ptr;
00171         }
00172 
00173         inline T* get() const throw()
00174         {
00175             return d_ptr;
00176         }
00177 
00178         inline bool isNull() const throw()
00179         {
00180             return d_ptr == 0;
00181         }
00182     
00183         void reset(T* ptr= 0) throw()
00184         {
00185             if (d_ptr != ptr) {
00186                 dispose();
00187                 d_ptr = ptr;
00188                 d_usg = newUsageCounter(ptr);
00189             }   
00190         }
00191 
00192         inline bool operator<(const gc_ptr<T>& a) const {
00193             return *d_ptr < *a.d_ptr;
00194         }
00195 
00196         template<class Y>
00197         operator gc_ptr_ref<Y, TM>() throw() {
00198             return gc_ptr_ref<Y, TM>(d_ptr, d_usg);
00199         }
00200 
00201     protected:
00202         T* d_ptr;
00203         usg_cnt* d_usg;
00204 
00205         inline void dispose() throw() {
00206             if (d_usg != 0 && d_usg->dec() == 0) {
00207                 if (!Conversion<T, usg_cnt>::exists) {
00208                     delete d_usg;
00209                 }
00210                 delete d_ptr;
00211             }
00212         }
00213 
00214         // advanced magic, thx to Andrei ;)
00215         // if the object we point to derives from usg_cnt,
00216         // then we use that usg_cnt and don't allocate a seperate one
00217         // in that case, we even don't need to check for 0, 
00218         // because in case d_ptr is null, d_cnt should anyaywas also be null
00219         static inline usg_cnt* newUsageCounter(const T* p) {
00220             return ( (Conversion<T, usg_cnt>::exists ?  
00221                       (usg_cnt*)(p) 
00222                     : (p != 0 ? 
00223                           new usg_cnt()
00224                         : 0))
00225             ) ;
00226         }
00227 };
00228 
00229 } // namespace fatalmind
00230 
00231 #endif

Generated on Mon Nov 9 16:21:24 2009 for ResourcePool by  doxygen 1.5.3