00001
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 #include<new>
00012
00013 template<std::size_t size, typename T>
00014 int testPool();
00015
00016
00017
00018 namespace Dune
00019 {
00020
00021 template<typename T, std::size_t s>
00022 class Pool;
00023
00024 template<typename T, std::size_t s>
00025 class PoolAllocator;
00026
00027 }
00028
00029 namespace std
00030 {
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 }
00047
00048
00049 namespace Dune
00050 {
00081 template<class T, std::size_t s>
00082 class Pool
00083 {
00084 friend int ::testPool<s,T>();
00085
00086
00087 template< class, std::size_t > friend class PoolAllocator;
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
00156
00158 char chunk_[chunkSize];
00159
00164 char* memory_;
00165
00167 Chunk *next_;
00168
00172 Chunk()
00173 {
00174
00175
00176 unsigned long long lmemory = reinterpret_cast<unsigned long long>(chunk_);
00177 if(lmemory % alignment != 0)
00178 lmemory = (lmemory / alignment + 1)
00179 * alignment;
00180
00181 memory_ = reinterpret_cast<char *>(lmemory);
00182 }
00183 };
00184
00185 public:
00187 inline Pool();
00189 inline ~Pool();
00194 inline void* allocate();
00199 inline void free(void* o);
00200
00204 inline void print(std::ostream& os);
00205
00206 private:
00207
00208
00209 Pool(const Pool<MemberType,s>&);
00210
00211 void operator=(const Pool<MemberType,s>& pool) const;
00213 inline void grow();
00215 Reference *head_;
00217 Chunk *chunks_;
00218
00219
00220
00221 };
00222
00240 template<class T, std::size_t s>
00241 class PoolAllocator
00242 {
00243
00244
00245 public:
00249 typedef T value_type;
00250
00251 enum
00252 {
00257 size=s*sizeof(value_type)
00258 };
00259
00263 typedef T* pointer;
00264
00268 typedef const T* const_pointer;
00269
00273 typedef T& reference;
00274
00278 typedef const T& const_reference;
00279
00283 typedef std::size_t size_type;
00284
00288 typedef std::ptrdiff_t difference_type;
00289
00293 inline PoolAllocator();
00294
00298 template<typename U, std::size_t u>
00299 inline PoolAllocator(const PoolAllocator<U,u>&)
00300 {}
00301
00308 inline pointer allocate(std::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
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
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)
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 }
00467
00468 template<class T, std::size_t S>
00469 inline Pool<T,S>::~Pool()
00470 {
00471
00472
00473
00474
00475
00476
00477
00478 Chunk *current=chunks_;
00479
00480 while(current!=0)
00481 {
00482 Chunk *tmp = current;
00483 current = current->next_;
00484 delete tmp;
00485 }
00486 }
00487
00488 template<class T, std::size_t S>
00489 inline void Pool<T,S>::print(std::ostream& os)
00490 {
00491 Chunk* current=chunks_;
00492 while(current){
00493 os<<current<<" ";
00494 current=current->next_;
00495 }
00496 os<<current<<" ";
00497 }
00498
00499 template<class T, std::size_t S>
00500 inline void Pool<T,S>::grow()
00501 {
00502 Chunk *newChunk = new Chunk;
00503 newChunk->next_ = chunks_;
00504 chunks_ = newChunk;
00505
00506 char* start = chunks_->memory_;
00507 char* last = &start[elements*alignedSize];
00508 Reference* ref = new (start) (Reference);
00509
00510
00511 assert(!head_);
00512
00513 head_ = ref;
00514
00515 for(char* element=start+alignedSize; element<last; element=element+alignedSize){
00516 Reference* next = new (element) (Reference);
00517 ref->next_ = next;
00518 ref = next;
00519 }
00520 ref->next_=0;
00521 }
00522
00523 template<class T, std::size_t S>
00524 inline void Pool<T,S>::free(void* b)
00525 {
00526 if(b){
00527 Reference* freed = static_cast<Reference*>(b);
00528 freed->next_ = head_;
00529 head_ = freed;
00530
00531 }else
00532 std::cerr<< "Tried to free null pointer! "<<b<<std::endl;
00533 }
00534
00535 template<class T, std::size_t S>
00536 inline void* Pool<T,S>::allocate()
00537 {
00538 if(!head_)
00539 grow();
00540
00541 Reference* p = head_;
00542 head_ = p->next_;
00543
00544 return p;
00545 }
00546
00547 template<class T, std::size_t s>
00548 typename PoolAllocator<T,s>::PoolType PoolAllocator<T,s>::memoryPool_;
00549
00550 template<class T, std::size_t s>
00551 inline PoolAllocator<T,s>::PoolAllocator()
00552 { }
00553
00554 template<class T, std::size_t s>
00555 inline typename PoolAllocator<T,s>::pointer
00556 PoolAllocator<T,s>::allocate(std::size_t n, const_pointer hint)
00557 {
00558 if(n==1)
00559 return static_cast<T*>(memoryPool_.allocate());
00560 else
00561 throw std::bad_alloc();
00562 }
00563
00564 template<class T, std::size_t s>
00565 inline void PoolAllocator<T,s>::deallocate(T* p, std::size_t n)
00566 {
00567 for(size_t i=0; i<n; i++)
00568 memoryPool_.free(p++);
00569 }
00570
00571 template<class T, std::size_t s>
00572 inline void PoolAllocator<T,s>::construct(pointer p, const_reference value)
00573 {
00574 ::new (static_cast<void*>(p)) T(value);
00575 }
00576
00577 template<class T, std::size_t s>
00578 inline void PoolAllocator<T,s>::destroy(T* p)
00579 {
00580 p->~T();
00581 }
00582
00584 }
00585 #endif