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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3118 - (hide annotations) (download) (as text)
Fri Apr 21 13:33:03 2017 UTC (7 years 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 schoenebeck 271 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 3073 * Copyright (C) 2005 - 2017 Christian Schoenebeck *
7 schoenebeck 271 * *
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 schoenebeck 554 #ifdef HAVE_CONFIG_H
28     # include <config.h>
29 schoenebeck 271 #endif
30    
31     // we just use exceptions for debugging, better not in the final realtime thread !
32 schoenebeck 554 #ifndef CONFIG_RT_EXCEPTIONS
33     # define CONFIG_RT_EXCEPTIONS 0
34 schoenebeck 271 #endif
35    
36 schoenebeck 554 #if CONFIG_RT_EXCEPTIONS
37 schoenebeck 271 # include <stdexcept>
38     # include <string>
39 schoenebeck 554 #endif // CONFIG_RT_EXCEPTIONS
40 schoenebeck 271
41 schoenebeck 3118 #include <iostream>
42    
43 schoenebeck 554 #if CONFIG_DEVMODE
44     # include <string>
45 schoenebeck 472 const std::string __err_msg_iterator_invalidated = "Pool/RTList iterator invalidated";
46 schoenebeck 554 #endif // CONFIG_DEVMODE
47 schoenebeck 472
48 schoenebeck 1800 const std::string __err_msg_resize_while_in_use = "Pool::resizePool() ERROR: elements still in use!";
49    
50 schoenebeck 2879 /**
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 schoenebeck 271 // 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 schoenebeck 361 template<typename T1>
74 schoenebeck 271 struct _Node {
75 schoenebeck 361 _Node<T1>* next;
76     _Node<T1>* prev;
77     T1* data;
78 schoenebeck 554 #if CONFIG_DEVMODE
79 schoenebeck 361 RTListBase<T1>* list; // list to which this node currently belongs to
80 schoenebeck 554 #endif // CONFIG_DEVMODE
81 schoenebeck 2879 uint reincarnation; // just for Pool::fromID()
82 schoenebeck 271
83     _Node() {
84     next = NULL;
85     prev = NULL;
86     data = NULL;
87 schoenebeck 554 #if CONFIG_DEVMODE
88 schoenebeck 271 list = NULL;
89 schoenebeck 554 #endif // CONFIG_DEVMODE
90 schoenebeck 2598 reincarnation = 0;
91 schoenebeck 271 }
92 schoenebeck 2879
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 schoenebeck 271 };
99     typedef _Node<T> Node;
100    
101     public:
102 schoenebeck 2879 /**
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 schoenebeck 361 template<typename T1>
111 schoenebeck 271 class _Iterator {
112     public:
113     _Iterator() {
114     current = NULL;
115     fallback = NULL;
116 schoenebeck 554 #if CONFIG_DEVMODE
117 schoenebeck 271 list = NULL;
118 schoenebeck 554 #endif // CONFIG_DEVMODE
119 schoenebeck 271 }
120    
121     /// prefix increment op.
122     inline _Iterator& operator++() {
123 schoenebeck 554 #if CONFIG_DEVMODE
124 schoenebeck 472 if (!isValid()) {
125 schoenebeck 554 #if CONFIG_RT_EXCEPTIONS
126 schoenebeck 472 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 schoenebeck 554 #endif // CONFIG_RT_EXCEPTIONS
131 schoenebeck 472 }
132 schoenebeck 554 #endif // CONFIG_DEVMODE
133 schoenebeck 271 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 schoenebeck 472 ++*this; // use prefix operator implementation
142 schoenebeck 271 return preval;
143     }
144    
145     /// prefix decrement op.
146     inline _Iterator& operator--() {
147 schoenebeck 554 #if CONFIG_DEVMODE
148 schoenebeck 472 if (!isValid()) {
149 schoenebeck 554 #if CONFIG_RT_EXCEPTIONS
150 schoenebeck 472 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 schoenebeck 554 #endif // CONFIG_RT_EXCEPTIONS
155     }
156     #endif // CONFIG_DEVMODE
157 schoenebeck 271 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 schoenebeck 472 --*this; // use prefix operator implementation
166 schoenebeck 271 return preval;
167     }
168    
169 schoenebeck 361 inline T1& operator*() {
170 schoenebeck 554 #if CONFIG_DEVMODE
171 schoenebeck 472 if (!isValid()) { // if iterator became invalidated
172 schoenebeck 554 #if CONFIG_RT_EXCEPTIONS
173 schoenebeck 472 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 schoenebeck 554 #endif // CONFIG_RT_EXCEPTIONS
178 schoenebeck 472 }
179 schoenebeck 554 #endif // CONFIG_DEVMODE
180 schoenebeck 271 return *current->data;
181 schoenebeck 2598 }
182 schoenebeck 554
183 schoenebeck 2598 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 schoenebeck 271 }
196    
197 schoenebeck 361 inline T1* operator->() {
198 schoenebeck 554 #if CONFIG_DEVMODE
199 schoenebeck 472 if (!isValid()) { // if iterator became invalidated
200 schoenebeck 554 #if CONFIG_RT_EXCEPTIONS
201 schoenebeck 472 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 schoenebeck 554 #endif // CONFIG_RT_EXCEPTIONS
206 schoenebeck 472 }
207 schoenebeck 554 #endif // CONFIG_DEVMODE
208     return current->data;
209 schoenebeck 271 }
210    
211 schoenebeck 2598 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 schoenebeck 271 return current == other.current;
227     }
228    
229 schoenebeck 2598 inline bool operator!=(const _Iterator<T1> other) const {
230 schoenebeck 271 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 schoenebeck 2871 /**
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 schoenebeck 361 inline _Iterator moveToEndOf(RTListBase<T1>* pDstList) {
265 schoenebeck 271 detach();
266     pDstList->append(*this);
267     _Iterator iterOnDstList = _Iterator(current);
268     current = fallback;
269     return iterOnDstList;
270     }
271    
272 schoenebeck 2871 /**
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 schoenebeck 361 inline _Iterator moveToBeginOf(RTListBase<T1>* pDstList) {
296 schoenebeck 271 detach();
297     pDstList->prepend(*this);
298     _Iterator iterOnDstList = _Iterator(current);
299     current = fallback;
300     return iterOnDstList;
301     }
302    
303 schoenebeck 2871 /**
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 schoenebeck 554 #if CONFIG_DEVMODE
370 schoenebeck 2598 inline bool isValid() const {
371 schoenebeck 271 return current->list == list;
372     }
373 schoenebeck 554 #endif // CONFIG_DEVMODE
374 schoenebeck 271
375     protected:
376     Node* current;
377     Node* fallback;
378     enum dir_t {
379     dir_forward,
380     dir_backward
381     };
382 schoenebeck 554 #if CONFIG_DEVMODE
383 schoenebeck 361 RTListBase<T1>* list;
384 schoenebeck 554 #endif // CONFIG_DEVMODE
385 schoenebeck 271
386     _Iterator(Node* pNode, dir_t direction = dir_forward) {
387     current = pNode;
388     fallback = (direction == dir_forward) ? pNode->prev : pNode->next;
389 schoenebeck 554 #if CONFIG_DEVMODE
390 schoenebeck 271 list = pNode->list;
391 schoenebeck 554 #endif // CONFIG_DEVMODE
392 schoenebeck 271 }
393    
394     inline Node* node() {
395 schoenebeck 554 #if CONFIG_DEVMODE
396     #if CONFIG_RT_EXCEPTIONS
397 schoenebeck 271 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 schoenebeck 554 #endif // CONFIG_RT_EXCEPTIONS
402 schoenebeck 271 #else
403     return current;
404 schoenebeck 554 #endif // CONFIG_DEVMODE
405 schoenebeck 271 }
406    
407 schoenebeck 2598 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 schoenebeck 271 inline void detach() {
421 schoenebeck 361 RTListBase<T1>::detach(*this);
422 schoenebeck 271 }
423    
424 schoenebeck 361 friend class RTListBase<T1>;
425     friend class RTList<T1>;
426     friend class Pool<T1>;
427 schoenebeck 271 };
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 schoenebeck 2598 inline bool isEmpty() const {
447 schoenebeck 271 return _begin.next == &_end;
448     }
449    
450 schoenebeck 1800 inline int count() {
451     int elements = 0;
452     for (Iterator it = first(); it != end(); ++it) ++elements;
453     return elements;
454     }
455    
456 schoenebeck 271 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 schoenebeck 1800 init();
462     }
463    
464     void init() {
465 schoenebeck 271 // 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 schoenebeck 554 #if CONFIG_DEVMODE
473 schoenebeck 271 _begin.list = this;
474     _end.list = this;
475 schoenebeck 554 #endif // CONFIG_DEVMODE
476 schoenebeck 271 }
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 schoenebeck 554 #if CONFIG_DEVMODE
486 schoenebeck 271 pNode->list = this;
487 schoenebeck 554 #endif // CONFIG_DEVMODE
488 schoenebeck 271 }
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 schoenebeck 554 #if CONFIG_DEVMODE
499 schoenebeck 271 for (Node* pNode = pFirst; true; pNode = pNode->next) {
500     pNode->list = this;
501     if (pNode == pLast) break;
502     }
503 schoenebeck 554 #endif // CONFIG_DEVMODE
504 schoenebeck 271 }
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 schoenebeck 554 #if CONFIG_DEVMODE
514 schoenebeck 271 pNode->list = this;
515 schoenebeck 554 #endif // CONFIG_DEVMODE
516 schoenebeck 271 }
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 schoenebeck 554 #if CONFIG_DEVMODE
527 schoenebeck 271 for (Node* pNode = pFirst; true; pNode = pNode->next) {
528     pNode->list = this;
529     if (pNode == pLast) break;
530     }
531 schoenebeck 554 #endif // CONFIG_DEVMODE
532 schoenebeck 271 }
533    
534 schoenebeck 2871 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 schoenebeck 271 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 schoenebeck 277 friend class _Iterator<T>;
576     friend class RTList<T>;
577 schoenebeck 271 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 iliev 2244
596     /**
597     * Copy constructor
598     */
599     RTList(RTList<T>& list) : RTListBase<T>::RTListBase() {
600     this->pPool = list.pPool;
601 iliev 2247 Iterator it = list.first();
602     Iterator end = list.end();
603 iliev 2244 for(; it != end; ++it) {
604     if (poolIsEmpty()) break;
605     *(allocAppend()) = *it;
606     }
607     }
608 schoenebeck 271
609     virtual ~RTList() {
610     clear();
611     }
612    
613 schoenebeck 2598 inline bool poolIsEmpty() const {
614 schoenebeck 271 return pPool->poolIsEmpty();
615     }
616    
617     inline Iterator allocAppend() {
618     if (pPool->poolIsEmpty()) return RTListBase<T>::begin();
619     Iterator element = pPool->alloc();
620 persson 2335 this->append(element);
621 schoenebeck 554 #if CONFIG_DEVMODE
622 schoenebeck 271 element.list = this;
623 schoenebeck 554 #endif // CONFIG_DEVMODE
624 schoenebeck 271 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 schoenebeck 554 #if CONFIG_DEVMODE
632 schoenebeck 271 element.list = this;
633 schoenebeck 554 #endif // CONFIG_DEVMODE
634 schoenebeck 271 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 schoenebeck 3073 inline pool_element_id_t getID(const T* obj) const {
653 schoenebeck 2598 return pPool->getID(obj);
654     }
655    
656 schoenebeck 3073 inline pool_element_id_t getID(const Iterator& it) const {
657 schoenebeck 2598 return pPool->getID(&*it);
658     }
659    
660 schoenebeck 2879 inline Iterator fromID(pool_element_id_t id) const {
661 schoenebeck 2598 return pPool->fromID(id);
662     }
663    
664 schoenebeck 2871 inline Iterator fromPtr(const T* obj) const {
665     return pPool->fromPtr(obj);
666     }
667    
668 schoenebeck 271 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 schoenebeck 2879 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 schoenebeck 271
687 schoenebeck 2879 Pool(int Elements) : RTList<T>::RTList(this), reservedbits(0) {
688 schoenebeck 1800 _init(Elements);
689 schoenebeck 271 }
690    
691     virtual ~Pool() {
692     if (nodes) delete[] nodes;
693     if (data) delete[] data;
694     }
695    
696 schoenebeck 2598 inline bool poolIsEmpty() const {
697 schoenebeck 271 return freelist.isEmpty();
698     }
699    
700 schoenebeck 1800 /**
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 schoenebeck 2879 uint poolSize() const {
709 schoenebeck 1800 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 schoenebeck 2598 /**
742 schoenebeck 2879 * 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 schoenebeck 2598 * Returns an abstract, unique numeric ID for the given object of
760 schoenebeck 2879 * this pool, it returns 0 in case the passed object is not a member
761 schoenebeck 2598 * 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 schoenebeck 2879 *
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 schoenebeck 2598 *
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 schoenebeck 2879 * @returns unique numeric ID (!= 0) of @a obj or 0 if pointer was invalid
783 schoenebeck 2598 */
784 schoenebeck 2879 pool_element_id_t getID(const T* obj) const {
785     if (!poolsize) return 0;
786 schoenebeck 3054 int index = int( obj - &data[0] );
787 schoenebeck 2879 if (index < 0 || index >= poolsize) return 0;
788     return ((nodes[index].reincarnation << poolsizebits) | index) + 1;
789 schoenebeck 2598 }
790    
791     /**
792     * Overridden convenience method, behaves like the method above.
793     */
794 schoenebeck 3073 pool_element_id_t getID(const Iterator& it) const {
795 schoenebeck 2598 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 schoenebeck 2879 * @param id - unique ID (!= 0) of a Pool's data member
816 schoenebeck 2598 * @returns Iterator object pointing to Pool's data element, invalid
817     * Iterator in case ID was invalid or data element was freed
818     */
819 schoenebeck 2879 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 schoenebeck 2598 uint index = id & ((1 << bits) - 1);
825     if (index >= poolsize) return Iterator(); // invalid iterator
826     Node* node = &nodes[index];
827 schoenebeck 2879 uint reincarnation = id >> bits;
828 schoenebeck 2598 if (reincarnation != node->reincarnation) return Iterator(); // invalid iterator
829     return Iterator(node);
830     }
831    
832 schoenebeck 2871 /**
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 schoenebeck 3054 int index = int( obj - &data[0] );
845 schoenebeck 2871 if (index < 0 || index >= poolsize) return Iterator(); // invalid iterator
846     return Iterator(&nodes[index]);
847     }
848    
849 schoenebeck 271 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 schoenebeck 2879 itElement.node()->bumpReincarnation(reincarnationbits);
859 schoenebeck 271 freelist.append(itElement);
860     }
861    
862     inline void freeToPool(Iterator itFirst, Iterator itLast) {
863 schoenebeck 2598 for (Node* n = itFirst.node(); true; n = n->next) {
864 schoenebeck 2879 n->bumpReincarnation(reincarnationbits);
865 schoenebeck 2598 if (n == itLast.node()) break;
866     }
867 schoenebeck 271 freelist.append(itFirst, itLast);
868     }
869    
870     friend class RTList<T>;
871 schoenebeck 1800
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 schoenebeck 2879 poolsizebits = bitsForSize(poolsize + 1); // +1 here just because IDs are always incremented by one (to avoid them ever being zero)
882     updateReincarnationBits();
883 schoenebeck 1800 }
884 schoenebeck 2598
885 schoenebeck 2879 inline void updateReincarnationBits() {
886     reincarnationbits = sizeof(pool_element_id_t) * 8 - poolsizebits - reservedbits;
887     }
888    
889 schoenebeck 2598 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 schoenebeck 271 };
897    
898     #endif // __LS_POOL_H__

  ViewVC Help
Powered by ViewVC