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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2871 - (show 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 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2016 Christian Schoenebeck *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #ifndef __LS_POOL_H__
25 #define __LS_POOL_H__
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 // we just use exceptions for debugging, better not in the final realtime thread !
32 #ifndef CONFIG_RT_EXCEPTIONS
33 # define CONFIG_RT_EXCEPTIONS 0
34 #endif
35
36 #if CONFIG_RT_EXCEPTIONS
37 # include <stdexcept>
38 # include <string>
39 #endif // CONFIG_RT_EXCEPTIONS
40
41 #if CONFIG_DEVMODE
42 # include <string>
43 # include <iostream>
44 const std::string __err_msg_iterator_invalidated = "Pool/RTList iterator invalidated";
45 #endif // CONFIG_DEVMODE
46
47 const std::string __err_msg_resize_while_in_use = "Pool::resizePool() ERROR: elements still in use!";
48
49 // 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 template<typename T1>
57 struct _Node {
58 _Node<T1>* next;
59 _Node<T1>* prev;
60 T1* data;
61 #if CONFIG_DEVMODE
62 RTListBase<T1>* list; // list to which this node currently belongs to
63 #endif // CONFIG_DEVMODE
64 int reincarnation; // just for Pool::fromID()
65
66 _Node() {
67 next = NULL;
68 prev = NULL;
69 data = NULL;
70 #if CONFIG_DEVMODE
71 list = NULL;
72 #endif // CONFIG_DEVMODE
73 reincarnation = 0;
74 }
75 };
76 typedef _Node<T> Node;
77
78 public:
79 template<typename T1>
80 class _Iterator {
81 public:
82 _Iterator() {
83 current = NULL;
84 fallback = NULL;
85 #if CONFIG_DEVMODE
86 list = NULL;
87 #endif // CONFIG_DEVMODE
88 }
89
90 /// prefix increment op.
91 inline _Iterator& operator++() {
92 #if CONFIG_DEVMODE
93 if (!isValid()) {
94 #if CONFIG_RT_EXCEPTIONS
95 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 #endif // CONFIG_RT_EXCEPTIONS
100 }
101 #endif // CONFIG_DEVMODE
102 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 ++*this; // use prefix operator implementation
111 return preval;
112 }
113
114 /// prefix decrement op.
115 inline _Iterator& operator--() {
116 #if CONFIG_DEVMODE
117 if (!isValid()) {
118 #if CONFIG_RT_EXCEPTIONS
119 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 #endif // CONFIG_RT_EXCEPTIONS
124 }
125 #endif // CONFIG_DEVMODE
126 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 --*this; // use prefix operator implementation
135 return preval;
136 }
137
138 inline T1& operator*() {
139 #if CONFIG_DEVMODE
140 if (!isValid()) { // if iterator became invalidated
141 #if CONFIG_RT_EXCEPTIONS
142 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 #endif // CONFIG_RT_EXCEPTIONS
147 }
148 #endif // CONFIG_DEVMODE
149 return *current->data;
150 }
151
152 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 }
165
166 inline T1* operator->() {
167 #if CONFIG_DEVMODE
168 if (!isValid()) { // if iterator became invalidated
169 #if CONFIG_RT_EXCEPTIONS
170 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 #endif // CONFIG_RT_EXCEPTIONS
175 }
176 #endif // CONFIG_DEVMODE
177 return current->data;
178 }
179
180 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 return current == other.current;
196 }
197
198 inline bool operator!=(const _Iterator<T1> other) const {
199 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 /**
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 inline _Iterator moveToEndOf(RTListBase<T1>* pDstList) {
234 detach();
235 pDstList->append(*this);
236 _Iterator iterOnDstList = _Iterator(current);
237 current = fallback;
238 return iterOnDstList;
239 }
240
241 /**
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 inline _Iterator moveToBeginOf(RTListBase<T1>* pDstList) {
265 detach();
266 pDstList->prepend(*this);
267 _Iterator iterOnDstList = _Iterator(current);
268 current = fallback;
269 return iterOnDstList;
270 }
271
272 /**
273 * Moves the element pointed by this Iterator from its current
274 * 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 #if CONFIG_DEVMODE
339 inline bool isValid() const {
340 return current->list == list;
341 }
342 #endif // CONFIG_DEVMODE
343
344 protected:
345 Node* current;
346 Node* fallback;
347 enum dir_t {
348 dir_forward,
349 dir_backward
350 };
351 #if CONFIG_DEVMODE
352 RTListBase<T1>* list;
353 #endif // CONFIG_DEVMODE
354
355 _Iterator(Node* pNode, dir_t direction = dir_forward) {
356 current = pNode;
357 fallback = (direction == dir_forward) ? pNode->prev : pNode->next;
358 #if CONFIG_DEVMODE
359 list = pNode->list;
360 #endif // CONFIG_DEVMODE
361 }
362
363 inline Node* node() {
364 #if CONFIG_DEVMODE
365 #if CONFIG_RT_EXCEPTIONS
366 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 #endif // CONFIG_RT_EXCEPTIONS
371 #else
372 return current;
373 #endif // CONFIG_DEVMODE
374 }
375
376 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 inline void detach() {
390 RTListBase<T1>::detach(*this);
391 }
392
393 friend class RTListBase<T1>;
394 friend class RTList<T1>;
395 friend class Pool<T1>;
396 };
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 inline bool isEmpty() const {
416 return _begin.next == &_end;
417 }
418
419 inline int count() {
420 int elements = 0;
421 for (Iterator it = first(); it != end(); ++it) ++elements;
422 return elements;
423 }
424
425 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 init();
431 }
432
433 void init() {
434 // 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 #if CONFIG_DEVMODE
442 _begin.list = this;
443 _end.list = this;
444 #endif // CONFIG_DEVMODE
445 }
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 #if CONFIG_DEVMODE
455 pNode->list = this;
456 #endif // CONFIG_DEVMODE
457 }
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 #if CONFIG_DEVMODE
468 for (Node* pNode = pFirst; true; pNode = pNode->next) {
469 pNode->list = this;
470 if (pNode == pLast) break;
471 }
472 #endif // CONFIG_DEVMODE
473 }
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 #if CONFIG_DEVMODE
483 pNode->list = this;
484 #endif // CONFIG_DEVMODE
485 }
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 #if CONFIG_DEVMODE
496 for (Node* pNode = pFirst; true; pNode = pNode->next) {
497 pNode->list = this;
498 if (pNode == pLast) break;
499 }
500 #endif // CONFIG_DEVMODE
501 }
502
503 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 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 friend class _Iterator<T>;
545 friend class RTList<T>;
546 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
565 /**
566 * Copy constructor
567 */
568 RTList(RTList<T>& list) : RTListBase<T>::RTListBase() {
569 this->pPool = list.pPool;
570 Iterator it = list.first();
571 Iterator end = list.end();
572 for(; it != end; ++it) {
573 if (poolIsEmpty()) break;
574 *(allocAppend()) = *it;
575 }
576 }
577
578 virtual ~RTList() {
579 clear();
580 }
581
582 inline bool poolIsEmpty() const {
583 return pPool->poolIsEmpty();
584 }
585
586 inline Iterator allocAppend() {
587 if (pPool->poolIsEmpty()) return RTListBase<T>::begin();
588 Iterator element = pPool->alloc();
589 this->append(element);
590 #if CONFIG_DEVMODE
591 element.list = this;
592 #endif // CONFIG_DEVMODE
593 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 #if CONFIG_DEVMODE
601 element.list = this;
602 #endif // CONFIG_DEVMODE
603 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 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 inline Iterator fromPtr(const T* obj) const {
634 return pPool->fromPtr(obj);
635 }
636
637 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 int poolsize;
651
652 Pool(int Elements) : RTList<T>::RTList(this) {
653 _init(Elements);
654 }
655
656 virtual ~Pool() {
657 if (nodes) delete[] nodes;
658 if (data) delete[] data;
659 }
660
661 inline bool poolIsEmpty() const {
662 return freelist.isEmpty();
663 }
664
665 /**
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 /**
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 /**
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 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 itElement.node()->reincarnation++;
801 freelist.append(itElement);
802 }
803
804 inline void freeToPool(Iterator itFirst, Iterator itLast) {
805 for (Node* n = itFirst.node(); true; n = n->next) {
806 n->reincarnation++;
807 if (n == itLast.node()) break;
808 }
809 freelist.append(itFirst, itLast);
810 }
811
812 friend class RTList<T>;
813
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
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 };
833
834 #endif // __LS_POOL_H__

  ViewVC Help
Powered by ViewVC