Follow this link to skip to the main content

auto_reference.h

Go to the documentation of this file.
00001 // -*-c++-*-
00002 //----------------------------< /-/ CLARAty /-/ >------------------------------
00003 /**
00004  * @file  auto_reference.h
00005  *
00006  * Auto reference similar to auto pointers
00007  *
00008  * <br>@b Designer(s):  Randy Sargent
00009  * <br>@b Author(s):    Randy Sargent
00010  * <br>@b Date:         March 13, 2004
00011  *
00012  * <b>Software License:</b><br>
00013  * <code> http://claraty.jpl.nasa.gov/license/open_src/  or 
00014  *        file: license/open_src.txt </code>
00015  *
00016  * &copy; 2006, Jet Propulsion Laboratory, California Institute of Technology<br>
00017  * &copy; 2006, NASA Ames Research Center
00018  *
00019  * $Revision: 1.4 $
00020  */
00021 //-----------------------------------------------------------------------------
00022 
00023 #ifndef  AUTO_REF_H
00024 #define  AUTO_REF_H
00025 
00026 #include "claraty/share.h"
00027 
00028 #include <iostream>
00029 #include <assert.h>
00030 
00031 // ACE includes
00032 //#include "ace/Synch.h"
00033 #include "claraty/semaphore.h"
00034 
00035 namespace claraty {
00036 
00037 template <class T> class Auto_Ref;
00038 template <class T> class const_Auto_Ref;
00039 
00040 // Clay had to pull this out of the private section of Auto_Ref because of
00041 // compiler confusion resulting from mixing Auto_Ref's of different types.
00042 // So instead of keeping it as a private Auto_Ref helper class, the thing is
00043 // entirely private, but it keeps Auto_Ref as a friend.
00044 template<class RT>
00045 class ref_counter {
00046   int refcount;
00047   //mutable ACE_Recursive_Thread_Mutex lock;
00048   mutable Semaphore lock; 
00049   RT *_rep;
00050 
00051   explicit ref_counter(const ref_counter&);
00052 
00053   friend class Auto_Ref<RT>;
00054   friend class const_Auto_Ref<RT>;
00055 
00056   ref_counter(RT *&r) : refcount(1), lock(), _rep(r) { }
00057   ref_counter() : refcount(1), lock(), _rep(NULL) { }
00058   ~ref_counter() { }
00059 
00060   void inc() {
00061     lock.acquire();
00062     refcount++;
00063     lock.release();
00064   }
00065 
00066   int dec() {
00067     lock.acquire();
00068     if (--refcount == 0)
00069       delete _rep;
00070     int val = refcount;
00071     lock.release();
00072     return val;
00073   }
00074 
00075   // Calling this function probably won't do what you want, since
00076   // the refcount can be invalidated before it is returned
00077   int get_count() const {
00078     lock.acquire();
00079     int val = refcount;
00080     lock.release();
00081     return val;
00082   }
00083 
00084   void make_null_if_unique() {
00085     lock.acquire();
00086     if (refcount == 1) {
00087       delete _rep;
00088       _rep= NULL;
00089     }
00090     lock.release();
00091   }
00092 };
00093 
00094 template <class T>
00095 class Auto_Ref {
00096   friend class const_Auto_Ref<T>;
00097 
00098   ref_counter<T> *_rc;
00099   
00100 public:
00101   Auto_Ref() { _rc= new ref_counter<T>(); }
00102   explicit Auto_Ref(T *&ptr) { _rc = new ref_counter<T>(ptr); ptr = 0; }
00103   Auto_Ref(const Auto_Ref& rhs) {
00104     _rc = rhs._rc;
00105     _rc->inc();
00106   }
00107   ~Auto_Ref() {
00108     if (_rc->dec() == 0) delete _rc;
00109   }
00110 
00111   // Why does this function have such a long name? To remind you that you
00112   // really shouldn't be calling it, ever. It should only be used by the
00113   // internal operator== function.
00114   const void *get_const_representation_pointer() const { return _rc; }
00115 
00116   Auto_Ref& operator=(const Auto_Ref& rhs) {
00117     if (_rc != rhs._rc) {
00118       if (_rc->dec() == 0) delete _rc;
00119       _rc = rhs._rc;
00120       _rc->inc();
00121     }
00122     return *this;
00123   }
00124 
00125   template <class R>
00126   bool operator==(const Auto_Ref<R>& rhs) const {
00127     return static_cast<void*>(_rc) == rhs.get_const_representation_pointer();
00128   }
00129 
00130   template <class R>
00131   bool operator!=(const Auto_Ref<R>& rhs) const {
00132     return !operator==(rhs);
00133   }
00134 
00135   // evil casting function, which casts what we're reffing to a subclass
00136   // thereof. This would throw bad cast if the dynamic cast fails, but for now
00137   // it simply causes the program to abort.
00138   template <class S>
00139   void cast_to(Auto_Ref<S>& rhs) {
00140     if (dynamic_cast<S*>(_rc->_rep) == NULL) {
00141       std::cerr << "Illegal attempt to cast an Auto_Ref<T> to an Auto_Ref<U> where "
00142         "U is not castable from T (or from a NULL Auto_Ref)" << std::endl;
00143       S& dummy = dynamic_cast<S&>(*_rc->_rep); // will throw bad_cast
00144     }
00145     ref_counter<S> *rc_subclass = reinterpret_cast<ref_counter<S>*>(_rc);
00146     rhs.reset_rc(rc_subclass);
00147   }
00148 
00149   // casting to something of the same type is esy
00150   void cast_to(Auto_Ref<T>& rhs) {
00151     rhs = *this;
00152   }
00153 
00154   // This can only be called by other Auto_Ref's since they're the only ones
00155   // who have access to the ref_counter sibling type. The function is public
00156   // because Auto_Ref's of other types are not our friends.
00157   void reset_rc(ref_counter<T> *new_rc) {
00158     if (_rc->dec() == 0) delete _rc;
00159     _rc = new_rc;
00160     _rc->inc();
00161   }
00162 
00163   void reset(T *&ptr) {
00164     if (_rc->dec() == 0) delete _rc;
00165     _rc = new ref_counter<T>(ptr);
00166     ptr = 0;
00167   }
00168 
00169   T *get() const {
00170     return _rc->_rep;
00171   }
00172 
00173   void get_ptr(T *&p) const {
00174     p = _rc->_rep;
00175   }
00176 
00177   template <class U>
00178   void get_ptr(U *&p) {
00179     p = dynamic_cast<U*>(_rc->_rep);
00180   }
00181 
00182   // Frees object and changes pointer to NULL if you have
00183   // the only copy
00184   void make_null_if_unique() {
00185     _rc->make_null_if_unique();
00186   }
00187   
00188   void make_unique() {
00189     _rc->lock.acquire();
00190     if (_rc->get_count() <= 1) {
00191       assert(_rc->get_count() == 1); // should never get to zero while we care
00192       _rc->lock.release();
00193     } else {
00194       T *copy = _rc->_rep->clone();
00195       ref_counter<T> *rc = new ref_counter<T>(copy);
00196       _rc->dec();
00197       assert(_rc->get_count() > 0); // since we know it was greater than 1
00198       _rc->lock.release();
00199       _rc = rc;
00200     }
00201   }
00202   
00203   const T& operator*() const {
00204     return *_rc->_rep;
00205   }
00206 
00207   const T *operator->() const {
00208     return _rc->_rep;
00209   }
00210 
00211   T& operator*() {
00212     return *_rc->_rep;
00213   }
00214 
00215   T *operator->() {
00216     return _rc->_rep;
00217   }
00218 
00219   operator bool() const {
00220     return !!_rc->_rep;
00221   }
00222   bool operator!() const {
00223     return !_rc->_rep;
00224   }
00225 };
00226 
00227 template <class T>
00228 class const_Auto_Ref {
00229   ref_counter<T> *_rc;
00230 public:
00231   const_Auto_Ref() { _rc = new ref_counter<T>(); }
00232   const_Auto_Ref(const const_Auto_Ref& rhs) {
00233     _rc = rhs._rc;
00234     _rc->inc();
00235   }
00236   const_Auto_Ref(const Auto_Ref<T>& rhs) {
00237     _rc = rhs._rc;
00238     _rc->inc();
00239   }
00240   ~const_Auto_Ref() {
00241     if (_rc->dec() == 0) delete _rc;
00242   }
00243 
00244   // Why does this function have such a long name? To remind you that you
00245   // really shouldn't be calling it, ever. It should only be used by the
00246   // internal operator== function.
00247   const void *get_const_representation_pointer() const { return _rc; }
00248 
00249   const_Auto_Ref& operator=(const const_Auto_Ref& rhs) {
00250     if (_rc != rhs._rc) {
00251       if (_rc->dec() == 0) delete _rc;
00252       _rc = rhs._rc;
00253       _rc->inc();
00254     }
00255     return *this;
00256   }
00257 
00258   // evil casting function, which casts what we're reffing to a subclass
00259   // thereof. This would throw bad cast if the dynamic cast fails, but for now
00260   // it simply causes the program to abort.
00261   template <class S>
00262   void cast_to(const_Auto_Ref<S>& rhs) {
00263     if (dynamic_cast<S*>(_rc->_rep) == NULL) {
00264       std::cerr << "Illegal attempt to cast an Auto_Ref<T> to an Auto_Ref<U> where "
00265         "U is not castable from T (or from a NULL Auto_Ref)" << std::endl;
00266       S& dummy = dynamic_cast<S&>(*_rc->_rep); // will throw bad_cast
00267     }
00268     ref_counter<S> *rc_subclass = reinterpret_cast<ref_counter<S>*>(_rc);
00269     rhs.reset_rc(rc_subclass);
00270   }
00271 
00272   // casting to something of the same type is esy
00273   void cast_to(const_Auto_Ref<T>& rhs) {
00274     rhs = *this;
00275   }
00276 
00277   // This can only be called by other Auto_Ref's since they're the only ones
00278   // who have access to the ref_counter sibling type. The function is public
00279   // because Auto_Ref's of other types are not our friends.
00280   void reset_rc(ref_counter<T> *new_rc) {
00281     if (_rc->dec() == 0) delete _rc;
00282     _rc = new_rc;
00283     _rc->inc();
00284   }
00285 
00286   template <class R>
00287   bool operator==(const const_Auto_Ref<R>& rhs) const {
00288     return static_cast<void*>(_rc) == rhs.get_const_representation_pointer();
00289   }
00290 
00291   template <class R>
00292   bool operator!=(const const_Auto_Ref<R>& rhs) const {
00293     return !operator==(rhs);
00294   }
00295   const T& operator*() const {
00296     return *_rc->_rep;
00297   }
00298 
00299   const T *operator->() const {
00300     return _rc->_rep;
00301   }
00302 
00303   operator bool() const {
00304     return !!_rc->_rep;
00305   }
00306   bool operator!() const {
00307     return !_rc->_rep;
00308   }
00309 };
00310 
00311 } // namespace claraty
00312 
00313 #endif // AUTO_REF_H