poolallocator.hh

Go to the documentation of this file.
00001 // $Id: poolallocator.hh 5521 2009-05-12 16:10:08Z mnolte $
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 
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 s>
00021 class Pool;
00022 
00023 template<typename T, std::size_t s>
00024 class PoolAllocator;
00025 
00026 }
00027 
00028 namespace std
00029 {
00030   /*
00031   template<class T, std::size_t S>
00032   inline ostream& operator<<(ostream& os, Dune::Pool<T,S>& pool)
00033   {
00034     os<<"pool="<<&pool<<" allocated_="<<pool.allocated_;
00035     return os;
00036   }
00037   
00038   template<class T, std::size_t S>
00039   inline ostream& operator<<(ostream& os, Dune::PoolAllocator<T,S>& pool)
00040   {
00041     os<<pool.memoryPool_<<std::endl;
00042     return os;
00043   }
00044   */
00045 }
00046 
00047 
00048 namespace Dune
00049 {  
00082   template<class T, std::size_t s>
00083   class Pool
00084   {
00085     friend int ::testPool<s,T>();
00086     
00087     //friend std::ostream& std::operator<<<>(std::ostream&,Pool<T,s>&);
00088     template< class, std::size_t > friend class PoolAllocator;
00089 
00090   private:
00091     
00093     struct Reference
00094     {
00095       Reference *next_;
00096     };
00097 
00098     public:
00099 
00101     typedef T MemberType;
00102     enum 
00103       {
00104         
00108         unionSize = ((sizeof(MemberType) < sizeof(Reference)) ? 
00109                      sizeof(Reference) : sizeof(MemberType)),
00110                      
00115         size = ((sizeof(MemberType) <= s && sizeof(Reference) <= s)? 
00116                 s : unionSize),
00117         
00122         alignment = Lcm<AlignmentOf<MemberType>::value,AlignmentOf<Reference>::value>::value,
00123 
00130         alignedSize = ((unionSize % alignment == 0) ?
00131                        unionSize : 
00132                        ((unionSize / alignment + 1) * alignment)),
00133 
00141         chunkSize = ((size % alignment == 0)? 
00142                      size : ((size / alignment + 1)* alignment)) 
00143         + alignment - 1,
00144 
00148         elements = ((chunkSize - alignment + 1)/ alignedSize)
00149       };
00150 
00151   private:
00153     struct Chunk
00154     {
00155 
00156       //friend int testPool<s,T>();
00157 
00159       char chunk_[chunkSize];
00160 
00165       char* memory_;
00166       
00168       Chunk *next_;
00169       
00173       Chunk()
00174       { 
00175         unsigned long lmemory = reinterpret_cast<unsigned long>(chunk_);
00176         if(lmemory % alignment != 0)
00177           lmemory = (lmemory / alignment + 1)
00178             * alignment;
00179         
00180         memory_ = reinterpret_cast<char *>(lmemory);
00181       }
00182     };
00183   
00184   public:
00186     inline Pool();
00188     inline ~Pool();
00193     inline T *allocate();
00198     inline void free(void* o);
00199 
00203     inline void print(std::ostream& os);
00204 
00205   private:
00206   
00207     // Prevent Copying!
00208     Pool(const Pool<MemberType,s>&);
00209 
00210     void operator=(const Pool<MemberType,s>& pool) const;
00212     inline void grow();
00214     Reference *head_;
00216     Chunk *chunks_;
00217     /* @brief The number of currently allocated elements. */
00218     //size_t allocated_;
00219 
00220   };
00221 
00239   template<class T, std::size_t s>
00240   class PoolAllocator
00241   {
00242     //friend std::ostream& std::operator<<<>(std::ostream&,PoolAllocator<T,s>&);
00243     
00244   public:
00248     typedef T value_type;
00249 
00250     enum
00251       {
00256         size=s*sizeof(value_type)
00257       };
00258 
00262     typedef T* pointer;
00263 
00267     typedef const T* const_pointer;
00268 
00272     typedef T& reference;
00273 
00277     typedef const T& const_reference;
00278 
00282     typedef std::size_t size_type;
00283     
00287     typedef std::ptrdiff_t difference_type;
00288     
00292     inline PoolAllocator();
00293 
00297     template<typename U, std::size_t u>
00298     inline PoolAllocator(const PoolAllocator<U,u>&)
00299     {}
00300     
00308     inline pointer allocate(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   }
00465   
00466   template<class T, std::size_t S>
00467   inline Pool<T,S>::~Pool()
00468   {
00469     /*
00470     if(allocated_!=0)
00471       std::cerr<<"There are still "<<allocated_<<" allocated elements by the Pool<"<<typeid(T).name()<<","<<S<<"> "
00472                <<static_cast<void*>(this)<<"! This is a memory leak and might result in segfaults"
00473                <<std::endl;
00474     */
00475     // delete the allocated chunks.
00476     Chunk *current=chunks_;
00477     
00478     while(current!=0)
00479       {
00480         Chunk *tmp = current;
00481         current = current->next_;
00482         delete tmp;
00483       }
00484   }
00485 
00486   template<class T, std::size_t S>
00487   inline void Pool<T,S>::print(std::ostream& os)
00488   {
00489     Chunk* current=chunks_;
00490     while(current){
00491       os<<current<<" ";
00492       current=current->next_;
00493     }
00494     os<<current<<" ";
00495   }
00496   
00497   template<class T, std::size_t S>
00498   inline void Pool<T,S>::grow()
00499   {
00500     Chunk *newChunk = new Chunk;
00501     newChunk->next_ = chunks_;
00502     chunks_ = newChunk;
00503     
00504     char* start = reinterpret_cast<char *>(chunks_->memory_);
00505     char* last  = &start[(elements-1)*alignedSize];
00506 
00507     for(char* element=start; element<last; element=element+alignedSize){
00508       reinterpret_cast<Reference*>(element)->next_
00509         = reinterpret_cast<Reference*>(element+alignedSize);
00510     }
00511     
00512     reinterpret_cast<Reference*>(last)->next_=0;
00513     head_ = reinterpret_cast<Reference*>(start);
00514   }
00515 
00516   template<class T, std::size_t S>
00517   inline void Pool<T,S>::free(void* b)
00518   {
00519     if(b){
00520     Reference* freed = reinterpret_cast<Reference*>(b);
00521     freed->next_ = head_;
00522     head_ = freed;
00523     //--allocated_;
00524     }else
00525       std::cerr<< "Tried to free null pointer! "<<b<<std::endl;
00526   }
00527 
00528   template<class T, std::size_t S>
00529   inline T* Pool<T,S>::allocate()
00530   {
00531     if(!head_)
00532       grow();
00533 
00534     Reference* p = head_;
00535     head_ = p->next_;
00536     //++allocated_;
00537     return reinterpret_cast<T*>(p);
00538   }
00539 
00540   template<class T, std::size_t s> 
00541   typename PoolAllocator<T,s>::PoolType PoolAllocator<T,s>::memoryPool_;
00542 
00543   template<class T, std::size_t s> 
00544   inline PoolAllocator<T,s>::PoolAllocator()
00545   { }
00546 
00547   template<class T, std::size_t s>
00548   inline T* PoolAllocator<T,s>::allocate(std::size_t n, const T* hint)
00549   {
00550     assert(n==1);//<=(Pool<T,s>::elements));
00551     return memoryPool_.allocate();
00552   }
00553 
00554   template<class T, std::size_t s>
00555   inline void PoolAllocator<T,s>::deallocate(T* p, std::size_t n)
00556   {
00557     for(size_t i=0; i<n; i++)
00558       memoryPool_.free(p++);
00559   }
00560   
00561   template<class T, std::size_t s>
00562   inline void PoolAllocator<T,s>::construct(T* p, const T& value)
00563   {
00564     ::new (static_cast<void*>(p)) T(value);
00565   }
00566 
00567   template<class T, std::size_t s>
00568   inline void PoolAllocator<T,s>::destroy(T* p)
00569   {
00570     p->~T();
00571   }
00572 
00574 }
00575 #endif

Generated on Tue Jul 28 22:27:50 2009 for dune-common by  doxygen 1.5.6