/[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 3557 - (hide annotations) (download) (as text)
Sun Aug 18 00:06:04 2019 UTC (4 years, 8 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 38305 byte(s)
* NKSP: Introducing 64 bit support for NKSP integer scripts
  variables (declare $foo).
* Require C++11 compiler support.
* Autoconf: Added m4/ax_cxx_compile_stdcxx.m4 macro which is used
  for checking in configure for C++11 support (as mandatory
  requirement) and automatically adds compiler argument if required
  (e.g. -std=C++11).
* Bumped version (2.1.1.svn3).

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

  ViewVC Help
Powered by ViewVC