/[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 2871 - (hide annotations) (download) (as text)
Sun Apr 10 18:22:23 2016 UTC (8 years ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 33648 byte(s)
* All engines: Implemented scheduler for delayed MIDI events and for
  suspended real-time instrument scripts.
* Real-Time instrument scripts: Implemented support for built-in "wait()"
  function's "duration-us" argument, thus scripts using this function are
  now correctly resumed after the requested amount of microseconds.
* Real-Time instrument scripts: Implemented support for built-in
  "play_note()" function's "duration-us" argument, thus notes triggered
  with this argument are now correctly released after the requested amount
  of microseconds.
* Real-Time instrument scripts: Fixed crash which happened when trying to
  reference an undeclared script variable.
* Real-Time instrument scripts: Script events were not cleared when
  engine channel was reset, potentially causing undefined behavior.
* All engines: Attempt to partly fix resetting engine channels vs.
  resetting engine, an overall cleanup of the Reset*(),
  ConnectAudioDevice(), DisconnectAudioDevice() API methods would still be
  desirable though, because the current situation is still inconsistent
  and error prone.
* Bumped version (2.0.0.svn2).

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

  ViewVC Help
Powered by ViewVC