dune-common 2.1.1
|
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