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
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
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
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
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 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
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
00217
00218
00219 };
00220
00238 template<class T, std::size_t s>
00239 class PoolAllocator
00240 {
00241
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
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
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)
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
00467
00468
00469
00470
00471
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
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
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);
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