00001 /** @file nub/refcounted.h reference-counted base class, allowing 00002 intrusive smart pointers to be used */ 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: Sun Oct 22 14:40:19 2000 00011 // commit: $Id: refcounted.h 8249 2007-04-12 06:03:40Z rjpeters $ 00012 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/nub/refcounted.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_REFCOUNTED_H_UTC20050626084018_DEFINED 00036 #define GROOVX_NUB_REFCOUNTED_H_UTC20050626084018_DEFINED 00037 00038 #include "rutz/atomic.h" 00039 00040 #include <cstdlib> 00041 00042 namespace nub 00043 { 00044 class ref_counts; 00045 class ref_counted; 00046 } 00047 00048 00049 // If we want to enforce that destructors of objects derived form 00050 // nub::ref_counted (and nub::object) should have an empty throw-spec 00051 // (i.e. "throw()"), then need "#define GVX_DTOR_NOTHROW throw()", 00052 // otherwise we just define GVX_DTOR_NOTHROW to be empty 00053 #ifndef GVX_DTOR_NOTHROW 00054 # define GVX_DTOR_NOTHROW 00055 #endif 00056 00057 /////////////////////////////////////////////////////////////////////// 00058 /** 00059 * 00060 * nub::ref_counts manages strong+weak reference counts for 00061 * nub::ref_counted objects. Its main purpose is to allow weak 00062 * ref-counting; a client who wants to do weak ref-counting can get a 00063 * hold of the nub::ref_counted object's nub::ref_counts, and then check 00064 * whether is_owner_alive() to know whether the nub::ref_counted object 00065 * is still valid. This technique is implemented by nub::soft_ref. The 00066 * nub::ref_counts object will delete itself when both its strong and 00067 * weak counts go to 0. 00068 * 00069 **/ 00070 /////////////////////////////////////////////////////////////////////// 00071 00072 struct nub::ref_counts 00073 { 00074 public: 00075 friend class nub::ref_counted; 00076 00077 void* operator new(size_t bytes); 00078 void operator delete(void* space, size_t bytes); 00079 00080 ref_counts() throw(); 00081 00082 private: 00083 /// Private destructor since the object destroys itself eventually in release_weak(). 00084 ~ref_counts() throw(); 00085 00086 public: 00087 00088 bool is_owner_alive() const throw() { return m_owner_alive; } 00089 00090 void acquire_weak() throw(); 00091 int release_weak() throw(); 00092 00093 void debug_dump() const throw(); 00094 00095 private: 00096 ref_counts(const ref_counts&) throw(); 00097 ref_counts& operator=(const ref_counts&) throw(); 00098 00099 void acquire_strong() throw(); 00100 int release_strong() throw(); 00101 void release_strong_no_delete() throw(); 00102 00103 rutz::atomic_int_t m_strong; 00104 rutz::atomic_int_t m_weak; 00105 bool m_owner_alive; 00106 bool m_volatile; 00107 }; 00108 00109 00110 00111 /////////////////////////////////////////////////////////////////////// 00112 /** 00113 * 00114 * nub::ref_counted is a reference counting base class that allows both 00115 * strong and weak reference counting. nub::ref_counted objects use a 00116 * nub::ref_counts object to manage their reference counts, so clients 00117 * that need to know if a nub::ref_counted object is still around can 00118 * check the is_owner_alive() from its nub::ref_counts object. Finally, 00119 * subclasses of nub::ref_counted can declare themselves volatile (by 00120 * calling mark_as_volatile()) if their lifetime cannot be fully 00121 * controlled by reference-counting; clients of such volatile objects 00122 * must use weak reference counts only. No manipulation of the 00123 * reference count is allowed for volatile objects; only the weak 00124 * reference count may be used. 00125 * 00126 **/ 00127 /////////////////////////////////////////////////////////////////////// 00128 00129 class nub::ref_counted 00130 { 00131 private: 00132 ref_counts* const m_ref_counts; 00133 00134 // These are disallowed since ref_counted's should always be in 00135 // one-to-one correspondence with their pointee's. 00136 ref_counted(const ref_counted& other); 00137 ref_counted& operator=(const ref_counted& other); 00138 00139 // If GVX_ENFORCE_FACTORY_FUNCTIONS, then we make operator new() and 00140 // delete() protected, as well as the default constructor and 00141 // destructor. This means that only derived classes can use operator 00142 // new() and delete(), and that thus derived classes are required to 00143 // define functions of the form "static nub::ref<derived_class> 00144 // make() { return nub::ref<derived_class>(new derived_class)." 00145 // While this is a bit of extra typing, it helps ensure that 00146 // ref_counted objects are not constructed on the stack, and are not 00147 // handled by the wrong type of smart pointer (such as a 00148 // shared_ptr). 00149 #ifdef GVX_ENFORCE_FACTORY_FUNCTIONS 00150 protected: 00151 #else 00152 public: 00153 #endif 00154 00155 /** Class-specific operator new; protected to ensure that clients 00156 use factory functions. */ 00157 void* operator new(size_t bytes); 00158 00159 /** Class-specific operator delete; private since deletion should 00160 only happen in ref_counted::decr_ref_count. */ 00161 void operator delete(void* space, size_t bytes); 00162 00163 /// Default constructor. 00164 ref_counted(); 00165 00166 /** Virtual destructor is protected, so that we can prevent clients 00167 from instantiating ref_counted's on the stack and from destroying 00168 them explicitly. Instead, ref_counted objects will only be 00169 destroyed by a 'delete this' call inside decr_ref_count() if the 00170 reference count falls to zero or below. Clients are forced to 00171 create ref_counted objects dynamically using \c new, which is 00172 what we need in order for 'delete this' to be valid later on. */ 00173 virtual ~ref_counted() GVX_DTOR_NOTHROW; 00174 00175 /// Mark this object as a volatile (unshareable) object. 00176 void mark_as_volatile() throw(); 00177 00178 public: 00179 /// Increment the object's reference count. 00180 /** This operation (on the strong reference count) is not permitted if 00181 the object is unshareable. Unshareable objects can only have their 00182 weak reference counts manipulated. */ 00183 void incr_ref_count() const throw(); 00184 00185 /// Decrement the object's reference count. 00186 /** If this causes the reference count to fall to zero or below, the 00187 pointee and the pointer will be destroyed by a call to 'delete 00188 this'. This operation (on the strong reference count) is not 00189 permitted if the object is unshareable. Unshareable objects can only 00190 have their weak reference counts manipulated. */ 00191 void decr_ref_count() const throw(); 00192 00193 /// Decrement the object's reference count, but don't delete it. 00194 /** Unlike decr_ref_count(), the object will NOT be delete'd if the 00195 reference count falls to zero. This operation (on the strong 00196 reference count) is not permitted if the object is 00197 unshareable. Unshareable objects can only have their weak reference 00198 counts manipulated. */ 00199 void decr_ref_count_no_delete() const throw(); 00200 00201 /// Returns true if no external client has sole ownership of the object. 00202 /** This may occur if either (1) the reference count is greater than one, 00203 or (2) the object is_not_shareable(), meaning that the object itself is 00204 the only "owner". */ 00205 bool is_shared() const throw(); 00206 00207 /// Returns true if there is a sole external owner of the object. 00208 /** This occurs if the reference count is one or less and the object is 00209 shareable. */ 00210 bool is_unshared() const throw(); 00211 00212 /** Returns true if the object is not shareable for any reason. This 00213 could be because its lifespan is volatile (such as objects 00214 representing on-screen windows that can be dismissed by the 00215 user). The default is for objects to be shareable; objects can 00216 declare themselves as unshareable by calling mark_as_volatile(). */ 00217 bool is_not_shareable() const throw(); 00218 00219 /// Returns the object's reference count manager. 00220 ref_counts* get_counts() const throw(); 00221 00222 00223 /// FOR TEST/DEBUG ONLY! Returns the object's (strong) reference count. 00224 int dbg_ref_count() const throw(); 00225 00226 /// FOR TEST/DEBUG ONLY! Returns the object's weak reference count. 00227 int dbg_weak_ref_count() const throw(); 00228 }; 00229 00230 static const char __attribute__((used)) vcid_groovx_nub_refcounted_h_utc20050626084018[] = "$Id: refcounted.h 8249 2007-04-12 06:03:40Z rjpeters $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/nub/refcounted.h $"; 00231 #endif // !GROOVX_NUB_REFCOUNTED_H_UTC20050626084018_DEFINED