00001 #ifndef s11n_net_s11n_refcount_REFCOUNT_HPP_INCLUDED 00002 #define s11n_net_s11n_refcount_REFCOUNT_HPP_INCLUDED 1 00003 // reminders to self: 00004 // - think about lazyassptr<T> which lazily instantiates its 00005 // pointee. That would take a Constructor functor, providing symmetry 00006 // with rcptr<>. 00007 00008 #include <map> 00009 00010 00011 namespace s11n { 00012 /** 00013 The refcount namespace encapsulates code for a reference-counted 00014 smart pointer. It is capable of tracking and destroying objects and 00015 arbitrary pointers (including void pointers) and destroying them 00016 using a user-defined finalizer functor. This allows, e.g., the 00017 reference-counted sharing of memory allocated via malloc() or by 00018 third-party functions such as dlopen() or sqlite3_open(). 00019 00020 This code is not generic, industrial-strength reference counting 00021 and is as much an experiment as anything else. 00022 00023 Author: stephan at s11n dot net 00024 00025 License: Public Domain 00026 */ 00027 namespace refcount { 00028 00029 00030 /** 00031 A no-op "destructor" for use with rcptr. 00032 */ 00033 struct no_delete_finalizer 00034 { 00035 /** Assigs t to 0 without deleting t. */ 00036 template <typename T> 00037 void operator()( T * & t ) 00038 { 00039 t = 0; 00040 } 00041 }; 00042 00043 /** 00044 The default destructor/cleanup functor for use with 00045 rcptr<>. 00046 */ 00047 struct plain_delete_finalizer 00048 { 00049 /** 00050 Calls delete t and assigns t to 0. 00051 00052 Specialized dtors need not call delete, but should 00053 assign t to 0, as this simplifies some client code. 00054 00055 T must be non-CVP-qualified and for this 00056 implementation (delete t) must be legal. 00057 */ 00058 template <typename T> 00059 void operator()( T * & t ) 00060 { 00061 delete t; 00062 t = 0; 00063 } 00064 }; 00065 00066 /** 00067 All classes in this namespace are "internal details" of the 00068 classes in the refcount namespace, and should not be 00069 directly used by client code. 00070 */ 00071 namespace Detail 00072 { 00073 /** 00074 Internal detail for dereferencing pointers. 00075 */ 00076 template <typename T> 00077 struct ref_type 00078 { 00079 /** Same as (T&). */ 00080 typedef T & type; 00081 /** Returns *t. */ 00082 static type deref( T *t ) { return *t; } 00083 }; 00084 /** 00085 Internal detail for dereferencing pointers. 00086 */ 00087 template <> 00088 struct ref_type<void> 00089 { 00090 /** Same as (void*&). */ 00091 typedef void * & type; 00092 /** Returns xx. */ 00093 static type deref( type xx ) { return xx; } 00094 }; 00095 } // namespace Detail 00096 00097 /** 00098 A bare-bones non-intrusive reference-counted pointer type 00099 with the ability for the client to specify a 00100 finalization/destruction functor for the pointed-to type. 00101 00102 HandleT must be a non-CVP-qualified type. As a special 00103 case, if HandleT is void then some code in this class will 00104 work a bit differently, notably the operator*(), because we 00105 cannot form a reference to void. Void is supported because 00106 (void *) is commonly used for opaque handles (e.g. libdl) 00107 or multibyte string pointers (e.g. libsqlite3). 00108 00109 FinalizerT must be a type compatible with the 00110 plain_delete_finalizer interface. A default-constructed 00111 instance of that FinalizerT type will be created to 00112 "finalize" an object when the reference count for that 00113 object drops to zero. The exact behaviour of the FinalizerT 00114 is not specified here, but semantically it must "finalize" 00115 the object passed to it. The default finalizer simply 00116 deletes the object, whereas a more advanced finalizer might 00117 push the object into a garbage collection pool. For 00118 purposes of this class, after finalization of an object, 00119 client code (and this type) should no longer use the object 00120 - it is considered to be destroyed. 00121 00122 This type does not currently have any built-in support for 00123 copy-on-write, so all copies are extremely shallow. 00124 00125 Notes of Utmost Significance to Potential Users: 00126 00127 - Implicit conversions to/from HandleT are not implemented 00128 after much deliberation on the subject. Clients will *have* 00129 to know they're using this class, as opposed to a plain 00130 pointer type. This is safest for everyone, IMO. 00131 00132 - Don't mix plain and rcptr-hosted pointers, as the rcptr 00133 wrappers own the pointers and will clean them up, leaving 00134 any unadorned pointers dangling. 00135 00136 - Thread safety: no special guarantees, along with lots of 00137 caveats and potential gotchas. 00138 00139 - Don't mix different smart pointer types, not even 00140 rcptrs with the same HandleT type but different 00141 FinalizerT types. This will almost certainly bring about 00142 the incorrect finalization of a pointer. 00143 00144 - The usage of a finalizer functor means that this type can 00145 be used with arbitrary types, regardless of whether the 00146 delete operation is legal or not on them. For example, the 00147 client code for which this class was written uses a functor 00148 to finalize sqlite3 database handles using the 00149 sqlite3_close() function. 00150 00151 00152 00153 Design notes: 00154 00155 - While originally based off of the presentation of 00156 rc-pointers in Meyers' "More Effective C++", Item 29, i 00157 believe his approach to storing the reference count in his 00158 RCIPtr class is flawed, as it allows multiple rc-pointers 00159 to delete the same pointer. Consider: 00160 00161 \code 00162 typedef RCIPtr<MyType> myPtrType; 00163 MyType * t = new MyType; 00164 myPtrType x(t); 00165 myPtrType y(t); 00166 \endcode 00167 00168 In theory, his presentation (admittedly 10+ years old now) 00169 would cause a double-delete for that case. In this model, 00170 that case is handled as if we had constructed y using y(x) 00171 instead of y(t), so both x and y share the reference count. 00172 00173 - The reference count is stored in a static-space std::map, 00174 and that map is specific to this type and its combination 00175 of HandleT/FinalizerT types. If we made the map only 00176 specific to the HandleT, then we would get 00177 strange/undesired behaviour when we did: 00178 00179 \code 00180 rcptr<T1,finalizerT1> p1( new T1 ); 00181 rcptr<T2,finalizerT2> p2( p1.get() ); 00182 \endcode 00183 00184 because the actual finalizer used would be the one for 00185 which the rcptr is destroyed *last*. Since destruction 00186 order is not always determinate, this mixture would be a 00187 bad idea. Note that it is still illegal to add the same 00188 pointer to multiple different shared pointer types. The 00189 above example, while illegal, will at least cause 00190 determinate behaviour: a double finalization (but the order 00191 is still unspecified in the general case)! 00192 00193 */ 00194 template <typename HandleT, 00195 typename FinalizerT = plain_delete_finalizer> 00196 class rcptr 00197 { 00198 public: 00199 /** 00200 The basic type of object pointed to. 00201 */ 00202 typedef HandleT type; 00203 /** 00204 The basic pointer type. 00205 */ 00206 typedef type * pointer_type; 00207 /** The type of functor used to clean up pointer_type objects. */ 00208 typedef FinalizerT finalizer_type; 00209 private: 00210 mutable pointer_type m_ptr; 00211 typedef int counter_type; 00212 typedef std::map<pointer_type,counter_type> map_type; 00213 /** Returns a shared map holding the reference 00214 counts for all instances of pointer_type 00215 tracked by this class. This is not 00216 post-main() safe. 00217 */ 00218 static map_type & map() 00219 { 00220 static map_type bob; 00221 return bob; 00222 } 00223 00224 /** 00225 Decrements the reference count to ptr. If the 00226 count goes to 0, an instance of finalizer_type is 00227 used to "destruct" ptr. On success, the current 00228 reference count is returned. If 0 is returned, 00229 ptr should be considered invalid (though this 00230 actually depends on finalizer_type's 00231 implementation, the semantics are that destruction 00232 leaves us with an unusable object). On error 00233 (passed a null ptr), a number less than 0 is 00234 returned. 00235 */ 00236 static counter_type decrement( pointer_type & ptr ) 00237 { 00238 if( ! ptr ) return false; 00239 typename map_type::iterator it = map().find(ptr); 00240 if( map().end() == it ) return false; 00241 if( 0 == (*it).second ) return 0; // can happen, e.g., if take() is called. 00242 counter_type rc = --(*it).second; 00243 if ( 0 == rc ) 00244 { 00245 map().erase( it ); 00246 finalizer_type()( ptr ); 00247 } 00248 return rc; 00249 } 00250 00251 /** 00252 If ! ptr, does nothing, else it increases the 00253 reference count for ptr by one. Returns the current 00254 reference count (guaranteed to be 1 or higher) on 00255 success, or a negative number if passed a null ptr. 00256 */ 00257 static counter_type increment( pointer_type & ptr ) 00258 { 00259 if( ! ptr ) return -1; 00260 return ++(map()[ptr]); 00261 } 00262 public: 00263 /** 00264 Transfers ownership of h, or allows h to 00265 participate in ownership with other rcptr 00266 objects pointing at h. 00267 */ 00268 explicit rcptr( pointer_type h ) : m_ptr(h) 00269 { 00270 this->increment( this->m_ptr ); 00271 } 00272 /** 00273 rhs and this object will both manage the same 00274 underlying pointer. 00275 */ 00276 rcptr( rcptr const & rhs ) : m_ptr(rhs.m_ptr) 00277 { 00278 this->increment( this->m_ptr ); 00279 } 00280 /** 00281 First disowns any connected pointer (using 00282 take(0)), then rhs and this object will 00283 both manage the same underlying pointer. If 00284 by chance rhs.get() == this->get() when 00285 this function starts then this function 00286 does nothing and has no side effects. 00287 */ 00288 rcptr & operator=( rcptr const & rhs ) 00289 { 00290 if( rhs.m_ptr == this->m_ptr ) return *this; 00291 this->decrement( this->m_ptr ); 00292 this->m_ptr = rhs.m_ptr; 00293 this->increment( this->m_ptr ); 00294 return *this; 00295 } 00296 /** 00297 An empty shared pointer, useful only as a target of 00298 assigment or take(). 00299 */ 00300 rcptr() : m_ptr(0) 00301 {} 00302 00303 /** 00304 Efficiently swaps this object and rhs, such that they 00305 swap ownership of their underlying pointers. 00306 This does not require fiddling with the reference 00307 counts, so it is much faster than using an rcptr 00308 copy to perform a swap. 00309 */ 00310 void swap( rcptr & rhs ) 00311 { 00312 if( this->m_ptr != rhs ) 00313 { 00314 pointer_type x = this->m_ptr; 00315 this->m_ptr = rhs.m_ptr; 00316 rhs.m_ptr = x; 00317 } 00318 } 00319 00320 00321 /** 00322 See decrement(); 00323 */ 00324 ~rcptr() 00325 { 00326 this->decrement( this->m_ptr ); 00327 } 00328 00329 /** Returns (this->m_ptr == rhs.m_ptr). */ 00330 bool operator==( rcptr const & rhs ) const 00331 { 00332 return this->m_ptr == rhs.m_ptr; 00333 } 00334 /** Returns (this->m_ptr != rhs.m_ptr). */ 00335 bool operator!=( rcptr const & rhs ) const 00336 { 00337 return this->m_ptr != rhs.m_ptr; 00338 } 00339 00340 /** 00341 Returns this->get() < rhs.get(). Implemented so that 00342 this type can be used as keys in STL containers. 00343 */ 00344 bool operator<( rcptr const & rhs ) const 00345 { 00346 return this->m_ptr < rhs.m_ptr; 00347 } 00348 00349 /** Returns this object's underlying pointer, which 00350 may be 0. This does not transfer ownership. This 00351 object still owns (or participates in the 00352 ownership of) the returned pointer. 00353 */ 00354 pointer_type get() const { return this->m_ptr; } 00355 00356 /** 00357 Gives ownership of p to this object (or a 00358 collection of like-types rcptr objects). Drops 00359 ownership of this->get() before making the 00360 takeover. If (this->get() == p) then this function 00361 does nothing. 00362 */ 00363 void take( pointer_type p ) 00364 { 00365 if( p == this->m_ptr ) return; 00366 this->decrement( this->m_ptr ); 00367 this->increment( this->m_ptr = p ); 00368 } 00369 00370 /** 00371 Transfers ownership of this->get() to the caller. 00372 00373 ALL rcptr<> objects which point to that object 00374 (except this rcptr) STILL point to that object, 00375 but they will not activate the destructor functor 00376 when they die, so they are safe as long as they 00377 remain unsued or are destroyed before the "raw" 00378 pointer returned from this function is destroyed. 00379 */ 00380 pointer_type take() 00381 { 00382 if( this->m_ptr ) 00383 { 00384 pointer_type t = this->m_ptr; 00385 this->map().erase( this->m_ptr ); 00386 this->m_ptr = 0; 00387 return t; 00388 } 00389 return this->m_ptr; 00390 } 00391 00392 /** 00393 The same as this->get(). 00394 */ 00395 pointer_type operator->() const { return this->m_ptr; } 00396 00397 00398 /** 00399 reference_type is the same as (T&) unless T is void, 00400 in which case it is the same as (void*&) because 00401 (void&) is not legal. 00402 */ 00403 typedef typename Detail::ref_type<type>::type reference_type; 00404 00405 /** 00406 The same as *(this->get()). Behaviour is undefined 00407 if (!this->get()). We would throw an exception, but 00408 this code is specifically intended for use on 00409 platforms where exceptions are not allowed or not 00410 supported (e.g. some embedded platforms). 00411 00412 SPECIAL CASE: rcptr::type is void 00413 00414 If rcptr::type is void then this function returns a 00415 refernce to a pointer instead of a reference. This 00416 is to allow this type to work with (void*) handle 00417 types, such as handles returned from dlopen() or 00418 memory returned from malloc(). Finalizers for such 00419 handles could call dlclose() or free(), as 00420 appropriate. 00421 */ 00422 reference_type operator*() const 00423 { 00424 return Detail::ref_type<type>::deref( this->m_ptr ); 00425 } 00426 /** 00427 Returns the number of references to this object's pointer, 00428 or zero if no pointer is bound. This function should be 00429 considered a debugging/informational function, and not 00430 a "feature" of this type. 00431 00432 Complexity = that of a std::map lookup. 00433 */ 00434 size_t ref_count() const 00435 { 00436 if( ! this->m_ptr ) return 0; 00437 typename map_type::iterator it = map().find(this->m_ptr); 00438 return ( map().end() == it ) ? 0 : (*it).second; 00439 } 00440 00441 /** 00442 Returns the same as (!this->get()). 00443 */ 00444 bool empty() const { return 0 == this->m_ptr; } 00445 00446 // Adding deep copy support requires a copy ctor/functor for our 00447 // pointee type, but this type should/must be usable with opaque 00448 // pointer handles as well as object pointers (e.g. sqlite3 db handles 00449 // and ncurses WINDOW handles). But if you did want to implement 00450 // copy(), here's how you might go about doing it... 00451 // /** 00452 // Makes a copy of p using (new type(*p)) and 00453 // transfers ownership of that copy to this 00454 // object. Further copies of this object will point to 00455 // that copy unless/until copy() is called on 00456 // them. This function is intended to simplify 00457 // implementation of copy-on-write. If p is null then 00458 // this object points to null. 00459 00460 // To force an rcptr to copy its current pointer, simply 00461 // call ptr.copy( ptr.get() ). 00462 // */ 00463 // void copy( pointer_type p ) 00464 // { 00465 // pointer_type x = this->m_ptr; 00466 // if( p ) 00467 // { 00468 // this->m_ptr = new type(*p); 00469 // this->increment( this->m_ptr ); 00470 // } 00471 // else 00472 // { 00473 // this->m_ptr = 0; 00474 // } 00475 // this->decrement(x); 00476 // } 00477 // Some things to consider: 00478 // bool m_shareable; 00479 // bool shareable() const { return this->m_shareable; } 00480 // void shareable( bool s ) { this->m_shareable = s; } 00481 // bool shared() const { return this->ref_count() > 1; } 00482 00483 00484 }; 00485 00486 00487 }} // namespaces 00488 00489 00490 #endif // s11n_net_s11n_refcount_REFCOUNT_HPP_INCLUDED