ref.h

Go to the documentation of this file.
00001 /** @file nub/ref.h smart pointers (both strong and weak) using
00002     intrusive ref-counting with nub::object and derivatives */
00003 
00004 ///////////////////////////////////////////////////////////////////////
00005 //
00006 // Copyright (c) 2000-2004 California Institute of Technology
00007 // Copyright (c) 2004-2007 University of Southern California
00008 // Rob Peters <rjpeters at usc dot edu>
00009 //
00010 // created: Thu Oct 26 17:50:59 2000
00011 // commit: $Id: ref.h 8249 2007-04-12 06:03:40Z rjpeters $
00012 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/nub/ref.h $
00013 //
00014 // --------------------------------------------------------------------
00015 //
00016 // This file is part of GroovX.
00017 //   [http://ilab.usc.edu/rjpeters/groovx/]
00018 //
00019 // GroovX is free software; you can redistribute it and/or modify it
00020 // under the terms of the GNU General Public License as published by
00021 // the Free Software Foundation; either version 2 of the License, or
00022 // (at your option) any later version.
00023 //
00024 // GroovX is distributed in the hope that it will be useful, but
00025 // WITHOUT ANY WARRANTY; without even the implied warranty of
00026 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00027 // General Public License for more details.
00028 //
00029 // You should have received a copy of the GNU General Public License
00030 // along with GroovX; if not, write to the Free Software Foundation,
00031 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00032 //
00033 ///////////////////////////////////////////////////////////////////////
00034 
00035 #ifndef GROOVX_NUB_REF_H_UTC20050626084019_DEFINED
00036 #define GROOVX_NUB_REF_H_UTC20050626084019_DEFINED
00037 
00038 #include "nub/handle.h"
00039 #include "nub/object.h"
00040 #include "nub/weak_handle.h"
00041 
00042 #include "rutz/fileposition.h" // for SRC_POS macro
00043 #include "rutz/stderror.h"     // for rutz::throw_bad_cast()
00044 #include "rutz/traits.h"
00045 
00046 #include <typeinfo>
00047 
00048 namespace nub
00049 {
00050   template <class T> class ref;
00051   template <class T> class soft_ref;
00052   template <class T> class floating_ref;
00053 
00054   //! Get the current default visibility (will control ref_vis DEFAULT).
00055   ref_vis get_default_ref_vis();
00056 
00057   //! Set the current default visibility (will control ref_vis DEFAULT).
00058   void set_default_ref_vis(ref_vis vis);
00059 
00060   namespace detail
00061   {
00062     bool is_valid_uid(nub::uid id) throw();
00063     nub::object* get_checked_item(nub::uid id);
00064 
00065     void insert_item(nub::object* obj, ref_vis vis);
00066 
00067     template <class T>
00068     inline T* get_casted_item(nub::uid id)
00069     {
00070       nub::object* obj = get_checked_item(id);
00071       T* t = dynamic_cast<T*>(obj);
00072       if (t == 0)
00073         rutz::throw_bad_cast(typeid(T), typeid(nub::object), SRC_POS);
00074       return t;
00075     }
00076 
00077     template <>
00078     inline nub::object* get_casted_item<nub::object>(nub::uid id)
00079     { return get_checked_item(id); }
00080 
00081     /// Policy class which unrefs objects by decrementing their ref count.
00082     template <class T>
00083     struct default_unref_policy
00084     {
00085       static void unref(T* t) throw() { t->decr_ref_count(); }
00086     };
00087 
00088     /// Policy class which decrements ref count without deletion.
00089     template <class T>
00090     struct no_delete_unref_policy
00091     {
00092       static void unref(T* t) throw() { t->decr_ref_count_no_delete(); }
00093     };
00094 
00095   } // end namespace nub::detail
00096 
00097 } // end namespace nub
00098 
00099 namespace rutz
00100 {
00101   /// type_traits specialization for nub::ref smart pointer
00102   template <class T>
00103   struct type_traits<nub::ref<T> >
00104   {
00105     typedef T pointee_t;
00106   };
00107 
00108   /// type_traits specialization for soft_ref smart pointer.
00109   template <class T>
00110   struct type_traits<nub::soft_ref<T> >
00111   {
00112     typedef T pointee_t;
00113   };
00114 }
00115 
00116 
00117 
00118 
00119 ///////////////////////////////////////////////////////////
00120 /**
00121  *
00122  * nub::ref<T> is a ref-counted smart pointer for holding ref_counted
00123  * objects. A nub::ref<T> is guaranteed to always point to a valid
00124  * ref_counted object, and uses ref_counted's strong ref counts to
00125  * achieve this. In order to provide this guarantee, it is possible
00126  * that construction of a nub::ref<T> may throw an exception. For
00127  * example, a nub::ref<T> cannot be constructed for a volatlie
00128  * ref_counted object for which only weak references are available.
00129  *
00130  **/
00131 ///////////////////////////////////////////////////////////
00132 
00133 template <class T>
00134 class nub::ref
00135 {
00136 private:
00137 
00138   typedef nub::detail::handle<T, nub::detail::default_unref_policy<T> >
00139   handle;
00140 
00141   handle m_handle;
00142 
00143 public:
00144   // Default destructor, copy constructor, operator=() are fine
00145 
00146   explicit ref(nub::uid i)
00147     : m_handle(detail::get_casted_item<T>(i)) {}
00148 
00149   explicit ref(T* ptr, ref_vis vis = DEFAULT) :
00150     m_handle(ptr)
00151   {
00152     detail::insert_item(ptr, vis);
00153   }
00154 
00155   template <class U>
00156   ref(const ref<U>& other) : m_handle(other.get()) {}
00157 
00158   // Will raise an exception if the soft_ref is invalid
00159   template <class U>
00160   ref(const soft_ref<U>& other);
00161 
00162   /// Shorthand for assignment.
00163   /** Given ref<T> rr and T* p, then rr.reset(p) is shorthand for
00164       rr=ref<T>(p). But of course, rr.reset(p) is much less typing
00165       if T happens to be spelt SomeLongType<WithTemplateParams>. */
00166   void reset(T* p) { *this = ref(p); }
00167 
00168   T* operator->() const throw() { return get(); }
00169   T& operator*()  const throw() { return *(get()); }
00170 
00171   T* get()        const throw() { return m_handle.get(); }
00172 
00173   bool operator==(const ref& other) const throw()
00174   { return m_handle == other.m_handle; }
00175 
00176   bool operator!=(const ref& other) const throw()
00177   { return !(operator==(other)); }
00178 
00179   nub::uid id() const throw()
00180   { return get()->id(); }
00181 
00182   /// Comparison operator for sorting.
00183   /** E.g. to allow insertion into std::map or std::set, etc. */
00184   bool operator<(const ref& other) const throw()
00185   { return get() < other.get(); }
00186 };
00187 
00188 template <class To, class Fr>
00189 nub::ref<To> dyn_cast(nub::ref<Fr> p)
00190 {
00191   Fr* f = p.get();
00192   To* t = dynamic_cast<To*>(f);
00193   if (t == 0)
00194     rutz::throw_bad_cast(typeid(To), typeid(Fr), SRC_POS);
00195   return nub::ref<To>(t);
00196 }
00197 
00198 template <class To, class Fr>
00199 void dyn_cast_to_from(nub::ref<To>& dest, nub::ref<Fr> p)
00200 {
00201   dest = dyn_cast<To, Fr>(p);
00202 }
00203 
00204 // Compatibility interface with alternate function-naming:
00205 
00206 template <class To, class Fr>
00207 nub::ref<To> dynCast(nub::ref<Fr> p)
00208 { return dyn_cast<To, Fr>(p); }
00209 
00210 template <class To, class Fr>
00211 void dynCastToFrom(nub::ref<To>& dest, nub::ref<Fr> p)
00212 { dyn_cast_to_from<To, Fr>(dest, p); }
00213 
00214 
00215 ///////////////////////////////////////////////////////////
00216 /**
00217  *
00218  * nub::soft_ref<T> is a ref-counted smart pointer (like nub::ref<T>)
00219  * for holding ref_counted objects. Construction of a nub::soft_ref<T>
00220  * is guaranteed not to fail. Because of this, however, a
00221  * nub::soft_ref<T> is not guaranteed to always point to a valid
00222  * object (this must be tested with is_valid() before
00223  * dereferencing). With these characteristics, a nub::soft_ref<T> can
00224  * be used with volatile ref_counted objects for which only weak
00225  * references are available.
00226  *
00227  **/
00228 ///////////////////////////////////////////////////////////
00229 
00230 template <class T>
00231 class nub::soft_ref
00232 {
00233 private:
00234   mutable detail::weak_handle<T> m_handle;
00235 
00236 public:
00237   soft_ref() : m_handle(0, STRONG) {}
00238 
00239   explicit soft_ref(nub::uid i, ref_type tp = STRONG)
00240     :
00241     m_handle(detail::is_valid_uid(i) ?
00242              detail::get_casted_item<T>(i) : 0,
00243              tp)
00244   {}
00245 
00246   explicit soft_ref(T* master,
00247                     ref_type tp = STRONG, ref_vis vis = DEFAULT)
00248     :
00249     m_handle(master,tp)
00250   {
00251     if (m_handle.is_valid())
00252       {
00253         detail::insert_item(m_handle.get(), vis);
00254       }
00255   }
00256 
00257   template <class U>
00258   soft_ref(const soft_ref<U>& other) :
00259     m_handle(other.is_valid() ? other.get() : 0, STRONG) {}
00260 
00261   template <class U>
00262   soft_ref(const ref<U>& other) : m_handle(other.get(), STRONG) {}
00263 
00264   // Default destructor, copy constructor, operator=() are fine
00265 
00266   /// Shorthand for assignment.
00267   /** Given ref<T> rr and T* p, then rr.reset(p) is shorthand for
00268       rr=ref<T>(p). But of course, rr.reset(p) is much less typing
00269       if T happens to be spelt SomeLongType<WithTemplateParams>. */
00270   void reset(T* p = 0) { *this = soft_ref(p); }
00271 
00272   /** Returns the pointee, or if throws an exception if there is not a
00273       valid pointee. */
00274   T* get()         const { return m_handle.get(); }
00275 
00276   T* operator->()  const { return m_handle.get(); }
00277   T& operator*()   const { return *(m_handle.get()); }
00278 
00279   /** Returns the pointee, or returns null if there is not a valid
00280       pointee. Will not throw an exception. */
00281   T* get_weak() const throw() { return m_handle.get_weak(); }
00282 
00283   ref_type get_ref_type() const throw() { return m_handle.get_ref_type(); }
00284 
00285   bool is_valid()   const throw() { return m_handle.is_valid(); }
00286   bool is_invalid() const throw() { return !(is_valid()); }
00287 
00288   bool operator==(const soft_ref& other) const throw()
00289   { return get_weak() == other.get_weak(); }
00290 
00291   bool operator!=(const soft_ref& other) const throw()
00292   { return get_weak() != other.get_weak(); }
00293 
00294   /// Comparison operator for sorting, to insert in std::map or std::set, etc.
00295   bool operator<(const soft_ref& other) const throw()
00296   { return get_weak() < other.get_weak(); }
00297 
00298   nub::uid id() const throw()
00299   { return m_handle.is_valid() ? m_handle.get()->id() : 0; }
00300 
00301   // Compatibility interface with alternate function-naming:
00302 
00303   T*   getWeak()   const throw() { return this->get_weak(); }
00304   bool isValid()   const throw() { return this->is_valid(); }
00305   bool isInvalid() const throw() { return this->is_invalid(); }
00306 };
00307 
00308 
00309 
00310 template <class To, class Fr>
00311 inline nub::soft_ref<To> dyn_cast(nub::soft_ref<Fr> p)
00312 {
00313   if (p.is_valid())
00314     {
00315       Fr* f = p.get();
00316       To* t = dynamic_cast<To*>(f);
00317       if (t == 0)
00318         rutz::throw_bad_cast(typeid(To), typeid(Fr), SRC_POS);
00319       return nub::soft_ref<To>(t);
00320     }
00321   return nub::soft_ref<To>(p.id());
00322 }
00323 
00324 template <class To, class Fr>
00325 inline void dyn_cast_to_from(nub::soft_ref<To>& dest,
00326                              nub::soft_ref<Fr> p)
00327 {
00328   dest = dyn_cast<To, Fr>(p);
00329 }
00330 
00331 
00332 template <class To, class Fr>
00333 inline nub::soft_ref<To> dyn_cast_weak(nub::soft_ref<Fr> p)
00334 {
00335   if (p.is_valid())
00336     {
00337       Fr* f = p.get();
00338       To* t = dynamic_cast<To*>(f);
00339       if (t == 0)
00340         return nub::soft_ref<To>(); // return a null soft_ref
00341       return nub::soft_ref<To>(t);
00342     }
00343   return nub::soft_ref<To>(p.id());
00344 }
00345 
00346 template <class To, class Fr>
00347 inline void dyn_cast_weak_to_from(nub::soft_ref<To>& dest,
00348                                   nub::soft_ref<Fr> p)
00349 {
00350   dest = dyn_cast<To, Fr>(p);
00351 }
00352 
00353 
00354 template <class To, class Fr>
00355 inline nub::soft_ref<To> dyn_cast_weak(nub::ref<Fr> p)
00356 {
00357   Fr* f = p.get();
00358   To* t = dynamic_cast<To*>(f);
00359   if (t == 0)
00360     return nub::soft_ref<To>(); // return a null soft_ref
00361   return nub::soft_ref<To>(t);
00362 }
00363 
00364 template <class To, class Fr>
00365 inline void dyn_cast_weak_to_from(nub::soft_ref<To>& dest,
00366                                   nub::ref<Fr> p)
00367 {
00368   dest = dyn_cast<To, Fr>(p);
00369 }
00370 
00371 
00372 // Compatibility interface with alternate function-naming:
00373 
00374 template <class To, class Fr>
00375 inline nub::soft_ref<To> dynCast(nub::soft_ref<Fr> p)
00376 { return dyn_cast<To, Fr>(p); }
00377 
00378 
00379 template <class To, class Fr>
00380 inline void dynCastToFrom(nub::soft_ref<To>& dest,
00381                           nub::soft_ref<Fr> p)
00382 { dyn_cast_to_from<To, Fr>(dest, p); }
00383 
00384 
00385 template <class To, class Fr>
00386 inline nub::soft_ref<To> dynCastWeak(nub::soft_ref<Fr> p)
00387 { return dyn_cast_weak<To, Fr>(p); }
00388 
00389 
00390 template <class To, class Fr>
00391 inline void dynCastWeakToFrom(nub::soft_ref<To>& dest,
00392                               nub::soft_ref<Fr> p)
00393 { dyn_cast_weak_to_from<To, Fr>(dest, p); }
00394 
00395 
00396 template <class To, class Fr>
00397 inline nub::soft_ref<To> dynCastWeak(nub::ref<Fr> p)
00398 { return dyn_cast_weak<To, Fr>(p); }
00399 
00400 
00401 template <class To, class Fr>
00402 inline void dynCastWeakToFrom(nub::soft_ref<To>& dest,
00403                               nub::ref<Fr> p)
00404 { dyn_cast_weak_to_from<To, Fr>(dest, p); }
00405 
00406 
00407 ///////////////////////////////////////////////////////////
00408 /**
00409  *
00410  * nub::floating_ref<T> is a ref-counted smart pointer that will NOT
00411  * delete its pointee when exiting scope. This can be of use to
00412  * clients who need to allow an object to be returned to a clean
00413  * state (i.e. with ref count == 0), but need to ref the object
00414  * temporarily. Since floating_ref should only be used in restricted
00415  * scopes, copying and assignment are disallowed.
00416  *
00417  **/
00418 ///////////////////////////////////////////////////////////
00419 
00420 template <class T>
00421 class nub::floating_ref
00422 {
00423 private:
00424 
00425   typedef nub::detail::handle<T, nub::detail::no_delete_unref_policy<T> >
00426   handle;
00427 
00428   handle m_handle;
00429 
00430   floating_ref(const floating_ref&);
00431   floating_ref& operator=(const floating_ref&);
00432 
00433 public:
00434   // Default dtor is fine
00435 
00436   explicit floating_ref(T* ptr) : m_handle(ptr) {}
00437 
00438   T* operator->() const throw() { return get(); }
00439   T& operator*()  const throw() { return *(get()); }
00440 
00441   T* get()        const throw() { return m_handle.get(); }
00442 };
00443 
00444 
00445 
00446 
00447 ///////////////////////////////////////////////////////////////////////
00448 //
00449 // inline member definitions
00450 //
00451 ///////////////////////////////////////////////////////////////////////
00452 
00453 template <class T>
00454 template <class U>
00455 inline nub::ref<T>::ref(const soft_ref<U>& other) :
00456   m_handle(other.get())
00457 {}
00458 
00459 static const char __attribute__((used)) vcid_groovx_nub_ref_h_utc20050626084019[] = "$Id: ref.h 8249 2007-04-12 06:03:40Z rjpeters $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/nub/ref.h $";
00460 #endif // !GROOVX_NUB_REF_H_UTC20050626084019_DEFINED
Generated on Sun May 8 08:05:30 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3