library of assembled shared sources

http://lass.cocamware.com

smart_ptr_policies.h

Go to the documentation of this file.
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 doxygen 1.5.7.1
SourceForge.net Logo