Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

ListMemBuf.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_ListMemBuf_h
00003 #define INCLUDED_ListMemBuf_h
00004 
00005 //! Provides some degree of dynamic allocation of a templated type from a buffer of set size.
00006 /*! Think of this as a self-contained mini-malloc...
00007     
00008     This is handy for classes which inhabit a shared memory region, where
00009     it's a bad idea to have pointers to other memory.  By instantiating one
00010     of these in your class, you can allocate space internally for up to
00011     MAX objects of type T_t.  ListMemBuf will worry about keeping track
00012     of which ones are in use or are free.
00013 
00014     Each time you request a entry to be created, the destructor will be
00015     called followed by the the defaul constructor before it is given to
00016     you, so the fields should be reliably 'fresh', not what was in the
00017     entry last time it was used.
00018 */
00019 template < class T_t, unsigned int MAX, class idx_t=unsigned short >
00020 class ListMemBuf {
00021   public:
00022   
00023   ListMemBuf(); //!<constructor
00024   ~ListMemBuf(); //!<destructor
00025   
00026   //!Allows outside access to storage type
00027   typedef T_t T;
00028   //!Allows outside access to number of entries
00029   static const unsigned int MAX_ENTRIES = MAX;
00030   //!Allows outside access to index type
00031   typedef idx_t index_t;
00032   
00033   static index_t getMaxCapacity() { return MAX_ENTRIES; } //!<returns the maximum number of objects which can be used at any given time
00034   index_t size() const { return cursize; } //!<returns the current number of objects in use
00035   index_t countf() const; //!< for debugging, should equal size
00036   index_t countb() const; //!< for debugging, should equal size
00037   bool empty() const { return cursize==0; } //!<returns true if no objects are in use
00038 
00039   inline T& operator[](unsigned int x) { return *reinterpret_cast<T*>(entries[x].data); } //!<allows direct access to elements - be careful, can access 'free' elements this way
00040   inline const T& operator[](unsigned int x) const { return *reinterpret_cast<const T*>(entries[x].data); } //!<allows direct access to elements - be careful, can access 'free' elements this way
00041 
00042   inline index_t begin() const { return activeBegin; } //!<returns index of first used entry
00043   T& front() { return *reinterpret_cast<T*>(entries[activeBegin].data); } //!< returns reference to first used entry
00044   const T& front() const { return *reinterpret_cast<const T*>(entries[activeBegin].data); } //!< returns const reference to first used entry
00045 
00046   inline index_t end() const { return (index_t)-1; } //!<returns the one-past-end index
00047   T& back() { return *reinterpret_cast<T*>(entries[activeBack].data); } //!<returns reference to last used entry
00048   const T& back() const { return *reinterpret_cast<const T*>(entries[activeBack].data); } //!<returns const reference to last used entry
00049 
00050   index_t new_front(); //!<pushes a 'blank' entry on the front of the used list
00051   index_t push_front(const T& data) { index_t tmp=new_front(); if(tmp!=end()) operator[](tmp)=data; return tmp; } //!<pushes an entry on the front of the used chain and assigns @a data to it
00052   void pop_front(); //!<pops the front of the used chain
00053   void pop_front(T& ret) { ret=front(); pop_front(); } //!<pops the front of the chain into @a ret
00054 
00055   index_t new_back(); //!<pushes a 'blank' entry on the back of the used list
00056   index_t push_back(const T& data) { index_t tmp=new_back(); if(tmp!=end()) operator[](tmp)=data; return tmp; } //!<pushes an entry on the back of the used chain and assigns @a data to it
00057   void pop_back(); //!<pops the last of the used chain
00058   void pop_back(T& ret) { ret=back(); pop_back(); } //!<pops the last of the used chain into @a ret
00059 
00060   index_t new_before(index_t x); //!<inserts a 'blank' entry before element @a x in the used chain
00061   index_t push_before(index_t x, const T& data) { index_t tmp=new_before(x); if(tmp!=end()) operator[](tmp)=data; return tmp; } //!<inserts a 'blank' entry before element @a x in the used chain and assigns @a data to it
00062 
00063   index_t new_after(index_t x) { return new_before(next(x)); } //!<inserts a 'blank' entry after element @a x in the used chain
00064   index_t push_after(index_t x, const T& data) { index_t tmp=new_after(x); if(tmp!=end()) operator[](tmp)=data; return tmp; } //!<inserts a 'blank' entry after element @a x in the used chain and assigns @a data to it
00065 
00066   void erase(index_t x); //!<removes element @a x from the used chain
00067   void clear(); //!<frees all used entries
00068 
00069   void swap(index_t a, index_t b); //!<swaps the two entries' position in the list
00070 
00071   index_t next(index_t x) const { return x==end()?activeBegin:entries[x].next; } //!< returns the next used element following @a x
00072   index_t prev(index_t x) const { return x==end()?activeBack:entries[x].prev; } //!< returns the preceeding used element following @a x
00073  
00074   protected:
00075   index_t pop_free(); //!<removes an element from the front of the free list, returns its index
00076   void push_free(index_t x); //!<pushes @a x onto the back of the free list
00077   
00078   //!holds data about an entry in the free/used lists
00079   struct entry_t {
00080     //!constructor
00081     entry_t() : next(static_cast<index_t>(-1)), prev(static_cast<index_t>(-1)) {}
00082     double data[(sizeof(T)-1)/sizeof(double)+1]; //!<The data being stored, not actually an instantiation of T, but big enough to hold it.  (Funky array size is to ensure proper alignment of contents)
00083     index_t next; //!<The next element in the used or free chain
00084     index_t prev; //!<The previous element in the used chain, invalid if in the free chain
00085   };
00086   entry_t entries[MAX_ENTRIES]; //!<the main block of data
00087   index_t activeBegin; //!<beginning of used chain
00088   index_t activeBack; //!<end of used chain
00089   index_t freeBegin; //!<beginning of free chain
00090   index_t freeBack; //!<end of free chain
00091   index_t cursize; //!< current number of used elements
00092 };
00093 
00094 template < class T, unsigned int MAX, class index_t >
00095 ListMemBuf<T,MAX,index_t>::ListMemBuf()
00096   : activeBegin(end()), activeBack(end()), freeBegin(end()), freeBack(end()), cursize(0)
00097 {
00098   for(unsigned int x=0; x+1<MAX_ENTRIES; x++)
00099     entries[x].next=x+1;
00100   entries[MAX_ENTRIES-1].next=end();
00101   freeBegin=0;
00102   freeBack=MAX_ENTRIES-1;
00103 }
00104 
00105 template < class T, unsigned int MAX, class index_t >
00106 ListMemBuf<T,MAX,index_t>::~ListMemBuf() {
00107   clear();
00108 }
00109 
00110 template < class T, unsigned int MAX, class index_t>
00111 index_t
00112 ListMemBuf<T,MAX,index_t>::countf() const {
00113   int x=0;
00114   for(index_t c=begin(); c!=end(); c=next(c))
00115     x++;
00116   return x;
00117 }
00118 
00119 template < class T, unsigned int MAX, class index_t>
00120 index_t
00121 ListMemBuf<T,MAX,index_t>::countb() const {
00122   int x=0;
00123   for(index_t c=end(); c!=begin(); c=prev(c))
00124     x++;
00125   return x;
00126 }
00127 
00128 template < class T, unsigned int MAX, class index_t >
00129 index_t
00130 ListMemBuf<T,MAX,index_t>::new_front() {
00131   index_t tmp = pop_free();
00132   if(tmp==end())
00133     return end();
00134   entries[tmp].prev=end();
00135   entries[tmp].next=activeBegin;
00136   if(activeBegin!=end())
00137     entries[activeBegin].prev=tmp;
00138   else
00139     activeBack=tmp;
00140   activeBegin=tmp;
00141   return tmp;
00142 }
00143 
00144 template < class T, unsigned int MAX, class index_t >
00145 index_t
00146 ListMemBuf<T,MAX,index_t>::new_back() {
00147   index_t tmp = pop_free();
00148   if(tmp==end())
00149     return end();
00150   entries[tmp].prev=activeBack;
00151   entries[tmp].next=end();
00152   if(activeBack!=end())
00153     entries[activeBack].next=tmp;
00154   else
00155     activeBegin=tmp;
00156   activeBack=tmp;
00157   return tmp;
00158 }
00159 
00160 template < class T, unsigned int MAX, class index_t >
00161 index_t
00162 ListMemBuf<T,MAX,index_t>::new_before(index_t x) {
00163   if(x==end())
00164     return new_back();
00165   if(entries[x].prev==end())
00166     return new_front();
00167   index_t tmp = pop_free();
00168   if(tmp==end())
00169     return end();
00170   entries[tmp].next=x;
00171   entries[tmp].prev=entries[x].prev;
00172   entries[x].prev=tmp;
00173   entries[ entries[tmp].prev ].next = tmp;
00174   return tmp;
00175 }
00176 
00177 template < class T, unsigned int MAX, class index_t >
00178 void
00179 ListMemBuf<T,MAX,index_t>::pop_front() {
00180   index_t tmp = activeBegin;
00181   activeBegin = entries[activeBegin].next;
00182   if(activeBegin==end())
00183     activeBack=end();
00184   else
00185     entries[activeBegin].prev = end();
00186   push_free(tmp);
00187 }
00188 
00189 template < class T, unsigned int MAX, class index_t >
00190 void
00191 ListMemBuf<T,MAX,index_t>::pop_back() {
00192   index_t tmp = activeBack;
00193   activeBack = entries[activeBack].prev;
00194   if(activeBack==end())
00195     activeBegin=end();
00196   else
00197     entries[activeBack].next = end();
00198   push_free(tmp);
00199 }
00200 
00201 template < class T, unsigned int MAX, class index_t >
00202 void
00203 ListMemBuf<T,MAX,index_t>::erase(index_t x) {
00204   if(x==activeBegin) {
00205     pop_front();
00206     return;
00207   }
00208   if(x==activeBack) {
00209     pop_back();
00210     return;
00211   }
00212   entries[ entries[x].next ].prev = entries[x].prev;
00213   entries[ entries[x].prev ].next = entries[x].next;
00214   push_free(x);
00215 }
00216 
00217 template < class T, unsigned int MAX, class index_t >
00218 void
00219 ListMemBuf<T,MAX,index_t>::clear() {
00220   if(cursize!=0) {
00221     for(index_t it=activeBegin; it!=end(); it=entries[it].next)
00222       operator[](it).~T();
00223     if(freeBack==end())
00224       freeBegin=activeBegin;
00225     else
00226       entries[freeBack].next=activeBegin;
00227     freeBack=activeBack;
00228     activeBegin=activeBack=end();
00229   }
00230   cursize=0;
00231 }
00232 
00233 template < class T, unsigned int MAX, class index_t >
00234 void
00235 ListMemBuf<T,MAX,index_t>::swap(index_t a, index_t b) {
00236   if(a==b || a==end() || b==end())
00237     return;
00238   if(entries[a].prev==b) {
00239     entries[a].prev=entries[b].prev;
00240     entries[b].next=entries[a].next;
00241     entries[a].next=b;
00242     entries[b].prev=a;
00243     if(entries[a].prev!=end())
00244       entries[entries[a].prev].next=a;
00245     else
00246       activeBegin=a;
00247     if(entries[b].next!=end())
00248       entries[entries[b].next].prev=b;
00249     else
00250       activeBack=b;
00251   } else if(entries[a].next==b) {
00252     entries[a].next=entries[b].next;
00253     entries[b].prev=entries[a].prev;
00254     entries[a].prev=b;
00255     entries[b].next=a;
00256     if(entries[a].next!=end())
00257       entries[entries[a].next].prev=a;
00258     else
00259       activeBack=a;
00260     if(entries[b].prev!=end())
00261       entries[entries[b].prev].next=b;
00262     else
00263       activeBegin=b;
00264   } else {
00265     index_t tmpp=entries[a].prev, tmpn=entries[a].next;
00266     entries[a].prev=entries[b].prev;
00267     entries[a].next=entries[b].next;
00268     entries[b].prev=tmpp;
00269     entries[b].next=tmpn;
00270     if(entries[a].prev!=end())
00271       entries[entries[a].prev].next=a;
00272     else
00273       activeBegin=a;
00274     if(entries[a].next!=end())
00275       entries[entries[a].next].prev=a;
00276     else
00277       activeBack=a;
00278     if(entries[b].prev!=end())
00279       entries[entries[b].prev].next=b;
00280     else
00281       activeBegin=b;
00282     if(entries[b].next!=end())
00283       entries[entries[b].next].prev=b;
00284     else
00285       activeBack=b;
00286   }
00287   /*
00288   // Front Back => Front Back
00289   //  a     b       b     a
00290   //  a     -       b     -
00291   //  b     a       a     b
00292   //  b     -       a     -
00293   //  -     a       -     b
00294   //  -     b       -     a
00295   if(activeBegin==a) {
00296     activeBegin=b;
00297     if(activeBack==b)
00298       activeBack=a;
00299   } else if(activeBegin==b) {
00300     activeBegin=a;
00301     if(activeBack==a)
00302       activeBack=b;
00303   } else {
00304     if(activeBack==a)
00305       activeBack=b;
00306     else if(activeBack=b)
00307       activeBack==a;
00308   }
00309   */
00310 }
00311 
00312 /*! free list is a queue... pop front, push back - hopefully more robust with multi-threads
00313     is purposely sloppy with unused links, a little faster*/
00314 template < class T, unsigned int MAX, class index_t >
00315 index_t
00316 ListMemBuf<T,MAX,index_t>::pop_free() {
00317   if(freeBegin==end())
00318     return end();
00319   index_t tmp=freeBegin;
00320   if(freeBegin==freeBack)
00321     freeBegin=freeBack=end();
00322   else
00323     freeBegin=entries[freeBegin].next;
00324   cursize++;
00325   new (entries[tmp].data) T;  //calls constructor so that the data is "fresh"
00326   return tmp;
00327 }
00328 
00329 /*! @see pop_free() */
00330 template < class T, unsigned int MAX, class index_t >
00331 void
00332 ListMemBuf<T,MAX,index_t>::push_free(index_t x) {
00333   if(freeBack==end())
00334     freeBegin=x;
00335   else
00336     entries[freeBack].next=x;
00337   freeBack=x;
00338   cursize--;
00339   operator[](x).~T(); //to match the constructor call in pop_free() (or the entry_t constructor during initialization)
00340 }
00341 
00342 /*! @file
00343  * @brief Defines ListMemBuf, which provides some degree of dynamic allocation of a templated type from a buffer of set size.
00344  * @author ejt (Creator)
00345  *
00346  * $Author: ejt $
00347  * $Name: tekkotsu-2_4_1 $
00348  * $Revision: 1.2 $
00349  * $State: Exp $
00350  * $Date: 2005/06/01 05:47:46 $
00351  */
00352  
00353  #endif

Tekkotsu v2.4.1
Generated Tue Aug 16 16:32:47 2005 by Doxygen 1.4.4