poolallocator.hh

Go to the documentation of this file.
00001 // $Id: poolallocator.hh 5984 2010-04-23 09:13:12Z christi $
00002 #ifndef DUNE_COMMON_POOLALLOCATOR_HH
00003 #define DUNE_COMMON_POOLALLOCATOR_HH
00004 
00005 #include"alignment.hh"
00006 #include"static_assert.hh"
00007 #include"lcm.hh"
00008 #include<typeinfo>
00009 #include<iostream>
00010 #include<cassert>
00011 #include<new>
00012 
00013 template<std::size_t size, typename T>
00014 int testPool();
00015 
00016 //forward declarations.
00017 
00018 namespace Dune
00019 {
00020   
00021 template<typename T, std::size_t s>
00022 class Pool;
00023 
00024 template<typename T, std::size_t s>
00025 class PoolAllocator;
00026 
00027 }
00028 
00029 namespace std
00030 {
00031   /*
00032   template<class T, std::size_t S>
00033   inline ostream& operator<<(ostream& os, Dune::Pool<T,S>& pool)
00034   {
00035     os<<"pool="<<&pool<<" allocated_="<<pool.allocated_;
00036     return os;
00037   }
00038   
00039   template<class T, std::size_t S>
00040   inline ostream& operator<<(ostream& os, Dune::PoolAllocator<T,S>& pool)
00041   {
00042     os<<pool.memoryPool_<<std::endl;
00043     return os;
00044   }
00045   */
00046 }
00047 
00048 
00049 namespace Dune
00050 {  
00081   template<class T, std::size_t s>
00082   class Pool
00083   {
00084     friend int ::testPool<s,T>();
00085     
00086     //friend std::ostream& std::operator<<<>(std::ostream&,Pool<T,s>&);
00087     template< class, std::size_t > friend class PoolAllocator;
00088 
00089   private:
00090     
00092     struct Reference
00093     {
00094       Reference *next_;
00095     };
00096 
00097     public:
00098 
00100     typedef T MemberType;
00101     enum 
00102       {
00103         
00107         unionSize = ((sizeof(MemberType) < sizeof(Reference)) ? 
00108                      sizeof(Reference) : sizeof(MemberType)),
00109                      
00114         size = ((sizeof(MemberType) <= s && sizeof(Reference) <= s)? 
00115                 s : unionSize),
00116         
00121         alignment = Lcm<AlignmentOf<MemberType>::value,AlignmentOf<Reference>::value>::value,
00122 
00129         alignedSize = ((unionSize % alignment == 0) ?
00130                        unionSize : 
00131                        ((unionSize / alignment + 1) * alignment)),
00132 
00140         chunkSize = ((size % alignment == 0)? 
00141                      size : ((size / alignment + 1)* alignment)) 
00142         + alignment - 1,
00143 
00147         elements = ((chunkSize - alignment + 1)/ alignedSize)
00148       };
00149 
00150   private:
00152     struct Chunk
00153     {
00154 
00155       //friend int testPool<s,T>();
00156 
00158       char chunk_[chunkSize];
00159 
00164       char* memory_;
00165       
00167       Chunk *next_;
00168       
00172       Chunk()
00173       { 
00174         // Make sure the alignment is correct!
00175         // long long should be 64bit safe!
00176         unsigned long long lmemory = reinterpret_cast<unsigned long long>(chunk_);
00177         if(lmemory % alignment != 0)
00178           lmemory = (lmemory / alignment + 1)
00179             * alignment;
00180         
00181         memory_ = reinterpret_cast<char *>(lmemory);
00182       }
00183     };
00184   
00185   public:
00187     inline Pool();
00189     inline ~Pool();
00194     inline void* allocate();
00199     inline void free(void* o);
00200 
00204     inline void print(std::ostream& os);
00205 
00206   private:
00207   
00208     // Prevent Copying!
00209     Pool(const Pool<MemberType,s>&);
00210 
00211     void operator=(const Pool<MemberType,s>& pool) const;
00213     inline void grow();
00215     Reference *head_;
00217     Chunk *chunks_;
00218     /* @brief The number of currently allocated elements. */
00219     //size_t allocated_;
00220 
00221   };
00222 
00240   template<class T, std::size_t s>
00241   class PoolAllocator
00242   {
00243     //friend std::ostream& std::operator<<<>(std::ostream&,PoolAllocator<T,s>&);
00244     
00245   public:
00249     typedef T value_type;
00250 
00251     enum
00252       {
00257         size=s*sizeof(value_type)
00258       };
00259 
00263     typedef T* pointer;
00264 
00268     typedef const T* const_pointer;
00269 
00273     typedef T& reference;
00274 
00278     typedef const T& const_reference;
00279 
00283     typedef std::size_t size_type;
00284     
00288     typedef std::ptrdiff_t difference_type;
00289     
00293     inline PoolAllocator();
00294 
00298     template<typename U, std::size_t u>
00299     inline PoolAllocator(const PoolAllocator<U,u>&)
00300     {}
00301     
00308     inline pointer allocate(std::size_t n, const_pointer hint=0);
00309     
00317     inline void deallocate(pointer p, std::size_t n);
00318 
00324     inline void construct(pointer p, const_reference value);
00325 
00330     inline void destroy(pointer p);
00331 
00335     inline pointer  address(reference x) const { return &x; }
00336 
00337     
00341     inline const_pointer address(const_reference x) const { return &x; }
00342 
00346     inline int max_size() const throw(){ return 1;}
00347     
00351     template<class U>
00352     struct rebind
00353     {
00354       typedef PoolAllocator<U,s> other;
00355     };
00356 
00358     typedef Pool<T,size> PoolType;
00359 
00360   private:
00364     static PoolType memoryPool_;
00365   };
00366 
00367   // specialization for void
00368   template <std::size_t s> 
00369   class PoolAllocator<void,s> 
00370   {
00371   public:
00372     typedef void*       pointer;
00373     typedef const void* const_pointer;
00374     // reference to void members are impossible.
00375     typedef void value_type;
00376     template <class U> struct rebind 
00377     { 
00378       typedef PoolAllocator<U,s> other; 
00379     };
00380 
00381     template<typename T, std::size_t t>
00382     PoolAllocator(const PoolAllocator<T,t>&)
00383     {}
00384     
00385   };
00386 
00387 
00388   template<typename T1, std::size_t t1, typename T2, std::size_t t2>
00389   bool operator==(const PoolAllocator<T1,t1>&, const PoolAllocator<T2,t2>&)
00390   {
00391     return false;
00392   }
00393   
00394 
00395   template<typename T1, std::size_t t1, typename T2, std::size_t t2>
00396   bool operator!=(const PoolAllocator<T1,t1>&, const PoolAllocator<T2,t2>&)
00397   {
00398     return true;
00399   }
00400 
00401   template<typename T, std::size_t t1, std::size_t t2>
00402   bool operator==(const PoolAllocator<T,t1>&, const PoolAllocator<T,t2>&)
00403   {
00404     return Pool<T,t1>::chunkSize == Pool<T,t2>::chunkSize;
00405   }
00406   
00407 
00408   template<typename T, std::size_t t1, std::size_t t2>
00409   bool operator!=(const PoolAllocator<T,t1>&, const PoolAllocator<T,t2>&)
00410   {
00411     return Pool<T,t1>::chunkSize != Pool<T,t2>::chunkSize;
00412   }
00413 
00414 
00415   template<typename T, std::size_t t1, std::size_t t2>
00416   bool operator==(const PoolAllocator<T,t1>&, const PoolAllocator<void,t2>&)
00417   {
00418     return false;
00419   }
00420   
00421 
00422   template<typename T, std::size_t t1, std::size_t t2>
00423   bool operator!=(const PoolAllocator<T,t1>&, const PoolAllocator<void,t2>&)
00424   {
00425     return true;
00426   }
00427 
00428   template<typename T, std::size_t t1, std::size_t t2>
00429   bool operator==(const PoolAllocator<void,t1>&, const PoolAllocator<T,t2>&)
00430   {
00431     return false;
00432   }
00433   
00434 
00435   template<typename T, std::size_t t1, std::size_t t2>
00436   bool operator!=(const PoolAllocator<void,t1>&, const PoolAllocator<T,t2>&)
00437   {
00438     return true;
00439   }
00440   template<std::size_t t1, std::size_t t2>
00441   bool operator==(const PoolAllocator<void,t1>&, const PoolAllocator<void,t2>&)
00442   {
00443     return true;
00444   }
00445 
00446   template<std::size_t t1, std::size_t t2>
00447   bool operator!=(const PoolAllocator<void,t1>&, const PoolAllocator<void,t2>&)
00448   {
00449     return false;
00450   }
00451 
00452   template<class T, std::size_t S>
00453   inline Pool<T,S>::Pool()
00454     :head_(0), chunks_(0)//, allocated_(0)
00455   {
00456     dune_static_assert(sizeof(T)<=unionSize, "Library Error: type T is too big");
00457     dune_static_assert(sizeof(Reference)<=unionSize, "Library Error: type of referene is too big");
00458     dune_static_assert(unionSize<=alignedSize, "Library Error: alignedSize too small");
00459     dune_static_assert(sizeof(T)<=chunkSize, "Library Error: chunkSize must be able to hold at least one value");
00460     dune_static_assert(sizeof(Reference)<=chunkSize, "Library Error: chunkSize must be able to hold at least one reference");
00461     dune_static_assert((chunkSize - (alignment - 1)) % alignment == 0, "Library Error: compiler cannot calculate!");
00462     dune_static_assert(elements>=1, "Library Error: we need to hold at least one element!");
00463     dune_static_assert(elements*alignedSize<=chunkSize, "Library Error: aligned elements must fit into chuck!");
00464     /*    std::cout<<"s= "<<S<<" : T: "<<sizeof(T)<<" Reference: "<<sizeof(Reference)<<" union: "<<unionSize<<" alignment: "<<alignment<<
00465           "aligned: "<<alignedSize<<" chunk: "<< chunkSize<<" elements: "<<elements<<std::endl;*/
00466   }
00467   
00468   template<class T, std::size_t S>
00469   inline Pool<T,S>::~Pool()
00470   {
00471     /*
00472     if(allocated_!=0)
00473       std::cerr<<"There are still "<<allocated_<<" allocated elements by the Pool<"<<typeid(T).name()<<","<<S<<"> "
00474                <<static_cast<void*>(this)<<"! This is a memory leak and might result in segfaults"
00475                <<std::endl;
00476     */
00477     // delete the allocated chunks.
00478     Chunk *current=chunks_;
00479     
00480     while(current!=0)
00481       {
00482         Chunk *tmp = current;
00483         current = current->next_;
00484         delete tmp;
00485       }
00486   }
00487 
00488   template<class T, std::size_t S>
00489   inline void Pool<T,S>::print(std::ostream& os)
00490   {
00491     Chunk* current=chunks_;
00492     while(current){
00493       os<<current<<" ";
00494       current=current->next_;
00495     }
00496     os<<current<<" ";
00497   }
00498   
00499   template<class T, std::size_t S>
00500   inline void Pool<T,S>::grow()
00501   {
00502     Chunk *newChunk = new Chunk;
00503     newChunk->next_ = chunks_;
00504     chunks_ = newChunk;
00505     
00506     char* start = chunks_->memory_;
00507     char* last  = &start[elements*alignedSize];
00508     Reference* ref = new (start) (Reference);
00509 
00510     // grow is only called if head==0, 
00511     assert(!head_);
00512 
00513     head_ = ref;
00514       
00515     for(char* element=start+alignedSize; element<last; element=element+alignedSize){
00516       Reference* next = new (element) (Reference);
00517       ref->next_ = next;
00518       ref = next;
00519     }
00520     ref->next_=0;
00521   }
00522 
00523   template<class T, std::size_t S>
00524   inline void Pool<T,S>::free(void* b)
00525   {
00526     if(b){
00527     Reference* freed = static_cast<Reference*>(b);
00528     freed->next_ = head_;
00529     head_ = freed;
00530     //--allocated_;
00531     }else
00532       std::cerr<< "Tried to free null pointer! "<<b<<std::endl;
00533   }
00534 
00535   template<class T, std::size_t S>
00536   inline void* Pool<T,S>::allocate()
00537   {
00538     if(!head_)
00539       grow();
00540       
00541     Reference* p = head_;
00542     head_ = p->next_;
00543     //++allocated_;
00544     return p;
00545   }
00546 
00547   template<class T, std::size_t s> 
00548   typename PoolAllocator<T,s>::PoolType PoolAllocator<T,s>::memoryPool_;
00549 
00550   template<class T, std::size_t s> 
00551   inline PoolAllocator<T,s>::PoolAllocator()
00552   { }
00553 
00554   template<class T, std::size_t s>
00555   inline typename PoolAllocator<T,s>::pointer
00556   PoolAllocator<T,s>::allocate(std::size_t n, const_pointer hint)
00557   {
00558     if(n==1)
00559       return static_cast<T*>(memoryPool_.allocate());
00560     else
00561       throw std::bad_alloc();
00562   }
00563 
00564   template<class T, std::size_t s>
00565   inline void PoolAllocator<T,s>::deallocate(T* p, std::size_t n)
00566   {
00567     for(size_t i=0; i<n; i++)
00568       memoryPool_.free(p++);
00569   }
00570   
00571   template<class T, std::size_t s>
00572   inline void PoolAllocator<T,s>::construct(pointer p, const_reference value)
00573   {
00574     ::new (static_cast<void*>(p)) T(value);
00575   }
00576 
00577   template<class T, std::size_t s>
00578   inline void PoolAllocator<T,s>::destroy(T* p)
00579   {
00580     p->~T();
00581   }
00582 
00584 }
00585 #endif
Generated on Mon Apr 26 10:45:21 2010 for dune-common by  doxygen 1.6.3