util/cklists.h

Go to the documentation of this file.
00001 #ifndef _CKLISTS_H
00002 #define _CKLISTS_H
00003 
00004 //#include <converse.h> // for size_t
00005 #include "pup.h"
00006 #include <stdlib.h> // for size_t
00007 #include <string.h> // for memcpy
00008 
00009 //"Documentation" class: prevents people from using copy constructors 
00010 class CkNoncopyable {
00011         //These aren't defined anywhere-- don't use them!
00012         CkNoncopyable(const CkNoncopyable &c);
00013         CkNoncopyable &operator=(const CkNoncopyable &c);
00014 public:
00015         CkNoncopyable(void) {}
00016 };
00017 
00018 //Implementation class 
00019 template <class T>
00020 class CkSTLHelper {
00021 protected:
00022     //Copy nEl elements from src into dest
00023     void elementCopy(T *dest,const T *src,int nEl) {
00024       for (int i=0;i<nEl;i++) dest[i]=src[i];
00025     }
00026 };
00027 
00028 // Forward declarations:
00029 template <class T> class CkQ;
00030 template <class T> void pupCkQ(PUP::er &p,CkQ<T> &q);
00031 
00034 template <class T>
00035 class CkQ : private CkSTLHelper<T>, private CkNoncopyable {
00036     T *block;
00037     int blklen;
00038     int first;
00039     int len;
00040     int mask;
00041     void _expand(void) {
00042       // blklen is always kept as a power of 2
00043       int newlen = blklen<<1;
00044       mask |= blklen;
00045       if (blklen==0) {
00046         newlen = 16;
00047         mask = 0x0f;
00048       }
00049       T *newblk = new T[newlen];
00050       elementCopy(newblk,block+first,blklen-first);
00051       elementCopy(newblk+blklen-first,block,first);
00052       delete[] block; block = newblk;
00053       blklen = newlen; first = 0;
00054     }
00055   public:
00056     CkQ() : block(NULL), blklen(0), first(0),len(0),mask(0) {}
00057     CkQ(int sz) :first(0),len(0) {
00058       int size = 2;
00059       mask = 0x03;
00060       while (1<<size < sz) { mask |= 1<<size; size++; }
00061       blklen = 1<<size;
00062       block = new T[blklen];
00063     }
00064     ~CkQ() { delete[] block; }
00065     int length(void) { return len; }
00066     int isEmpty(void) { return (len==0); }
00067     T deq(void) {
00068       if(len>0) {
00069         T &ret = block[first];
00070         first = (first+1)&mask;
00071         len--;
00072         return ret;
00073       } else return T(); //For builtin types like int, void*, this is equivalent to T(0)
00074     }
00075     void enq(const T &elt) {
00076       if(len==blklen) _expand();
00077       block[(first+len)&mask] = elt;
00078       len++;
00079     }
00080     // stack semantics, needed to replace FIFO_QUEUE of converse
00081     void push(const T &elt) {
00082       if(len==blklen) _expand();
00083       first = (first-1+blklen)&mask;
00084       block[first] = elt;
00085       len++;
00086     }
00087     // insert an element at pos.
00088     void insert(int pos, const T &elt) {
00089       while(len==blklen || pos>=blklen) _expand();
00090       for (int i=len; i>pos; i--)
00091         block[(i+first)&mask] = block[(i-1+first)&mask];
00092       block[(pos+first)&mask] = elt;
00093       if (pos > len) len = pos+1;
00094       else len++;
00095     }
00096     // delete an element at pos
00097     T remove(int pos) {
00098       if (pos >= len) return T(0);
00099       T ret = block[(pos+first)&mask];
00100       for (int i=pos; i<len-1; i++)
00101         block[(i+first)&mask] = block[(i+1+first)&mask];
00102       len--;
00103       return ret;
00104     }
00105     // delete all elements from pos
00106     void removeFrom(int pos) {
00107       CmiAssert (pos < len && pos>=0);
00108       len = pos;
00109     }
00110     //Peek at the n'th item from the queue
00111     T& operator[](size_t n)
00112     {
00113         n=(n+first)&mask;
00114         return block[n];
00115     }
00116     // needed to replace FIFO_Enumerate
00117     T* getArray(void) {
00118       T *newblk = new T[len];
00119       int i,j;
00120       for(i=0,j=first;i<len;i++){
00121         newblk[i] = block[j];
00122         j = (j+1)&mask;
00123       }
00124       return newblk;
00125     }
00126 #ifdef _MSC_VER
00127 /* Visual C++ 6.0's operator overloading is buggy,
00128    so use default operator|, which calls this pup routine. */
00129      void pup(PUP::er &p) {
00130         pupCkQ(p,*this);
00131      }
00132 #endif
00133 };
00134 
00136 template <class T>
00137 inline void pupCkQ(PUP::er &p,CkQ<T> &q) {
00138     p.syncComment(PUP::sync_begin_array);
00139     int l=q.length();
00140     p|l;
00141     for (int i=0;i<l;i++) {
00142         p.syncComment(PUP::sync_item);
00143         if (p.isUnpacking()) {
00144                 T t;
00145                 p|t;
00146                 q.enq(t);
00147         } else {
00148                 p|q[i];
00149         }
00150     }
00151     p.syncComment(PUP::sync_end_array);
00152 }
00153 
00154 #ifndef _MSC_VER
00156 template <class T>
00157 inline void operator|(PUP::er &p,CkQ<T> &q) {pupCkQ(p,q);}
00158 #endif
00159 
00163 class CkSkipInitialization {};
00164 
00165 // Forward declarations:
00166 template <class T> class CkVec;
00167 template <class T> void pupCkVec(PUP::er &p,CkVec<T> &vec);
00168 
00174 template <class T>
00175 class CkVec : private CkSTLHelper<T> {
00176     typedef CkVec<T> this_type;
00177 
00178     T *block; //Elements of vector
00179     int blklen; //Allocated size of block (STL capacity) 
00180     int len; //Number of used elements in block (STL size; <= capacity)
00181     void makeBlock(int blklen_,int len_) {
00182        if (blklen_==0) block=NULL; //< saves 1-byte allocations
00183        else {
00184          block=new T[blklen_];
00185          if (block == NULL) blklen_=len_= 0;
00186        }
00187        blklen=blklen_; len=len_;
00188     }
00189     void freeBlock(void) {
00190        len=0; blklen=0;
00191        delete[] block; 
00192        block=NULL;
00193     }
00194     void copyFrom(const this_type &src) {
00195        makeBlock(src.blklen, src.len);
00196        elementCopy(block,src.block,blklen);
00197     }
00198   public:
00199     CkVec(): block(NULL), blklen(0), len(0) {}
00200     ~CkVec() { freeBlock(); }
00201     CkVec(const this_type &src) {copyFrom(src);}
00202     CkVec(int size) { makeBlock(size,size); } 
00203     CkVec(int size, int used) { makeBlock(size,used); } 
00204     CkVec(const CkSkipInitialization &skip) {/* don't initialize */}
00205     this_type &operator=(const this_type &src) {
00206       freeBlock();
00207       copyFrom(src);
00208       return *this;
00209     }
00210 
00211     int &length(void) { return len; }
00212     int length(void) const {return len;}
00213     T *getVec(void) { return block; }
00214     const T *getVec(void) const { return block; }
00215     
00216     T& operator[](size_t n) {
00217 #if CMK_PARANOID 
00218       if (n >= len || n < 0) 
00219         CmiAbort("CkVec Out Of Bounds\n\n"); 
00220 #endif
00221       return block[n]; 
00222     }
00223     
00224     const T& operator[](size_t n) const { 
00225 #if CMK_PARANOID 
00226       if (n >= len || n < 0) 
00227         CmiAbort("CkVec Out Of Bounds\n\n");  
00228 #endif
00229       return block[n]; 
00230     }
00231     
00233     int reserve(int newcapacity) {
00234       if (newcapacity<=blklen) return 1; /* already there */
00235       T *oldBlock=block; 
00236       makeBlock(newcapacity,len);
00237       if (newcapacity != blklen) return 0;
00238       elementCopy(block,oldBlock,len);
00239       delete[] oldBlock; //WARNING: leaks if element copy throws exception
00240       return 1;
00241     }
00242     inline int capacity(void) const {return blklen;}
00243 
00245     int resize(int newsize) {
00246       if (!reserve(newsize)) return 0;
00247       len=newsize;
00248       return 1;
00249     }
00250 
00252     void free() {
00253       freeBlock();
00254     }
00255 
00256     //Grow to contain at least this position:
00257     void growAtLeast(int pos) {
00258       if (pos>=blklen) reserve(pos*2+16);
00259     }
00260     void insert(int pos, const T &elt) {
00261       if (pos>=len) { 
00262         growAtLeast(pos);
00263         len=pos+1;
00264       }
00265       block[pos] = elt;
00266     }
00267     void remove(int pos) {
00268       if (pos<0 || pos>=len) 
00269         {
00270           CmiAbort("CkVec ERROR: out of bounds\n\n"); 
00271           return;
00272         }
00273       for (int i=pos; i<len-1; i++)
00274         block[i] = block[i+1];
00275       len--;
00276     }
00277     void removeAll() {
00278       len = 0;
00279     }
00280     void insertAtEnd(const T &elt) {insert(length(),elt);}
00281 
00282 //STL-compatability:
00283     void push_back(const T &elt) {insert(length(),elt);}
00284     int size(void) const {return len;}
00285 
00286 //verbose position for easier removal
00287     int push_back_v(const T &elt) {insert(length(),elt);return length()-1;}
00288 
00289  
00290 //PUP routine help:
00291     //Only pup the length of this vector, which is returned:
00292     int pupbase(PUP::er &p) {
00293        int l=len;
00294        p(l);
00295        if (p.isUnpacking()) resize(l); 
00296        return l;
00297     }
00298     
00299 #ifdef _MSC_VER
00300 /* Visual C++ 6.0's operator overloading is buggy,
00301    so use default operator|, which calls this pup routine. */
00302      void pup(PUP::er &p) {
00303         pupCkVec(p,*this);
00304      }
00305 #endif
00306 
00307                 inline void quickSort(){
00308                   q_sort(0, len - 1,128);
00309                 }
00310 
00311                 inline void quickSort(int changeOverSize){
00312                         q_sort(0,len-1,changeOverSize);
00313                 }
00314                 
00315 
00316                 inline void q_sort(int left, int right,int changeOverSize){
00317                   int l_hold, r_hold;
00318                         int pivot;
00319                         
00320                         if(left >= right)
00321                                 return;
00322                         
00323                         //swap the center element with the left one
00324                         int mid =  (left+right)/2;
00325                         T temp = block[mid];
00326                         block[mid] = block[left];
00327                         block[left] = temp;
00328                         
00329                   l_hold = left;
00330                   r_hold = right;
00331                         pivot = left;
00332                         if(right - left <= changeOverSize){
00333                                 bubbleSort(left,right);
00334                                 return;
00335                         }
00336                   while (left < right)
00337                   {
00338                 while ((block[right] >= block[pivot]) && (left < right))
00339                       right--;
00340                     while ((block[left] <= block[pivot]) && (left < right))
00341                       left++;
00342                         
00343                                 if(left < right){
00344                                         T val = block[left];
00345                                         block[left] = block[right];
00346                                         block[right] = val;
00347                                 }
00348                         }
00349                         T val = block[left];
00350                         block[left] = block[pivot];
00351                         block[pivot] = val;
00352                   pivot = left;
00353                   left = l_hold;
00354                   right = r_hold;
00355                   if (left < pivot)
00356                 q_sort(left, pivot-1,changeOverSize);
00357                   if (right > pivot)
00358                 q_sort(pivot+1, right,changeOverSize);
00359                 }
00360 
00361                 inline void bubbleSort(int left,int right){
00362                         for(int i=left;i<=right;i++){
00363                                 for(int j=i+1;j<=right;j++){
00364                                         if(block[i] >= block[j]){
00365                                                 T val = block[i];
00366                                                 block[i] = block[j];
00367                                                 block[j] = val;
00368                                         }
00369                                 }
00370                         }
00371                 }
00372 
00373 };
00374 
00376 template <class T>
00377 inline void pupCkVec(PUP::er &p,CkVec<T> &vec) {
00378     int len=vec.pupbase(p);
00379     if (len) PUParray(p,&vec[0],len);
00380 }
00381 
00382 #ifndef _MSC_VER
00384 template <class T>
00385 inline void operator|(PUP::er &p,CkVec<T> &vec) {pupCkVec(p,vec);}
00386 #endif
00387 
00388 /* OLD: Deprecated name for vector of basic types. */
00389 #define CkPupBasicVec CkVec
00390 
00393 template <class T> 
00394 class CkPupAlwaysAllocatePtr {
00395 public:
00396         void pup(PUP::er &p,T *&ptr) {
00397                 if (p.isUnpacking()) ptr=new T;
00398                 p|*ptr;
00399         }
00400 };
00401 
00404 template <class T> 
00405 class CkPupAllocatePtr {
00406 public:
00407         void pup(PUP::er &p,T *&ptr) {
00408                 int isNull=(ptr==0);
00409                 p(isNull);
00410                 if (isNull) ptr=0;
00411                 else {
00412                         if (p.isUnpacking()) ptr=new T;
00413                         p|*ptr;
00414                 }
00415         }
00416 };
00417 
00419 template <class T> 
00420 class CkPupAblePtr {
00421 public:
00422         void pup(PUP::er &p,T *&ptr) {
00423                 p|ptr;
00424         }
00425 };
00426 
00428 template <class T, class PUP_PTR=CkPupAllocatePtr<T> > 
00429 class CkZeroPtr {
00430 protected:
00431         T *storage;
00432 public:
00433         CkZeroPtr() {storage=0;}
00434         CkZeroPtr(T *sto) {storage=sto;}
00435         CkZeroPtr(const CkZeroPtr &src) { storage=src.storage; }
00436         CkZeroPtr &operator=(const CkZeroPtr &src) {
00437                 storage=src.storage; return *this;
00438         }
00439         T *operator=(T *sto) {storage=sto; return sto;}
00440         
00441         operator T* () const {return storage;}
00442 
00443         T *release() {
00444                 T *ret=storage; storage=0; return ret;
00445         }
00446         
00447         //Stolen from boost::scoped_ptr:
00448         T & operator*() const // never throws
00449                 { return *storage; }
00450         T * operator->() const // never throws
00451                 { return storage; }
00452 
00453         
00454         //Free referenced pointer:
00455         void destroy(void) {
00456                 delete storage;
00457                 storage=0;
00458         }
00459         
00460         void pup(PUP::er &p) {   
00461                 PUP_PTR ppr;
00462                 ppr.pup(p,storage);
00463         }
00464         friend void operator|(PUP::er &p,CkZeroPtr<T,PUP_PTR> &v) {v.pup(p);}
00465 };
00466 
00467 
00469 template <class T, class PUP_PTR=CkPupAllocatePtr<T> >
00470 class CkPupPtrVec : public CkVec< CkZeroPtr<T, PUP_PTR> > {
00471   public:
00472   typedef CkPupPtrVec<T,PUP_PTR> this_type;
00473   typedef CkVec< CkZeroPtr<T, PUP_PTR> > super;
00474   CkPupPtrVec() {}
00475   CkPupPtrVec(int size) :super(size) {}
00476   
00477   ~CkPupPtrVec() {
00478     for (int i=0;i<this->length();i++)
00479       this->operator[] (i).destroy();
00480   }
00481   void pup(PUP::er &p) { pupCkVec(p,*this); }
00482   friend void operator|(PUP::er &p,this_type &v) {v.pup(p);}
00483 };
00484 
00486 template <class T>
00487 class CkPupAblePtrVec : public CkVec< CkZeroPtr<T, CkPupAblePtr<T> > > {
00488  public:
00489         typedef CkPupAblePtrVec<T> this_type;
00490         typedef CkVec< CkZeroPtr<T, CkPupAblePtr<T> > > super;
00491         CkPupAblePtrVec() {}
00492         CkPupAblePtrVec(int size) :super(size) {}
00493         CkPupAblePtrVec(const this_type &t) {
00494                 copy_from(t);
00495         }
00496         this_type &operator=(const this_type &t) {
00497                 destroy();
00498                 copy_from(t);
00499                 return *this;
00500         }
00501         void copy_from(const this_type &t) {
00502                 for (int i=0;i<t.length();i++)
00503                         push_back((T *)t[i]->clone());
00504         }
00505         void destroy(void) {
00506                 for (int i=0;i<this->length();i++)
00507                         this->operator[] (i).destroy();
00508                 this->length()=0;
00509         }
00510         ~CkPupAblePtrVec() {
00511                 destroy();
00512         }
00513         void pup(PUP::er &p) { pupCkVec(p,*this); }
00514         friend void operator|(PUP::er &p,this_type &v) {v.pup(p);}
00515 };
00516 
00517 #define MAXMSGS 32
00518 
00519 // thread safe pool, also safe with sig io with immediate messages
00520 template <class T>
00521 class SafePool {
00522   protected:
00523     int num;
00524     T msgs[MAXMSGS];
00525     typedef T (*allocFn)();
00526     typedef void (*freeFn)(T);
00527     allocFn allocfn;
00528     freeFn  freefn;
00529   public:
00530     SafePool(allocFn _afn, freeFn _ffn): allocfn(_afn), freefn(_ffn) {
00531       for(int i=0;i<MAXMSGS;i++)
00532         msgs[i] = allocfn();
00533       num = MAXMSGS;
00534     }
00535     T get(void) {
00536       /* CkAllocSysMsg() called in .def.h is not thread of sigio safe */
00537       if (CmiImmIsRunning()) return allocfn();
00538       return (num ? msgs[--num] : allocfn());
00539     }
00540     void put(T m) {
00541       if (num==MAXMSGS || CmiImmIsRunning())
00542         freefn(m);
00543       else
00544         msgs[num++] = m;
00545     }
00546 };
00547 
00562 template <class T>
00563 class CkPagedVector : private CkNoncopyable {
00568         enum {pageSize=256u};
00569         T **pages;
00570         int nPages;
00571         void allocatePages(int nEntries) {
00572                 nPages=(nEntries+pageSize-1)/pageSize; // round up
00573                 pages=new T*[nPages];
00574                 for (int pg=0;pg<nPages;pg++) pages[pg]=0;
00575         }
00576         void allocatePage(int pg) {
00577                 T *np=new T[pageSize];
00578                 // Initialize the new elements of the page to 0:
00579                 for (int of=0;of<pageSize;of++) np[of]=T();
00580                 pages[pg]=np;
00581         }
00582 public:
00583         CkPagedVector() :pages(0), nPages(0) {}
00584         CkPagedVector(int nEntries) {init(nEntries);}
00585         ~CkPagedVector() {
00586                 for (int pg=0;pg<nPages;pg++) 
00587                         if (pages[pg]) 
00588                                 delete[] pages[pg];
00589                 delete[] pages;
00590         }
00591         void init(int nEntries) {
00592                 allocatePages(nEntries);
00593         }
00594         
00595         inline T &operator[] (unsigned int i) {
00596                 // This divide and mod should be fast, 
00597                 //  as long as pageSize is a power of 2:
00598                 int pg=i/pageSize; 
00599                 int of=i%pageSize;
00600                 if (pages[pg]==NULL) allocatePage(pg);
00601                 return pages[pg][of];
00602         }
00603         
00604         inline T get (unsigned int i) {
00605                 int pg=i/pageSize; 
00606                 int of=i%pageSize;
00607                 return pages[pg]==NULL? T():pages[pg][of];
00608         }
00609 
00610         void pupPage(PUP::er &p,int pg) {
00611                 if (p.isUnpacking()) allocatePage(pg);
00612                 for (int of=0;of<pageSize;of++) 
00613                         p|pages[pg][of];
00614         }
00615         void pup(PUP::er &p) {
00616                 int pg, o;
00617                 unsigned int i;
00618                 p|nPages;
00619                 if (!p.isUnpacking()) 
00620                 { // Packing phase: save each used page
00621                         for (pg=0;pg<nPages;pg++) 
00622                         if (pages[pg]) {
00623                                 p|pg;
00624                                 pupPage(p,pg);
00625                         }
00626                         pg=-1;
00627                         p|pg;
00628                 } else 
00629                 { // Unpacking phase: allocate and restore
00630                         allocatePages(nPages*pageSize);
00631                         p|pg;
00632                         while (pg!=-1) {
00633                                 pupPage(p,pg);
00634                                 p|pg;
00635                         }
00636                 }
00637         }
00638 };
00639 
00640 
00641 #endif

Generated on Sun Jun 29 13:29:27 2008 for Charm++ by  doxygen 1.5.1