Homepage Demos Overview Downloads Tutorials 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   
00025   //!Allows outside access to storage type
00026   typedef T_t T;
00027   //!Allows outside access to number of entries
00028   static const unsigned int MAX_ENTRIES = MAX;
00029   //!Allows outside access to index type
00030   typedef idx_t index_t;
00031   
00032   index_t getMaxCapacity() const { return MAX_ENTRIES; } //!<returns the maximum number of objects which can be used at any given time
00033   index_t size() const { return cursize; } //!<returns the current number of objects in use
00034   index_t countf() const; //!< for debugging, should equal size
00035   index_t countb() const; //!< for debugging, should equal size
00036   bool empty() const { return cursize==0; } //!<returns true if no objects are in use
00037 
00038   inline T& operator[](unsigned int x) { return (entries[x].data); } //!<allows direct access to elements - be careful, can access 'free' elements this way
00039   inline const T& operator[](unsigned int x) const { return (entries[x].data); } //!<allows direct access to elements - be careful, can access 'free' elements this way
00040 
00041   inline index_t begin() const { return activeBegin; } //!<returns index of first used entry
00042   T& front() { return (entries[activeBegin].data); } //!< returns reference to first used entry
00043   const T& front() const { return (entries[activeBegin].data); } //!< returns const reference to first used entry
00044 
00045   inline index_t end() const { return (index_t)-1; } //!<returns the one-past-end index
00046   T& back() { return (entries[activeBack].data); } //!<returns reference to last used entry
00047   const T& back() const { return (entries[activeBack].data); } //!<returns const reference to last used entry
00048 
00049   index_t new_front(); //!<pushes a 'blank' entry on the front of the used list
00050   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
00051   void pop_front(); //!<pops the front of the used chain
00052   void pop_front(T& ret) { ret=front(); pop_front(); } //!<pops the front of the chain into @a ret
00053 
00054   index_t new_back(); //!<pushes a 'blank' entry on the back of the used list
00055   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
00056   void pop_back(); //!<pops the last of the used chain
00057   void pop_back(T& ret) { ret=back(); pop_back(); } //!<pops the last of the used chain into @a ret
00058 
00059   index_t new_before(index_t x); //!<inserts a 'blank' entry before element @a x in the used chain
00060   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
00061 
00062   index_t new_after(index_t x) { return new_before(next(x)); } //!<inserts a 'blank' entry after element @a x in the used chain
00063   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
00064 
00065   void erase(index_t x); //!<removes element @a x from the used chain
00066   void clear(); //!<frees all used entries
00067 
00068   void swap(index_t a, index_t b); //!<swaps the two entries' position in the list
00069 
00070   index_t next(index_t x) const { return x==end()?activeBegin:entries[x].next; } //!< returns the next used element following @a x
00071   index_t prev(index_t x) const { return x==end()?activeBack:entries[x].prev; } //!< returns the preceeding used element following @a x
00072  
00073   protected:
00074   index_t pop_free(); //!<removes an element from the front of the free list, returns its index
00075   void push_free(index_t x); //!<pushes @a x onto the back of the free list
00076   
00077   //!holds data about an entry in the free/used lists
00078   struct entry_t {
00079     //!constructor
00080     entry_t() : data(), next(static_cast<index_t>(-1)), prev(static_cast<index_t>(-1)) {}
00081     T data; //!<The data being stored, not actually an instantiation of T, but big enough to hold it.
00082     index_t next; //!<The next element in the used or free chain
00083     index_t prev; //!<The previous element in the used chain, invalid if in the free chain
00084   };
00085   entry_t entries[MAX_ENTRIES]; //!<the main block of data
00086   index_t activeBegin; //!<beginning of used chain
00087   index_t activeBack; //!<end of used chain
00088   index_t freeBegin; //!<beginning of free chain
00089   index_t freeBack; //!<end of free chain
00090   index_t cursize; //!< current number of used elements
00091 };
00092 
00093 template < class T, unsigned int MAX, class index_t >
00094 ListMemBuf<T,MAX,index_t>::ListMemBuf()
00095   : activeBegin(end()), activeBack(end()), freeBegin(end()), freeBack(end()), cursize(0)
00096 {
00097   for(push_free(0); freeBack<MAX_ENTRIES-1; push_free(freeBack+1)) {}
00098   cursize=0; //important to do this - push_free() above will subtract one each time otherwise
00099 }
00100 
00101 template < class T, unsigned int MAX, class index_t>
00102 index_t
00103 ListMemBuf<T,MAX,index_t>::countf() const {
00104   int x=0;
00105   for(index_t c=begin(); c!=end(); c=next(c))
00106     x++;
00107   return x;
00108 }
00109 
00110 template < class T, unsigned int MAX, class index_t>
00111 index_t
00112 ListMemBuf<T,MAX,index_t>::countb() const {
00113   int x=0;
00114   for(index_t c=end(); c!=begin(); c=prev(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>::new_front() {
00122   index_t tmp = pop_free();
00123   if(tmp==end())
00124     return end();
00125   entries[tmp].prev=end();
00126   entries[tmp].next=activeBegin;
00127   if(activeBegin!=end())
00128     entries[activeBegin].prev=tmp;
00129   else
00130     activeBack=tmp;
00131   activeBegin=tmp;
00132   return tmp;
00133 }
00134 
00135 template < class T, unsigned int MAX, class index_t >
00136 index_t
00137 ListMemBuf<T,MAX,index_t>::new_back() {
00138   index_t tmp = pop_free();
00139   if(tmp==end())
00140     return end();
00141   entries[tmp].prev=activeBack;
00142   entries[tmp].next=end();
00143   if(activeBack!=end())
00144     entries[activeBack].next=tmp;
00145   else
00146     activeBegin=tmp;
00147   activeBack=tmp;
00148   return tmp;
00149 }
00150 
00151 template < class T, unsigned int MAX, class index_t >
00152 index_t
00153 ListMemBuf<T,MAX,index_t>::new_before(index_t x) {
00154   if(x==end())
00155     return new_back();
00156   if(entries[x].prev==end())
00157     return new_front();
00158   index_t tmp = pop_free();
00159   if(tmp==end())
00160     return end();
00161   entries[tmp].next=x;
00162   entries[tmp].prev=entries[x].prev;
00163   entries[x].prev=tmp;
00164   entries[ entries[tmp].prev ].next = tmp;
00165   return tmp;
00166 }
00167 
00168 template < class T, unsigned int MAX, class index_t >
00169 void
00170 ListMemBuf<T,MAX,index_t>::pop_front() {
00171   index_t tmp = activeBegin;
00172   activeBegin = entries[activeBegin].next;
00173   if(activeBegin==end())
00174     activeBack=end();
00175   else
00176     entries[activeBegin].prev = end();
00177   push_free(tmp);
00178 }
00179 
00180 template < class T, unsigned int MAX, class index_t >
00181 void
00182 ListMemBuf<T,MAX,index_t>::pop_back() {
00183   index_t tmp = activeBack;
00184   activeBack = entries[activeBack].prev;
00185   if(activeBack==end())
00186     activeBegin=end();
00187   else
00188     entries[activeBack].next = end();
00189   push_free(tmp);
00190 }
00191 
00192 template < class T, unsigned int MAX, class index_t >
00193 void
00194 ListMemBuf<T,MAX,index_t>::erase(index_t x) {
00195   if(x==activeBegin) {
00196     pop_front();
00197     return;
00198   }
00199   if(x==activeBack) {
00200     pop_back();
00201     return;
00202   }
00203   entries[ entries[x].next ].prev = entries[x].prev;
00204   entries[ entries[x].prev ].next = entries[x].next;
00205   push_free(x);
00206 }
00207 
00208 template < class T, unsigned int MAX, class index_t >
00209 void
00210 ListMemBuf<T,MAX,index_t>::clear() {
00211   if(cursize!=0) {
00212     if(freeBack==end())
00213       freeBegin=activeBegin;
00214     else
00215       entries[freeBack].next=activeBegin;
00216     freeBack=activeBack;
00217     activeBegin=activeBack=end();
00218   }
00219   cursize=0;
00220 }
00221 
00222 template < class T, unsigned int MAX, class index_t >
00223 void
00224 ListMemBuf<T,MAX,index_t>::swap(index_t a, index_t b) {
00225   if(a==b || a==end() || b==end())
00226     return;
00227   if(entries[a].prev==b) {
00228     entries[a].prev=entries[b].prev;
00229     entries[b].next=entries[a].next;
00230     entries[a].next=b;
00231     entries[b].prev=a;
00232     if(entries[a].prev!=end())
00233       entries[entries[a].prev].next=a;
00234     else
00235       activeBegin=a;
00236     if(entries[b].next!=end())
00237       entries[entries[b].next].prev=b;
00238     else
00239       activeBack=b;
00240   } else if(entries[a].next==b) {
00241     entries[a].next=entries[b].next;
00242     entries[b].prev=entries[a].prev;
00243     entries[a].prev=b;
00244     entries[b].next=a;
00245     if(entries[a].next!=end())
00246       entries[entries[a].next].prev=a;
00247     else
00248       activeBack=a;
00249     if(entries[b].prev!=end())
00250       entries[entries[b].prev].next=b;
00251     else
00252       activeBegin=b;
00253   } else {
00254     index_t tmpp=entries[a].prev, tmpn=entries[a].next;
00255     entries[a].prev=entries[b].prev;
00256     entries[a].next=entries[b].next;
00257     entries[b].prev=tmpp;
00258     entries[b].next=tmpn;
00259     if(entries[a].prev!=end())
00260       entries[entries[a].prev].next=a;
00261     else
00262       activeBegin=a;
00263     if(entries[a].next!=end())
00264       entries[entries[a].next].prev=a;
00265     else
00266       activeBack=a;
00267     if(entries[b].prev!=end())
00268       entries[entries[b].prev].next=b;
00269     else
00270       activeBegin=b;
00271     if(entries[b].next!=end())
00272       entries[entries[b].next].prev=b;
00273     else
00274       activeBack=b;
00275   }
00276   /*
00277   // Front Back => Front Back
00278   //  a     b       b     a
00279   //  a     -       b     -
00280   //  b     a       a     b
00281   //  b     -       a     -
00282   //  -     a       -     b
00283   //  -     b       -     a
00284   if(activeBegin==a) {
00285     activeBegin=b;
00286     if(activeBack==b)
00287       activeBack=a;
00288   } else if(activeBegin==b) {
00289     activeBegin=a;
00290     if(activeBack==a)
00291       activeBack=b;
00292   } else {
00293     if(activeBack==a)
00294       activeBack=b;
00295     else if(activeBack=b)
00296       activeBack==a;
00297   }
00298   */
00299 }
00300 
00301 
00302 /*! free list is a queue... pop front, push back - hopefully more robust with multi-threads
00303     is purposely sloppy with unused links, a little faster*/
00304 template < class T, unsigned int MAX, class index_t >
00305 index_t
00306 ListMemBuf<T,MAX,index_t>::pop_free() {
00307   if(freeBegin==end())
00308     return end();
00309   index_t tmp=freeBegin;
00310   if(freeBegin==freeBack)
00311     freeBegin=freeBack=end();
00312   else
00313     freeBegin=entries[freeBegin].next;
00314   cursize++;
00315   new (&entries[tmp].data) T;  //calls constructor so that the data is "fresh"
00316   return tmp;
00317 }
00318 
00319 /*! @see pop_free() */
00320 template < class T, unsigned int MAX, class index_t >
00321 void
00322 ListMemBuf<T,MAX,index_t>::push_free(index_t x) {
00323   if(freeBack==end())
00324     freeBegin=x;
00325   else
00326     entries[freeBack].next=x;
00327   freeBack=x;
00328   cursize--;
00329   operator[](x).~T(); //to match the constructor call in pop_free() (or the entry_t constructor during initialization)
00330 }
00331 
00332 /*! @file
00333  * @brief Defines ListMemBuf, which provides some degree of dynamic allocation of a templated type from a buffer of set size.
00334  * @author ejt (Creator)
00335  *
00336  * $Author: ejt $
00337  * $Name: tekkotsu-2_2 $
00338  * $Revision: 1.8 $
00339  * $State: Rel $
00340  * $Date: 2003/09/25 15:31:53 $
00341  */
00342  
00343  #endif

Tekkotsu v2.2
Generated Tue Oct 19 14:19:14 2004 by Doxygen 1.3.9.1