CrystalSpace

Public API Reference

csutil/ref.h

Go to the documentation of this file.
00001 /*
00002   Crystal Space Smart Pointers
00003   Copyright (C) 2002 by Jorrit Tyberghein and Matthias Braun
00004 
00005   This library is free software; you can redistribute it and/or
00006   modify it under the terms of the GNU Library General Public
00007   License as published by the Free Software Foundation; either
00008   version 2 of the License, or (at your option) any later version.
00009 
00010   This library 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 GNU
00013   Library General Public License for more details.
00014 
00015   You should have received a copy of the GNU Library General Public
00016   License along with this library; if not, write to the Free
00017   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 */
00019 
00020 #ifndef __CS_REF_H__
00021 #define __CS_REF_H__
00022 
00027 #include "csextern.h"
00028 
00029 #define CS_VOIDED_PTR ((intptr_t)-1)
00030 
00031 template <class T> class csRef;
00032 
00033 #if defined(CS_DEBUG)
00034 #  define CS_TEST_VOIDPTRUSAGE
00035 #else
00036 #  undef CS_TEST_VOIDPTRUSAGE
00037 #endif
00038 
00039 #ifdef CS_REF_TRACKER
00040  #include <typeinfo>
00041  #include "csutil/reftrackeraccess.h"
00042 
00043  #define CSREF_TRACK(x, cmd, refCount, obj, tag)    \
00044   {                                                 \
00045     const int rc = obj ? refCount : -1;             \
00046     if (obj)                                        \
00047     {                                               \
00048       cmd;                                          \
00049       csRefTrackerAccess::SetDescription (obj,      \
00050         typeid(T).name());                          \
00051       csRefTrackerAccess::Match ## x (obj, rc, tag);\
00052     }                                               \
00053   }
00054  #define CSREF_TRACK_INCREF(obj,tag)    \
00055   CSREF_TRACK(IncRef, obj->IncRef(), obj->GetRefCount(), obj, tag);
00056  #define CSREF_TRACK_DECREF(obj,tag)    \
00057   CSREF_TRACK(DecRef, obj->DecRef(), obj->GetRefCount(), obj, tag);
00058  #define CSREF_TRACK_ASSIGN(obj,tag)    \
00059   CSREF_TRACK(IncRef, void(0), obj->GetRefCount() - 1, obj, tag);
00060 #else
00061  #define CSREF_TRACK_INCREF(obj,tag) \
00062   if (obj) obj->IncRef();
00063  #define CSREF_TRACK_DECREF(obj,tag) \
00064   if (obj) obj->DecRef();
00065  #define CSREF_TRACK_ASSIGN(obj,tag)
00066 #endif
00067 
00084 template <class T>
00085 class  csPtr
00086 {
00087 private:
00088   friend class csRef<T>;
00089   T* obj;
00090 
00091 public:
00092   csPtr (T* p) : obj (p) { CSREF_TRACK_ASSIGN(obj, this); }
00093 
00094   template <class T2>
00095   explicit csPtr (csRef<T2> const& r) : obj((T2*)r) 
00096   { 
00097     CSREF_TRACK_INCREF (obj, this);
00098   }
00099 
00100 #ifdef CS_TEST_VOIDPTRUSAGE
00101   ~csPtr ()
00102   {
00103     // If not assigned to a csRef we have a problem (leak).
00104     // So if this assert fires for you, then you are calling
00105     // a function that returns a csPtr and not using the result
00106     // (or at least not assigning it to a csRef). This is a memory
00107     // leak and you should fix that.
00108     CS_ASSERT_MSG ("csPtr<> was not assigned to a csRef<> prior destruction", 
00109       obj == (T*)CS_VOIDED_PTR);
00110   }
00111 #endif
00112 
00113   csPtr (const csPtr<T>& copy)
00114   {
00115     obj = copy.obj;
00116 #ifdef CS_TEST_VOIDPTRUSAGE
00117     ((csPtr<T>&)copy).obj = (T*)CS_VOIDED_PTR;
00118 #endif
00119   }
00120 };
00121 
00132 template <class T>
00133 class  csRef
00134 {
00135 private:
00136   T* obj;
00137 
00138 public:
00144   csRef () : obj (0) {}
00145 
00151   csRef (const csPtr<T>& newobj)
00152   {
00153     obj = newobj.obj;
00154 #   ifdef CS_TEST_VOIDPTRUSAGE
00155     CS_ASSERT_MSG ("csPtr<> was already assigned to a csRef<>",
00156       newobj.obj != (T*)CS_VOIDED_PTR);
00157 #   endif
00158     // The following line is outside the ifdef to make sure
00159     // we have binary compatibility.
00160     ((csPtr<T>&)newobj).obj = (T*)CS_VOIDED_PTR;
00161   }
00162 
00167   csRef (T* newobj) : obj (newobj)
00168   {
00169     CSREF_TRACK_INCREF (obj, this);
00170   }
00171 
00176   template <class T2>
00177   csRef (T2* newobj) : obj ((T2*)newobj)
00178   {
00179     CSREF_TRACK_INCREF (obj, this);
00180   }
00181   
00185   template <class T2>
00186   csRef (csRef<T2> const& other) : obj ((T2*)other)
00187   {
00188     CSREF_TRACK_INCREF (obj, this);
00189   }
00190 
00194   csRef (csRef const& other) : obj (other.obj)
00195   {
00196     CSREF_TRACK_INCREF (obj, this);
00197   }
00198 
00202   ~csRef ()
00203   {
00204     CSREF_TRACK_DECREF (obj, this);
00205   }
00206 
00216   csRef& operator = (const csPtr<T>& newobj)
00217   {
00218     T* oldobj = obj;
00219     // First assign and then DecRef() of old object!
00220     obj = newobj.obj;
00221 #   ifdef CS_TEST_VOIDPTRUSAGE
00222     CS_ASSERT_MSG ("csPtr<> was already assigned to a csRef<>",
00223       newobj.obj != (T*)CS_VOIDED_PTR);
00224 #   endif
00225     // The following line is outside the ifdef to make sure
00226     // we have binary compatibility.
00227     ((csPtr<T>&)newobj).obj = (T*)CS_VOIDED_PTR;
00228     CSREF_TRACK_DECREF (oldobj, this);
00229     return *this;
00230   }
00231 
00244   csRef& operator = (T* newobj)
00245   {
00246     if (obj != newobj)
00247     {
00248       T* oldobj = obj;
00249       // It is very important to first assign the new value to
00250       // 'obj' BEFORE calling DecRef() on the old object. Otherwise
00251       // it is easy to get in infinite loops with objects being
00252       // destructed forever (when ref=0 is used for example).
00253       obj = newobj;
00254       CSREF_TRACK_INCREF (newobj, this);
00255       CSREF_TRACK_DECREF (oldobj, this);
00256     }
00257     return *this;
00258   }
00259 
00282   void AttachNew (csPtr<T> newObj)
00283   {
00284     // Note: The parameter usage of csPtr<T> instead of csPtr<T>& is
00285     // deliberate and not to be considered a bug.
00286 
00287     // Just Re-use csPtr assignment logic
00288     *this = newObj;
00289   }
00290 
00292   template <class T2>
00293   csRef& operator = (csRef<T2> const& other)
00294   {
00295     T* p = (T2*)other;
00296     this->operator=(p);
00297     return *this;
00298   }
00299 
00301   csRef& operator = (csRef const& other)
00302   {
00303     this->operator=(other.obj);
00304     return *this;
00305   }
00306 
00308   inline friend bool operator == (const csRef& r1, const csRef& r2)
00309   {
00310     return r1.obj == r2.obj;
00311   }
00313   inline friend bool operator != (const csRef& r1, const csRef& r2)
00314   {
00315     return r1.obj != r2.obj;
00316   }
00318   inline friend bool operator == (const csRef& r1, T* obj)
00319   {
00320     return r1.obj == obj;
00321   }
00323   inline friend bool operator != (const csRef& r1, T* obj)
00324   {
00325     return r1.obj != obj;
00326   }
00328   inline friend bool operator == (T* obj, const csRef& r1)
00329   {
00330     return r1.obj == obj;
00331   }
00333   inline friend bool operator != (T* obj, const csRef& r1)
00334   {
00335     return r1.obj != obj;
00336   }
00342   inline friend bool operator < (const csRef& r1, const csRef& r2)
00343   {
00344     return r1.obj < r2.obj;
00345   }
00346 
00347 
00349   T* operator -> () const
00350   { return obj; }
00351   
00353   operator T* () const
00354   { return obj; }
00355   
00357   T& operator* () const
00358   { return *obj; }
00359 
00364   bool IsValid () const
00365   { return (obj != 0); }
00366 
00368   void Invalidate()
00369   { *this = (T*)0; }
00370 
00372   uint GetHash() const
00373   { return (uintptr_t)obj;  }
00374 };
00375 
00376 #undef CSREF_TRACK_INCREF
00377 #undef CSREF_TRACK_DECREF
00378 #undef CSREF_TRACK_ASSIGN
00379 
00380 #endif // __CS_REF_H__

Generated for Crystal Space by doxygen 1.4.7