src/Utility/RefBlock.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  *
00007  * Visit http://people.web.psi.ch/adelmann/ for more details
00008  *
00009  ***************************************************************************/
00010 
00011 /***********************************************************************
00012 
00013 This little gadget lets you allocate an array of elements of type T
00014 and reference count the whole block.  As long as you refer to the block
00015 using objects of the type RefBlockP it will keep the block around.  As
00016 soon as the last RefBlockP that refers to the block is deleted, it
00017 deletes the block.
00018 
00019 You create a block like: RefBlockP<T> p(size)
00020 Then you use p like a pointer. Pointer operations are as efficient as 
00021 with a bare pointer as long as bounds checking is off.
00022 
00023 It has a second template argument for whether to do bounds checking.
00024 It defaults to the value of the preprocessor symbol
00025 REFBLOCK_BOUNDS_CHECK_DEFAULT.  If you don't define that symbol it 
00026 is set to false, for no bounds checking.
00027 
00028 To turn bounds checking on for your whole code define
00029 REFBLOCK_BOUNDS_CHECK_DEFAULT as true.
00030 
00031 To turn bounds checking on for a particular RefBlockP you 
00032 declare it like:
00033 
00034 RefBlockP<T,true> p;
00035 
00036 To turn it off you declare it as:
00037 
00038 RefBlockP<T,false> p;
00039 
00040 ***********************************************************************/
00041 
00042 #ifndef REF_BLOCK_H
00043 #define REF_BLOCK_H
00044 
00045 // include files
00046 #include "Utility/RefCounted.h"
00047 
00048 #include <assert.h>
00049 #include <stddef.h>
00050 
00051 //----------------------------------------------------------------------
00052 #ifndef REFBLOCK_BOUNDS_CHECK_DEFAULT
00053 #  ifndef BOUNDS_CHECK_DEFAULT
00054 #    define REFBLOCK_BOUNDS_CHECK_DEFAULT false
00055 #  else
00056 #    define REFBLOCK_BOUNDS_CHECK_DEFAULT BOUNDS_CHECK_DEFAULT
00057 #  endif
00058 #endif
00059 
00060 template<class T, bool BoundsCheck=REFBLOCK_BOUNDS_CHECK_DEFAULT>
00061 class RefBlockP
00062 {
00063   // 
00064   // Allow the other bounds checking polarity to look in here.
00065   // 
00066 // friend class RefBlockP<T,!BoundsCheck>;
00067 
00068 private:
00069   //
00070   // A simple class that has the pointer to the beginning of the block.
00071   // Because it is refcounted, when the last reference to the
00072   // block goes away, this dies and takes the block with it.
00073   //
00074   class RefBlockController : public RefCounted
00075     {
00076     public: 
00077       T* P;
00078       T* Pend;
00079       bool Dealloc;
00080       RefBlockController(T *p, size_t size)
00081         : P(p),Pend(p+size),Dealloc(false)
00082           {
00083           }
00084       RefBlockController(size_t size)
00085         : P(new T[size]),Pend(P+size),Dealloc(true)
00086           {
00087           }
00088       ~RefBlockController()
00089         {
00090           if (Dealloc)
00091             delete P;
00092         }
00093       T* getBlock()
00094         {
00095           return P;
00096         }
00097       bool checkDeref(T* p)
00098         {
00099           return (P<=p) && (p<Pend) ;
00100         }
00101     };
00102 
00103   //
00104   // We have two data items in each RefBlockP:
00105   //    A bare pointer that points somewhere in the block.
00106   //    A refcounted pointer to the block controller.
00107   //
00108   T* P;
00109   RefCountedP< RefBlockController > Controller;
00110 
00111 public:
00112 
00113   //
00114   // Null ctor for arrays.  Initialize w/ null ptr.
00115   //
00116   RefBlockP() : P(0) {}
00117 
00118   //
00119   // Initialize a block of a given size.
00120   //
00121   RefBlockP(size_t size)
00122     : Controller(new RefBlockController(size))
00123       {
00124         P = Controller->getBlock();
00125       }
00126 
00127   //
00128   // Initialize with a user allocated pointer.
00129   // This turns off the deallocation but not the bounds checking.
00130   //
00131   RefBlockP(T* p, size_t size)
00132     : P(p), Controller( new RefBlockController(p,size) )
00133       {
00134       }
00135   
00136   // Copy ctor and assignment
00137   RefBlockP(const RefBlockP<T,BoundsCheck>& b)
00138     : P(b.P), Controller(b.Controller)
00139       {
00140       }
00141   RefBlockP<T,BoundsCheck>& operator=(const RefBlockP<T,BoundsCheck>& rhs)
00142     {
00143       P = rhs.P;
00144       Controller = rhs.Controller;
00145       return *this;
00146     }
00147 
00148   // Copy ctor and assignment from a RefBlockP opposite bounds checking.
00149 //  RefBlockP(const RefBlockP<T,!BoundsCheck>& b)
00150 //    : P(b.P), Controller(b.Controller)
00151 //      {
00152 //      }
00153 //  RefBlockP<T,BoundsCheck>& operator=(const RefBlockP<T,!BoundsCheck>& rhs)
00154 //    {
00155 //      P = rhs.P;
00156 //      Controller = rhs.Controller;
00157 //      return *this;
00158 //    }
00159 
00160   //
00161   // Provide all the usual pointer manipulation functions.
00162   // Each one makes sure it is legal to do the operation if
00163   // it is marked for bounds checking.
00164   // Because BoundsCheck is a compile time parameter, if you don't use it
00165   // the asserts will be optimized away.
00166   //
00167   RefBlockP<T,BoundsCheck>& operator++()
00168     {
00169       ++P;
00170       return *this;
00171     }
00172   RefBlockP<T,BoundsCheck> operator++(int)
00173     {
00174       RefBlockP<T> save(*this);
00175       ++P;
00176       return save;
00177     }
00178   RefBlockP<T,BoundsCheck>& operator--()
00179     {
00180       --P;
00181       return *this;
00182     }
00183   RefBlockP<T,BoundsCheck> operator--(int)
00184     {
00185       RefBlockP<T,BoundsCheck> save(*this);
00186       --P;
00187       return save;
00188     }
00189 
00190   T& operator*() const
00191     {
00192       if ( BoundsCheck ) 
00193         assert( Controller->checkDeref(P) );
00194       return *P;
00195     }
00196   T& operator[](int i) const
00197     {
00198       T* p = P+i;
00199       if ( BoundsCheck )
00200         assert( Controller->checkDeref(p) );
00201       return *p;
00202     }
00203   T* operator->() const
00204     {
00205       if ( BoundsCheck )
00206         assert( P==0 || Controller->checkDeref(P) );
00207       return P;
00208     }
00209 
00210   void operator+=(int i)
00211     {
00212       P += i;
00213     }
00214   void operator-=(int i)
00215     {
00216       P -= i;
00217     }
00218 
00219   RefBlockP<T,BoundsCheck> operator+(int i)
00220     {
00221       RefBlockP<T,BoundsCheck> ret(*this);
00222       ret += i;
00223       return ret;
00224     }
00225   RefBlockP<T,BoundsCheck> operator-(int i)
00226     {
00227       RefBlockP<T,BoundsCheck> ret(*this);
00228       ret -= i;
00229       return ret;
00230     }
00231 
00232   bool operator==(const RefBlockP<T,BoundsCheck>& a) const 
00233     {
00234       return P == a.P;
00235     }
00236 //  bool operator==(const RefBlockP<T,!BoundsCheck>& a) const 
00237 //    {
00238 //      return P == a.P;
00239 //    }
00240 
00241   void invalidate()
00242     {
00243       Controller.invalidate();
00244       P = 0;
00245     }
00246   bool valid()
00247     {
00248       return P!=0;
00249     }
00250 
00251   //
00252   // If something needs a T*, convert it.
00253   //
00254   operator T*() const 
00255     {
00256       return P;
00257     }
00258 };
00259 
00261 
00262 #endif // REF_BLOCK_H
00263 
00264 /***************************************************************************
00265  * $RCSfile: RefBlock.h,v $   $Author: adelmann $
00266  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:33 $
00267  * IPPL_VERSION_ID: $Id: RefBlock.h,v 1.1.1.1 2003/01/23 07:40:33 adelmann Exp $ 
00268  ***************************************************************************/

Generated on Mon Jan 16 13:23:59 2006 for IPPL by  doxygen 1.4.6