Dune Core Modules (unstable)

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 // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
5 #ifndef DUNE_COMMON_POOLALLOCATOR_HH
6 #define DUNE_COMMON_POOLALLOCATOR_HH
7 
12 #include <numeric>
13 #include <typeinfo>
14 #include <iostream>
15 #include <cassert>
16 #include <new>
17 
18 #ifndef DOXYGEN
19 // forward declarations.
20 // we need to know the test function to declare it friend
21 template<std::size_t size, typename T>
22 struct testPoolMain;
23 #endif
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>
32  class PoolAllocator;
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 
113  constexpr static int unionSize = (sizeof(MemberType) < sizeof(Reference)) ?
114  sizeof(Reference) : sizeof(MemberType);
115 
120  constexpr static int size = (sizeof(MemberType) <= s && sizeof(Reference) <= s) ?
121  s : unionSize;
122 
127  constexpr static int alignment = std::lcm(alignof(MemberType), alignof(Reference));
128 
135  constexpr static int alignedSize = (unionSize % alignment == 0) ?
136  unionSize :
137  ((unionSize / alignment + 1) * alignment);
138 
144  constexpr static int chunkSize = (size % alignment == 0) ?
145  size : ((size / alignment + 1)* alignment);
146 
150  constexpr static int elements = (chunkSize / alignedSize);
151 
152  private:
154  struct Chunk
155  {
156 
157  //friend int testPool<s,T>();
158 
160  alignas(alignment) char chunk_[chunkSize];
161 
163  Chunk *next_;
164  };
165 
166  public:
168  inline Pool();
170  inline ~Pool();
175  inline void* allocate();
180  inline void free(void* o);
181 
185  inline void print(std::ostream& os);
186 
187  private:
188 
189  // Prevent Copying!
190  Pool(const Pool<MemberType,s>&);
191 
192  void operator=(const Pool<MemberType,s>& pool) const;
194  inline void grow();
196  Reference *head_;
198  Chunk *chunks_;
199  /* @brief The number of currently allocated elements. */
200  //size_t allocated_;
201 
202  };
203 
221  template<class T, std::size_t s>
223  {
224  //friend std::ostream& std::operator<<<>(std::ostream&,PoolAllocator<T,s>&);
225 
226  public:
230  typedef T value_type;
231 
236  constexpr static int size = s * sizeof(value_type);
237 
241  typedef T* pointer;
242 
246  typedef const T* const_pointer;
247 
251  typedef T& reference;
252 
256  typedef const T& const_reference;
257 
261  typedef std::size_t size_type;
262 
266  typedef std::ptrdiff_t difference_type;
267 
271  inline PoolAllocator();
272 
276  template<typename U, std::size_t u>
278  {
279  // we allow copying but never copy the pool
280  // to have a clear ownership of allocated pointers.
281  }
282 
285  {
286  // we allow copying but never copy the pool
287  // to have a clear ownership of allocated pointers.
288  // For this behaviour we have to implement
289  // the copy constructor, because the default
290  // one would copy the pool and deallocation
291  // of it would break.
292  }
299  inline pointer allocate(std::size_t n, const_pointer hint=0);
300 
308  inline void deallocate(pointer p, std::size_t n);
309 
315  inline void construct(pointer p, const_reference value);
316 
321  inline void destroy(pointer p);
322 
326  inline pointer address(reference x) const { return &x; }
327 
328 
332  inline const_pointer address(const_reference x) const { return &x; }
333 
337  inline int max_size() const noexcept { return 1; }
338 
342  template<class U>
343  struct rebind
344  {
345  typedef PoolAllocator<U,s> other;
346  };
347 
350 
351  private:
355  PoolType memoryPool_;
356  };
357 
358  // specialization for void
359  template <std::size_t s>
360  class PoolAllocator<void,s>
361  {
362  public:
363  typedef void* pointer;
364  typedef const void* const_pointer;
365  // reference to void members are impossible.
366  typedef void value_type;
367  template <class U> struct rebind
368  {
369  typedef PoolAllocator<U,s> other;
370  };
371  };
372 
373 
374  template<typename T1, std::size_t t1, typename T2, std::size_t t2>
375  bool operator==(const PoolAllocator<T1,t1>&, const PoolAllocator<T2,t2>&)
376  {
377  return false;
378  }
379 
380 
381  template<typename T1, std::size_t t1, typename T2, std::size_t t2>
382  bool operator!=(const PoolAllocator<T1,t1>&, const PoolAllocator<T2,t2>&)
383  {
384  return true;
385  }
386 
387  template<typename T, std::size_t t1, std::size_t t2>
388  bool operator==(const PoolAllocator<T,t1>& p1, const PoolAllocator<T,t2>& p2)
389  {
390  return &p1==&p2;
391  }
392 
393 
394  template<typename T, std::size_t t1, std::size_t t2>
395  bool operator!=(const PoolAllocator<T,t1>& p1, const PoolAllocator<T,t2>& p2)
396  {
397  return &p1 != &p2;
398  }
399 
400  template<typename T, std::size_t t1, std::size_t t2>
401  bool operator==(const PoolAllocator<void,t1>&, const PoolAllocator<T,t2>&)
402  {
403  return false;
404  }
405 
406 
407  template<typename T, std::size_t t1, std::size_t t2>
408  bool operator!=(const PoolAllocator<void,t1>&, const PoolAllocator<T,t2>&)
409  {
410  return true;
411  }
412 
413  template<std::size_t t1, std::size_t t2>
414  bool operator==(const PoolAllocator<void,t1>& p1, const PoolAllocator<void,t2>& p2)
415  {
416  return &p1==&p2;
417  }
418 
419  template<std::size_t t1, std::size_t t2>
420  bool operator!=(const PoolAllocator<void,t1>& p1, const PoolAllocator<void,t2>& p2)
421  {
422  return &p1!=&p2;
423  }
424 
425  template<class T, std::size_t S>
427  : head_(0), chunks_(0) //, allocated_(0)
428  {
429  static_assert(sizeof(T)<=unionSize, "Library Error: type T is too big");
430  static_assert(sizeof(Reference)<=unionSize, "Library Error: type of reference is too big");
431  static_assert(unionSize<=alignedSize, "Library Error: alignedSize too small");
432  static_assert(sizeof(T)<=chunkSize, "Library Error: chunkSize must be able to hold at least one value");
433  static_assert(sizeof(Reference)<=chunkSize, "Library Error: chunkSize must be able to hold at least one reference");
434  static_assert(chunkSize % alignment == 0, "Library Error: compiler cannot calculate!");
435  static_assert(elements>=1, "Library Error: we need to hold at least one element!");
436  static_assert(elements*alignedSize<=chunkSize, "Library Error: aligned elements must fit into chuck!");
437  }
438 
439  template<class T, std::size_t S>
441  {
442  /*
443  if(allocated_!=0)
444  std::cerr<<"There are still "<<allocated_<<" allocated elements by the Pool<"<<typeid(T).name()<<","<<S<<"> "
445  <<static_cast<void*>(this)<<"! This is a memory leak and might result in segfaults"
446  <<std::endl;
447  */
448  // delete the allocated chunks.
449  Chunk *current=chunks_;
450 
451  while(current!=0)
452  {
453  Chunk *tmp = current;
454  current = current->next_;
455  delete tmp;
456  }
457  }
458 
459  template<class T, std::size_t S>
460  inline void Pool<T,S>::print(std::ostream& os)
461  {
462  Chunk* current=chunks_;
463  while(current) {
464  os<<current<<" ";
465  current=current->next_;
466  }
467  os<<current<<" ";
468  }
469 
470  template<class T, std::size_t S>
471  inline void Pool<T,S>::grow()
472  {
473  Chunk *newChunk = new Chunk;
474  newChunk->next_ = chunks_;
475  chunks_ = newChunk;
476 
477  char* start = chunks_->chunk_;
478  char* last = &start[elements*alignedSize];
479  Reference* ref = new (start) (Reference);
480 
481  // grow is only called if head==0,
482  assert(!head_);
483 
484  head_ = ref;
485 
486  for(char* element=start+alignedSize; element<last; element=element+alignedSize) {
487  Reference* next = new (element) (Reference);
488  ref->next_ = next;
489  ref = next;
490  }
491  ref->next_=0;
492  }
493 
494  template<class T, std::size_t S>
495  inline void Pool<T,S>::free(void* b)
496  {
497  if(b) {
498 #ifndef NDEBUG
499  Chunk* current=chunks_;
500  while(current) {
501  if(static_cast<void*>(current->chunk_)<=b &&
502  static_cast<void*>(current->chunk_+chunkSize)>b)
503  break;
504  current=current->next_;
505  }
506  if(!current)
507  throw std::bad_alloc();
508 #endif
509  Reference* freed = static_cast<Reference*>(b);
510  freed->next_ = head_;
511  head_ = freed;
512  //--allocated_;
513  }
514  else
515  {
516  std::cerr<< "Tried to free null pointer! "<<b<<std::endl;
517  throw std::bad_alloc();
518  }
519  }
520 
521  template<class T, std::size_t S>
522  inline void* Pool<T,S>::allocate()
523  {
524  if(!head_)
525  grow();
526 
527  Reference* p = head_;
528  head_ = p->next_;
529  //++allocated_;
530  return p;
531  }
532 
533  template<class T, std::size_t s>
535  { }
536 
537  template<class T, std::size_t s>
538  inline typename PoolAllocator<T,s>::pointer
540  {
541  if(n==1)
542  return static_cast<T*>(memoryPool_.allocate());
543  else
544  throw std::bad_alloc();
545  }
546 
547  template<class T, std::size_t s>
548  inline void PoolAllocator<T,s>::deallocate(pointer p, std::size_t n)
549  {
550  for(size_t i=0; i<n; i++)
551  memoryPool_.free(p++);
552  }
553 
554  template<class T, std::size_t s>
556  {
557  ::new (static_cast<void*>(p))T(value);
558  }
559 
560  template<class T, std::size_t s>
562  {
563  p->~T();
564  }
565 
567 }
568 #endif
An allocator managing a pool of objects for reuse.
Definition: poolallocator.hh:223
Pool< T, size > PoolType
The type of the memory pool we use.
Definition: poolallocator.hh:349
const_pointer address(const_reference x) const
Convert a reference to a pointer.
Definition: poolallocator.hh:332
const T & const_reference
The constant reference type.
Definition: poolallocator.hh:256
std::size_t size_type
The size type.
Definition: poolallocator.hh:261
T value_type
Type of the values we construct and allocate.
Definition: poolallocator.hh:230
T & reference
The reference type.
Definition: poolallocator.hh:251
PoolAllocator(const PoolAllocator &)
Copy constructor that does not copy the memory pool.
Definition: poolallocator.hh:284
const T * const_pointer
The constant pointer type.
Definition: poolallocator.hh:246
pointer address(reference x) const
Convert a reference to a pointer.
Definition: poolallocator.hh:326
constexpr static int size
The number of objects to fit into one memory chunk allocated.
Definition: poolallocator.hh:236
T * pointer
The pointer type.
Definition: poolallocator.hh:241
PoolAllocator(const PoolAllocator< U, u > &)
Copy Constructor that does not copy the memory pool.
Definition: poolallocator.hh:277
std::ptrdiff_t difference_type
The difference_type.
Definition: poolallocator.hh:266
int max_size() const noexcept
Not correctly implemented, yet!
Definition: poolallocator.hh:337
A memory pool of objects.
Definition: poolallocator.hh:90
constexpr static int elements
The number of element each chunk can hold.
Definition: poolallocator.hh:150
constexpr static int size
Size requirement. At least one object has to stored.
Definition: poolallocator.hh:120
constexpr static int chunkSize
The size of each chunk memory chunk.
Definition: poolallocator.hh:144
constexpr static int unionSize
The size of a union of Reference and MemberType.
Definition: poolallocator.hh:113
constexpr static int alignedSize
The aligned size of the type.
Definition: poolallocator.hh:135
T MemberType
The type of object we allocate memory for.
Definition: poolallocator.hh:108
constexpr static int alignment
The alignment that suits both the MemberType and the Reference (i.e. their least common multiple).
Definition: poolallocator.hh:127
void construct(pointer p, const_reference value)
Construct an object.
Definition: poolallocator.hh:555
void free(void *o)
Free an object.
Definition: poolallocator.hh:495
~Pool()
Destructor.
Definition: poolallocator.hh:440
void * allocate()
Get a new or recycled object.
Definition: poolallocator.hh:522
void print(std::ostream &os)
Print elements in pool for debugging.
Definition: poolallocator.hh:460
pointer allocate(std::size_t n, const_pointer hint=0)
Allocates objects.
Definition: poolallocator.hh:539
Pool()
Constructor.
Definition: poolallocator.hh:426
void deallocate(pointer p, std::size_t n)
Free objects.
Definition: poolallocator.hh:548
void destroy(pointer p)
Destroy an object without freeing memory.
Definition: poolallocator.hh:561
PoolAllocator()
Constructor.
Definition: poolallocator.hh:534
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:259
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:237
Dune namespace.
Definition: alignedallocator.hh:13
Rebind the allocator to another type.
Definition: poolallocator.hh:344
Get the 'const' version of a reference to a mutable object.
Definition: genericiterator.hh:87
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 1, 22:29, 2024)