00001
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
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
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
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
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
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
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
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);
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