poolallocator.hh

Go to the documentation of this file.
00001 // $Id: poolallocator.hh 4566 2006-05-19 12:33:19Z mblatt $
00002 #ifndef DUNE_COMMON_POOLALLOCATOR_HH
00003 #define DUNE_COMMON_POOLALLOCATOR_HH
00004 
00005 #include"alignment.hh"
00006 #include"helpertemplates.hh"
00007 #include"lcm.hh"
00008 #include<typeinfo>
00009 #include<iostream>
00010 #include<cassert>
00011 
00012 template<std::size_t size, typename T>
00013 int testPool();
00014 
00015 //forward declarations.
00016 
00017 namespace Dune
00018 {
00019   
00020 template<typename T, std::size_t size>
00021 class Pool;
00022 
00023 template<typename T, std::size_t s>
00024 class PoolAllocator;
00025 
00026 }
00027 
00028 namespace std
00029 {
00030   template<class T, std::size_t S>
00031   inline ostream& operator<<(ostream& os, Dune::Pool<T,S>& pool)
00032   {
00033     os<<"pool="<<&pool<<" allocated_="<<pool.allocated_;
00034     return os;
00035   }
00036   
00037   template<class T, std::size_t S>
00038   inline ostream& operator<<(ostream& os, Dune::PoolAllocator<T,S>& pool)
00039   {
00040     os<<pool.memoryPool_<<std::endl;
00041     return os;
00042   }
00043 }
00044 
00045 
00046 namespace Dune
00047 {  
00077   template<class T, std::size_t s>
00078   class Pool
00079   {
00080     friend int ::testPool<s,T>();
00081     
00082     friend std::ostream& std::operator<<<>(std::ostream&,Pool<T,s>&);
00083 
00084   private:
00085     
00087     struct Reference
00088     {
00089       Reference *next_;
00090     };
00091 
00092     public:
00093 
00095     typedef T MemberType;
00096     enum 
00097       {
00098         
00102         unionSize = ((sizeof(MemberType) < sizeof(Reference)) ? 
00103                      sizeof(Reference) : sizeof(MemberType)),
00104                      
00109         size = ((sizeof(MemberType) <= s && sizeof(Reference) <= s)? 
00110                 s : unionSize),
00111         
00116         alignment = Lcm<AlignmentOf<MemberType>::value,AlignmentOf<Reference>::value>::value,
00117 
00124         alignedSize = ((unionSize % alignment == 0) ?
00125                        unionSize : 
00126                        ((unionSize / alignment + 1) * alignment)),
00127 
00135         chunkSize = ((size % alignment == 0)? 
00136                      size : ((size / alignment + 1)* alignment)) 
00137         + alignment - 1,
00138 
00142         elements = ((chunkSize - alignment + 1)/ alignedSize)
00143       };
00144 
00145   private:
00147     struct Chunk
00148     {
00149 
00150       //friend int testPool<s,T>();
00151 
00153       char chunk_[chunkSize];
00154 
00159       char* memory_;
00160       
00162       Chunk *next_;
00163       
00167       Chunk()
00168       { 
00169         unsigned long lmemory = reinterpret_cast<unsigned long>(chunk_);
00170         if(lmemory % alignment != 0)
00171           lmemory = (lmemory / alignment + 1)
00172             * alignment;
00173         
00174         memory_ = reinterpret_cast<char *>(lmemory);
00175       }
00176     };
00177   
00178   public:
00180     inline Pool();
00182     inline ~Pool();
00187     inline T *allocate();
00192     inline void free(void* o);
00193 
00197     inline void print(std::ostream& os);
00198 
00199   private:
00200   
00201     // Prevent Copying!
00202     Pool(const Pool<MemberType,s>&);
00203 
00204     void operator=(const Pool<MemberType,s>& pool) const;
00206     inline void grow();
00208     Reference *head_;
00210     Chunk *chunks_;
00211     /* @brief The number of currently allocated elements. */
00212     size_t allocated_;
00213 
00214   };
00215 
00226   template<class T, std::size_t s>
00227   class PoolAllocator
00228   {
00229     friend std::ostream& std::operator<<<>(std::ostream&,PoolAllocator<T,s>&);
00230     
00231   public:
00235     typedef T value_type;
00236 
00237     enum
00238       {
00243         size=s
00244       };
00245 
00249     typedef T* pointer;
00250 
00254     typedef const T* const_pointer;
00255 
00259     typedef T& reference;
00260 
00264     typedef const T& const_reference;
00265 
00269     typedef std::size_t size_type;
00270     
00274     typedef std::ptrdiff_t difference_type;
00275     
00279     inline PoolAllocator();
00280 
00284     template<typename U, std::size_t u>
00285     inline PoolAllocator(const PoolAllocator<U,u>&)
00286     {}
00287     
00295     inline pointer allocate(size_t n, const_pointer hint=0);
00296     
00304     inline void deallocate(pointer p, std::size_t n);
00305 
00311     inline void construct(pointer p, const_reference value);
00312 
00317     inline void destroy(pointer p);
00318 
00322     inline pointer  address(reference x) const { return &x; }
00323 
00324     
00328     inline const_pointer address(const_reference x) const { return &x; }
00329 
00333     inline int max_size() const throw(){ return 1;}
00334     
00338     template<class U>
00339     struct rebind
00340     {
00341       typedef PoolAllocator<U,s> other;
00342     };
00343 
00344   private:
00348     static Pool<T,s> memoryPool_;
00349   };
00350 
00351   // specialization for void
00352   template <std::size_t s> 
00353   class PoolAllocator<void,s> 
00354   {
00355   public:
00356     typedef void*       pointer;
00357     typedef const void* const_pointer;
00358     // reference to void members are impossible.
00359     typedef void value_type;
00360     template <class U> struct rebind 
00361     { 
00362       typedef PoolAllocator<U,s> other; 
00363     };
00364 
00365     template<typename T, std::size_t t>
00366     PoolAllocator(const PoolAllocator<T,t>&)
00367     {}
00368     
00369   };
00370 
00371 
00372   template<typename T1, std::size_t t1, typename T2, std::size_t t2>
00373   bool operator==(const PoolAllocator<T1,t1>&, const PoolAllocator<T2,t2>&)
00374   {
00375     return false;
00376   }
00377   
00378 
00379   template<typename T1, std::size_t t1, typename T2, std::size_t t2>
00380   bool operator!=(const PoolAllocator<T1,t1>&, const PoolAllocator<T2,t2>&)
00381   {
00382     return true;
00383   }
00384 
00385   template<typename T, std::size_t t1, std::size_t t2>
00386   bool operator==(const PoolAllocator<T,t1>&, const PoolAllocator<T,t2>&)
00387   {
00388     return Pool<T,t1>::chunkSize == Pool<T,t2>::chunkSize;
00389   }
00390   
00391 
00392   template<typename T, std::size_t t1, std::size_t t2>
00393   bool operator!=(const PoolAllocator<T,t1>&, const PoolAllocator<T,t2>&)
00394   {
00395     return Pool<T,t1>::chunkSize != Pool<T,t2>::chunkSize;
00396   }
00397 
00398 
00399   template<typename T, std::size_t t1, std::size_t t2>
00400   bool operator==(const PoolAllocator<T,t1>&, const PoolAllocator<void,t2>&)
00401   {
00402     return false;
00403   }
00404   
00405 
00406   template<typename T, std::size_t t1, std::size_t t2>
00407   bool operator!=(const PoolAllocator<T,t1>&, const PoolAllocator<void,t2>&)
00408   {
00409     return true;
00410   }
00411 
00412   template<typename T, std::size_t t1, std::size_t t2>
00413   bool operator==(const PoolAllocator<void,t1>&, const PoolAllocator<T,t2>&)
00414   {
00415     return false;
00416   }
00417   
00418 
00419   template<typename T, std::size_t t1, std::size_t t2>
00420   bool operator!=(const PoolAllocator<void,t1>&, const PoolAllocator<T,t2>&)
00421   {
00422     return true;
00423   }
00424   template<std::size_t t1, std::size_t t2>
00425   bool operator==(const PoolAllocator<void,t1>&, const PoolAllocator<void,t2>&)
00426   {
00427     return true;
00428   }
00429 
00430   template<std::size_t t1, std::size_t t2>
00431   bool operator!=(const PoolAllocator<void,t1>&, const PoolAllocator<void,t2>&)
00432   {
00433     return false;
00434   }
00435 
00436   template<class T, std::size_t S>
00437   inline Pool<T,S>::Pool()
00438     :head_(0), chunks_(0), allocated_(0)
00439   {
00440     IsTrue<sizeof(T)<=unionSize>::yes();
00441     IsTrue<sizeof(Reference)<=unionSize>::yes();
00442     IsTrue<unionSize<=alignedSize>::yes();
00443     IsTrue<sizeof(T)<=chunkSize>::yes();
00444     IsTrue<sizeof(Reference)<=chunkSize>::yes();
00445     IsTrue<(chunkSize - (alignment - 1)) % alignment == 0>::yes();
00446     IsTrue<elements>=1>::yes();
00447     IsTrue<elements*alignedSize<=chunkSize>::yes();
00448   }
00449   
00450   template<class T, std::size_t S>
00451   inline Pool<T,S>::~Pool()
00452   {
00453 
00454     if(allocated_!=0)
00455       std::cerr<<"There are still "<<allocated_<<" allocated elements by the Pool<"<<typeid(T).name()<<","<<S<<"> "
00456                <<static_cast<void*>(this)<<"! This is a memory leak and might result in segfaults"
00457                <<std::endl;
00458 
00459     // delete the allocated chunks.
00460     Chunk *current=chunks_;
00461     
00462     while(current!=0)
00463       {
00464         Chunk *tmp = current;
00465         current = current->next_;
00466         delete tmp;
00467       }
00468   }
00469 
00470   template<class T, std::size_t S>
00471   inline void Pool<T,S>::print(std::ostream& os)
00472   {
00473     Chunk* current=chunks_;
00474     while(current){
00475       os<<current<<" ";
00476       current=current->next_;
00477     }
00478     os<<current<<" ";
00479   }
00480   
00481   template<class T, std::size_t S>
00482   inline void Pool<T,S>::grow()
00483   {
00484     Chunk *newChunk = new Chunk;
00485     newChunk->next_ = chunks_;
00486     chunks_ = newChunk;
00487     
00488     char* start = reinterpret_cast<char *>(chunks_->memory_);
00489     char* last  = &start[(elements-1)*alignedSize];
00490 
00491     for(char* element=start; element<last; element=element+alignedSize){
00492       reinterpret_cast<Reference*>(element)->next_
00493         = reinterpret_cast<Reference*>(element+alignedSize);
00494     }
00495     
00496     reinterpret_cast<Reference*>(last)->next_=0;
00497     head_ = reinterpret_cast<Reference*>(start);
00498   }
00499 
00500   template<class T, std::size_t S>
00501   inline void Pool<T,S>::free(void* b)
00502   {
00503     if(b){
00504     Reference* freed = reinterpret_cast<Reference*>(b);
00505     freed->next_ = head_;
00506     head_ = freed;
00507     --allocated_;
00508     }else
00509       std::cerr<< "Tried to free null pointer! "<<b<<std::endl;
00510   }
00511 
00512   template<class T, std::size_t S>
00513   inline T* Pool<T,S>::allocate()
00514   {
00515     if(!head_)
00516       grow();
00517 
00518     Reference* p = head_;
00519     head_ = p->next_;
00520     ++allocated_;
00521     return reinterpret_cast<T*>(p);
00522   }
00523 
00524   template<class T, std::size_t s> 
00525   Pool<T,s> PoolAllocator<T,s>::memoryPool_;
00526 
00527   template<class T, std::size_t s> 
00528   inline PoolAllocator<T,s>::PoolAllocator()
00529   { }
00530 
00531   template<class T, std::size_t s>
00532   inline T* PoolAllocator<T,s>::allocate(std::size_t n, const T* hint)
00533   {
00534     assert(n==1);//<=(Pool<T,s>::elements));
00535     return memoryPool_.allocate();
00536   }
00537 
00538   template<class T, std::size_t s>
00539   inline void PoolAllocator<T,s>::deallocate(T* p, std::size_t n)
00540   {
00541     for(size_t i=0; i<n; i++)
00542       memoryPool_.free(p++);
00543   }
00544   
00545   template<class T, std::size_t s>
00546   inline void PoolAllocator<T,s>::construct(T* p, const T& value)
00547   {
00548     ::new (static_cast<void*>(p)) T(value);
00549   }
00550 
00551   template<class T, std::size_t s>
00552   inline void PoolAllocator<T,s>::destroy(T* p)
00553   {
00554     p->~T();
00555   }
00556 
00558 }
00559 #endif

Generated on 12 Dec 2007 with Doxygen (ver 1.5.1)