poolallocator.hh

Go to the documentation of this file.
00001 // $Id: poolallocator.hh 5387 2008-12-03 06:45:39Z sander $
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 size>
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 
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         unsigned long lmemory = reinterpret_cast<unsigned long>(chunk_);
00175         if(lmemory % alignment != 0)
00176           lmemory = (lmemory / alignment + 1)
00177             * alignment;
00178         
00179         memory_ = reinterpret_cast<char *>(lmemory);
00180       }
00181     };
00182   
00183   public:
00185     inline Pool();
00187     inline ~Pool();
00192     inline T *allocate();
00197     inline void free(void* o);
00198 
00202     inline void print(std::ostream& os);
00203 
00204   private:
00205   
00206     // Prevent Copying!
00207     Pool(const Pool<MemberType,s>&);
00208 
00209     void operator=(const Pool<MemberType,s>& pool) const;
00211     inline void grow();
00213     Reference *head_;
00215     Chunk *chunks_;
00216     /* @brief The number of currently allocated elements. */
00217     //size_t allocated_;
00218 
00219   };
00220 
00238   template<class T, std::size_t s>
00239   class PoolAllocator
00240   {
00241     //friend std::ostream& std::operator<<<>(std::ostream&,PoolAllocator<T,s>&);
00242     
00243   public:
00247     typedef T value_type;
00248 
00249     enum
00250       {
00255         size=s*sizeof(value_type)
00256       };
00257 
00261     typedef T* pointer;
00262 
00266     typedef const T* const_pointer;
00267 
00271     typedef T& reference;
00272 
00276     typedef const T& const_reference;
00277 
00281     typedef std::size_t size_type;
00282     
00286     typedef std::ptrdiff_t difference_type;
00287     
00291     inline PoolAllocator();
00292 
00296     template<typename U, std::size_t u>
00297     inline PoolAllocator(const PoolAllocator<U,u>&)
00298     {}
00299     
00307     inline pointer allocate(size_t n, const_pointer hint=0);
00308     
00316     inline void deallocate(pointer p, std::size_t n);
00317 
00323     inline void construct(pointer p, const_reference value);
00324 
00329     inline void destroy(pointer p);
00330 
00334     inline pointer  address(reference x) const { return &x; }
00335 
00336     
00340     inline const_pointer address(const_reference x) const { return &x; }
00341 
00345     inline int max_size() const throw(){ return 1;}
00346     
00350     template<class U>
00351     struct rebind
00352     {
00353       typedef PoolAllocator<U,s> other;
00354     };
00355 
00356   private:
00360     static Pool<T,PoolAllocator::size> memoryPool_;
00361   };
00362 
00363   // specialization for void
00364   template <std::size_t s> 
00365   class PoolAllocator<void,s> 
00366   {
00367   public:
00368     typedef void*       pointer;
00369     typedef const void* const_pointer;
00370     // reference to void members are impossible.
00371     typedef void value_type;
00372     template <class U> struct rebind 
00373     { 
00374       typedef PoolAllocator<U,s> other; 
00375     };
00376 
00377     template<typename T, std::size_t t>
00378     PoolAllocator(const PoolAllocator<T,t>&)
00379     {}
00380     
00381   };
00382 
00383 
00384   template<typename T1, std::size_t t1, typename T2, std::size_t t2>
00385   bool operator==(const PoolAllocator<T1,t1>&, const PoolAllocator<T2,t2>&)
00386   {
00387     return false;
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 true;
00395   }
00396 
00397   template<typename T, std::size_t t1, std::size_t t2>
00398   bool operator==(const PoolAllocator<T,t1>&, const PoolAllocator<T,t2>&)
00399   {
00400     return Pool<T,t1>::chunkSize == Pool<T,t2>::chunkSize;
00401   }
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<void,t2>&)
00413   {
00414     return false;
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 true;
00422   }
00423 
00424   template<typename T, std::size_t t1, std::size_t t2>
00425   bool operator==(const PoolAllocator<void,t1>&, const PoolAllocator<T,t2>&)
00426   {
00427     return false;
00428   }
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 true;
00435   }
00436   template<std::size_t t1, std::size_t t2>
00437   bool operator==(const PoolAllocator<void,t1>&, const PoolAllocator<void,t2>&)
00438   {
00439     return true;
00440   }
00441 
00442   template<std::size_t t1, std::size_t t2>
00443   bool operator!=(const PoolAllocator<void,t1>&, const PoolAllocator<void,t2>&)
00444   {
00445     return false;
00446   }
00447 
00448   template<class T, std::size_t S>
00449   inline Pool<T,S>::Pool()
00450     :head_(0), chunks_(0)//, allocated_(0)
00451   {
00452     dune_static_assert(sizeof(T)<=unionSize, "Library Error: type T is too big");
00453     dune_static_assert(sizeof(Reference)<=unionSize, "Library Error: type of referene is too big");
00454     dune_static_assert(unionSize<=alignedSize, "Library Error: alignedSize too small");
00455     dune_static_assert(sizeof(T)<=chunkSize, "Library Error: chunkSize must be able to hold at least one value");
00456     dune_static_assert(sizeof(Reference)<=chunkSize, "Library Error: chunkSize must be able to hold at least one reference");
00457     dune_static_assert((chunkSize - (alignment - 1)) % alignment == 0, "Library Error: compiler cannot calculate!");
00458     dune_static_assert(elements>=1, "Library Error: we need to hold at least one element!");
00459     dune_static_assert(elements*alignedSize<=chunkSize, "Library Error: aligned elements must fit into chuck!");
00460   }
00461   
00462   template<class T, std::size_t S>
00463   inline Pool<T,S>::~Pool()
00464   {
00465     /*
00466     if(allocated_!=0)
00467       std::cerr<<"There are still "<<allocated_<<" allocated elements by the Pool<"<<typeid(T).name()<<","<<S<<"> "
00468                <<static_cast<void*>(this)<<"! This is a memory leak and might result in segfaults"
00469                <<std::endl;
00470     */
00471     // delete the allocated chunks.
00472     Chunk *current=chunks_;
00473     
00474     while(current!=0)
00475       {
00476         Chunk *tmp = current;
00477         current = current->next_;
00478         delete tmp;
00479       }
00480   }
00481 
00482   template<class T, std::size_t S>
00483   inline void Pool<T,S>::print(std::ostream& os)
00484   {
00485     Chunk* current=chunks_;
00486     while(current){
00487       os<<current<<" ";
00488       current=current->next_;
00489     }
00490     os<<current<<" ";
00491   }
00492   
00493   template<class T, std::size_t S>
00494   inline void Pool<T,S>::grow()
00495   {
00496     Chunk *newChunk = new Chunk;
00497     newChunk->next_ = chunks_;
00498     chunks_ = newChunk;
00499     
00500     char* start = reinterpret_cast<char *>(chunks_->memory_);
00501     char* last  = &start[(elements-1)*alignedSize];
00502 
00503     for(char* element=start; element<last; element=element+alignedSize){
00504       reinterpret_cast<Reference*>(element)->next_
00505         = reinterpret_cast<Reference*>(element+alignedSize);
00506     }
00507     
00508     reinterpret_cast<Reference*>(last)->next_=0;
00509     head_ = reinterpret_cast<Reference*>(start);
00510   }
00511 
00512   template<class T, std::size_t S>
00513   inline void Pool<T,S>::free(void* b)
00514   {
00515     if(b){
00516     Reference* freed = reinterpret_cast<Reference*>(b);
00517     freed->next_ = head_;
00518     head_ = freed;
00519     //--allocated_;
00520     }else
00521       std::cerr<< "Tried to free null pointer! "<<b<<std::endl;
00522   }
00523 
00524   template<class T, std::size_t S>
00525   inline T* Pool<T,S>::allocate()
00526   {
00527     if(!head_)
00528       grow();
00529 
00530     Reference* p = head_;
00531     head_ = p->next_;
00532     //++allocated_;
00533     return reinterpret_cast<T*>(p);
00534   }
00535 
00536   template<class T, std::size_t s> 
00537   Pool<T,PoolAllocator<T,s>::size> PoolAllocator<T,s>::memoryPool_;
00538 
00539   template<class T, std::size_t s> 
00540   inline PoolAllocator<T,s>::PoolAllocator()
00541   { }
00542 
00543   template<class T, std::size_t s>
00544   inline T* PoolAllocator<T,s>::allocate(std::size_t n, const T* hint)
00545   {
00546     assert(n==1);//<=(Pool<T,s>::elements));
00547     return memoryPool_.allocate();
00548   }
00549 
00550   template<class T, std::size_t s>
00551   inline void PoolAllocator<T,s>::deallocate(T* p, std::size_t n)
00552   {
00553     for(size_t i=0; i<n; i++)
00554       memoryPool_.free(p++);
00555   }
00556   
00557   template<class T, std::size_t s>
00558   inline void PoolAllocator<T,s>::construct(T* p, const T& value)
00559   {
00560     ::new (static_cast<void*>(p)) T(value);
00561   }
00562 
00563   template<class T, std::size_t s>
00564   inline void PoolAllocator<T,s>::destroy(T* p)
00565   {
00566     p->~T();
00567   }
00568 
00570 }
00571 #endif

Generated on Thu Apr 2 10:39:54 2009 for dune-common by  doxygen 1.5.6