dune-common 2.1.1
poolallocator.hh
Go to the documentation of this file.
00001 // -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002 // vi: set et ts=8 sw=2 sts=2:
00003 // $Id: poolallocator.hh 6330 2011-02-08 19:42:43Z sander $
00004 #ifndef DUNE_COMMON_POOLALLOCATOR_HH
00005 #define DUNE_COMMON_POOLALLOCATOR_HH
00006 
00007 #include"alignment.hh"
00008 #include"static_assert.hh"
00009 #include"lcm.hh"
00010 #include<typeinfo>
00011 #include<iostream>
00012 #include<cassert>
00013 #include<new>
00014 
00015 //forward declarations.
00016 
00017 // we need to know the test function to declare it friend
00018 template<std::size_t size, typename T>
00019 struct testPoolMain;
00020 
00021 namespace Dune
00022 {
00023   
00024 template<typename T, std::size_t s>
00025 class Pool;
00026 
00027 template<typename T, std::size_t s>
00028 class PoolAllocator;
00029 
00030 }
00031 
00032 namespace std
00033 {
00034   /*
00035   template<class T, std::size_t S>
00036   inline ostream& operator<<(ostream& os, Dune::Pool<T,S>& pool)
00037   {
00038     os<<"pool="<<&pool<<" allocated_="<<pool.allocated_;
00039     return os;
00040   }
00041   
00042   template<class T, std::size_t S>
00043   inline ostream& operator<<(ostream& os, Dune::PoolAllocator<T,S>& pool)
00044   {
00045     os<<pool.memoryPool_<<std::endl;
00046     return os;
00047   }
00048   */
00049 }
00050 
00051 
00052 namespace Dune
00053 {  
00084   template<class T, std::size_t s>
00085   class Pool
00086   {
00087     // make the test function friend
00088     friend struct ::testPoolMain<s,T>;
00089     
00090     //friend std::ostream& std::operator<<<>(std::ostream&,Pool<T,s>&);
00091     template< class, std::size_t > friend class PoolAllocator;
00092 
00093   private:
00094     
00096     struct Reference
00097     {
00098       Reference *next_;
00099     };
00100 
00101   public:
00102 
00104     typedef T MemberType;
00105     enum 
00106     {
00110       unionSize = ((sizeof(MemberType) < sizeof(Reference)) ? 
00111         sizeof(Reference) : sizeof(MemberType)),
00112       
00117       size = ((sizeof(MemberType) <= s && sizeof(Reference) <= s)? 
00118         s : unionSize),
00119       
00124       alignment = Lcm<AlignmentOf<MemberType>::value,AlignmentOf<Reference>::value>::value,
00125       
00132       alignedSize = ((unionSize % alignment == 0) ?
00133         unionSize : 
00134         ((unionSize / alignment + 1) * alignment)),
00135       
00143       chunkSize = ((size % alignment == 0)? 
00144         size : ((size / alignment + 1)* alignment)) 
00145       + alignment - 1,
00146       
00150       elements = ((chunkSize - alignment + 1)/ alignedSize)
00151     };
00152     
00153   private:
00155     struct Chunk
00156     {
00157 
00158       //friend int testPool<s,T>();
00159 
00161       char chunk_[chunkSize];
00162 
00167       char* memory_;
00168       
00170       Chunk *next_;
00171       
00175       Chunk()
00176       {
00177         // Make sure the alignment is correct!
00178         // long long should be 64bit safe!
00179         unsigned long long lmemory = reinterpret_cast<unsigned long long>(chunk_);
00180         if(lmemory % alignment != 0)
00181           lmemory = (lmemory / alignment + 1)
00182             * alignment;
00183         
00184         memory_ = reinterpret_cast<char *>(lmemory);
00185       }
00186     };
00187   
00188   public:
00190     inline Pool();
00192     inline ~Pool();
00197     inline void* allocate();
00202     inline void free(void* o);
00203 
00207     inline void print(std::ostream& os);
00208 
00209   private:
00210   
00211     // Prevent Copying!
00212     Pool(const Pool<MemberType,s>&);
00213 
00214     void operator=(const Pool<MemberType,s>& pool) const;
00216     inline void grow();
00218     Reference *head_;
00220     Chunk *chunks_;
00221     /* @brief The number of currently allocated elements. */
00222     //size_t allocated_;
00223 
00224   };
00225 
00243   template<class T, std::size_t s>
00244   class PoolAllocator
00245   {
00246     //friend std::ostream& std::operator<<<>(std::ostream&,PoolAllocator<T,s>&);
00247     
00248   public:
00252     typedef T value_type;
00253 
00254     enum
00255     {
00260       size=s*sizeof(value_type)
00261     };
00262     
00266     typedef T* pointer;
00267 
00271     typedef const T* const_pointer;
00272 
00276     typedef T& reference;
00277 
00281     typedef const T& const_reference;
00282 
00286     typedef std::size_t size_type;
00287     
00291     typedef std::ptrdiff_t difference_type;
00292     
00296     inline PoolAllocator();
00297 
00301     template<typename U, std::size_t u>
00302     inline PoolAllocator(const PoolAllocator<U,u>&)
00303     {}
00304     
00311     inline pointer allocate(std::size_t n, const_pointer hint=0);
00312     
00320     inline void deallocate(pointer p, std::size_t n);
00321 
00327     inline void construct(pointer p, const_reference value);
00328 
00333     inline void destroy(pointer p);
00334 
00338     inline pointer  address(reference x) const { return &x; }
00339 
00340     
00344     inline const_pointer address(const_reference x) const { return &x; }
00345 
00349     inline int max_size() const throw(){ return 1;}
00350     
00354     template<class U>
00355     struct rebind
00356     {
00357       typedef PoolAllocator<U,s> other;
00358     };
00359 
00361     typedef Pool<T,size> PoolType;
00362 
00363   private:
00367     static PoolType memoryPool_;
00368   };
00369 
00370   // specialization for void
00371   template <std::size_t s> 
00372   class PoolAllocator<void,s> 
00373   {
00374   public:
00375     typedef void*       pointer;
00376     typedef const void* const_pointer;
00377     // reference to void members are impossible.
00378     typedef void value_type;
00379     template <class U> struct rebind 
00380     { 
00381       typedef PoolAllocator<U,s> other; 
00382     };
00383 
00384     template<typename T, std::size_t t>
00385     PoolAllocator(const PoolAllocator<T,t>&)
00386     {}
00387     
00388   };
00389 
00390 
00391   template<typename T1, std::size_t t1, typename T2, std::size_t t2>
00392   bool operator==(const PoolAllocator<T1,t1>&, const PoolAllocator<T2,t2>&)
00393   {
00394     return false;
00395   }
00396   
00397 
00398   template<typename T1, std::size_t t1, typename T2, std::size_t t2>
00399   bool operator!=(const PoolAllocator<T1,t1>&, const PoolAllocator<T2,t2>&)
00400   {
00401     return true;
00402   }
00403 
00404   template<typename T, std::size_t t1, std::size_t t2>
00405   bool operator==(const PoolAllocator<T,t1>&, const PoolAllocator<T,t2>&)
00406   {
00407     return Pool<T,t1>::chunkSize == Pool<T,t2>::chunkSize;
00408   }
00409   
00410 
00411   template<typename T, std::size_t t1, std::size_t t2>
00412   bool operator!=(const PoolAllocator<T,t1>&, const PoolAllocator<T,t2>&)
00413   {
00414     return Pool<T,t1>::chunkSize != Pool<T,t2>::chunkSize;
00415   }
00416 
00417 
00418   template<typename T, std::size_t t1, std::size_t t2>
00419   bool operator==(const PoolAllocator<T,t1>&, const PoolAllocator<void,t2>&)
00420   {
00421     return false;
00422   }
00423   
00424 
00425   template<typename T, std::size_t t1, std::size_t t2>
00426   bool operator!=(const PoolAllocator<T,t1>&, const PoolAllocator<void,t2>&)
00427   {
00428     return true;
00429   }
00430 
00431   template<typename T, std::size_t t1, std::size_t t2>
00432   bool operator==(const PoolAllocator<void,t1>&, const PoolAllocator<T,t2>&)
00433   {
00434     return false;
00435   }
00436   
00437 
00438   template<typename T, std::size_t t1, std::size_t t2>
00439   bool operator!=(const PoolAllocator<void,t1>&, const PoolAllocator<T,t2>&)
00440   {
00441     return true;
00442   }
00443   template<std::size_t t1, std::size_t t2>
00444   bool operator==(const PoolAllocator<void,t1>&, const PoolAllocator<void,t2>&)
00445   {
00446     return true;
00447   }
00448 
00449   template<std::size_t t1, std::size_t t2>
00450   bool operator!=(const PoolAllocator<void,t1>&, const PoolAllocator<void,t2>&)
00451   {
00452     return false;
00453   }
00454 
00455   template<class T, std::size_t S>
00456   inline Pool<T,S>::Pool()
00457     :head_(0), chunks_(0)//, allocated_(0)
00458   {
00459     dune_static_assert(sizeof(T)<=unionSize, "Library Error: type T is too big");
00460     dune_static_assert(sizeof(Reference)<=unionSize, "Library Error: type of referene is too big");
00461     dune_static_assert(unionSize<=alignedSize, "Library Error: alignedSize too small");
00462     dune_static_assert(sizeof(T)<=chunkSize, "Library Error: chunkSize must be able to hold at least one value");
00463     dune_static_assert(sizeof(Reference)<=chunkSize, "Library Error: chunkSize must be able to hold at least one reference");
00464     dune_static_assert((chunkSize - (alignment - 1)) % alignment == 0, "Library Error: compiler cannot calculate!");
00465     dune_static_assert(elements>=1, "Library Error: we need to hold at least one element!");
00466     dune_static_assert(elements*alignedSize<=chunkSize, "Library Error: aligned elements must fit into chuck!");
00467     /*    std::cout<<"s= "<<S<<" : T: "<<sizeof(T)<<" Reference: "<<sizeof(Reference)<<" union: "<<unionSize<<" alignment: "<<alignment<<
00468           "aligned: "<<alignedSize<<" chunk: "<< chunkSize<<" elements: "<<elements<<std::endl;*/
00469   }
00470   
00471   template<class T, std::size_t S>
00472   inline Pool<T,S>::~Pool()
00473   {
00474     /*
00475     if(allocated_!=0)
00476       std::cerr<<"There are still "<<allocated_<<" allocated elements by the Pool<"<<typeid(T).name()<<","<<S<<"> "
00477                <<static_cast<void*>(this)<<"! This is a memory leak and might result in segfaults"
00478                <<std::endl;
00479     */
00480     // delete the allocated chunks.
00481     Chunk *current=chunks_;
00482     
00483     while(current!=0)
00484     {
00485       Chunk *tmp = current;
00486       current = current->next_;
00487       delete tmp;
00488     }
00489   }
00490 
00491   template<class T, std::size_t S>
00492   inline void Pool<T,S>::print(std::ostream& os)
00493   {
00494     Chunk* current=chunks_;
00495     while(current){
00496       os<<current<<" ";
00497       current=current->next_;
00498     }
00499     os<<current<<" ";
00500   }
00501   
00502   template<class T, std::size_t S>
00503   inline void Pool<T,S>::grow()
00504   {
00505     Chunk *newChunk = new Chunk;
00506     newChunk->next_ = chunks_;
00507     chunks_ = newChunk;
00508     
00509     char* start = chunks_->memory_;
00510     char* last  = &start[elements*alignedSize];
00511     Reference* ref = new (start) (Reference);
00512 
00513     // grow is only called if head==0, 
00514     assert(!head_);
00515 
00516     head_ = ref;
00517       
00518     for(char* element=start+alignedSize; element<last; element=element+alignedSize){
00519       Reference* next = new (element) (Reference);
00520       ref->next_ = next;
00521       ref = next;
00522     }
00523     ref->next_=0;
00524   }
00525 
00526   template<class T, std::size_t S>
00527   inline void Pool<T,S>::free(void* b)
00528   {
00529     if(b){
00530     Reference* freed = static_cast<Reference*>(b);
00531     freed->next_ = head_;
00532     head_ = freed;
00533     //--allocated_;
00534     }else
00535       std::cerr<< "Tried to free null pointer! "<<b<<std::endl;
00536   }
00537 
00538   template<class T, std::size_t S>
00539   inline void* Pool<T,S>::allocate()
00540   {
00541     if(!head_)
00542       grow();
00543       
00544     Reference* p = head_;
00545     head_ = p->next_;
00546     //++allocated_;
00547     return p;
00548   }
00549 
00550   template<class T, std::size_t s> 
00551   typename PoolAllocator<T,s>::PoolType PoolAllocator<T,s>::memoryPool_;
00552 
00553   template<class T, std::size_t s> 
00554   inline PoolAllocator<T,s>::PoolAllocator()
00555   { }
00556 
00557   template<class T, std::size_t s>
00558   inline typename PoolAllocator<T,s>::pointer
00559   PoolAllocator<T,s>::allocate(std::size_t n, const_pointer hint)
00560   {
00561     if(n==1)
00562       return static_cast<T*>(memoryPool_.allocate());
00563     else
00564       throw std::bad_alloc();
00565   }
00566 
00567   template<class T, std::size_t s>
00568   inline void PoolAllocator<T,s>::deallocate(pointer p, std::size_t n)
00569   {
00570     for(size_t i=0; i<n; i++)
00571       memoryPool_.free(p++);
00572   }
00573   
00574   template<class T, std::size_t s>
00575   inline void PoolAllocator<T,s>::construct(pointer p, const_reference value)
00576   {
00577     ::new (static_cast<void*>(p)) T(value);
00578   }
00579 
00580   template<class T, std::size_t s>
00581   inline void PoolAllocator<T,s>::destroy(pointer p)
00582   {
00583     p->~T();
00584   }
00585 
00587 }
00588 #endif