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