dune-common  2.3.1-rc1
poolallocator.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 // $Id$
4 #ifndef DUNE_COMMON_POOLALLOCATOR_HH
5 #define DUNE_COMMON_POOLALLOCATOR_HH
6 
11 #include "alignment.hh"
12 #include "static_assert.hh"
13 #include "lcm.hh"
14 #include <typeinfo>
15 #include <iostream>
16 #include <cassert>
17 #include <new>
18 
19 //forward declarations.
20 
21 // we need to know the test function to declare it friend
22 template<std::size_t size, typename T>
23 struct testPoolMain;
24 
25 namespace Dune
26 {
27 
28  template<typename T, std::size_t s>
29  class Pool;
30 
31  template<typename T, std::size_t s>
33 
34 }
35 
36 namespace std
37 {
38  /*
39  template<class T, std::size_t S>
40  inline ostream& operator<<(ostream& os, Dune::Pool<T,S>& pool)
41  {
42  os<<"pool="<<&pool<<" allocated_="<<pool.allocated_;
43  return os;
44  }
45 
46  template<class T, std::size_t S>
47  inline ostream& operator<<(ostream& os, Dune::PoolAllocator<T,S>& pool)
48  {
49  os<<pool.memoryPool_<<std::endl;
50  return os;
51  }
52  */
53 }
54 
55 
56 namespace Dune
57 {
88  template<class T, std::size_t s>
89  class Pool
90  {
91  // make the test function friend
92  friend struct ::testPoolMain<s,T>;
93 
94  //friend std::ostream& std::operator<<<>(std::ostream&,Pool<T,s>&);
95  template< class, std::size_t > friend class PoolAllocator;
96 
97  private:
98 
100  struct Reference
101  {
102  Reference *next_;
103  };
104 
105  public:
106 
108  typedef T MemberType;
109  enum
110  {
114  unionSize = ((sizeof(MemberType) < sizeof(Reference)) ?
115  sizeof(Reference) : sizeof(MemberType)),
116 
121  size = ((sizeof(MemberType) <= s && sizeof(Reference) <= s) ?
122  s : unionSize),
123 
129 
136  alignedSize = ((unionSize % alignment == 0) ?
137  unionSize :
138  ((unionSize / alignment + 1) * alignment)),
139 
147  chunkSize = ((size % alignment == 0) ?
148  size : ((size / alignment + 1)* alignment))
149  + alignment - 1,
150 
155  };
156 
157  private:
159  struct Chunk
160  {
161 
162  //friend int testPool<s,T>();
163 
165  char chunk_[chunkSize];
166 
171  char* memory_;
172 
174  Chunk *next_;
175 
179  Chunk()
180  {
181  // Make sure the alignment is correct!
182  // long long should be 64bit safe!
183  unsigned long long lmemory = reinterpret_cast<unsigned long long>(chunk_);
184  if(lmemory % alignment != 0)
185  lmemory = (lmemory / alignment + 1)
186  * alignment;
187 
188  memory_ = reinterpret_cast<char *>(lmemory);
189  }
190  };
191 
192  public:
194  inline Pool();
196  inline ~Pool();
201  inline void* allocate();
206  inline void free(void* o);
207 
211  inline void print(std::ostream& os);
212 
213  private:
214 
215  // Prevent Copying!
216  Pool(const Pool<MemberType,s>&);
217 
218  void operator=(const Pool<MemberType,s>& pool) const;
220  inline void grow();
222  Reference *head_;
224  Chunk *chunks_;
225  /* @brief The number of currently allocated elements. */
226  //size_t allocated_;
227 
228  };
229 
247  template<class T, std::size_t s>
248  class PoolAllocator
249  {
250  //friend std::ostream& std::operator<<<>(std::ostream&,PoolAllocator<T,s>&);
251 
252  public:
256  typedef T value_type;
257 
258  enum
259  {
264  size=s*sizeof(value_type)
265  };
266 
270  typedef T* pointer;
271 
275  typedef const T* const_pointer;
276 
280  typedef T& reference;
281 
285  typedef const T& const_reference;
286 
290  typedef std::size_t size_type;
291 
295  typedef std::ptrdiff_t difference_type;
296 
300  inline PoolAllocator();
301 
305  template<typename U, std::size_t u>
307  {
308  // we allow copying but never copy the pool
309  // to have a clear ownership of allocated pointers.
310  }
311 
314  {
315  // we allow copying but never copy the pool
316  // to have a clear ownership of allocated pointers.
317  // For this behaviour we have to implement
318  // the copy constructor, because the default
319  // one would copy the pool and deallocation
320  // of it would break.
321  }
328  inline pointer allocate(std::size_t n, const_pointer hint=0);
329 
337  inline void deallocate(pointer p, std::size_t n);
338 
344  inline void construct(pointer p, const_reference value);
345 
350  inline void destroy(pointer p);
351 
355  inline pointer address(reference x) const { return &x; }
356 
357 
361  inline const_pointer address(const_reference x) const { return &x; }
362 
366  inline int max_size() const throw(){ return 1;}
367 
371  template<class U>
372  struct rebind
373  {
375  };
376 
379 
380  private:
384  PoolType memoryPool_;
385  };
386 
387  // specialization for void
388  template <std::size_t s>
389  class PoolAllocator<void,s>
390  {
391  public:
392  typedef void* pointer;
393  typedef const void* const_pointer;
394  // reference to void members are impossible.
395  typedef void value_type;
396  template <class U> struct rebind
397  {
399  };
400  };
401 
402 
403  template<typename T1, std::size_t t1, typename T2, std::size_t t2>
405  {
406  return false;
407  }
408 
409 
410  template<typename T1, std::size_t t1, typename T2, std::size_t t2>
412  {
413  return true;
414  }
415 
416  template<typename T, std::size_t t1, std::size_t t2>
418  {
419  return &p1==&p2;
420  }
421 
422 
423  template<typename T, std::size_t t1, std::size_t t2>
425  {
426  return &p1 != &p2;
427  }
428 
429  template<typename T, std::size_t t1, std::size_t t2>
431  {
432  return false;
433  }
434 
435 
436  template<typename T, std::size_t t1, std::size_t t2>
438  {
439  return true;
440  }
441 
442  template<std::size_t t1, std::size_t t2>
444  {
445  return &p1==&p2;
446  }
447 
448  template<std::size_t t1, std::size_t t2>
450  {
451  return &p1!=&p2;
452  }
453 
454  template<class T, std::size_t S>
456  : head_(0), chunks_(0) //, allocated_(0)
457  {
458  dune_static_assert(sizeof(T)<=unionSize, "Library Error: type T is too big");
459  dune_static_assert(sizeof(Reference)<=unionSize, "Library Error: type of referene is too big");
460  dune_static_assert(unionSize<=alignedSize, "Library Error: alignedSize too small");
461  dune_static_assert(sizeof(T)<=chunkSize, "Library Error: chunkSize must be able to hold at least one value");
462  dune_static_assert(sizeof(Reference)<=chunkSize, "Library Error: chunkSize must be able to hold at least one reference");
463  dune_static_assert((chunkSize - (alignment - 1)) % alignment == 0, "Library Error: compiler cannot calculate!");
464  dune_static_assert(elements>=1, "Library Error: we need to hold at least one element!");
465  dune_static_assert(elements*alignedSize<=chunkSize, "Library Error: aligned elements must fit into chuck!");
466  }
467 
468  template<class T, std::size_t S>
470  {
471  /*
472  if(allocated_!=0)
473  std::cerr<<"There are still "<<allocated_<<" allocated elements by the Pool<"<<typeid(T).name()<<","<<S<<"> "
474  <<static_cast<void*>(this)<<"! This is a memory leak and might result in segfaults"
475  <<std::endl;
476  */
477  // delete the allocated chunks.
478  Chunk *current=chunks_;
479 
480  while(current!=0)
481  {
482  Chunk *tmp = current;
483  current = current->next_;
484  delete tmp;
485  }
486  }
487 
488  template<class T, std::size_t S>
489  inline void Pool<T,S>::print(std::ostream& os)
490  {
491  Chunk* current=chunks_;
492  while(current) {
493  os<<current<<" ";
494  current=current->next_;
495  }
496  os<<current<<" ";
497  }
498 
499  template<class T, std::size_t S>
500  inline void Pool<T,S>::grow()
501  {
502  Chunk *newChunk = new Chunk;
503  newChunk->next_ = chunks_;
504  chunks_ = newChunk;
505 
506  char* start = chunks_->memory_;
507  char* last = &start[elements*alignedSize];
508  Reference* ref = new (start) (Reference);
509 
510  // grow is only called if head==0,
511  assert(!head_);
512 
513  head_ = ref;
514 
515  for(char* element=start+alignedSize; element<last; element=element+alignedSize) {
516  Reference* next = new (element) (Reference);
517  ref->next_ = next;
518  ref = next;
519  }
520  ref->next_=0;
521  }
522 
523  template<class T, std::size_t S>
524  inline void Pool<T,S>::free(void* b)
525  {
526  if(b) {
527 #ifndef NDEBUG
528  Chunk* current=chunks_;
529  while(current) {
530  if(static_cast<void*>(&current->chunk_)<=b &&
531  static_cast<void*>((&current->chunk_)+chunkSize)>b)
532  break;
533  current=current->next_;
534  }
535  if(!current)
536  throw std::bad_alloc();
537 #endif
538  Reference* freed = static_cast<Reference*>(b);
539  freed->next_ = head_;
540  head_ = freed;
541  //--allocated_;
542  }
543  else
544  {
545  std::cerr<< "Tried to free null pointer! "<<b<<std::endl;
546  throw std::bad_alloc();
547  }
548  }
549 
550  template<class T, std::size_t S>
551  inline void* Pool<T,S>::allocate()
552  {
553  if(!head_)
554  grow();
555 
556  Reference* p = head_;
557  head_ = p->next_;
558  //++allocated_;
559  return p;
560  }
561 
562  template<class T, std::size_t s>
564  { }
565 
566  template<class T, std::size_t s>
567  inline typename PoolAllocator<T,s>::pointer
569  {
570  if(n==1)
571  return static_cast<T*>(memoryPool_.allocate());
572  else
573  throw std::bad_alloc();
574  }
575 
576  template<class T, std::size_t s>
577  inline void PoolAllocator<T,s>::deallocate(pointer p, std::size_t n)
578  {
579  for(size_t i=0; i<n; i++)
580  memoryPool_.free(p++);
581  }
582 
583  template<class T, std::size_t s>
585  {
586  ::new (static_cast<void*>(p))T(value);
587  }
588 
589  template<class T, std::size_t s>
591  {
592  p->~T();
593  }
594 
596 }
597 #endif
void deallocate(pointer p, std::size_t n)
Free objects.
Definition: poolallocator.hh:577
const_pointer address(const_reference x) const
Convert a reference to a pointer.
Definition: poolallocator.hh:361
const void * const_pointer
Definition: poolallocator.hh:393
Pool()
Constructor.
Definition: poolallocator.hh:455
void print(std::ostream &os)
Print elements in pool for debugging.
Definition: poolallocator.hh:489
A memory pool of objects.
Definition: poolallocator.hh:29
void free(void *o)
Free an object.
Definition: poolallocator.hh:524
~Pool()
Destructor.
Definition: poolallocator.hh:469
PoolAllocator< U, s > other
Definition: poolallocator.hh:374
Statically compute the least common multiple of two integers.
void value_type
Definition: poolallocator.hh:395
Rebind the allocator to another type.
Definition: poolallocator.hh:372
An allocator managing a pool of objects for reuse.
Definition: poolallocator.hh:32
T MemberType
The type of object we allocate memory for.
Definition: poolallocator.hh:108
const T * const_pointer
The constant pointer type.
Definition: poolallocator.hh:275
T * pointer
The pointer type.
Definition: poolallocator.hh:270
This file implements a template class to determine alignment requirements of types at compile time...
Pool< T, size > PoolType
The type of the memory pool we use.
Definition: poolallocator.hh:378
#define dune_static_assert(COND, MSG)
Helper template so that compilation fails if condition is not true.
Definition: static_assert.hh:79
PoolAllocator(const PoolAllocator &)
Copy constructor that does not copy the memory pool.
Definition: poolallocator.hh:313
Calculate the least common multiple of two numbers.
Definition: lcm.hh:30
void construct(pointer p, const_reference value)
Construct an object.
Definition: poolallocator.hh:584
pointer address(reference x) const
Convert a reference to a pointer.
Definition: poolallocator.hh:355
The size of each chunk memory chunk.
Definition: poolallocator.hh:147
T value_type
Type of the values we construct and allocate.
Definition: poolallocator.hh:256
EnableIfInterOperable< T1, T2, bool >::type operator!=(const ForwardIteratorFacade< T1, V1, R1, D > &lhs, const ForwardIteratorFacade< T2, V2, R2, D > &rhs)
Checks for inequality.
Definition: iteratorfacades.hh:253
Calculates the alignment requirement of a type.
Definition: alignment.hh:99
Definition: poolallocator.hh:23
Fallback implementation of the C++0x static_assert feature.
void * allocate()
Get a new or recycled object.
Definition: poolallocator.hh:551
PoolAllocator(const PoolAllocator< U, u > &)
Copy Constructor that does not copy the memory pool.
Definition: poolallocator.hh:306
The number of element each chunk can hold.
Definition: poolallocator.hh:154
PoolAllocator()
Constructor.
Definition: poolallocator.hh:563
std::size_t size_type
The size type.
Definition: poolallocator.hh:290
EnableIfInterOperable< T1, T2, bool >::type operator==(const ForwardIteratorFacade< T1, V1, R1, D > &lhs, const ForwardIteratorFacade< T2, V2, R2, D > &rhs)
Checks for equality.
Definition: iteratorfacades.hh:231
The size of a union of Reference and MemberType.
Definition: poolallocator.hh:114
The alignment that suits both the MemberType and the Reference (i.e. their least common multiple)...
Definition: poolallocator.hh:128
The number of objects to fit into one memory chunk allocated.
Definition: poolallocator.hh:264
PoolAllocator< U, s > other
Definition: poolallocator.hh:398
pointer allocate(std::size_t n, const_pointer hint=0)
Allocates objects.
Definition: poolallocator.hh:568
The aligned size of the type.
Definition: poolallocator.hh:136
void * pointer
Definition: poolallocator.hh:392
void destroy(pointer p)
Destroy an object without freeing memory.
Definition: poolallocator.hh:590
std::ptrdiff_t difference_type
The difference_type.
Definition: poolallocator.hh:295
Size requirement. At least one object has to stored.
Definition: poolallocator.hh:121
int max_size() const
Not correctly implemented, yet!
Definition: poolallocator.hh:366
T & reference
The reference type.
Definition: poolallocator.hh:280
const T & const_reference
The constant reference type.
Definition: poolallocator.hh:285