/[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 3118 - (show annotations) (download) (as text)
Fri Apr 21 13:33:03 2017 UTC (4 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 37269 byte(s)
* NKSP: Fixed crash when using built-in script array variable "%ALL_EVENTS".
* NKSP: Added built-in function "change_amp_lfo_depth()".
* NKSP: Added built-in function "change_amp_lfo_freq()".
* NKSP: Added built-in function "change_pitch_lfo_depth()".
* NKSP: Added built-in function "change_pitch_lfo_freq()".
* Bumped version (2.0.0.svn44).

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 inline bool poolIsEmpty() const {
697 return freelist.isEmpty();
698 }
699
700 /**
701 * Returns the current size of the pool, that is the amount of
702 * pre-allocated elements from the operating system. It equals the
703 * amount of elements given to the constructor unless resizePool()
704 * is called.
705 *
706 * @see resizePool()
707 */
708 uint poolSize() const {
709 return poolsize;
710 }
711
712 /**
713 * Alters the amount of elements to be pre-allocated from the
714 * operating system for this pool object.
715 *
716 * @e CAUTION: you MUST free all elements in use before calling this
717 * method ( e.g. by calling clear() )! Also make sure that no
718 * references of elements before this call will still be used after this
719 * call, since all elements will be reallocated and their old memory
720 * addresses become invalid!
721 *
722 * @see poolSize()
723 */
724 void resizePool(int Elements) {
725 if (freelist.count() != poolsize) {
726 #if CONFIG_DEVMODE
727 throw std::runtime_error(__err_msg_resize_while_in_use);
728 #else
729 std::cerr << __err_msg_resize_while_in_use << std::endl << std::flush;
730 // if we're here something's terribly wrong, but we try to do the best
731 RTList<T>::clear();
732 #endif
733 }
734 if (nodes) delete[] nodes;
735 if (data) delete[] data;
736 freelist.init();
737 RTListBase<T>::init();
738 _init(Elements);
739 }
740
741 /**
742 * Sets the amount of bits on the left hand side of pool_element_id_t
743 * numbers to be reserved for 3rd party usage. So if you pass @c 1 for
744 * argument @a bits for example, then all generated element IDs will be
745 * maximum 31 bit large.
746 *
747 * By default there are no reserved bits, and thus by default all IDs
748 * are max. 32 bit large.
749 *
750 * @param bits - amount of bits to reserve on every ID for other purposes
751 * @see pool_element_id_t
752 */
753 void setPoolElementIDsReservedBits(uint bits) {
754 reservedbits = bits;
755 updateReincarnationBits();
756 }
757
758 /**
759 * Returns an abstract, unique numeric ID for the given object of
760 * this pool, it returns 0 in case the passed object is not a member
761 * of this Pool, i.e. because it is simply an invalid pointer or member
762 * of another Pool. The returned ID is unique among all elements of this
763 * Pool and it differs with each reincarnation of an object. That means
764 * each time you free an element to and allocate the same element back
765 * from the Pool, it will have a different ID.
766 *
767 * A valid ID will never be zero, so you may use ID values of 0 in your
768 * data structures for special purposes (i.e. reflecting an invalid
769 * object ID or not yet assigned object).
770 *
771 * Members are always translated both, from Iterators/pointers to IDs,
772 * and from IDs to Iterators/pointers in constant time.
773 *
774 * You might want to use this alternative approach of referencing Pool
775 * members under certain scenarios. For example if you need to expose
776 * an ID to the end user and/or if you want to represent an object of
777 * this pool by a smaller number instead of a native pointer (i.e. 16
778 * bits vs. 64 bits). You can also detect this way whether the object
779 * has already been freed / reallocated from the Pool in the meantime.
780 *
781 * @param obj - raw pointer to a data member of this Pool
782 * @returns unique numeric ID (!= 0) of @a obj or 0 if pointer was invalid
783 */
784 pool_element_id_t getID(const T* obj) const {
785 if (!poolsize) return 0;
786 int index = int( obj - &data[0] );
787 if (index < 0 || index >= poolsize) return 0;
788 return ((nodes[index].reincarnation << poolsizebits) | index) + 1;
789 }
790
791 /**
792 * Overridden convenience method, behaves like the method above.
793 */
794 pool_element_id_t getID(const Iterator& it) const {
795 return getID(&*it);
796 }
797
798 /**
799 * Returns an Iterator object of the Pool data member reflected by the
800 * given abstract, unique numeric ID, it returns an invalid Iterator in
801 * case the ID is invalid or if the Pool's data element reflected by
802 * given ID was at least once released/freed back to the Pool in the
803 * meantime.
804 *
805 * Members are always translated both, from Iterators/pointers to IDs,
806 * and from IDs to Iterators/pointers in constant time.
807 *
808 * You might want to use this alternative approach of referencing Pool
809 * members under certain scenarios. For example if you need to expose
810 * an ID to the end user and/or if you want to represent an object of
811 * this pool by a smaller number instead of a native pointer (i.e. 16
812 * bits vs. 64 bits). You can also detect this way whether the object
813 * has already been freed / reallocated from the Pool in the meantime.
814 *
815 * @param id - unique ID (!= 0) of a Pool's data member
816 * @returns Iterator object pointing to Pool's data element, invalid
817 * Iterator in case ID was invalid or data element was freed
818 */
819 Iterator fromID(pool_element_id_t id) const {
820 //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
821 if (id == 0 || id == -1) return Iterator(); // invalid iterator
822 id--;
823 const uint bits = poolsizebits;
824 uint index = id & ((1 << bits) - 1);
825 if (index >= poolsize) return Iterator(); // invalid iterator
826 Node* node = &nodes[index];
827 uint reincarnation = id >> bits;
828 if (reincarnation != node->reincarnation) return Iterator(); // invalid iterator
829 return Iterator(node);
830 }
831
832 /**
833 * Returns an Iterator object for the object pointed by @a obj. This
834 * method will check whether the supplied object is actually part of
835 * this pool, and if it is not part of this pool an invalid Iterator is
836 * returned instead.
837 *
838 * @param obj - raw pointer to an object managed by this pool
839 * @returns Iterator object pointing to the supplied object, invalid
840 * Iterator in case object is not part of this pool
841 */
842 Iterator fromPtr(const T* obj) const {
843 if (!poolsize) return Iterator(); // invalid iterator
844 int index = int( obj - &data[0] );
845 if (index < 0 || index >= poolsize) return Iterator(); // invalid iterator
846 return Iterator(&nodes[index]);
847 }
848
849 protected:
850 // caution: assumes pool (that is freelist) is not empty!
851 inline Iterator alloc() {
852 Iterator element = freelist.last();
853 element.detach();
854 return element;
855 }
856
857 inline void freeToPool(Iterator itElement) {
858 itElement.node()->bumpReincarnation(reincarnationbits);
859 freelist.append(itElement);
860 }
861
862 inline void freeToPool(Iterator itFirst, Iterator itLast) {
863 for (Node* n = itFirst.node(); true; n = n->next) {
864 n->bumpReincarnation(reincarnationbits);
865 if (n == itLast.node()) break;
866 }
867 freelist.append(itFirst, itLast);
868 }
869
870 friend class RTList<T>;
871
872 private:
873 void _init(int Elements) {
874 data = new T[Elements];
875 nodes = new Node[Elements];
876 for (int i = 0; i < Elements; i++) {
877 nodes[i].data = &data[i];
878 freelist.append(&nodes[i]);
879 }
880 poolsize = Elements;
881 poolsizebits = bitsForSize(poolsize + 1); // +1 here just because IDs are always incremented by one (to avoid them ever being zero)
882 updateReincarnationBits();
883 }
884
885 inline void updateReincarnationBits() {
886 reincarnationbits = sizeof(pool_element_id_t) * 8 - poolsizebits - reservedbits;
887 }
888
889 inline static int bitsForSize(int size) {
890 if (!size) return 0;
891 size--;
892 int bits = 0;
893 for (; size > 1; bits += 2, size >>= 2);
894 return bits + size;
895 }
896 };
897
898 #endif // __LS_POOL_H__

  ViewVC Help
Powered by ViewVC