ref.H

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00020 #ifndef ARCHON_UTILITIES_REF_H
00021 #define ARCHON_UTILITIES_REF_H
00022 
00023 #include <string>
00024 #include <vector>
00025 #include <algorithm>
00026 
00027 #include <archon/util/exception.H>
00028 #include <archon/util/mutex.H>
00029 
00030 #include <archon/util/cxx_demangle.H>
00031 
00032 namespace Archon
00033 {
00034   namespace Utilities
00035   {
00036     using namespace std;
00037 
00038     template<typename T> struct BackRef;
00039     struct RefMapBase;
00040     template<typename T> struct RefMap;
00041     struct Thread;
00042 
00043     struct ForwardDestroyedException: Exception
00044     {
00045       ForwardDestroyedException(string l): Exception(l) {}
00046     };
00047 
00048 
00052     struct RefNoLockTag {};
00053 
00057     struct RefSafeIncTag {};
00058 
00059 
00166     template<typename T>
00167     struct Ref
00168     {
00169       typedef T ObjectType;
00170 
00171       Ref(): p(0) {}
00172 
00177       Ref(T *p): p(p) { inc(); }
00178 
00179       Ref(const Ref &r): p(r.p) { inc(); }
00180       template<typename U> Ref(const Ref<U> &r): p(r.p) { inc(); }
00181 
00182       ~Ref() { dec(); }
00183 
00191       void reset(T *p=0);
00192 
00197       void swap(Ref &r) { std::swap(p, r.p); }
00198 
00199       Ref &operator=(const Ref &);
00200       template<typename U> Ref &operator=(const Ref<U> &);
00201 
00202       template<typename U> bool operator==(const Ref<U> &) const;
00203       template<typename U> bool operator!=(const Ref<U> &) const;
00204       template<typename U> bool operator<(const Ref<U> &) const;
00205       template<typename U> bool operator>(const Ref<U> &) const;
00206 
00210       T *operator->() const;
00211 
00212       operator bool() const { return p; }
00213 
00225       T *get() const { return p; }
00226 
00230       bool sole() const { return p && p->refSole(); }
00231 
00232 
00237       Ref(T *p, RefNoLockTag): p(p) { incNoLock(); }
00238 
00239 
00380       Ref(T *p, RefSafeIncTag);
00381 
00382     private:
00383       template<typename U> friend struct Ref;
00384       friend struct BackRef<T>;
00385       friend struct RefMap<T>;
00386 
00387       T *p;
00388 
00389       void inc() const { if(p) p->refInc(); }
00390       void dec() const { if(p) p->refDec(); }
00391 
00392       void incNoLock() const { if(p) p->refIncNoLock(); }
00393     };
00394 
00395 
00396 
00423     struct RefObjectBase: protected virtual Mutex
00424     {
00428       virtual ~RefObjectBase() {}
00429 
00430       unsigned long getUseCount() const;
00431 
00432     protected:
00433       RefObjectBase(): useCount(0) {}
00434 
00456       virtual void refDispose(Mutex::Lock &);
00457 
00458       unsigned long getUseCountNoLock() const { return useCount; }
00459 
00460     private:
00461       template<typename T> friend struct Ref;
00462       template<typename T> friend struct BackRef;
00463       friend struct BackRefObjectBase;
00464       friend struct RefMapBase;
00465       friend struct Thread;
00466 
00467       void refInc() const;
00468       void refDec() const;
00469 
00470       void refIncNoLock() const;
00471 
00475       virtual bool refTryInc() const;
00476 
00480       bool refSole() const;
00481 
00482       mutable unsigned long useCount;
00483     };
00484 
00485 
00486     typedef Ref<RefObjectBase> RefAny;
00487     typedef Ref<const RefObjectBase> RefAnyConst;
00488 
00489 
00497     template<typename T>
00498     struct RefObject: virtual RefObjectBase
00499     {
00500       T value;
00501       RefObject(T v): value(v) {}
00502     };
00503 
00504 
00505 
00506 
00624     template<typename T>
00625     struct BackRef
00626     {
00627       typedef T ObjectType;
00628 
00629       BackRef(): p(0) {}
00630 
00631       BackRef(const Ref<T> &r): p(r.get()) { inc(); }
00632       BackRef(const BackRef &r): p(r.p) { inc(); }
00633       template<typename U> BackRef(const BackRef<U> &r): p(r.p) { inc(); }
00634 
00635      ~BackRef() { dec(); }
00636 
00641       void reset() { reset(0); }
00642 
00647       void reset(const Ref<T> &r) { reset(r.p); }
00648 
00653       void swap(BackRef &r) { std::swap(p, r.p); }
00654 
00655       BackRef &operator=(const BackRef &);
00656       template<typename U> BackRef &operator=(const BackRef<U> &);
00657 
00658       template<typename U> bool operator==(const BackRef<U> &) const;
00659       template<typename U> bool operator!=(const BackRef<U> &) const;
00660 
00661       template<typename U> bool operator==(const Ref<U> &) const;
00662       template<typename U> bool operator!=(const Ref<U> &) const;
00663 
00664       template<typename U> bool operator==(const U *) const;
00665       template<typename U> bool operator!=(const U *) const;
00666 
00670       Ref<T> operator->() const throw(ForwardDestroyedException);
00671 
00672       operator bool() const { return p; }
00673 
00674       Ref<T> getRef() const throw(ForwardDestroyedException);
00675 
00676     private:
00677       template<typename U> friend struct BackRef;
00678 
00679       T *p;
00680 
00681       void reset(T *p);
00682 
00683       void inc() const { if(p) p->backRefInc(); }
00684       void dec() const { if(p) p->backRefDec(); }
00685     };
00686 
00687 
00695     struct BackRefObjectBase: virtual RefObjectBase
00696     {
00697       unsigned long getBackUseCount() const;
00698 
00699     protected:
00700       BackRefObjectBase(): backUseCount(0), forwardDestroyed(false) {}
00701 
00702       virtual void refDispose(Mutex::Lock &);
00703 
00725       virtual void refForwardDestroy() = 0;
00726 
00727       unsigned long getBackUseCountNoLock() const { return backUseCount; }
00728 
00729     private:
00730       template<typename T> friend struct Ref;
00731       template<typename T> friend struct BackRef;
00732 
00733       void backRefInc() const;
00734       void backRefDec() const;
00735 
00736       virtual bool refTryInc() const;
00737 
00738       mutable unsigned long backUseCount;
00739       bool forwardDestroyed;
00740     };
00741 
00742 
00743 
00744 
00745 
00751     struct RefMapBase
00752     {
00753     protected:
00754       unsigned long get(RefObjectBase *, bool create);
00755 
00756       RefObjectBase *getNoLock(unsigned long key) const
00757       {
00758         return key < refs.size() ? refs[key].first : 0;
00759       }
00760 
00761       void remove(unsigned long key, unsigned long transCount)
00762       {
00763         if(!key) return;
00764         Mutex::Lock l(refMapMutex);
00765         if(key >= refs.size()) return;
00766         removeNoLock(refs[key].first, transCount);
00767       }
00768 
00769       void remove(RefObjectBase *r)
00770       {
00771         Mutex::Lock l(refMapMutex);
00772         removeNoLock(r, 0);
00773       }
00774 
00775       void clearNoLock(bool destroyRefs);
00776 
00777       Mutex refMapMutex;
00778       // Pairs of refs and translation count
00779       vector<pair<RefObjectBase *, unsigned long> > refs;
00780 
00781       unsigned long size()
00782       {
00783         Mutex::Lock l(refMapMutex);
00784         return refs.size() - unused.size() - 1;
00785       }
00786 
00787       string disp();
00788 
00789       RefMapBase();
00790       ~RefMapBase();
00791 
00792     private:
00793       static const unsigned long hashSize = 127;
00794 
00795       vector<unsigned long> *chunks[hashSize];
00796       vector<unsigned long> unused;
00797 
00798       void removeNoLock(RefObjectBase *, unsigned long transCount);
00799     };
00800 
00874     template<typename T>
00875     struct RefMap: private RefMapBase
00876     {
00880       RefMapBase::size;
00881 
00885       RefMapBase::disp;
00886 
00896       unsigned long get(Ref<T> r, bool create=true)
00897       {
00898         return RefMapBase::get(const_cast<RefObjectBase *>
00899                                (static_cast<const RefObjectBase *>
00900                                 (r.get())), create);
00901       }
00902 
00914       Ref<T> operator()(unsigned long key) const
00915       {
00916         Mutex::Lock l(refMapMutex);
00917         return dynamic_cast<T *>(getNoLock(key));
00918       }
00919 
00927       void remove(unsigned long key, unsigned long transCount=0)
00928       {
00929         RefMapBase::remove(key, transCount);
00930       }
00931 
00936       void remove(Ref<T> r)
00937       {
00938         RefMapBase::remove(const_cast<RefObjectBase *>
00939                            (static_cast<const RefObjectBase *>(r.get())));
00940       }
00941 
00942       void clear(vector<Ref<T> > *remains = 0)
00943       {
00944         if(remains)
00945         {
00946           remains->clear();
00947           remains->resize(size());
00948           Mutex::Lock l(refMapMutex);
00949           unsigned j = 0;
00950           for(unsigned i = 1; i<refs.size(); ++i)
00951           {
00952             RefObjectBase *r = refs[i].first;
00953             if(r) remains->operator[](j++).p = dynamic_cast<T *>(r);
00954           }
00955           RefMapBase::clearNoLock(false);
00956         }
00957         else
00958         {
00959           Mutex::Lock l(refMapMutex);
00960           RefMapBase::clearNoLock(true);
00961         }
00962       }
00963     };
00964 
00965 
00966 
00967 
00968 
00969     template<typename T>
00970     inline void Ref<T>::reset(T *_p)
00971     {
00972       if(p == _p) return;
00973       dec();
00974       p = _p;
00975       inc();
00976     }
00977 
00978     template<typename T>
00979     inline Ref<T> &Ref<T>::operator=(const Ref &r)
00980     {
00981       reset(r.p);
00982       return *this;
00983     }
00984 
00985     template<typename T> template<typename U>
00986     inline Ref<T> &Ref<T>::operator=(const Ref<U> &r)
00987     {
00988       reset(r.p);
00989       return *this;
00990     }
00991 
00992     template<typename T> template<typename U>
00993     inline bool Ref<T>::operator==(const Ref<U> &r) const
00994     {
00995       return p == r.p;
00996     }
00997 
00998     template<typename T> template<typename U>
00999     inline bool Ref<T>::operator!=(const Ref<U> &r) const
01000     {
01001       return p != r.p;
01002     }
01003 
01004     template<typename T> template<typename U>
01005     inline bool Ref<T>::operator<(const Ref<U> &r) const
01006     {
01007       return p < r.p;
01008     }
01009 
01010     template<typename T> template<typename U>
01011     inline bool Ref<T>::operator>(const Ref<U> &r) const
01012     {
01013       return p > r.p;
01014     }
01015 
01016     template<typename T>
01017     inline T *Ref<T>::operator->() const
01018     {
01019       if(p) return p;
01020       ARCHON_THROW1(StateException, "Dereferencing null");
01021     }
01022 
01023     template<typename T>
01024     inline Ref<T>::Ref(T *_p, RefSafeIncTag): p(0)
01025     {
01026       if(_p && _p->refTryInc()) p = _p;
01027     }
01028 
01029 
01030 
01031     inline void RefObjectBase::refInc() const
01032     {
01033       Mutex::Lock l(*this);
01034       ++useCount;
01035     }
01036 
01037     inline void RefObjectBase::refDec() const
01038     {
01039       Mutex::Lock l(*this);
01040       if(!--useCount) const_cast<RefObjectBase *>(this)->refDispose(l);
01041     }
01042 
01043     inline void RefObjectBase::refIncNoLock() const
01044     {
01045       ++useCount;
01046     }
01047 
01048     inline void RefObjectBase::refDispose(Mutex::Lock &l)
01049     {
01050       l.release();
01051       // Note: The validity of this self destruction relies on the
01052       // fact that no explicit or implict references to "this" are
01053       // made after the delete statement (keep it like that).
01054       delete this;
01055     }
01056 
01057     inline bool RefObjectBase::refTryInc() const
01058     {
01059       Mutex::Lock l(*this);
01060       if(useCount)
01061       {
01062         ++useCount;
01063         return true;
01064       }
01065       return false;
01066     }
01067 
01068     inline bool RefObjectBase::refSole() const
01069     {
01070       Mutex::Lock l(*this);
01071       return useCount == 1;
01072     }
01073 
01074     inline unsigned long RefObjectBase::getUseCount() const
01075     {
01076       Mutex::Lock l(*this);
01077       return useCount;
01078     }
01079 
01080 
01081 
01082 
01083     template<typename T>
01084     inline void BackRef<T>::reset(T *_p)
01085     {
01086       if(p == _p) return;
01087       dec();
01088       p = _p;
01089       inc();
01090     }
01091 
01092     template<typename T>
01093     inline BackRef<T> &BackRef<T>::operator=(const BackRef &r)
01094     {
01095       reset(r.p);
01096       return *this;
01097     }
01098 
01099     template<typename T> template<typename U>
01100     inline BackRef<T> &BackRef<T>::operator=(const BackRef<U> &r)
01101     {
01102       reset(r.p);
01103       return *this;
01104     }
01105 
01106     template<typename T> template<typename U>
01107     inline bool BackRef<T>::operator==(const BackRef<U> &r) const
01108     {
01109       return p == r.p;
01110     }
01111 
01112     template<typename T> template<typename U>
01113     inline bool BackRef<T>::operator!=(const BackRef<U> &r) const
01114     {
01115       return p != r.p;
01116     }
01117 
01118     template<typename T> template<typename U>
01119     inline bool BackRef<T>::operator==(const Ref<U> &r) const
01120     {
01121       return p == r.get();
01122     }
01123 
01124     template<typename T> template<typename U>
01125     inline bool BackRef<T>::operator!=(const Ref<U> &r) const
01126     {
01127       return p != r.get();
01128     }
01129 
01130     template<typename T> template<typename U>
01131     inline bool BackRef<T>::operator==(const U *r) const
01132     {
01133       return p == r;
01134     }
01135 
01136     template<typename T> template<typename U>
01137     inline bool BackRef<T>::operator!=(const U *r) const
01138     {
01139       return p != r;
01140     }
01141 
01142     template<typename T>
01143     inline Ref<T> BackRef<T>::getRef() const throw(ForwardDestroyedException)
01144     {
01145       if(!p) return 0;
01146       Ref<T> r(p, RefSafeIncTag());
01147       if(!r) ARCHON_THROW(ForwardDestroyedException);
01148       return r;
01149     }
01150 
01151     template<typename T>
01152     inline Ref<T> BackRef<T>::operator->() const
01153       throw(ForwardDestroyedException)
01154     {
01155       if(!p) return 0;
01156       Ref<T> r(p, RefSafeIncTag());
01157       if(!r) ARCHON_THROW(ForwardDestroyedException);
01158       return r;
01159     }
01160 
01161 
01162 
01163 
01164     inline void BackRefObjectBase::backRefInc() const
01165     {
01166       Mutex::Lock l(*this);
01167       ++backUseCount;
01168     }
01169 
01170     inline void BackRefObjectBase::backRefDec() const
01171     {
01172       Mutex::Lock l(*this);
01173       if(!--backUseCount) const_cast<BackRefObjectBase *>(this)->refDispose(l);
01174     }
01175 
01176 
01177     inline bool BackRefObjectBase::refTryInc() const
01178     {
01179       Mutex::Lock l(*this);
01180       if(useCount&&!forwardDestroyed)
01181       {
01182         ++useCount;
01183         return true;
01184       }
01185       return false;
01186     }
01187 
01188 
01189     inline void BackRefObjectBase::refDispose(Mutex::Lock &l)
01190     {
01191       if(!useCount)
01192       {
01193         if(!backUseCount)
01194         {
01195           l.release();
01196 
01197           // Note: The validity of this self destruction relies on the
01198           // fact that no explicit or implict references to "this" are
01199           // made after the delete statement (keep it like that).
01200           delete this;
01201           return;
01202         }
01203 
01204         if(forwardDestroyed) return;
01205         forwardDestroyed = true;
01206         Ref<BackRefObjectBase> r(this, RefNoLockTag());
01207         l.release();
01208         r->refForwardDestroy();
01209       }
01210     }
01211 
01212     inline unsigned long BackRefObjectBase::getBackUseCount() const
01213     {
01214       Mutex::Lock l(*this);
01215       return backUseCount;
01216     }
01217   }
01218 }
01219 
01220 namespace std
01221 {
01222   template<typename T>
01223   void swap(Archon::Utilities::Ref<T> &r,
01224             Archon::Utilities::Ref<T> &s)
01225   {
01226     r.swap(s);
01227   }
01228 
01229   template<typename T>
01230   void swap(Archon::Utilities::BackRef<T> &r,
01231             Archon::Utilities::BackRef<T> &s)
01232   {
01233     r.swap(s);
01234   }
01235 }
01236 
01237 #endif // ARCHON_UTILITIES_REF_H

Generated on Sun Jul 30 22:55:45 2006 for Archon by  doxygen 1.4.4