FXRefedObject.h

Go to the documentation of this file.
00001 /********************************************************************************
00002 *                                                                               *
00003 *                          Reference counted objects                            *
00004 *                                                                               *
00005 *********************************************************************************
00006 *        Copyright (C) 2002,2003 by Niall Douglas.   All Rights Reserved.       *
00007 *       NOTE THAT I DO NOT PERMIT ANY OF MY CODE TO BE PROMOTED TO THE GPL      *
00008 *********************************************************************************
00009 * This code is free software; you can redistribute it and/or modify it under    *
00010 * the terms of the GNU Library General Public License v2.1 as published by the  *
00011 * Free Software Foundation EXCEPT that clause 3 does not apply ie; you may not  *
00012 * "upgrade" this code to the GPL without my prior written permission.           *
00013 * Please consult the file "License_Addendum2.txt" accompanying this file.       *
00014 *                                                                               *
00015 * This code is distributed in the hope that it will be useful,                  *
00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                          *
00018 *********************************************************************************
00019 * $Id:                                                                          *
00020 ********************************************************************************/
00021 
00022 #ifndef FXREFEDOBJECT_H
00023 #define FXREFEDOBJECT_H
00024 
00025 #include "QThread.h"
00026 #include "FXException.h"
00027 #include "FXPolicies.h"
00028 #include "qvaluelist.h"
00029 
00030 namespace FX {
00031 
00046 #ifndef FXREFINGOBJECT_DEBUGKNOWALLOC
00047  #ifdef DEBUG
00048   #define FXREFINGOBJECT_DEBUGKNOWALLOC 1
00049  #else
00050   #define FXREFINGOBJECT_DEBUGKNOWALLOC 0
00051  #endif
00052 #endif
00053 
00054 class FXRefingObjectBase
00055 {
00056 protected:
00057 #if FXREFINGOBJECT_DEBUGKNOWALLOC
00058     struct Allocated
00059     {
00060         const char *file;
00061         int lineno;
00062         Allocated(const char *_file, int _lineno) : file(_file), lineno(_lineno) { }
00063     } allocated;
00064     FXRefingObjectBase(const char *_file, int _lineno) : allocated(_file, _lineno) { }
00065 public:
00066     FXRefingObjectBase &operator=(const FXRefingObjectBase &o)
00067     {
00068         if(o.allocated.file)
00069         {
00070             allocated.file=o.allocated.file;
00071             allocated.lineno=o.allocated.lineno;
00072         }
00073         return *this;
00074     }
00075     const char *int_allocated_file() const throw() { return allocated.file; }
00076     int int_allocated_lineno() const throw() { return allocated.lineno; }
00077 #else
00078     FXRefingObjectBase(const char *_file, int _lineno) { }
00079 public:
00080     const char *int_allocated_file() const throw() { return 0; }
00081     int int_allocated_lineno() const throw() { return 0; }
00082 #endif
00083 };
00084 template<class type> class FXRefingObject;
00085 namespace FXRefingObjectImpl {
00086     template<bool mutexed, class type> struct dataHolderI;
00087     template<class type> class refedObject;
00088 }
00089 
00090 namespace FXRefedObjectImpl
00091 {
00092     template<typename type> class countHolder
00093     {
00094         type myrefcount;
00095         bool mydying;
00096     protected:
00097         bool int_increfcount()      // Returns true if not dead
00098         {
00099             if(mydying) return false;
00100             ++myrefcount;
00101             return true;
00102         }
00103         bool int_decrefcount()      // Returns false if kill me now please
00104         {
00105             if(!--myrefcount && !mydying)
00106             {
00107                 mydying=true;
00108                 return false;
00109             }
00110             return true;
00111         }
00112     public:
00113         countHolder() : myrefcount(0), mydying(false) { }
00114         countHolder(const countHolder &o) : myrefcount(0), mydying(false) { }
00116         const type &refCount() const throw() { return myrefcount; }
00118         void resetDying() throw() { mydying=false; }
00119     };
00120 //#ifdef FX_SMPBUILD        // Don't need it on non-SMP builds
00121     template<> class countHolder<FXAtomicInt>
00122     {   /* This specialisation for FXAtomicInt features a serialised checking and
00123         setting of dying so we can know when you can't create a new reference safely
00124         in a threadsafe fashion. */
00125         QShrdMemMutex myrefcountlock;
00126         int myrefcount;
00127         bool mydying;
00128     protected:
00129         bool int_increfcount()      // Returns true if not dead
00130         {
00131             myrefcountlock.lock();
00132             if(mydying)
00133             {
00134                 myrefcountlock.unlock();
00135                 return false;
00136             }
00137             ++myrefcount;
00138             myrefcountlock.unlock();
00139             return true;
00140         }
00141         bool int_decrefcount()      // Returns false if kill me now please
00142         {
00143             myrefcountlock.lock();
00144             if(!--myrefcount && !mydying)
00145             {
00146                 mydying=true;
00147                 myrefcountlock.unlock();
00148                 return false;
00149             }
00150             myrefcountlock.unlock();
00151             return true;
00152         }
00153     public:
00154         countHolder() : myrefcountlock(FXINFINITE), myrefcount(0), mydying(false) { }
00155         countHolder(const countHolder &o) : myrefcountlock(FXINFINITE), myrefcount(0), mydying(false) { }
00156         // Deliberately prevent direct alteration
00157         const int &refCount() const throw() { return myrefcount; }
00159         void resetDying() throw() { mydying=false; }
00160     };
00161 //#endif
00162 }
00163 
00164 namespace Pol {
00169     struct unknownReferrers
00170     {
00171     protected:
00172         struct ReferrerEntry { };
00173         unknownReferrers() { }
00174         void int_addReferrer(FXRefingObjectBase *r, QMutex *lock) { }
00175         void int_removeReferrer(FXRefingObjectBase *r, QMutex *lock) { }
00176         const QValueList<ReferrerEntry> *int_referrers() const { return 0; }
00177     };
00178 #ifdef _MSC_VER
00179 #pragma warning(push)
00180 #pragma warning(disable: 4251)
00181 #endif
00182 
00186     struct knowReferrers
00187     {
00188     protected:
00189         struct ReferrerEntry
00190         {
00191             FXRefingObjectBase *ref;
00192             FXulong threadId;
00193             ReferrerEntry(FXRefingObjectBase *_ref) : ref(_ref), threadId(QThread::id()) { }
00194             bool operator==(const ReferrerEntry &o) const throw() { return ref==o.ref; }
00195         };
00196         QValueList<ReferrerEntry> referrers;
00197         knowReferrers() { }
00198         void int_addReferrer(FXRefingObjectBase *r, QMutex *lock)
00199         {
00200             QMtxHold h(lock, QMtxHold::AcceptNullMutex);
00201             referrers.push_back(ReferrerEntry(r));
00202         }
00203         void int_removeReferrer(FXRefingObjectBase *r, QMutex *lock)
00204         {
00205             QMtxHold h(lock, QMtxHold::AcceptNullMutex);
00206             referrers.remove(ReferrerEntry(r));
00207         }
00208         const QValueList<ReferrerEntry> *int_referrers() const { return &referrers; }
00209     };
00210 #ifdef _MSC_VER
00211 #pragma warning(pop)
00212 #endif
00213 
00217     struct hasLastUsed
00218     {
00219     private:
00220         mutable FXuint lastusedtimestamp;
00221     protected:
00222         hasLastUsed() : lastusedtimestamp(0) { }
00223     public:
00227         FXuint lastUsed() const throw() { return lastusedtimestamp; }
00228     };
00229 }
00255 template<typename intType,
00256     class lastUsed=Pol::None0,
00257     class referrersPolicy=Pol::unknownReferrers> class FXRefedObject : public FXRefedObjectImpl::countHolder<intType>, public lastUsed, private referrersPolicy
00258 {
00259     template<class type> friend class FXRefingObjectImpl::refedObject;
00260     template<bool mutexed, class type> friend struct FXRefingObjectImpl::dataHolderI;
00261     template<class type> friend class FXRefedObject_DisableCount;
00262     typedef FXRefedObject MyFXRefedObjectSpec;
00263     intType disableCount;
00264 public:
00265     FXRefedObject() : disableCount(0) { }
00266     virtual ~FXRefedObject() { }
00267     FXRefedObject(const FXRefedObject &o) : lastUsed(o), referrersPolicy(), disableCount(o.disableCount) { /* new instance */ }
00268 protected:
00270     virtual void noMoreReferrers() { delete this; }
00271     using referrersPolicy::ReferrerEntry;
00272     using referrersPolicy::int_referrers;
00273 };
00274 
00275 namespace FXRefingObjectImpl {
00276     template<bool mutexed, class type> struct dataHolderI
00277     {
00278         type *data;
00279         dataHolderI(type *p) : data(p) { }
00280         inline void addRef();
00281         inline void delRef();
00282     };
00283     template<class type> struct dataHolderI<true, type>
00284     {
00285         type *data;
00286         dataHolderI(type *p) : data(p) { }
00287         inline void addRef();
00288         inline void delRef();
00289     };
00290     template<class type> struct dataHolder
00291         : public dataHolderI<Generic::convertible<QMutex &, type &>::value, type>
00292     {
00293         dataHolder(type *p) : dataHolderI<Generic::convertible<QMutex &, type &>::value, type>(p) { }
00294     };
00295     template<bool hasLastUsed, class type> class lastUsedI : protected dataHolder<type>
00296     {
00297     protected:
00298         lastUsedI(type *p) : dataHolder<type>(p) { }
00299         type *accessData() const throw() { return dataHolder<type>::data; }
00300     };
00301     template<class type> class lastUsedI<true, type> : protected dataHolder<type>
00302     {
00303     protected:
00304         lastUsedI(type *p) : dataHolder<type>(p) { }
00305         type *accessData() const
00306         {
00307             if(dataHolder<type>::data) dataHolder<type>::data->lastusedtimestamp=FXProcess::getMsCount();
00308             return dataHolder<type>::data;
00309         }
00310     };
00311     template<class type> class refedObject
00312         : private lastUsedI<Generic::convertible<Pol::hasLastUsed &, type &>::value, type>
00313     {
00314         template<bool, class> friend struct FXRefingObjectImpl::dataHolderI;
00315         typedef lastUsedI<Generic::convertible<Pol::hasLastUsed &, type &>::value, type> Base;
00316         void inc()
00317         {
00318             if(Base::data && !Base::data->disableCount)
00319             {
00320                 if(Base::data->int_increfcount())
00321                     Base::addRef();
00322                 else
00323                     Base::data=0;
00324             }
00325         }
00326         void dec()
00327         {
00328             if(Base::data && !Base::data->disableCount)
00329             {
00330                 Base::delRef();
00331                 if(!Base::data->int_decrefcount())
00332                     static_cast<typename type::MyFXRefedObjectSpec *>(Base::data)->noMoreReferrers();
00333                 Base::data=0;           // No longer usuable
00334             }
00335         }
00336     public:
00337         refedObject(type *d) : Base(d) { inc(); }
00338         refedObject(const refedObject &o) : Base(o) { inc(); }
00339         refedObject &operator=(const refedObject &o)
00340         {
00341             dec();
00342             Base::data=o.data;
00343             inc();
00344             return *this;
00345         }
00346         ~refedObject()
00347         {
00348             dec();
00349         }
00350         friend type *PtrPtr(refedObject &p) { return p.accessData(); }
00351         friend const type *PtrPtr(const refedObject &p) { return p.accessData(); }
00352         friend type *&PtrRef(refedObject &p) { return p.data; }
00353         friend const type *PtrRef(const refedObject &p) { return p.data; }
00354     };
00355 
00356 } // namespace
00357 
00361 template<class type> class FXRefedObject_DisableCount
00362 {
00363     type *object;
00364 public:
00365     FXRefedObject_DisableCount(type *obj) : object(obj) { ++object->disableCount; }
00366     ~FXRefedObject_DisableCount() { --object->disableCount; }
00367 };
00368 
00413 template<class type> class FXRefingObject
00414     : public FXRefingObjectBase, public Generic::ptr<type, FXRefingObjectImpl::refedObject>
00415 {
00416 public:
00418     FXRefingObject(type *data=0, const char *file=0, int lineno=0)
00419         : FXRefingObjectBase(file, lineno), Generic::ptr<type, FXRefingObjectImpl::refedObject>(data) { }
00420     explicit FXRefingObject(FXAutoPtr<type> &ptr)
00421         : FXRefingObjectBase(0, 0), Generic::ptr<type, FXRefingObjectImpl::refedObject>(ptr) { }
00422 #if FXREFINGOBJECT_DEBUGKNOWALLOC
00423  #if 1
00424     // Prefer original info over where copied
00425     FXRefingObject(const FXRefingObject &o, const char *file=0, int lineno=0)
00426         : FXRefingObjectBase(o.allocated.file ? o.allocated.file : file, o.allocated.file ? o.allocated.lineno : lineno), Generic::ptr<type, FXRefingObjectImpl::refedObject>(o) { }
00427  #else
00428     // Prefer where copied over original info
00429     FXRefingObject(const FXRefingObject &o, const char *file=0, int lineno=0)
00430         : FXRefingObjectBase(file ? file : o.allocated.file, file ? lineno : o.allocated.lineno), Generic::ptr<type, FXRefingObjectImpl::refedObject>(o) { }
00431  #endif
00432 #else
00433     FXRefingObject(const FXRefingObject &o, const char *file=0, int lineno=0)
00434         : FXRefingObjectBase(0, 0), Generic::ptr<type, FXRefingObjectImpl::refedObject>(o) { }
00435 #endif
00436 
00439     friend FXRefingObject PtrDetach(FXRefingObject &p)
00440     {
00441         FXAutoPtr<type> v;
00442         type *pv=PtrPtr(p);
00443         assert(pv);
00444         FXERRHM(v=new type(*pv));
00445         return FXRefingObject(v);
00446     }
00447 };
00448 
00449 namespace FXRefingObjectImpl
00450 {   // Now that we know FXRefingObject's relationship to its policy classes, we can static_cast<>
00451     template<bool mutexed, class type> inline void dataHolderI<mutexed, type>::addRef()
00452     {
00453         data->int_addReferrer(static_cast<FXRefingObject<type> *>(this), 0);
00454     }
00455     template<bool mutexed, class type> inline void dataHolderI<mutexed, type>::delRef()
00456     {
00457         data->int_removeReferrer(static_cast<FXRefingObject<type> *>(this), 0);
00458     }
00459     template<class type> inline void dataHolderI<true, type>::addRef()
00460     {
00461         data->int_addReferrer(static_cast<FXRefingObject<type> *>(this), data);
00462     }
00463     template<class type> inline void dataHolderI<true, type>::delRef()
00464     {
00465         data->int_removeReferrer(static_cast<FXRefingObject<type> *>(this), data);
00466     }
00467 }
00468 
00469 } // namespace
00470 
00471 #endif

(C) 2002-2009 Niall Douglas. Some parts (C) to assorted authors.
Generated on Fri Nov 20 18:31:24 2009 for TnFOX by doxygen v1.4.7