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 s>
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 template< class, std::size_t > friend class PoolAllocator;
00089
00090 private:
00091
00093 struct Reference
00094 {
00095 Reference *next_;
00096 };
00097
00098 public:
00099
00101 typedef T MemberType;
00102 enum
00103 {
00104
00108 unionSize = ((sizeof(MemberType) < sizeof(Reference)) ?
00109 sizeof(Reference) : sizeof(MemberType)),
00110
00115 size = ((sizeof(MemberType) <= s && sizeof(Reference) <= s)?
00116 s : unionSize),
00117
00122 alignment = Lcm<AlignmentOf<MemberType>::value,AlignmentOf<Reference>::value>::value,
00123
00130 alignedSize = ((unionSize % alignment == 0) ?
00131 unionSize :
00132 ((unionSize / alignment + 1) * alignment)),
00133
00141 chunkSize = ((size % alignment == 0)?
00142 size : ((size / alignment + 1)* alignment))
00143 + alignment - 1,
00144
00148 elements = ((chunkSize - alignment + 1)/ alignedSize)
00149 };
00150
00151 private:
00153 struct Chunk
00154 {
00155
00156
00157
00159 char chunk_[chunkSize];
00160
00165 char* memory_;
00166
00168 Chunk *next_;
00169
00173 Chunk()
00174 {
00175 unsigned long lmemory = reinterpret_cast<unsigned long>(chunk_);
00176 if(lmemory % alignment != 0)
00177 lmemory = (lmemory / alignment + 1)
00178 * alignment;
00179
00180 memory_ = reinterpret_cast<char *>(lmemory);
00181 }
00182 };
00183
00184 public:
00186 inline Pool();
00188 inline ~Pool();
00193 inline T *allocate();
00198 inline void free(void* o);
00199
00203 inline void print(std::ostream& os);
00204
00205 private:
00206
00207
00208 Pool(const Pool<MemberType,s>&);
00209
00210 void operator=(const Pool<MemberType,s>& pool) const;
00212 inline void grow();
00214 Reference *head_;
00216 Chunk *chunks_;
00217
00218
00219
00220 };
00221
00239 template<class T, std::size_t s>
00240 class PoolAllocator
00241 {
00242
00243
00244 public:
00248 typedef T value_type;
00249
00250 enum
00251 {
00256 size=s*sizeof(value_type)
00257 };
00258
00262 typedef T* pointer;
00263
00267 typedef const T* const_pointer;
00268
00272 typedef T& reference;
00273
00277 typedef const T& const_reference;
00278
00282 typedef std::size_t size_type;
00283
00287 typedef std::ptrdiff_t difference_type;
00288
00292 inline PoolAllocator();
00293
00297 template<typename U, std::size_t u>
00298 inline PoolAllocator(const PoolAllocator<U,u>&)
00299 {}
00300
00308 inline pointer allocate(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 template<class T, std::size_t S>
00467 inline Pool<T,S>::~Pool()
00468 {
00469
00470
00471
00472
00473
00474
00475
00476 Chunk *current=chunks_;
00477
00478 while(current!=0)
00479 {
00480 Chunk *tmp = current;
00481 current = current->next_;
00482 delete tmp;
00483 }
00484 }
00485
00486 template<class T, std::size_t S>
00487 inline void Pool<T,S>::print(std::ostream& os)
00488 {
00489 Chunk* current=chunks_;
00490 while(current){
00491 os<<current<<" ";
00492 current=current->next_;
00493 }
00494 os<<current<<" ";
00495 }
00496
00497 template<class T, std::size_t S>
00498 inline void Pool<T,S>::grow()
00499 {
00500 Chunk *newChunk = new Chunk;
00501 newChunk->next_ = chunks_;
00502 chunks_ = newChunk;
00503
00504 char* start = reinterpret_cast<char *>(chunks_->memory_);
00505 char* last = &start[(elements-1)*alignedSize];
00506
00507 for(char* element=start; element<last; element=element+alignedSize){
00508 reinterpret_cast<Reference*>(element)->next_
00509 = reinterpret_cast<Reference*>(element+alignedSize);
00510 }
00511
00512 reinterpret_cast<Reference*>(last)->next_=0;
00513 head_ = reinterpret_cast<Reference*>(start);
00514 }
00515
00516 template<class T, std::size_t S>
00517 inline void Pool<T,S>::free(void* b)
00518 {
00519 if(b){
00520 Reference* freed = reinterpret_cast<Reference*>(b);
00521 freed->next_ = head_;
00522 head_ = freed;
00523
00524 }else
00525 std::cerr<< "Tried to free null pointer! "<<b<<std::endl;
00526 }
00527
00528 template<class T, std::size_t S>
00529 inline T* Pool<T,S>::allocate()
00530 {
00531 if(!head_)
00532 grow();
00533
00534 Reference* p = head_;
00535 head_ = p->next_;
00536
00537 return reinterpret_cast<T*>(p);
00538 }
00539
00540 template<class T, std::size_t s>
00541 typename PoolAllocator<T,s>::PoolType PoolAllocator<T,s>::memoryPool_;
00542
00543 template<class T, std::size_t s>
00544 inline PoolAllocator<T,s>::PoolAllocator()
00545 { }
00546
00547 template<class T, std::size_t s>
00548 inline T* PoolAllocator<T,s>::allocate(std::size_t n, const T* hint)
00549 {
00550 assert(n==1);
00551 return memoryPool_.allocate();
00552 }
00553
00554 template<class T, std::size_t s>
00555 inline void PoolAllocator<T,s>::deallocate(T* p, std::size_t n)
00556 {
00557 for(size_t i=0; i<n; i++)
00558 memoryPool_.free(p++);
00559 }
00560
00561 template<class T, std::size_t s>
00562 inline void PoolAllocator<T,s>::construct(T* p, const T& value)
00563 {
00564 ::new (static_cast<void*>(p)) T(value);
00565 }
00566
00567 template<class T, std::size_t s>
00568 inline void PoolAllocator<T,s>::destroy(T* p)
00569 {
00570 p->~T();
00571 }
00572
00574 }
00575 #endif