Embedded Template Library  1.0
pool.h
Go to the documentation of this file.
1 
3 /******************************************************************************
4 The MIT License(MIT)
5 
6 Embedded Template Library.
7 https://github.com/ETLCPP/etl
8 https://www.etlcpp.com
9 
10 Copyright(c) 2014 jwellbelove
11 
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files(the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions :
18 
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21 
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 ******************************************************************************/
30 
31 #ifndef ETL_POOL_INCLUDED
32 #define ETL_POOL_INCLUDED
33 
34 #include "platform.h"
35 #include "algorithm.h"
36 #include "iterator.h"
37 #include "utility.h"
38 #include "error_handler.h"
39 #include "alignment.h"
40 #include "array.h"
41 #include "container.h"
42 #include "integral_limits.h"
43 #include "nullptr.h"
44 #include "alignment.h"
45 #include "static_assert.h"
46 #include "algorithm.h"
47 #include "placement_new.h"
48 
49 #undef ETL_FILE
50 #define ETL_FILE "11"
51 
52 #define ETL_POOL_CPP03_CODE 0
53 
54 //*****************************************************************************
58 //*****************************************************************************
59 
60 namespace etl
61 {
62  //***************************************************************************
65  //***************************************************************************
66  class pool_exception : public exception
67  {
68  public:
69 
70  pool_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
71  : exception(reason_, file_name_, line_number_)
72  {}
73  };
74 
75  //***************************************************************************
78  //***************************************************************************
80  {
81  public:
82 
83  explicit pool_no_allocation(string_type file_name_, numeric_type line_number_)
84  : pool_exception(ETL_ERROR_TEXT("pool:allocation", ETL_FILE"A"), file_name_, line_number_)
85  {}
86  };
87 
88  //***************************************************************************
91  //***************************************************************************
93  {
94  public:
95 
96  pool_object_not_in_pool(string_type file_name_, numeric_type line_number_)
97  : pool_exception(ETL_ERROR_TEXT("pool:not in pool", ETL_FILE"B"), file_name_, line_number_)
98  {}
99  };
100 
101  //***************************************************************************
104  //***************************************************************************
106  {
107  public:
108 
109  pool_element_size(string_type file_name_, numeric_type line_number_)
110  : pool_exception(ETL_ERROR_TEXT("pool:element size", ETL_FILE"C"), file_name_, line_number_)
111  {}
112  };
113 
114  //***************************************************************************
116  //***************************************************************************
117  class ipool
118  {
119  public:
120 
121  typedef size_t size_type;
122 
123  //*************************************************************************
127  //*************************************************************************
128  template <typename T>
129  T* allocate()
130  {
131  if (sizeof(T) > ITEM_SIZE)
132  {
133  ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size));
134  }
135 
136  return reinterpret_cast<T*>(allocate_item());
137  }
138 
139 #if ETL_CPP11_NOT_SUPPORTED || ETL_POOL_CPP03_CODE || ETL_USING_STLPORT
140  //*************************************************************************
144  //*************************************************************************
145  template <typename T>
146  T* create()
147  {
148  T* p = allocate<T>();
149 
150  if (p)
151  {
152  ::new (p) T();
153  }
154 
155  return p;
156  }
157 
158  //*************************************************************************
162  //*************************************************************************
163  template <typename T, typename T1>
164  T* create(const T1& value1)
165  {
166  T* p = allocate<T>();
167 
168  if (p)
169  {
170  ::new (p) T(value1);
171  }
172 
173  return p;
174  }
175 
176  template <typename T, typename T1, typename T2>
177  T* create(const T1& value1, const T2& value2)
178  {
179  T* p = allocate<T>();
180 
181  if (p)
182  {
183  ::new (p) T(value1, value2);
184  }
185 
186  return p;
187  }
188 
189  template <typename T, typename T1, typename T2, typename T3>
190  T* create(const T1& value1, const T2& value2, const T3& value3)
191  {
192  T* p = allocate<T>();
193 
194  if (p)
195  {
196  ::new (p) T(value1, value2, value3);
197  }
198 
199  return p;
200  }
201 
202  template <typename T, typename T1, typename T2, typename T3, typename T4>
203  T* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
204  {
205  T* p = allocate<T>();
206 
207  if (p)
208  {
209  ::new (p) T(value1, value2, value3, value4);
210  }
211 
212  return p;
213  }
214 #else
215  //*************************************************************************
217  //*************************************************************************
218  template <typename T, typename... Args>
219  T* create(Args&&... args)
220  {
221  T* p = allocate<T>();
222 
223  if (p)
224  {
225  ::new (p) T(etl::forward<Args>(args)...);
226  }
227 
228  return p;
229  }
230 #endif
231 
232  //*************************************************************************
236  //*************************************************************************
237  template <typename T>
238  void destroy(const T* const p_object)
239  {
240  if (sizeof(T) > ITEM_SIZE)
241  {
242  ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size));
243  }
244 
245  p_object->~T();
246  release(p_object);
247  }
248 
249  //*************************************************************************
254  //*************************************************************************
255  void release(const void* const p_object)
256  {
257  const uintptr_t p = uintptr_t(p_object);
258  release_item((char*)p);
259  }
260 
261  //*************************************************************************
263  //*************************************************************************
264  void release_all()
265  {
266  items_allocated = 0;
267  items_initialised = 0;
268  p_next = p_buffer;
269  }
270 
271  //*************************************************************************
275  //*************************************************************************
276  bool is_in_pool(const void* p_object) const
277  {
278  const uintptr_t p = uintptr_t(p_object);
279  return is_item_in_pool((const char*)p);
280  }
281 
282  //*************************************************************************
284  //*************************************************************************
285  size_t max_size() const
286  {
287  return MAX_SIZE;
288  }
289 
290  //*************************************************************************
292  //*************************************************************************
293  size_t capacity() const
294  {
295  return MAX_SIZE;
296  }
297 
298  //*************************************************************************
300  //*************************************************************************
301  size_t available() const
302  {
303  return MAX_SIZE - items_allocated;
304  }
305 
306  //*************************************************************************
308  //*************************************************************************
309  size_t size() const
310  {
311  return items_allocated;
312  }
313 
314  //*************************************************************************
317  //*************************************************************************
318  bool empty() const
319  {
320  return items_allocated == 0;
321  }
322 
323  //*************************************************************************
326  //*************************************************************************
327  bool full() const
328  {
329  return items_allocated == MAX_SIZE;
330  }
331 
332  protected:
333 
334  //*************************************************************************
336  //*************************************************************************
337  ipool(char* p_buffer_, uint32_t item_size_, uint32_t max_size_)
338  : p_buffer(p_buffer_),
339  p_next(p_buffer_),
340  items_allocated(0),
341  items_initialised(0),
342  ITEM_SIZE(item_size_),
343  MAX_SIZE(max_size_)
344  {
345  }
346 
347  private:
348 
349  //*************************************************************************
351  //*************************************************************************
352  char* allocate_item()
353  {
354  char* p_value = ETL_NULLPTR;
355 
356  // Any free space left?
357  if (items_allocated < MAX_SIZE)
358  {
359  // Initialise another one if necessary.
360  if (items_initialised < MAX_SIZE)
361  {
362  char* p = p_buffer + (items_initialised * ITEM_SIZE);
363  char* np = p + ITEM_SIZE;
364  *reinterpret_cast<char**>(p) = np;
365  ++items_initialised;
366  }
367 
368  // Get the address of new allocated item.
369  p_value = p_next;
370 
371  ++items_allocated;
372  if (items_allocated != MAX_SIZE)
373  {
374  // Set up the pointer to the next free item
375  p_next = *reinterpret_cast<char**>(p_next);
376  }
377  else
378  {
379  // No more left!
380  p_next = ETL_NULLPTR;
381  }
382  }
383  else
384  {
385  ETL_ASSERT(false, ETL_ERROR(pool_no_allocation));
386  }
387 
388  return p_value;
389  }
390 
391  //*************************************************************************
393  //*************************************************************************
394  void release_item(char* p_value)
395  {
396  // Does it belong to us?
397  ETL_ASSERT(is_item_in_pool(p_value), ETL_ERROR(pool_object_not_in_pool));
398 
399  if (p_next != ETL_NULLPTR)
400  {
401  // Point it to the current free item.
402  *(uintptr_t*)p_value = reinterpret_cast<uintptr_t>(p_next);
403  }
404  else
405  {
406  // This is the only free item.
407  *((uintptr_t*)p_value) = 0;
408  }
409 
410  p_next = p_value;
411 
412  --items_allocated;
413  }
414 
415  //*************************************************************************
417  //*************************************************************************
418  bool is_item_in_pool(const char* p) const
419  {
420  // Within the range of the buffer?
421  intptr_t distance = p - p_buffer;
422  bool is_within_range = (distance >= 0) && (distance <= intptr_t((ITEM_SIZE * MAX_SIZE) - ITEM_SIZE));
423 
424  // Modulus and division can be slow on some architectures, so only do this in debug.
425 #if defined(ETL_DEBUG)
426  // Is the address on a valid object boundary?
427  bool is_valid_address = ((distance % ITEM_SIZE) == 0);
428 #else
429  bool is_valid_address = true;
430 #endif
431 
432  return is_within_range && is_valid_address;
433  }
434 
435  // Disable copy construction and assignment.
436  ipool(const ipool&);
437  ipool& operator =(const ipool&);
438 
439  char* p_buffer;
440  char* p_next;
441 
442  uint32_t items_allocated;
443  uint32_t items_initialised;
444 
445  const uint32_t ITEM_SIZE;
446  const uint32_t MAX_SIZE;
447 
448  //*************************************************************************
450  //*************************************************************************
451 #if defined(ETL_POLYMORPHIC_POOL) || defined(ETL_POLYMORPHIC_CONTAINERS)
452  public:
453  virtual ~ipool()
454  {
455  }
456 #else
457  protected:
459  {
460  }
461 #endif
462  };
463 
464  //*************************************************************************
467  //*************************************************************************
468  template <const size_t TYPE_SIZE_, const size_t ALIGNMENT_, const size_t SIZE_>
469  class generic_pool : public etl::ipool
470  {
471  public:
472 
473  static const size_t SIZE = SIZE_;
474  static const size_t ALIGNMENT = ALIGNMENT_;
475  static const size_t TYPE_SIZE = TYPE_SIZE_;
476 
477  //*************************************************************************
479  //*************************************************************************
481  : etl::ipool(reinterpret_cast<char*>(&buffer[0]), ELEMENT_SIZE, SIZE)
482  {
483  }
484 
485  //*************************************************************************
490  //*************************************************************************
491  template <typename U>
492  U* allocate()
493  {
494  ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
495  ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
496  return ipool::allocate<U>();
497  }
498 
499 #if ETL_CPP11_NOT_SUPPORTED || ETL_POOL_CPP03_CODE || ETL_USING_STLPORT
500  //*************************************************************************
504  //*************************************************************************
505  template <typename U>
506  U* create()
507  {
508  ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
509  ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
510  return ipool::create<U>();
511  }
512 
513  //*************************************************************************
517  //*************************************************************************
518  template <typename U, typename T1>
519  U* create(const T1& value1)
520  {
521  ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
522  ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
523  return ipool::create<U>(value1);
524  }
525 
526  //*************************************************************************
530  //*************************************************************************
531  template <typename U, typename T1, typename T2>
532  U* create(const T1& value1, const T2& value2)
533  {
534  ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
535  ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
536  return ipool::create<U>(value1, value2);
537  }
538 
539  //*************************************************************************
543  //*************************************************************************
544  template <typename U, typename T1, typename T2, typename T3>
545  U* create(const T1& value1, const T2& value2, const T3& value3)
546  {
547  ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
548  ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
549  return ipool::create<U>(value1, value2, value3);
550  }
551 
552  //*************************************************************************
556  //*************************************************************************
557  template <typename U, typename T1, typename T2, typename T3, typename T4>
558  U* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
559  {
560  ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
561  ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
562  return ipool::create<U>(value1, value2, value3, value4);
563  }
564 #else
565  //*************************************************************************
567  //*************************************************************************
568  template <typename U, typename... Args>
569  U* create(Args&&... args)
570  {
571  ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
572  ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
573  return ipool::create<U>(etl::forward<Args>(args)...);
574  }
575 #endif
576 
577  //*************************************************************************
581  //*************************************************************************
582  template <typename U>
583  void destroy(const U* const p_object)
584  {
585  ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
586  ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
587  p_object->~U();
588  ipool::release(p_object);
589  }
590 
591  private:
592 
593  // The pool element.
594  union Element
595  {
596  char* next;
597  char value[TYPE_SIZE_];
598  typename etl::type_with_alignment<ALIGNMENT_>::type dummy;
599  };
600 
602  typename etl::aligned_storage<sizeof(Element), etl::alignment_of<Element>::value>::type buffer[SIZE];
603 
604  static const uint32_t ELEMENT_SIZE = sizeof(Element);
605 
606  // Should not be copied.
607  generic_pool(const generic_pool&);
608  generic_pool& operator =(const generic_pool&);
609  };
610 
611  //*************************************************************************
614  //*************************************************************************
615  template <typename T, const size_t SIZE_>
616  class pool : public etl::generic_pool<sizeof(T), etl::alignment_of<T>::value, SIZE_>
617  {
618  private:
619 
620  typedef etl::generic_pool<sizeof(T), etl::alignment_of<T>::value, SIZE_> base_t;
621 
622  public:
623 
624  using base_t::SIZE;
625  using base_t::ALIGNMENT;
626  using base_t::TYPE_SIZE;
627 
628  //*************************************************************************
630  //*************************************************************************
632  {
633  }
634 
635  //*************************************************************************
641  //*************************************************************************
642  T* allocate()
643  {
644  return base_t::template allocate<T>();
645  }
646 
647 #if ETL_CPP11_NOT_SUPPORTED || ETL_POOL_CPP03_CODE || ETL_USING_STLPORT
648  //*************************************************************************
652  //*************************************************************************
653  T* create()
654  {
655  return base_t::template create<T>();
656  }
657 
658  //*************************************************************************
662  //*************************************************************************
663  template <typename T1>
664  T* create(const T1& value1)
665  {
666  return base_t::template create<T>(value1);
667  }
668 
669  //*************************************************************************
673  //*************************************************************************
674  template <typename T1, typename T2>
675  T* create(const T1& value1, const T2& value2)
676  {
677  return base_t::template create<T>(value1, value2);
678  }
679 
680  //*************************************************************************
684  //*************************************************************************
685  template <typename T1, typename T2, typename T3>
686  T* create(const T1& value1, const T2& value2, const T3& value3)
687  {
688  return base_t::template create<T>(value1, value2, value3);
689  }
690 
691  //*************************************************************************
695  //*************************************************************************
696  template <typename T1, typename T2, typename T3, typename T4>
697  T* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
698  {
699  return base_t::template create<T>(value1, value2, value3, value4);
700  }
701 #else
702  //*************************************************************************
706  //*************************************************************************
707  template <typename... Args>
708  T* create(Args&&... args)
709  {
710  return base_t::template create<T>(etl::forward<Args>(args)...);
711  }
712 #endif
713 
714  //*************************************************************************
718  //*************************************************************************
719  template <typename U>
720  void destroy(const U* const p_object)
721  {
722  ETL_STATIC_ASSERT((etl::is_base_of<U, T>::value), "Pool does not contain this type");
723  p_object->~U();
724  base_t::release(p_object);
725  }
726 
727  private:
728 
729  // Should not be copied.
730  pool(const pool&);
731  pool& operator =(const pool&);
732  };
733 }
734 
735 #undef ETL_FILE
736 
737 #endif
738 
Definition: alignment.h:116
#define ETL_ASSERT(b, e)
Definition: error_handler.h:290
exception(string_type reason_, string_type file_, numeric_type line_)
Constructor.
Definition: exception.h:67
Definition: exception.h:47
size_t size() const
Returns the number of allocated items in the pool.
Definition: pool.h:309
void destroy(const U *const p_object)
Definition: pool.h:720
~ipool()
Destructor.
Definition: pool.h:458
bool empty() const
Definition: pool.h:318
T * create(const T1 &value1)
Definition: pool.h:664
bool is_in_pool(const void *p_object) const
Definition: pool.h:276
void release_all()
Release all objects in the pool.
Definition: pool.h:264
T * create(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition: pool.h:697
U * create(const T1 &value1, const T2 &value2, const T3 &value3)
Definition: pool.h:545
pool()
Constructor.
Definition: pool.h:631
generic_pool()
Constructor.
Definition: pool.h:480
bool full() const
Definition: pool.h:327
size_t max_size() const
Returns the maximum number of items in the pool.
Definition: pool.h:285
T * create(const T1 &value1)
Definition: pool.h:164
U * create(const T1 &value1, const T2 &value2)
Definition: pool.h:532
void release(const void *const p_object)
Definition: pool.h:255
size_t capacity() const
Returns the maximum number of items in the pool.
Definition: pool.h:293
ipool(char *p_buffer_, uint32_t item_size_, uint32_t max_size_)
Constructor.
Definition: pool.h:337
T * allocate()
Definition: pool.h:129
T * create()
Definition: pool.h:146
T * create(const T1 &value1, const T2 &value2)
Definition: pool.h:675
U * allocate()
Definition: pool.h:492
size_t available() const
Returns the number of free items in the pool.
Definition: pool.h:301
U * create()
Definition: pool.h:506
T * create()
Definition: pool.h:653
T * allocate()
Definition: pool.h:642
void destroy(const U *const p_object)
Definition: pool.h:583
U * create(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition: pool.h:558
void destroy(const T *const p_object)
Definition: pool.h:238
T * create(const T1 &value1, const T2 &value2, const T3 &value3)
Definition: pool.h:686
U * create(const T1 &value1)
Definition: pool.h:519
Definition: pool.h:470
Definition: pool.h:118
Definition: pool.h:617
Definition: pool.h:106
Definition: pool.h:67
Definition: pool.h:80
Definition: pool.h:93
add_rvalue_reference
Definition: type_traits_generator.h:1348
is_base_of
Definition: type_traits_generator.h:1289
Definition: absolute.h:37