Embedded Template Library 1.0
Loading...
Searching...
No Matches
ipool.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2014 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_IPOOL_INCLUDED
32#define ETL_IPOOL_INCLUDED
33
34#include "platform.h"
35#include "error_handler.h"
36#include "exception.h"
37#include "iterator.h"
38#include "static_assert.h"
39#include "utility.h"
40#include "memory.h"
41#include "placement_new.h"
42
43#define ETL_POOL_CPP03_CODE 0
44
45namespace etl
46{
47 //***************************************************************************
50 //***************************************************************************
51 class pool_exception : public exception
52 {
53 public:
54
55 pool_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
56 : exception(reason_, file_name_, line_number_)
57 {}
58 };
59
60 //***************************************************************************
63 //***************************************************************************
64 class pool_no_allocation : public pool_exception
65 {
66 public:
67
68 explicit pool_no_allocation(string_type file_name_, numeric_type line_number_)
69 : pool_exception(ETL_ERROR_TEXT("pool:allocation", ETL_POOL_FILE_ID"A"), file_name_, line_number_)
70 {}
71 };
72
73 //***************************************************************************
76 //***************************************************************************
77 class pool_object_not_in_pool : public pool_exception
78 {
79 public:
80
81 pool_object_not_in_pool(string_type file_name_, numeric_type line_number_)
82 : pool_exception(ETL_ERROR_TEXT("pool:not in pool", ETL_POOL_FILE_ID"B"), file_name_, line_number_)
83 {}
84 };
85
86 //***************************************************************************
89 //***************************************************************************
90 class pool_element_size : public pool_exception
91 {
92 public:
93
94 pool_element_size(string_type file_name_, numeric_type line_number_)
95 : pool_exception(ETL_ERROR_TEXT("pool:element size", ETL_POOL_FILE_ID"C"), file_name_, line_number_)
96 {}
97 };
98
99 //***************************************************************************
101 //***************************************************************************
102 class ipool
103 {
104 public:
105
106 typedef size_t size_type;
107
108 private:
109
110 //***************************************************************************
112 //***************************************************************************
113
114 const char* buffer_end() const
115 {
116 return p_buffer + Item_Size * items_initialised;
117 }
118
119 //***************************************************************************
123 //***************************************************************************
124 bool is_pointing_into_pool_or_end_or_nullptr(const char *address) const
125 {
126 return address == ETL_NULLPTR || (p_buffer <= address && address <= buffer_end());
127 }
128
129 //***************************************************************************
131 //***************************************************************************
132 bool is_in_free_list(const char* address) const
133 {
134 const char* i = p_next;
135 while (i != ETL_NULLPTR)
136 {
137 if (address == i)
138 {
139 return true;
140 }
141 i = *reinterpret_cast<const char* const*>(i);
142 }
143 return false;
144 }
145
146 public:
147
148 //***************************************************************************
149 template<bool is_const>
150 class ipool_iterator
151 {
152 public:
153
154 friend class ipool;
155
156 typedef typename etl::conditional<is_const, const char*, char*>::type value_type;
157 typedef typename etl::conditional<is_const, const char*&, char*&>::type reference;
158 typedef typename etl::conditional<is_const, const char**, char**>::type pointer;
159 typedef ptrdiff_t difference_type;
160 typedef ETL_OR_STD::forward_iterator_tag iterator_category;
161 typedef typename etl::conditional<is_const, const void*, void*>::type void_type;
162 typedef typename etl::conditional<is_const, const ipool, ipool>::type pool_type;
163 typedef typename etl::conditional<is_const, const char* const*, char**>::type pointer_type;
164
165 //***************************************************************************
166 ipool_iterator(const ipool_iterator& other)
167 : p_current(other.p_current)
168 , p_pool(other.p_pool)
169 {
170 find_allocated();
171 }
172
173 //***************************************************************************
174 ipool_iterator& operator ++()
175 {
176 p_current = p_current + p_pool->Item_Size;
177 find_allocated();
178 return *this;
179 }
180
181 //***************************************************************************
182 ipool_iterator operator ++(int)
183 {
184 ipool_iterator temp(*this);
185 p_current = p_current + p_pool->Item_Size;
186 find_allocated();
187 return temp;
188 }
189
190 //***************************************************************************
191 ipool_iterator& operator =(const ipool_iterator& other)
192 {
193 p_current = other.p_current;
194 p_pool = other.p_pool;
195 return *this;
196 }
197
198 //***************************************************************************
199 void_type operator *() const
200 {
201 return p_current;
202 }
203
204 //***************************************************************************
205 template <typename T>
206 T& get() const
207 {
208 return *reinterpret_cast<T*>(p_current);
209 }
210
211 //***************************************************************************
212 friend bool operator == (const ipool_iterator& lhs, const ipool_iterator& rhs)
213 {
214 return lhs.p_current == rhs.p_current;
215 }
216
217 //***************************************************************************
218 friend bool operator != (const ipool_iterator& lhs, const ipool_iterator& rhs)
219 {
220 return !(lhs == rhs);
221 }
222
223 private:
224
225 //***************************************************************************
228 //***************************************************************************
229 void find_allocated()
230 {
231 while (p_current < p_pool->buffer_end())
232 {
233 value_type value = *reinterpret_cast<pointer_type>(p_current);
234 if (!p_pool->is_pointing_into_pool_or_end_or_nullptr(value))
235 {
236 return;
237 }
238 if (!p_pool->is_in_free_list(p_current))
239 {
240 return;
241 }
242 p_current += p_pool->Item_Size;
243 }
244 }
245
246 //***************************************************************************
248 //***************************************************************************
249 ipool_iterator(value_type p, pool_type* pool_)
250 : p_current(p)
251 , p_pool(pool_)
252 {
253 find_allocated();
254 }
255
256 value_type p_current;
257 pool_type* p_pool;
258 };
259
260 template<bool is_const>
261 friend class ipool_iterator;
262
263 typedef ipool_iterator<false> iterator;
264
265 //***************************************************************************
266 class const_iterator : public ipool_iterator<true>
267 {
268 public:
269 const_iterator(const ipool_iterator& other) : ipool_iterator(other) {}
270 const_iterator(const ipool_iterator<false>& other) : ipool_iterator(other.p_current, other.p_pool) {}
271 const_iterator(value_type p, pool_type* pool_) : ipool_iterator<true>(p, pool_) {}
272 };
273
274 //***************************************************************************
275 iterator begin()
276 {
277 return iterator(p_buffer, this);
278 }
279
280 //***************************************************************************
281 iterator end()
282 {
283 return iterator(p_buffer + Item_Size * items_initialised, this);
284 }
285
286 //***************************************************************************
287 const_iterator begin() const
288 {
289 return const_iterator(p_buffer, this);
290 }
291
292 //***************************************************************************
293 const_iterator end() const
294 {
295 return const_iterator(p_buffer + Item_Size * items_initialised, this);
296 }
297
298 //***************************************************************************
299 const_iterator cbegin() const
300 {
301 return const_iterator(p_buffer, this);
302 }
303
304 //***************************************************************************
305 const_iterator cend() const
306 {
307 return const_iterator(p_buffer + Item_Size * items_initialised, this);
308 }
309
310 //*************************************************************************
314 //*************************************************************************
315 template <typename T>
317 {
318 if (sizeof(T) > Item_Size)
319 {
320 ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size));
321 }
322
323 return reinterpret_cast<T*>(allocate_item());
324 }
325
326#if ETL_CPP11_NOT_SUPPORTED || ETL_POOL_CPP03_CODE || ETL_USING_STLPORT
327 //*************************************************************************
331 //*************************************************************************
332 template <typename T>
334 {
335 T* p = allocate<T>();
336
337 if (p)
338 {
339 ::new (p) T();
340 }
341
342 return p;
343 }
344
345 //*************************************************************************
349 //*************************************************************************
350 template <typename T, typename T1>
351 T* create(const T1& value1)
352 {
353 T* p = allocate<T>();
354
355 if (p)
356 {
357 ::new (p) T(value1);
358 }
359
360 return p;
361 }
362
363 template <typename T, typename T1, typename T2>
364 T* create(const T1& value1, const T2& value2)
365 {
366 T* p = allocate<T>();
367
368 if (p)
369 {
370 ::new (p) T(value1, value2);
371 }
372
373 return p;
374 }
375
376 template <typename T, typename T1, typename T2, typename T3>
377 T* create(const T1& value1, const T2& value2, const T3& value3)
378 {
379 T* p = allocate<T>();
380
381 if (p)
382 {
383 ::new (p) T(value1, value2, value3);
384 }
385
386 return p;
387 }
388
389 template <typename T, typename T1, typename T2, typename T3, typename T4>
390 T* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
391 {
392 T* p = allocate<T>();
393
394 if (p)
395 {
396 ::new (p) T(value1, value2, value3, value4);
397 }
398
399 return p;
400 }
401#else
402 //*************************************************************************
404 //*************************************************************************
405 template <typename T, typename... Args>
406 T* create(Args&&... args)
407 {
408 T* p = allocate<T>();
409
410 if (p)
411 {
412 ::new (p) T(etl::forward<Args>(args)...);
413 }
414
415 return p;
416 }
417#endif
418
419 //*************************************************************************
423 //*************************************************************************
424 template <typename T>
425 void destroy(const T* const p_object)
426 {
427 if (sizeof(T) > Item_Size)
428 {
429 ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size));
430 }
431
432 p_object->~T();
433 release(p_object);
434 }
435
436 //*************************************************************************
441 //*************************************************************************
442 void release(const void* const p_object)
443 {
444 const uintptr_t p = uintptr_t(p_object);
445 release_item((char*)p);
446 }
447
448 //*************************************************************************
450 //*************************************************************************
452 {
453 items_allocated = 0;
454 items_initialised = 0;
455 p_next = p_buffer;
456 }
457
458 //*************************************************************************
462 //*************************************************************************
463 bool is_in_pool(const void* const p_object) const
464 {
465 const uintptr_t p = uintptr_t(p_object);
466 return is_item_in_pool((const char*)p);
467 }
468
469 //*************************************************************************
471 //*************************************************************************
472 size_t max_size() const
473 {
474 return Max_Size;
475 }
476
477 //*************************************************************************
479 //*************************************************************************
480 size_t max_item_size() const
481 {
482 return Item_Size;
483 }
484
485 //*************************************************************************
487 //*************************************************************************
488 size_t capacity() const
489 {
490 return Max_Size;
491 }
492
493 //*************************************************************************
495 //*************************************************************************
496 size_t available() const
497 {
498 return Max_Size - items_allocated;
499 }
500
501 //*************************************************************************
503 //*************************************************************************
504 size_t size() const
505 {
506 return items_allocated;
507 }
508
509 //*************************************************************************
512 //*************************************************************************
513 bool empty() const
514 {
515 return items_allocated == 0;
516 }
517
518 //*************************************************************************
521 //*************************************************************************
522 bool full() const
523 {
524 return items_allocated == Max_Size;
525 }
526
527 protected:
528
529 //*************************************************************************
531 //*************************************************************************
532 ipool(char* p_buffer_, uint32_t item_size_, uint32_t max_size_)
533 : p_buffer(p_buffer_),
534 p_next(p_buffer_),
535 items_allocated(0),
536 items_initialised(0),
537 Item_Size(item_size_),
538 Max_Size(max_size_)
539 {
540 }
541
542 private:
543
544 static ETL_CONSTANT uintptr_t invalid_item_ptr = 1;
545
546 //*************************************************************************
548 //*************************************************************************
549 char* allocate_item()
550 {
551 char* p_value = ETL_NULLPTR;
552
553 // Any free space left?
554 if (items_allocated < Max_Size)
555 {
556 // Initialise another one if necessary.
557 if (items_initialised < Max_Size)
558 {
559 char* p = p_buffer + (items_initialised * Item_Size);
560 char* np = p + Item_Size;
561 *reinterpret_cast<char**>(p) = np;
562 ++items_initialised;
563 }
564
565 // Get the address of new allocated item.
566 p_value = p_next;
567
568 ++items_allocated;
569 if (items_allocated < Max_Size)
570 {
571 // Set up the pointer to the next free item
572 p_next = *reinterpret_cast<char**>(p_next);
573 }
574 else
575 {
576 // No more left!
577 p_next = ETL_NULLPTR;
578 }
579
580 // invalid pointer, outside pool
581 // needs to be different from ETL_NULLPTR since ETL_NULLPTR is used
582 // as list endmarker
583 *reinterpret_cast<uintptr_t*>(p_value) = invalid_item_ptr;
584 }
585 else
586 {
587 ETL_ASSERT(false, ETL_ERROR(pool_no_allocation));
588 }
589
590 return p_value;
591 }
592
593 //*************************************************************************
595 //*************************************************************************
596 void release_item(char* p_value)
597 {
598 // Does it belong to us?
599 ETL_ASSERT(is_item_in_pool(p_value), ETL_ERROR(pool_object_not_in_pool));
600
601 if (items_allocated > 0)
602 {
603 // Point it to the current free item.
604 *(uintptr_t*)p_value = reinterpret_cast<uintptr_t>(p_next);
605
606 p_next = p_value;
607
608 --items_allocated;
609 }
610 else
611 {
612 ETL_ASSERT_FAIL(ETL_ERROR(pool_no_allocation));
613 }
614 }
615
616 //*************************************************************************
618 //*************************************************************************
619 bool is_item_in_pool(const char* p) const
620 {
621 // Within the range of the buffer?
622 intptr_t distance = p - p_buffer;
623 bool is_within_range = (distance >= 0) && (distance <= intptr_t((Item_Size * Max_Size) - Item_Size));
624
625 // Modulus and division can be slow on some architectures, so only do this in debug.
626#if ETL_IS_DEBUG_BUILD
627 // Is the address on a valid object boundary?
628 bool is_valid_address = ((distance % Item_Size) == 0);
629#else
630 bool is_valid_address = true;
631#endif
632
633 return is_within_range && is_valid_address;
634 }
635
636 // Disable copy construction and assignment.
637 ipool(const ipool&);
638 ipool& operator =(const ipool&);
639
640 char* p_buffer;
641 char* p_next;
642
643 uint32_t items_allocated;
644 uint32_t items_initialised;
645
646 const uint32_t Item_Size;
647 const uint32_t Max_Size;
648
649 //*************************************************************************
651 //*************************************************************************
652#if defined(ETL_POLYMORPHIC_POOL) || defined(ETL_POLYMORPHIC_CONTAINERS)
653 public:
654 virtual ~ipool()
655 {
656 }
657#else
658 protected:
660 {
661 }
662#endif
663 };
664}
665
666#endif
667
Definition ipool.h:267
Definition ipool.h:151
ETL_CONSTEXPR14 bool operator==(const etl::expected< TValue, TError > &lhs, const etl::expected< TValue2, TError2 > &rhs)
Equivalence operators.
Definition expected.h:962
#define ETL_ASSERT(b, e)
Definition error_handler.h:356
ETL_CONSTEXPR exception(string_type reason_, string_type, numeric_type line_)
Constructor.
Definition exception.h:69
size_t size() const
Returns the number of allocated items in the pool.
Definition ipool.h:504
~ipool()
Destructor.
Definition ipool.h:659
bool empty() const
Definition ipool.h:513
void release_all()
Release all objects in the pool.
Definition ipool.h:451
bool full() const
Definition ipool.h:522
size_t max_size() const
Returns the maximum number of items in the pool.
Definition ipool.h:472
T * allocate()
Definition ipool.h:316
void release(const void *const p_object)
Definition ipool.h:442
size_t capacity() const
Returns the maximum number of items in the pool.
Definition ipool.h:488
ipool(char *p_buffer_, uint32_t item_size_, uint32_t max_size_)
Constructor.
Definition ipool.h:532
size_t max_item_size() const
Returns the maximum size of an item in the pool.
Definition ipool.h:480
bool is_in_pool(const void *const p_object) const
Definition ipool.h:463
size_t available() const
Returns the number of free items in the pool.
Definition ipool.h:496
T * create()
Definition ipool.h:333
void destroy(const T *const p_object)
Definition ipool.h:425
T * create(const T1 &value1)
Definition ipool.h:351
Definition ipool.h:91
bitset_ext
Definition absolute.h:39
ETL_CONSTEXPR TContainer::iterator end(TContainer &container)
Definition iterator.h:992
iterator
Definition iterator.h:399