/[svn]/linuxsampler/trunk/src/common/Pool.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/common/Pool.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3293 - (show annotations) (download) (as text)
Tue Jun 27 22:19:19 2017 UTC (6 years, 9 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 37978 byte(s)
* NKSP: Added built-in script function "fork()".
* NKSP: Added built-in array variable %NKSP_CALLBACK_CHILD_ID[].
* NKSP: Added built-in variable $NKSP_CALLBACK_PARENT_ID.
* NKSP: Fixed potential crash when accessing dynamic built-in
  array variables.
* Bumped version (2.0.0.svn65).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2017 Christian Schoenebeck *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #ifndef __LS_POOL_H__
25 #define __LS_POOL_H__
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 // we just use exceptions for debugging, better not in the final realtime thread !
32 #ifndef CONFIG_RT_EXCEPTIONS
33 # define CONFIG_RT_EXCEPTIONS 0
34 #endif
35
36 #if CONFIG_RT_EXCEPTIONS
37 # include <stdexcept>
38 # include <string>
39 #endif // CONFIG_RT_EXCEPTIONS
40
41 #include <iostream>
42
43 #if CONFIG_DEVMODE
44 # include <string>
45 const std::string __err_msg_iterator_invalidated = "Pool/RTList iterator invalidated";
46 #endif // CONFIG_DEVMODE
47
48 const std::string __err_msg_resize_while_in_use = "Pool::resizePool() ERROR: elements still in use!";
49
50 /**
51 * Unique numeric ID for exactly one incarnation of one element allocated from
52 * a Pool. As soon as the respective element is once freed back to the Pool,
53 * the ID becomes invalid. Such an ID may be used to safely store an abstract
54 * reference to one Pool element for longer time. Since the Pool classes
55 * automatically detect whether an ID became invalid, using such an ID is thus
56 * safer than storing an Iterator or even a raw pointer in use case scenarios of
57 * storing long term references to Pool elements.
58 *
59 * This ID type is currently set (constrained) to 32-bit because the current
60 * real-time instrument script infrastructure implementation, which heavily
61 * relies on element IDs, is currently using 32-bit for its integer script
62 * variable type.
63 */
64 typedef uint32_t pool_element_id_t;
65
66 // just symbol prototyping
67 template<typename T> class Pool;
68 template<typename T> class RTList;
69
70 template<typename T>
71 class RTListBase {
72 protected:
73 template<typename T1>
74 struct _Node {
75 _Node<T1>* next;
76 _Node<T1>* prev;
77 T1* data;
78 #if CONFIG_DEVMODE
79 RTListBase<T1>* list; // list to which this node currently belongs to
80 #endif // CONFIG_DEVMODE
81 uint reincarnation; // just for Pool::fromID()
82
83 _Node() {
84 next = NULL;
85 prev = NULL;
86 data = NULL;
87 #if CONFIG_DEVMODE
88 list = NULL;
89 #endif // CONFIG_DEVMODE
90 reincarnation = 0;
91 }
92
93 inline void bumpReincarnation(uint bits) {
94 reincarnation++;
95 // constrain the bitrange of "reincarnation", because Pool::fromID() will shift up/down for pool_element_id_t and compare this bitwise
96 reincarnation &= ((1 << bits) - 1);
97 }
98 };
99 typedef _Node<T> Node;
100
101 public:
102 /**
103 * Pointer-like object which allows to iterate over elements of a RTList,
104 * similar to iterators of STL container classes. Note that the main
105 * purpose of this class is to access elements of a list / pool i.e.
106 * within a @c while() loop. If you rather want to keep a reference to
107 * one particular element (i.e. for longer time) then you might
108 * consider using @c pool_element_id_t variables instead.
109 */
110 template<typename T1>
111 class _Iterator {
112 public:
113 _Iterator() {
114 current = NULL;
115 fallback = NULL;
116 #if CONFIG_DEVMODE
117 list = NULL;
118 #endif // CONFIG_DEVMODE
119 }
120
121 /// prefix increment op.
122 inline _Iterator& operator++() {
123 #if CONFIG_DEVMODE
124 if (!isValid()) {
125 #if CONFIG_RT_EXCEPTIONS
126 throw std::runtime_error(__err_msg_iterator_invalidated);
127 #else
128 std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
129 return *(_Iterator*)NULL; // force segfault if iterator became invalidated
130 #endif // CONFIG_RT_EXCEPTIONS
131 }
132 #endif // CONFIG_DEVMODE
133 fallback = current;
134 current = current->next;
135 return *this;
136 }
137
138 /// postfix increment op.
139 inline _Iterator operator++(int) {
140 _Iterator preval = *this;
141 ++*this; // use prefix operator implementation
142 return preval;
143 }
144
145 /// prefix decrement op.
146 inline _Iterator& operator--() {
147 #if CONFIG_DEVMODE
148 if (!isValid()) {
149 #if CONFIG_RT_EXCEPTIONS
150 throw std::runtime_error(__err_msg_iterator_invalidated);
151 #else
152 std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
153 return *(_Iterator*)NULL; // force segfault if iterator became invalidated
154 #endif // CONFIG_RT_EXCEPTIONS
155 }
156 #endif // CONFIG_DEVMODE
157 fallback = current;
158 current = current->prev;
159 return *this;
160 }
161
162 /// postfix decrement op.
163 inline _Iterator operator--(int) {
164 _Iterator preval = *this;
165 --*this; // use prefix operator implementation
166 return preval;
167 }
168
169 inline T1& operator*() {
170 #if CONFIG_DEVMODE
171 if (!isValid()) { // if iterator became invalidated
172 #if CONFIG_RT_EXCEPTIONS
173 throw std::runtime_error(__err_msg_iterator_invalidated);
174 #else
175 std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
176 return *((T1*)NULL); // force segfault if iterator became invalidated
177 #endif // CONFIG_RT_EXCEPTIONS
178 }
179 #endif // CONFIG_DEVMODE
180 return *current->data;
181 }
182
183 inline const T1& operator*() const {
184 #if CONFIG_DEVMODE
185 if (!isValid()) { // if iterator became invalidated
186 #if CONFIG_RT_EXCEPTIONS
187 throw std::runtime_error(__err_msg_iterator_invalidated);
188 #else
189 std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
190 return *((const T1*)NULL); // force segfault if iterator became invalidated
191 #endif // CONFIG_RT_EXCEPTIONS
192 }
193 #endif // CONFIG_DEVMODE
194 return *current->data;
195 }
196
197 inline T1* operator->() {
198 #if CONFIG_DEVMODE
199 if (!isValid()) { // if iterator became invalidated
200 #if CONFIG_RT_EXCEPTIONS
201 throw std::runtime_error(__err_msg_iterator_invalidated);
202 #else
203 std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
204 return (T1*)NULL; // force segfault if iterator became invalidated
205 #endif // CONFIG_RT_EXCEPTIONS
206 }
207 #endif // CONFIG_DEVMODE
208 return current->data;
209 }
210
211 inline const T1* operator->() const {
212 #if CONFIG_DEVMODE
213 if (!isValid()) { // if iterator became invalidated
214 #if CONFIG_RT_EXCEPTIONS
215 throw std::runtime_error(__err_msg_iterator_invalidated);
216 #else
217 std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
218 return (const T1*)NULL; // force segfault if iterator became invalidated
219 #endif // CONFIG_RT_EXCEPTIONS
220 }
221 #endif // CONFIG_DEVMODE
222 return current->data;
223 }
224
225 inline bool operator==(const _Iterator<T1> other) const {
226 return current == other.current;
227 }
228
229 inline bool operator!=(const _Iterator<T1> other) const {
230 return current != other.current;
231 }
232
233 inline operator bool() const {
234 return current && current->data;
235 }
236
237 inline bool operator!() const {
238 return !(current && current->data);
239 }
240
241 /**
242 * Moves the element pointed by this Iterator from its current
243 * list to the beginning of the destination list @a pDstList.
244 *
245 * @b CAUTION: When this method returns, this Iterator does
246 * @b NOT point to the element on the new list anymore, instead it
247 * points at a completely different element! In case of a
248 * forward Iterator this Iterator object will point to the
249 * previous element on the source list, in case of a backward
250 * Iterator it will point to the subsequent element on the
251 * source list. This behavior is enforced to avoid breaking an
252 * active loop code working with this Iterator object.
253 *
254 * Thus if you intend to continue working with the same element,
255 * you should do like this:
256 * @code
257 * it = it.moveToEndOf(anotherList);
258 * @endcode
259 *
260 * @param pDstList - destination list
261 * @returns Iterator object pointing at the moved element on
262 * the destination list
263 */
264 inline _Iterator moveToEndOf(RTListBase<T1>* pDstList) {
265 detach();
266 pDstList->append(*this);
267 _Iterator iterOnDstList = _Iterator(current);
268 current = fallback;
269 return iterOnDstList;
270 }
271
272 /**
273 * Moves the element pointed by this Iterator from its current
274 * list to the end of destination list @a pDstList.
275 *
276 * @b CAUTION: When this method returns, this Iterator does
277 * @b NOT point to the element on the new list anymore, instead it
278 * points at a completely different element! In case of a
279 * forward Iterator this Iterator object will point to the
280 * previous element on the source list, in case of a backward
281 * Iterator it will point to the subsequent element on the
282 * source list. This behavior is enforced to avoid breaking an
283 * active loop code working with this Iterator object.
284 *
285 * Thus if you intend to continue working with the same element,
286 * you should do like this:
287 * @code
288 * it = it.moveToBeginOf(anotherList);
289 * @endcode
290 *
291 * @param pDstList - destination list
292 * @returns Iterator object pointing at the moved element on
293 * the destination list
294 */
295 inline _Iterator moveToBeginOf(RTListBase<T1>* pDstList) {
296 detach();
297 pDstList->prepend(*this);
298 _Iterator iterOnDstList = _Iterator(current);
299 current = fallback;
300 return iterOnDstList;
301 }
302
303 /**
304 * Moves the element pointed by this Iterator from its current
305 * position to the position right before @a itDst. That move
306 * may either be from and to the same list, or to a another
307 * list.
308 *
309 * @b CAUTION: When this method returns, this Iterator does
310 * @b NOT point to the element on the new list anymore, instead it
311 * points at a completely different element! In case of a
312 * forward Iterator this Iterator object will point to the
313 * previous element on the source list, in case of a backward
314 * Iterator it will point to the subsequent element on the
315 * source list. This behavior is enforced to avoid breaking an
316 * active loop code working with this Iterator object.
317 *
318 * Thus if you intend to continue working with the same element,
319 * you should do like this:
320 * @code
321 * itSourceElement = itSourceElement.moveBefore(itDestinationElement);
322 * @endcode
323 *
324 * @param itDst - destination element to be inserted before
325 * @returns Iterator object pointing at the moved element on
326 * the destination list
327 */
328 inline _Iterator moveBefore(_Iterator<T1> itDst) {
329 detach();
330 RTList<T1>::prependBefore(*this, itDst);
331 _Iterator iterOnDstList = _Iterator(current);
332 current = fallback;
333 return iterOnDstList;
334 }
335
336 /**
337 * Moves the element pointed by this Iterator from its current
338 * position to the position right after @a itDst. That move
339 * may either be from and to the same list, or to a another
340 * list.
341 *
342 * @b CAUTION: When this method returns, this Iterator does
343 * @b NOT point to the element on the new list anymore, instead it
344 * points at a completely different element! In case of a
345 * forward Iterator this Iterator object will point to the
346 * previous element on the source list, in case of a backward
347 * Iterator it will point to the subsequent element on the
348 * source list. This behavior is enforced to avoid breaking an
349 * active loop code working with this Iterator object.
350 *
351 * Thus if you intend to continue working with the same element,
352 * you should do like this:
353 * @code
354 * itSourceElement = itSourceElement.moveAfter(itDestinationElement);
355 * @endcode
356 *
357 * @param itDst - destination element to be inserted after
358 * @returns Iterator object pointing at the moved element on
359 * the destination list
360 */
361 inline _Iterator moveAfter(_Iterator<T1> itDst) {
362 detach();
363 RTList<T1>::appendAfter(*this, itDst);
364 _Iterator iterOnDstList = _Iterator(current);
365 current = fallback;
366 return iterOnDstList;
367 }
368
369 #if CONFIG_DEVMODE
370 inline bool isValid() const {
371 return current->list == list;
372 }
373 #endif // CONFIG_DEVMODE
374
375 protected:
376 Node* current;
377 Node* fallback;
378 enum dir_t {
379 dir_forward,
380 dir_backward
381 };
382 #if CONFIG_DEVMODE
383 RTListBase<T1>* list;
384 #endif // CONFIG_DEVMODE
385
386 _Iterator(Node* pNode, dir_t direction = dir_forward) {
387 current = pNode;
388 fallback = (direction == dir_forward) ? pNode->prev : pNode->next;
389 #if CONFIG_DEVMODE
390 list = pNode->list;
391 #endif // CONFIG_DEVMODE
392 }
393
394 inline Node* node() {
395 #if CONFIG_DEVMODE
396 #if CONFIG_RT_EXCEPTIONS
397 if (isValid()) return current;
398 else throw std::runtime_error(__err_msg_iterator_invalidated);
399 #else
400 return (isValid()) ? current : (Node*)NULL; // force segfault if iterator became invalidated
401 #endif // CONFIG_RT_EXCEPTIONS
402 #else
403 return current;
404 #endif // CONFIG_DEVMODE
405 }
406
407 inline const Node* node() const {
408 #if CONFIG_DEVMODE
409 #if CONFIG_RT_EXCEPTIONS
410 if (isValid()) return current;
411 else throw std::runtime_error(__err_msg_iterator_invalidated);
412 #else
413 return (isValid()) ? current : (const Node*)NULL; // force segfault if iterator became invalidated
414 #endif // CONFIG_RT_EXCEPTIONS
415 #else
416 return current;
417 #endif // CONFIG_DEVMODE
418 }
419
420 inline void detach() {
421 RTListBase<T1>::detach(*this);
422 }
423
424 friend class RTListBase<T1>;
425 friend class RTList<T1>;
426 friend class Pool<T1>;
427 };
428 typedef _Iterator<T> Iterator;
429
430 inline Iterator first() {
431 return Iterator(_begin.next, Iterator::dir_forward);
432 }
433
434 inline Iterator last() {
435 return Iterator(_end.prev, Iterator::dir_backward);
436 }
437
438 inline Iterator begin() {
439 return Iterator(&_begin, Iterator::dir_forward);
440 }
441
442 inline Iterator end() {
443 return Iterator(&_end, Iterator::dir_backward);
444 }
445
446 inline bool isEmpty() const {
447 return _begin.next == &_end;
448 }
449
450 inline int count() {
451 int elements = 0;
452 for (Iterator it = first(); it != end(); ++it) ++elements;
453 return elements;
454 }
455
456 protected:
457 Node _begin; // fake node (without data) which represents the begin of the list - not the first element!
458 Node _end; // fake node (without data) which represents the end of the list - not the last element!
459
460 RTListBase() {
461 init();
462 }
463
464 void init() {
465 // initialize boundary nodes
466 _begin.prev = &_begin;
467 _begin.next = &_end;
468 _begin.data = NULL;
469 _end.next = &_end;
470 _end.prev = &_begin;
471 _end.data = NULL;
472 #if CONFIG_DEVMODE
473 _begin.list = this;
474 _end.list = this;
475 #endif // CONFIG_DEVMODE
476 }
477
478 inline void append(Iterator itElement) {
479 Node* pNode = itElement.current;
480 Node* last = _end.prev;
481 last->next = pNode;
482 pNode->prev = last; // if a segfault happens here, then because 'itElement' Iterator became invalidated
483 pNode->next = &_end;
484 _end.prev = pNode;
485 #if CONFIG_DEVMODE
486 pNode->list = this;
487 #endif // CONFIG_DEVMODE
488 }
489
490 inline void append(Iterator itFirst, Iterator itLast) {
491 Node* pFirst = itFirst.current;
492 Node* pLast = itLast.current;
493 Node* last = _end.prev;
494 last->next = pFirst;
495 pFirst->prev = last; // if a segfault happens here, then because 'itFirst' Iterator became invalidated
496 pLast->next = &_end; // if a segfault happens here, then because 'itLast' Iterator became invalidated
497 _end.prev = pLast;
498 #if CONFIG_DEVMODE
499 for (Node* pNode = pFirst; true; pNode = pNode->next) {
500 pNode->list = this;
501 if (pNode == pLast) break;
502 }
503 #endif // CONFIG_DEVMODE
504 }
505
506 inline void prepend(Iterator itElement) {
507 Node* pNode = itElement.current;
508 Node* first = _begin.next;
509 _begin.next = pNode;
510 pNode->prev = &_begin; // if a segfault happens here, then because 'itElement' Iterator became invalidated
511 pNode->next = first;
512 first->prev = pNode;
513 #if CONFIG_DEVMODE
514 pNode->list = this;
515 #endif // CONFIG_DEVMODE
516 }
517
518 inline void prepend(Iterator itFirst, Iterator itLast) {
519 Node* pFirst = itFirst.current;
520 Node* pLast = itLast.current;
521 Node* first = _begin.next;
522 _begin.next = pFirst;
523 pFirst->prev = &_begin; // if a segfault happens here, then because 'itFirst' Iterator became invalidated
524 pLast->next = first; // if a segfault happens here, then because 'itLast' Iterator became invalidated
525 first->prev = pLast;
526 #if CONFIG_DEVMODE
527 for (Node* pNode = pFirst; true; pNode = pNode->next) {
528 pNode->list = this;
529 if (pNode == pLast) break;
530 }
531 #endif // CONFIG_DEVMODE
532 }
533
534 static inline void prependBefore(Iterator itSrc, Iterator itDst) {
535 Node* src = itSrc.current;
536 Node* dst = itDst.current;
537 Node* prev = dst->prev;
538 prev->next = src;
539 dst->prev = src;
540 src->prev = prev;
541 src->next = dst;
542 #if CONFIG_DEVMODE
543 src->list = this;
544 #endif // CONFIG_DEVMODE
545 }
546
547 static inline void appendAfter(Iterator itSrc, Iterator itDst) {
548 Node* src = itSrc.current;
549 Node* dst = itDst.current;
550 Node* next = dst->next;
551 next->prev = src;
552 dst->next = src;
553 src->prev = dst;
554 src->next = next;
555 #if CONFIG_DEVMODE
556 src->list = this;
557 #endif // CONFIG_DEVMODE
558 }
559
560 static inline void detach(Iterator itElement) {
561 Node* pNode = itElement.node();
562 Node* prev = pNode->prev; // if a segfault happens here, then because 'itElement' Iterator became invalidated
563 Node* next = pNode->next;
564 prev->next = next;
565 next->prev = prev;
566 }
567
568 static inline void detach(Iterator itFirst, Iterator itLast) {
569 Node* prev = itFirst.node()->prev; // if a segfault happens here, then because 'itFirst' Iterator became invalidated
570 Node* next = itLast.node()->next; // if a segfault happens here, then because 'itLast' Iterator became invalidated
571 prev->next = next;
572 next->prev = prev;
573 }
574
575 friend class _Iterator<T>;
576 friend class RTList<T>;
577 friend class Pool<T>;
578 };
579
580 template<typename T>
581 class RTList : public RTListBase<T> {
582 public:
583 typedef typename RTListBase<T>::Node Node;
584 typedef typename RTListBase<T>::Iterator Iterator;
585
586 /**
587 * Constructor
588 *
589 * @param pPool - pool this list uses for allocation and
590 * deallocation of elements
591 */
592 RTList(Pool<T>* pPool) : RTListBase<T>::RTListBase() {
593 this->pPool = pPool;
594 }
595
596 /**
597 * Copy constructor
598 */
599 RTList(RTList<T>& list) : RTListBase<T>::RTListBase() {
600 this->pPool = list.pPool;
601 Iterator it = list.first();
602 Iterator end = list.end();
603 for(; it != end; ++it) {
604 if (poolIsEmpty()) break;
605 *(allocAppend()) = *it;
606 }
607 }
608
609 virtual ~RTList() {
610 clear();
611 }
612
613 inline bool poolIsEmpty() const {
614 return pPool->poolIsEmpty();
615 }
616
617 inline Iterator allocAppend() {
618 if (pPool->poolIsEmpty()) return RTListBase<T>::begin();
619 Iterator element = pPool->alloc();
620 this->append(element);
621 #if CONFIG_DEVMODE
622 element.list = this;
623 #endif // CONFIG_DEVMODE
624 return element;
625 }
626
627 inline Iterator allocPrepend() {
628 if (pPool->poolIsEmpty()) return RTListBase<T>::end();
629 Iterator element = pPool->alloc();
630 prepend(element);
631 #if CONFIG_DEVMODE
632 element.list = this;
633 #endif // CONFIG_DEVMODE
634 return element;
635 }
636
637 inline void free(Iterator& itElement) {
638 itElement.detach();
639 pPool->freeToPool(itElement);
640 itElement.current = itElement.fallback;
641 }
642
643 inline void clear() {
644 if (!RTListBase<T>::isEmpty()) {
645 Node* first = RTListBase<T>::_begin.next;
646 Node* last = RTListBase<T>::_end.prev;
647 RTListBase<T>::detach(first, last);
648 pPool->freeToPool(first, last);
649 }
650 }
651
652 inline pool_element_id_t getID(const T* obj) const {
653 return pPool->getID(obj);
654 }
655
656 inline pool_element_id_t getID(const Iterator& it) const {
657 return pPool->getID(&*it);
658 }
659
660 inline Iterator fromID(pool_element_id_t id) const {
661 return pPool->fromID(id);
662 }
663
664 inline Iterator fromPtr(const T* obj) const {
665 return pPool->fromPtr(obj);
666 }
667
668 protected:
669 Pool<T>* pPool;
670 };
671
672 template<typename T>
673 class Pool : public RTList<T> {
674 public:
675 typedef typename RTList<T>::Node Node;
676 typedef typename RTList<T>::Iterator Iterator;
677
678 Node* nodes;
679 T* data;
680 RTListBase<T> freelist; // not yet allocated elements
681 uint poolsize;
682 // following 3 used for element ID generation (and vice versa)
683 uint poolsizebits; ///< Amount of bits required to index all elements of this pool (according to current pool size).
684 uint reservedbits; ///< 3rd party reserved bits on the left side of id (default: 0).
685 uint reincarnationbits; ///< Amount of bits allowed for reincarnation counter.
686
687 Pool(int Elements) : RTList<T>::RTList(this), reservedbits(0) {
688 _init(Elements);
689 }
690
691 virtual ~Pool() {
692 if (nodes) delete[] nodes;
693 if (data) delete[] data;
694 }
695
696 /**
697 * Returns true if there is at least one free element that could be
698 * allocated from the pool with i.e. allocAppend() or allocPreprend().
699 *
700 * @see poolHasFreeElements()
701 */
702 inline bool poolIsEmpty() const {
703 return freelist.isEmpty();
704 }
705
706 /**
707 * Returns true if at least the requested amount of free @a elements is
708 * currently available for being allocated from the pool with i.e.
709 * allocAppend() or allocPreprend().
710 *
711 * @see poolIsEmpty()
712 */
713 bool poolHasFreeElements(int elements) {
714 for (Iterator it = freelist.first(); it != freelist.end() && elements >= 0; ++it)
715 --elements;
716 return elements <= 0;
717 }
718
719 /**
720 * Returns the current size of the pool, that is the amount of
721 * pre-allocated elements from the operating system. It equals the
722 * amount of elements given to the constructor unless resizePool()
723 * is called.
724 *
725 * @see resizePool()
726 */
727 uint poolSize() const {
728 return poolsize;
729 }
730
731 /**
732 * Alters the amount of elements to be pre-allocated from the
733 * operating system for this pool object.
734 *
735 * @e CAUTION: you MUST free all elements in use before calling this
736 * method ( e.g. by calling clear() )! Also make sure that no
737 * references of elements before this call will still be used after this
738 * call, since all elements will be reallocated and their old memory
739 * addresses become invalid!
740 *
741 * @see poolSize()
742 */
743 void resizePool(int Elements) {
744 if (freelist.count() != poolsize) {
745 #if CONFIG_DEVMODE
746 throw std::runtime_error(__err_msg_resize_while_in_use);
747 #else
748 std::cerr << __err_msg_resize_while_in_use << std::endl << std::flush;
749 // if we're here something's terribly wrong, but we try to do the best
750 RTList<T>::clear();
751 #endif
752 }
753 if (nodes) delete[] nodes;
754 if (data) delete[] data;
755 freelist.init();
756 RTListBase<T>::init();
757 _init(Elements);
758 }
759
760 /**
761 * Sets the amount of bits on the left hand side of pool_element_id_t
762 * numbers to be reserved for 3rd party usage. So if you pass @c 1 for
763 * argument @a bits for example, then all generated element IDs will be
764 * maximum 31 bit large.
765 *
766 * By default there are no reserved bits, and thus by default all IDs
767 * are max. 32 bit large.
768 *
769 * @param bits - amount of bits to reserve on every ID for other purposes
770 * @see pool_element_id_t
771 */
772 void setPoolElementIDsReservedBits(uint bits) {
773 reservedbits = bits;
774 updateReincarnationBits();
775 }
776
777 /**
778 * Returns an abstract, unique numeric ID for the given object of
779 * this pool, it returns 0 in case the passed object is not a member
780 * of this Pool, i.e. because it is simply an invalid pointer or member
781 * of another Pool. The returned ID is unique among all elements of this
782 * Pool and it differs with each reincarnation of an object. That means
783 * each time you free an element to and allocate the same element back
784 * from the Pool, it will have a different ID.
785 *
786 * A valid ID will never be zero, so you may use ID values of 0 in your
787 * data structures for special purposes (i.e. reflecting an invalid
788 * object ID or not yet assigned object).
789 *
790 * Members are always translated both, from Iterators/pointers to IDs,
791 * and from IDs to Iterators/pointers in constant time.
792 *
793 * You might want to use this alternative approach of referencing Pool
794 * members under certain scenarios. For example if you need to expose
795 * an ID to the end user and/or if you want to represent an object of
796 * this pool by a smaller number instead of a native pointer (i.e. 16
797 * bits vs. 64 bits). You can also detect this way whether the object
798 * has already been freed / reallocated from the Pool in the meantime.
799 *
800 * @param obj - raw pointer to a data member of this Pool
801 * @returns unique numeric ID (!= 0) of @a obj or 0 if pointer was invalid
802 */
803 pool_element_id_t getID(const T* obj) const {
804 if (!poolsize) return 0;
805 int index = int( obj - &data[0] );
806 if (index < 0 || index >= poolsize) return 0;
807 return ((nodes[index].reincarnation << poolsizebits) | index) + 1;
808 }
809
810 /**
811 * Overridden convenience method, behaves like the method above.
812 */
813 pool_element_id_t getID(const Iterator& it) const {
814 return getID(&*it);
815 }
816
817 /**
818 * Returns an Iterator object of the Pool data member reflected by the
819 * given abstract, unique numeric ID, it returns an invalid Iterator in
820 * case the ID is invalid or if the Pool's data element reflected by
821 * given ID was at least once released/freed back to the Pool in the
822 * meantime.
823 *
824 * Members are always translated both, from Iterators/pointers to IDs,
825 * and from IDs to Iterators/pointers in constant time.
826 *
827 * You might want to use this alternative approach of referencing Pool
828 * members under certain scenarios. For example if you need to expose
829 * an ID to the end user and/or if you want to represent an object of
830 * this pool by a smaller number instead of a native pointer (i.e. 16
831 * bits vs. 64 bits). You can also detect this way whether the object
832 * has already been freed / reallocated from the Pool in the meantime.
833 *
834 * @param id - unique ID (!= 0) of a Pool's data member
835 * @returns Iterator object pointing to Pool's data element, invalid
836 * Iterator in case ID was invalid or data element was freed
837 */
838 Iterator fromID(pool_element_id_t id) const {
839 //TODO: -1 check here is a relict from older versions of Pool.h, once it is certain that no existing code base is still using -1 for "invalid" Pool elements then this -1 check can be removed
840 if (id == 0 || id == -1) return Iterator(); // invalid iterator
841 id--;
842 const uint bits = poolsizebits;
843 uint index = id & ((1 << bits) - 1);
844 if (index >= poolsize) return Iterator(); // invalid iterator
845 Node* node = &nodes[index];
846 uint reincarnation = id >> bits;
847 if (reincarnation != node->reincarnation) return Iterator(); // invalid iterator
848 return Iterator(node);
849 }
850
851 /**
852 * Returns an Iterator object for the object pointed by @a obj. This
853 * method will check whether the supplied object is actually part of
854 * this pool, and if it is not part of this pool an invalid Iterator is
855 * returned instead.
856 *
857 * @param obj - raw pointer to an object managed by this pool
858 * @returns Iterator object pointing to the supplied object, invalid
859 * Iterator in case object is not part of this pool
860 */
861 Iterator fromPtr(const T* obj) const {
862 if (!poolsize) return Iterator(); // invalid iterator
863 int index = int( obj - &data[0] );
864 if (index < 0 || index >= poolsize) return Iterator(); // invalid iterator
865 return Iterator(&nodes[index]);
866 }
867
868 protected:
869 // caution: assumes pool (that is freelist) is not empty!
870 inline Iterator alloc() {
871 Iterator element = freelist.last();
872 element.detach();
873 return element;
874 }
875
876 inline void freeToPool(Iterator itElement) {
877 itElement.node()->bumpReincarnation(reincarnationbits);
878 freelist.append(itElement);
879 }
880
881 inline void freeToPool(Iterator itFirst, Iterator itLast) {
882 for (Node* n = itFirst.node(); true; n = n->next) {
883 n->bumpReincarnation(reincarnationbits);
884 if (n == itLast.node()) break;
885 }
886 freelist.append(itFirst, itLast);
887 }
888
889 friend class RTList<T>;
890
891 private:
892 void _init(int Elements) {
893 data = new T[Elements];
894 nodes = new Node[Elements];
895 for (int i = 0; i < Elements; i++) {
896 nodes[i].data = &data[i];
897 freelist.append(&nodes[i]);
898 }
899 poolsize = Elements;
900 poolsizebits = bitsForSize(poolsize + 1); // +1 here just because IDs are always incremented by one (to avoid them ever being zero)
901 updateReincarnationBits();
902 }
903
904 inline void updateReincarnationBits() {
905 reincarnationbits = sizeof(pool_element_id_t) * 8 - poolsizebits - reservedbits;
906 }
907
908 inline static int bitsForSize(int size) {
909 if (!size) return 0;
910 size--;
911 int bits = 0;
912 for (; size > 1; bits += 2, size >>= 2);
913 return bits + size;
914 }
915 };
916
917 #endif // __LS_POOL_H__

  ViewVC Help
Powered by ViewVC