00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef _TemplateLibrary_LinearQueue_H_
00018 #define _TemplateLibrary_LinearQueue_H_ 1
00019
00029 #include <lib/sconfig.h>
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
00087 T ent[];
00088
00089 inline Chunk() : LinkedListBase<Chunk>() {}
00090 inline ~Chunk() {}
00091 };
00092
00093 public:
00096 class 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)
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
00148
00149
00150
00151
00152
00158 size_t first_idx;
00164 size_t last_idx;
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
00201
00202
00203 while(old_nents>keep_old)
00204 { _FreeChunk(old_list.PopFirst()); --old_nents; }
00205 }
00207 inline Chunk *_NewChunkCache()
00208 {
00209 Chunk *c;
00210
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()
00221 { clist.insert(_NewChunkCache()); first_idx=chunk_size-1; }
00224 void _AddChunkHead()
00225 { clist.append(_NewChunkCache()); last_idx=0; }
00226
00228 void _PopChunkTail()
00229 { _Add2Cache(clist.PopFirst()); first_idx=0; }
00231 void _PopChunkHead()
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 )
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 )
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