Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

/ray/src/lib/tl/tllinearqueue.h

Go to the documentation of this file.
00001 /*
00002  * lib/tl/tllinearqueue.h 
00003  * 
00004  * Implementation of a linear (non-priority) 2-ended queue. 
00005  * 
00006  * Copyright (c) 2004 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 
00007  * 
00008  * This file may be distributed and/or modified under the terms of the 
00009  * GNU General Public License version 2 as published by the Free Software 
00010  * Foundation. (See COPYING.GPL for details.)
00011  * 
00012  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00013  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00014  * 
00015  */
00016 
00017 #ifndef _TemplateLibrary_LinearQueue_H_
00018 #define _TemplateLibrary_LinearQueue_H_ 1
00019 
00029 #include <lib/sconfig.h>    /* MUST be first */
00030 
00031 #include <lib/salloc.h>
00032 #include <lib/tl/defop.h>
00033 #include <lib/tl/linkedlist.h>
00034 
00036 
00080 template<typename T,typename _OP=TLDefaultOperators_CDT<T> >class TLLinearQueue
00081 {
00082     public:
00084         struct Chunk : LinkedListBase<Chunk>
00085         {
00086             // For GCC, we may use ent[0]. (zero-length array)
00087             T ent[];  
00088             
00089             inline Chunk() : LinkedListBase<Chunk>() {}
00090             inline ~Chunk() {}
00091         };
00092     
00093     public:
00096         class Iterator  // <-- more like a const-iterator
00097         {
00098             private:
00099                 const TLLinearQueue *lq;
00100                 Chunk *chk;
00101                 size_t idx;
00102                 
00103                 inline bool _valid()
00104                     {  return(chk);  }
00105                 inline void _assign(const TLLinearQueue &_lq)
00106                     {  lq=&_lq; chk=lq->clist.first(); idx=lq->first_idx;  }
00107             public:
00109                 inline Iterator(const TLLinearQueue &_lq)  { _assign(_lq); }
00110                 inline ~Iterator() {}
00111                 
00114                 inline operator bool()
00115                     {  return(_valid());  }
00116                 
00119                 inline T *operator*()
00120                     {  return(_valid() ? &(chk->ent[idx]) : NULL);  }
00121                 
00122                 inline bool operator=(const TLLinearQueue &_lq)
00123                     {  _assign(_lq);  return(_valid());  }
00124                 
00126                 inline bool operator++()
00127                 {
00128                     if(!_valid())  return(0);
00129                     ++idx;
00130                     if(!chk->next && idx>lq->last_idx)  // reached end of list
00131                     {  chk=NULL;  }
00132                     else if(idx>=lq->chunk_size)
00133                     {  idx=0;  chk=chk->next;  }
00134                     return(_valid());
00135                 }
00136                 inline bool operator++(int)
00137                     {  return(operator++());  }
00138         };
00139         
00140     protected:
00141         size_t chunk_size;   
00142         int keep_old;        
00143         LinkedList<Chunk> clist;  
00144         size_t nelem;        
00145         
00146         //----------------------------------------------------------------------
00147         // Internal layout: 
00148         // 
00149         // tail->  [CHUNK]---[CHUNK]---[CHUNK]---[CHUNK]  <-head
00150         // FIRST,INSERT                              LAST,APPEND
00151         //----------------------------------------------------------------------
00152         
00158         size_t first_idx;  // 0
00164         size_t last_idx;  // chunk_size-1
00165         
00166         LinkedList<Chunk> old_list; 
00167         int old_nents;              
00168         
00169     public:
00171         _OP OP;
00172     
00173     private:
00175         inline Chunk *_AllocChunk()
00176         {
00177             char *mem=(char*)OP.alloc(sizeof(Chunk)+chunk_size*OP.size());
00178             Chunk *c = new(mem) Chunk();
00179             return(c);
00180         }
00182         inline void _FreeChunk(Chunk *c)
00183             {  c->Chunk::~Chunk();  OP.free((char*)c);  }
00184         
00186         void _FreeAllOld()
00187         {
00188             while(!old_list.IsEmpty())
00189             {  _FreeChunk(old_list.PopLast());  --old_nents;  }
00190             Assert(old_nents==0);
00191         }
00192         
00195         inline void _Add2Cache(Chunk *c)
00196         {
00197             if(!keep_old && !old_nents)
00198             {  _FreeChunk(c);  return;  }
00199             old_list.append(c);  ++old_nents;
00200             // Always add to the end of old_list because of caching strategy. 
00201             // In case there are too many elements, remove the oldest one 
00202             // (this is the first one). 
00203             while(old_nents>keep_old)
00204             {  _FreeChunk(old_list.PopFirst());  --old_nents;  }
00205         }
00207         inline Chunk *_NewChunkCache()
00208         {
00209             Chunk *c;
00210             // See if we can re-use a chunk. 
00211             if(!old_list.IsEmpty())
00212             {  c=old_list.PopLast();  --old_nents;  }
00213             else
00214             {  c=_AllocChunk();  }
00215             return(c);
00216         }
00217         
00220         void _AddChunkTail()  // <-- NON-inline. 
00221             {  clist.insert(_NewChunkCache());  first_idx=chunk_size-1;  }
00224         void _AddChunkHead()  // <-- NON-inline. 
00225             {  clist.append(_NewChunkCache());  last_idx=0;  }
00226         
00228         void _PopChunkTail()  // <-- NON-inline. 
00229             {  _Add2Cache(clist.PopFirst());  first_idx=0;  }
00231         void _PopChunkHead()  // <-- NON-inline. 
00232             {  _Add2Cache(clist.PopLast());  last_idx=chunk_size-1;  }
00233         
00235         inline void _DoPopTail()
00236         {
00237             OP.clr(&clist.first()->ent[first_idx]);  --nelem;
00238             if(!nelem /*first_idx==last_idx && clist.first()==clist.last()*/)
00239             {  last_idx=chunk_size-1;  _PopChunkTail();  return;  }
00240             if(++first_idx==chunk_size)  _PopChunkTail();
00241         }
00243         inline void _DoPopHead()
00244         {
00245             OP.clr(&clist.last()->ent[last_idx]);  --nelem;
00246             if(!nelem /*first_idx==last_idx && clist.first()==clist.last()*/)
00247             {  first_idx=0;  _PopChunkHead();  return;  }
00248             if(!last_idx)  _PopChunkHead();  else  --last_idx;
00249         }
00250         
00251     private:
00253         TLLinearQueue(const TLLinearQueue &);
00255         void operator=(const TLLinearQueue &);
00256     public:
00267         inline TLLinearQueue(size_t _chunk_size,int _keep_old=4,
00268             const _OP &op=_OP()) : 
00269             chunk_size(_chunk_size<1 ? 1 : _chunk_size),
00270             keep_old(_keep_old<0 ? 0 : _keep_old),
00271             clist(),nelem(0),first_idx(0),last_idx(chunk_size-1),
00272             old_list(),old_nents(0),OP(op)  {}
00274         inline ~TLLinearQueue()
00275             {  clear();  _FreeAllOld();  }
00276         
00278         inline bool IsEmpty() const
00279             {  return(clist.IsEmpty());  }
00280         
00282         inline size_t NElem() const
00283             {  return(nelem);  }
00284         
00286         void clear()
00287         {
00290             while(!IsEmpty())
00291             {  _DoPopTail();  }
00292             Assert(nelem==0);
00293         }
00294         
00303         inline T *head()
00304             {  return(clist.last() ? &clist.last()->ent[last_idx] : NULL);  }
00305         
00314         inline T *tail()
00315             {  return(clist.first() ? &clist.first()->ent[first_idx] : NULL);  }
00316         
00324         inline void PushTail(const T &e)
00325         {
00326             if(!first_idx)  _AddChunkTail();  else  --first_idx;
00327             Chunk *c=clist.first();  OP.ini(&c->ent[first_idx],e);  ++nelem;
00328         }
00329         
00337         inline void PushHead(const T &e)
00338         {
00339             if(++last_idx==chunk_size)  _AddChunkHead();
00340             Chunk *c=clist.last();  OP.ini(&c->ent[last_idx],e);  ++nelem;
00341         }
00342         
00353         int PopTail(T *re=NULL)
00354         {
00355             if(IsEmpty())  return(1);
00356             if(re)  OP.ass(*re,clist.first()->ent[first_idx]);
00357             _DoPopTail();
00358             return(0);
00359         }
00360         
00371         int PopHead(T *re=NULL)
00372         {
00373             if(IsEmpty())  return(1);
00374             if(re)  OP.ass(*re,clist.last()->ent[last_idx]);
00375             _DoPopHead();
00376             return(0);
00377         }
00378 };
00379 
00380 #endif  /* _TemplateLibrary_LinearQueue_H_ */

Generated on Sat Feb 19 22:33:46 2005 for Ray by doxygen 1.3.5