library of assembled shared sources |
http://lass.cocamware.com |
00001 /** @file 00002 * @author Bram de Greve (bramz@users.sourceforge.net) 00003 * @author Tom De Muer (tomdemuer@users.sourceforge.net) 00004 * 00005 * *** BEGIN LICENSE INFORMATION *** 00006 * 00007 * The contents of this file are subject to the Common Public Attribution License 00008 * Version 1.0 (the "License"); you may not use this file except in compliance with 00009 * the License. You may obtain a copy of the License at 00010 * http://lass.sourceforge.net/cpal-license. The License is based on the 00011 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 00012 * use of software over a computer network and provide for limited attribution for 00013 * the Original Developer. In addition, Exhibit A has been modified to be consistent 00014 * with Exhibit B. 00015 * 00016 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 00017 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific 00018 * language governing rights and limitations under the License. 00019 * 00020 * The Original Code is LASS - Library of Assembled Shared Sources. 00021 * 00022 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer. 00023 * The Original Developer is the Initial Developer. 00024 * 00025 * All portions of the code written by the Initial Developer are: 00026 * Copyright (C) 2004-2007 the Initial Developer. 00027 * All Rights Reserved. 00028 * 00029 * Contributor(s): 00030 * 00031 * Alternatively, the contents of this file may be used under the terms of the 00032 * GNU General Public License Version 2 or later (the GPL), in which case the 00033 * provisions of GPL are applicable instead of those above. If you wish to allow use 00034 * of your version of this file only under the terms of the GPL and not to allow 00035 * others to use your version of this file under the CPAL, indicate your decision by 00036 * deleting the provisions above and replace them with the notice and other 00037 * provisions required by the GPL License. If you do not delete the provisions above, 00038 * a recipient may use your version of this file under either the CPAL or the GPL. 00039 * 00040 * *** END LICENSE INFORMATION *** 00041 */ 00042 00043 /** @defgroup SmartPtr Smart Pointers 00044 * @brief collection of smart pointers as ScopedPtr, SharedPtr, ... 00045 * @author Bram de Greve [Bramz] 00046 * 00047 * @section Pointers 00048 * 00049 * - lass::util::ScopedPtr: a smart pointer for single ownership, deallocates on end of scope. 00050 * - lass::util::SharedPtr: a smart pointer for shared ownership, keeping track of reference count. 00051 * - lass::util::SmartI: a smart pointer to COM interfaces. 00052 * 00053 * @section StoragePolicy 00054 * 00055 * Storage polices control how the pointees are stored in the smart pointer and how they should 00056 * be deallocated. Two default storage policies are provided for objects allocated by @c new 00057 * and arrays allocated by @c new[], but it should be possible to write special storage policies 00058 * to embed other @e smart pointers in our lass::util smart pointer classes. 00059 * 00060 * @subsection StorageConcept concept of storage policy 00061 * 00062 * All storage policies should implement the following interface. Some functions like 00063 * @c at(size_t) should only be implemented for array-like pointees. So they can safely be 00064 * ommited if pointee does not act like an array. 00065 * 00066 * @code 00067 * template <typename T> 00068 * class StoragePolicy 00069 * { 00070 * public: 00071 * 00072 * typedef ... TStorage; // the type of the storage_ object (usually T*) 00073 * typedef ... TPointer; // return type of pointer() or operator-> (usually T*) 00074 * typedef ... TReference; // return type of operator* or operator[] (usually T&) 00075 * 00076 * TStorage& storage(); 00077 * // return reference to storage object (usualy to a pointer) 00078 * 00079 * const TStorage& storage() const; 00080 * // return const-reference to storage object 00081 * 00082 * protected: 00083 * 00084 * StoragePolicy(); 00085 * // should initialize with default storage object (in most cases: NULL) 00086 * 00087 * StoragePolicy(T* pointee); 00088 * // should initialize to store given pointee. 00089 * 00090 * TPointer pointer() const; 00091 * // should return a pointer to the pointee 00092 * 00093 * TReference at(size_t iIndex) const; 00094 * // for arrays only: should return reference to iIndex'th object in array 00095 * // (YOU CAN OMMIT THIS FOR NON-ARRAYS) 00096 * 00097 * void dispose(); 00098 * // deallocate the pointee (e.g. by a delete or delete []) 00099 * 00100 * bool isNull() const; 00101 * // return true if storage contains equivalent of NULL pointer. 00102 * 00103 * void swap(StoragePolicy<T>& other); 00104 * // swap storage object with other policy. 00105 * }; 00106 * @endcode 00107 * 00108 * @subsection StorageModels implemenated models of storage policy 00109 * 00110 * - lass::util::ObjectStorage: simple storage policy for objects allocated by @c new. 00111 * - lass::util::ArrayStorage: simple storage policy for arrays allocated by @c new[]. 00112 * 00113 * @section CounterPolicy 00114 * 00115 * Counter policies control how reference counting should be done. In contrary to the storage 00116 * policies, this is only used by the SharedPtr. 00117 * 00118 * @subsection CounterConcept concept of counter policy 00119 * 00120 * All counter policies should implement the following interface. The template parameter 00121 * @c TStorage is of the same type as @c TStorage in the used storage policy. It will useually 00122 * be a pointer to the pointee. 00123 * 00124 * @code 00125 * class CounterPolicy 00126 * { 00127 * public: 00128 * 00129 * typedef ... TCount; // type of reference counter variable (should be an integer) 00130 * 00131 * protected: 00132 * 00133 * DefaultCounter(); // brings object in valid state without setting any counter. 00134 * 00135 * template <typename TStorage> void init(TStorage& pointee); 00136 * // initialize reference count one one. This is called on acquring of object by first owner 00137 * // (increment isn't called for first owner). 00138 * 00139 * template <typename TStorage> void dispose(TStorage& pointee); 00140 * // clean up the counter (not the pointee). This is called when reference count drops to 00141 * // zero (thus on release by last owner). 00142 * 00143 * template <typename TStorage> void increment(TStorage& pointee); 00144 * // increment the reference count by one. This is called on acquiring of object by any owner 00145 * // except the first (the first one calls init(TStorage&) instead). 00146 * 00147 * template <typename TStorage> bool decrement(TStorage& pointee); 00148 * // decrement the reference count by one and returns true if it drops below one. This is 00149 * // called on every release of the object by any owner. It should return true if @e after 00150 * // the decrement the reference count turns out the be less than one (i.e. there are no more 00151 * // owners, this was the last one), to indicate the pointee should be deallocated now. In 00152 * // all other cases, it should return false @e after the (i.e. if the reference count is 00153 * // still non-zero after the decrement). 00154 * 00155 * template <typename TStorage> TCount count(TStorage& pointee) const; 00156 * // return the reference count, i.e. number of owners of the pointee 00157 * 00158 * void swap(DefaultCounter& other); 00159 * // swap any reference counters with other policy. 00160 * }; 00161 * @endcode 00162 * 00163 * @subsection CounterModels implemenated models of counter policy 00164 * 00165 * - lass::util::DefaultCounter: allocates extra counter on heap to keep track of reference count. 00166 * - lass::util::IntrusiveCounter: uses a member of the object as reference count. 00167 */ 00168 00169 #ifndef LASS_GUARDIAN_OF_INCLUSION_UTIL_SMART_PTR_POLICIES_H 00170 #define LASS_GUARDIAN_OF_INCLUSION_UTIL_SMART_PTR_POLICIES_H 00171 00172 #include "util_common.h" 00173 #include "atomic.h" 00174 #include "../meta/empty_type.h" 00175 00176 namespace lass 00177 { 00178 namespace util 00179 { 00180 00181 // --- storage policies ---------------------------------------------------------------------------- 00182 00183 /** @class ObjectStorage 00184 * @ingroup SmartPtr 00185 * @brief Default storage policy for single objects, implementation of StoragePolicy concept 00186 * @author Bram de Greve [Bramz] 00187 * 00188 * This policy is meant for simple pointees that are allocated in @c C++ by @c new or equivalent 00189 * (i.e. stuff that should be deallocated by @c delete ). The storage type @c TStorage used for 00190 * this policy simply is an ordinary pointer to that pointee (@c T*)/. 00191 */ 00192 template 00193 < 00194 typename T, 00195 typename Cascade = meta::EmptyType 00196 > 00197 class ObjectStorage: public Cascade 00198 { 00199 public: 00200 00201 typedef ObjectStorage<T, Cascade> TSelf; 00202 typedef T* TStorage; 00203 typedef T* TPointer; 00204 typedef T& TReference; 00205 00206 TStorage& storage() { return storage_; } 00207 const TStorage& storage() const { return storage_; } 00208 00209 protected: 00210 00211 ObjectStorage(): Cascade(), storage_(defaultStorage()) {} 00212 explicit ObjectStorage(T* pointee): Cascade(), storage_(pointee) {} 00213 ObjectStorage(const TSelf& other): Cascade(other), storage_(other.storage_) {} 00214 template <typename U> ObjectStorage(const ObjectStorage<U, Cascade>& other): Cascade(other), storage_(other.storage()) {} 00215 00216 TPointer pointer() const { return storage_; } 00217 00218 void dispose() 00219 { 00220 delete storage_; 00221 storage_ = 0; 00222 } 00223 00224 bool isNull() const { return !storage_; } 00225 void swap(TSelf& other) { Cascade::swap(other); std::swap(storage_, other.storage_); } 00226 00227 static TStorage defaultStorage() { return 0; } 00228 00229 private: 00230 00231 TStorage storage_; 00232 }; 00233 00234 00235 00236 /** @class ArrayStorage 00237 * @ingroup SmartPtr 00238 * @brief Default storage policy for arrays, implementation of StoragePolicy concept 00239 * @author Bram de Greve [Bramz] 00240 * 00241 * This policy is meant for simple arrays that are allocated in @c C++ by @c new[] or equivalent 00242 * (i.e. stuff that should be deallocated by @c delete[] ). The storage type @c TStorage used for 00243 * this policy simply is an ordinary pointer to that array (@c T*)/. 00244 */ 00245 template 00246 < 00247 typename T, 00248 typename Cascade = meta::EmptyType 00249 > 00250 class ArrayStorage: public Cascade 00251 { 00252 public: 00253 00254 typedef ArrayStorage<T, Cascade> TSelf; 00255 typedef T* TStorage; 00256 typedef T* TPointer; 00257 typedef T& TReference; 00258 00259 TStorage& storage() { return storage_; } 00260 const TStorage& storage() const { return storage_; } 00261 00262 protected: 00263 00264 ArrayStorage(): Cascade(), storage_(defaultStorage()) { } 00265 explicit ArrayStorage(T* pointee): Cascade(), storage_(pointee) { } 00266 ArrayStorage(const TSelf& other): Cascade(other), storage_(other.storage_) {} 00267 template <typename U> ArrayStorage(const ArrayStorage<U, Cascade>& other): Cascade(other), storage_(other.storage()) {} 00268 00269 TPointer pointer() const { return storage_; } 00270 TReference at(size_t index) const { return storage_[index]; } 00271 00272 void dispose() 00273 { 00274 delete [] storage_; 00275 storage_ = 0; 00276 } 00277 00278 bool isNull() const { return !storage_; } 00279 void swap(TSelf& other) { Cascade::swap(other); std::swap(storage_, other.storage_); } 00280 00281 static TStorage defaultStorage() { return 0; } 00282 00283 private: 00284 00285 TStorage storage_; 00286 }; 00287 00288 00289 00290 00291 00292 00293 // --- counter policies ---------------------------------------------------------------------------- 00294 00295 namespace impl 00296 { 00297 LASS_DLL void initHeapCounter(int*& ioCounter, int iInitialValue); 00298 LASS_DLL void disposeHeapCounter(int*& ioCounter); 00299 } 00300 00301 /** @class DefaultCounter 00302 * @ingroup SmartPtr 00303 * @brief The default counter for the shared pointers, implementation of CounterPolicy concept. 00304 * @author Bram de Greve [Bramz] 00305 * 00306 * The default counter will use an self-owned integer as counter object. It will allocate this on 00307 * the heap and share it between all smart pointers that own the same pointee (duh!). Of course 00308 * it will be so nice to clean it up by itself too. 00309 */ 00310 class DefaultCounter 00311 { 00312 public: 00313 00314 typedef int TCount; 00315 00316 protected: 00317 00318 DefaultCounter(): count_(0) {} 00319 00320 template <typename TStorage> void init(TStorage& /*pointee*/) 00321 { 00322 impl::initHeapCounter(count_, 1); 00323 LASS_ASSERT(count_ && *count_ == 1); 00324 } 00325 00326 template <typename TStorage> void dispose(TStorage& /*pointee*/) 00327 { 00328 LASS_ASSERT(count_ && *count_ == 0); 00329 impl::disposeHeapCounter(count_); 00330 } 00331 00332 template <typename TStorage> void increment(TStorage& /*pointee*/) 00333 { 00334 TCount oldCount = 0, newCount = 0; 00335 do 00336 { 00337 LASS_ASSERT(count_); 00338 oldCount = *count_; 00339 LASS_ASSERT(oldCount > 0); 00340 newCount = oldCount + 1; 00341 } 00342 while (!atomicCompareAndSwap(*count_, oldCount, newCount)); 00343 } 00344 00345 template <typename TStorage> bool decrement(TStorage& /*pointee*/) 00346 { 00347 TCount oldCount = 0, newCount = 0; 00348 do 00349 { 00350 LASS_ASSERT(count_); 00351 oldCount = *count_; 00352 LASS_ASSERT(oldCount > 0); 00353 newCount = oldCount - 1; 00354 } 00355 while (!atomicCompareAndSwap(*count_, oldCount, newCount)); 00356 return newCount == 0; 00357 } 00358 00359 template <typename TStorage> TCount count(TStorage& /*pointee*/) const 00360 { 00361 LASS_ASSERT(count_ && *count_ > 0); 00362 return *count_; 00363 } 00364 00365 void swap(DefaultCounter& other) { std::swap(count_, other.count_); } 00366 00367 private: 00368 00369 TCount* count_; 00370 }; 00371 00372 00373 00374 00375 /** @class IntrusiveCounter 00376 * @brief implementation of CounterPolicy concept, using a counter in the managed object itself. 00377 * @ingroup SmartPtr 00378 * @author Bram de Greve [Bramz] 00379 * 00380 * This comes from "C++ Templates, The Complete Guide" by David Vandevoorde and 00381 * Nicolai M. Josuttis. See their @c MemberReferenceCount policy. 00382 * 00383 * The DefaultCounter policy puts the reference counter outside the managed object. That's great in 00384 * most cases, because that way, the managed type doesn't have to be designed to be used with our 00385 * SharedPtr. However, in some cases it is more interesting to put the reference counter @e inside 00386 * the managed object. You can use the IntrusiveCounter policy to use such a reference counter with 00387 * our SharedPtr. 00388 * 00389 * @code 00390 * struct Foo 00391 * { 00392 * std::string blablabla; 00393 * int referenceCount; 00394 * }; 00395 * 00396 * typedef lass::util::SharedPtr 00397 * < 00398 * Foo, 00399 * lass::util::ObjectStorage, 00400 * lass::util::IntrusiveCounter 00401 * < 00402 * Foo, // the managed type (containing the counter) 00403 * int, // type of the counter 00404 * &Foo::referenceCount // pointer to the counter 00405 * > 00406 * > 00407 * TFooPtr; 00408 * 00409 * TFooPtr foo(new Foo); 00410 * @endcode 00411 */ 00412 template 00413 < 00414 typename T, 00415 typename CounterType, 00416 CounterType T::* referenceCounter 00417 > 00418 class IntrusiveCounter 00419 { 00420 public: 00421 00422 typedef IntrusiveCounter<T, CounterType, referenceCounter> TSelf; 00423 typedef CounterType TCount; 00424 00425 protected: 00426 00427 template <typename TStorage> void init(TStorage& pointee) 00428 { 00429 LASS_ASSERT(pointee); 00430 (pointee->*referenceCounter) = 1; 00431 } 00432 00433 template <typename TStorage> void dispose(TStorage& pointee) 00434 { 00435 LASS_ASSERT(pointee && (pointee->*referenceCounter) == 0); 00436 } 00437 00438 template <typename TStorage> void increment(TStorage& pointee) 00439 { 00440 LASS_ASSERT(pointee); 00441 TCount oldCount = 0, newCount = 0; 00442 do 00443 { 00444 oldCount = pointee->*referenceCounter; 00445 LASS_ASSERT(oldCount > 0); 00446 newCount = oldCount + 1; 00447 } 00448 while (!atomicCompareAndSwap(pointee->*referenceCounter, oldCount, newCount)); 00449 } 00450 00451 template <typename TStorage> bool decrement(TStorage& pointee) 00452 { 00453 LASS_ASSERT(pointee); 00454 TCount oldCount = 0, newCount = 0; 00455 do 00456 { 00457 oldCount = pointee->*referenceCounter; 00458 LASS_ASSERT(oldCount > 0); 00459 newCount = oldCount - 1; 00460 } 00461 while (!atomicCompareAndSwap(pointee->*referenceCounter, oldCount, newCount)); 00462 return newCount == 0; 00463 } 00464 00465 template <typename TStorage> TCount count(TStorage& pointee) const 00466 { 00467 LASS_ASSERT(pointee && (pointee->*referenceCounter) > 0); 00468 return pointee->*referenceCounter; 00469 } 00470 00471 void swap(TSelf& /*other*/) 00472 { 00473 } 00474 }; 00475 00476 00477 00478 } 00479 00480 } 00481 00482 #endif 00483 00484 // EOF
Generated on Mon Nov 10 14:21:34 2008 for Library of Assembled Shared Sources by 1.5.7.1 |