/[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 1800 - (show annotations) (download) (as text)
Sun Dec 7 01:26:46 2008 UTC (15 years, 3 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 19080 byte(s)
* maximum voices and disk streams can now be altered at runtime (added new
  LSCP commands "GET VOICES", "SET VOICES", "GET STREAMS", "SET STREAMS"
  and accordingly new LSCP events "GLOBAL_INFO:VOICES" and
  "GLOBAL_INFO:STREAMS")
* bumped version to 0.5.1.8cvs

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2008 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
65 _Node() {
66 next = NULL;
67 prev = NULL;
68 data = NULL;
69 #if CONFIG_DEVMODE
70 list = NULL;
71 #endif // CONFIG_DEVMODE
72 }
73 };
74 typedef _Node<T> Node;
75
76 public:
77 template<typename T1>
78 class _Iterator {
79 public:
80 _Iterator() {
81 current = NULL;
82 fallback = NULL;
83 #if CONFIG_DEVMODE
84 list = NULL;
85 #endif // CONFIG_DEVMODE
86 }
87
88 /// prefix increment op.
89 inline _Iterator& operator++() {
90 #if CONFIG_DEVMODE
91 if (!isValid()) {
92 #if CONFIG_RT_EXCEPTIONS
93 throw std::runtime_error(__err_msg_iterator_invalidated);
94 #else
95 std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
96 return *(_Iterator*)NULL; // force segfault if iterator became invalidated
97 #endif // CONFIG_RT_EXCEPTIONS
98 }
99 #endif // CONFIG_DEVMODE
100 fallback = current;
101 current = current->next;
102 return *this;
103 }
104
105 /// postfix increment op.
106 inline _Iterator operator++(int) {
107 _Iterator preval = *this;
108 ++*this; // use prefix operator implementation
109 return preval;
110 }
111
112 /// prefix decrement op.
113 inline _Iterator& operator--() {
114 #if CONFIG_DEVMODE
115 if (!isValid()) {
116 #if CONFIG_RT_EXCEPTIONS
117 throw std::runtime_error(__err_msg_iterator_invalidated);
118 #else
119 std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
120 return *(_Iterator*)NULL; // force segfault if iterator became invalidated
121 #endif // CONFIG_RT_EXCEPTIONS
122 }
123 #endif // CONFIG_DEVMODE
124 fallback = current;
125 current = current->prev;
126 return *this;
127 }
128
129 /// postfix decrement op.
130 inline _Iterator operator--(int) {
131 _Iterator preval = *this;
132 --*this; // use prefix operator implementation
133 return preval;
134 }
135
136 inline T1& operator*() {
137 #if CONFIG_DEVMODE
138 if (!isValid()) { // if iterator became invalidated
139 #if CONFIG_RT_EXCEPTIONS
140 throw std::runtime_error(__err_msg_iterator_invalidated);
141 #else
142 std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
143 return *((T1*)NULL); // force segfault if iterator became invalidated
144 #endif // CONFIG_RT_EXCEPTIONS
145 }
146 #endif // CONFIG_DEVMODE
147 return *current->data;
148
149 }
150
151 inline T1* operator->() {
152 #if CONFIG_DEVMODE
153 if (!isValid()) { // if iterator became invalidated
154 #if CONFIG_RT_EXCEPTIONS
155 throw std::runtime_error(__err_msg_iterator_invalidated);
156 #else
157 std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
158 return (T1*)NULL; // force segfault if iterator became invalidated
159 #endif // CONFIG_RT_EXCEPTIONS
160 }
161 #endif // CONFIG_DEVMODE
162 return current->data;
163 }
164
165 inline bool operator==(const _Iterator<T1> other) {
166 return current == other.current;
167 }
168
169 inline bool operator!=(const _Iterator<T1> other) {
170 return current != other.current;
171 }
172
173 inline operator bool() const {
174 return current && current->data;
175 }
176
177 inline bool operator!() const {
178 return !(current && current->data);
179 }
180
181 inline _Iterator moveToEndOf(RTListBase<T1>* pDstList) {
182 detach();
183 pDstList->append(*this);
184 _Iterator iterOnDstList = _Iterator(current);
185 current = fallback;
186 return iterOnDstList;
187 }
188
189 inline _Iterator moveToBeginOf(RTListBase<T1>* pDstList) {
190 detach();
191 pDstList->prepend(*this);
192 _Iterator iterOnDstList = _Iterator(current);
193 current = fallback;
194 return iterOnDstList;
195 }
196
197 #if CONFIG_DEVMODE
198 inline bool isValid() {
199 return current->list == list;
200 }
201 #endif // CONFIG_DEVMODE
202
203 protected:
204 Node* current;
205 Node* fallback;
206 enum dir_t {
207 dir_forward,
208 dir_backward
209 };
210 #if CONFIG_DEVMODE
211 RTListBase<T1>* list;
212 #endif // CONFIG_DEVMODE
213
214 _Iterator(Node* pNode, dir_t direction = dir_forward) {
215 current = pNode;
216 fallback = (direction == dir_forward) ? pNode->prev : pNode->next;
217 #if CONFIG_DEVMODE
218 list = pNode->list;
219 #endif // CONFIG_DEVMODE
220 }
221
222 inline Node* node() {
223 #if CONFIG_DEVMODE
224 #if CONFIG_RT_EXCEPTIONS
225 if (isValid()) return current;
226 else throw std::runtime_error(__err_msg_iterator_invalidated);
227 #else
228 return (isValid()) ? current : (Node*)NULL; // force segfault if iterator became invalidated
229 #endif // CONFIG_RT_EXCEPTIONS
230 #else
231 return current;
232 #endif // CONFIG_DEVMODE
233 }
234
235 inline void detach() {
236 RTListBase<T1>::detach(*this);
237 }
238
239 friend class RTListBase<T1>;
240 friend class RTList<T1>;
241 friend class Pool<T1>;
242 };
243 typedef _Iterator<T> Iterator;
244
245 inline Iterator first() {
246 return Iterator(_begin.next, Iterator::dir_forward);
247 }
248
249 inline Iterator last() {
250 return Iterator(_end.prev, Iterator::dir_backward);
251 }
252
253 inline Iterator begin() {
254 return Iterator(&_begin, Iterator::dir_forward);
255 }
256
257 inline Iterator end() {
258 return Iterator(&_end, Iterator::dir_backward);
259 }
260
261 inline bool isEmpty() {
262 return _begin.next == &_end;
263 }
264
265 inline int count() {
266 int elements = 0;
267 for (Iterator it = first(); it != end(); ++it) ++elements;
268 return elements;
269 }
270
271 protected:
272 Node _begin; // fake node (without data) which represents the begin of the list - not the first element!
273 Node _end; // fake node (without data) which represents the end of the list - not the last element!
274
275 RTListBase() {
276 init();
277 }
278
279 void init() {
280 // initialize boundary nodes
281 _begin.prev = &_begin;
282 _begin.next = &_end;
283 _begin.data = NULL;
284 _end.next = &_end;
285 _end.prev = &_begin;
286 _end.data = NULL;
287 #if CONFIG_DEVMODE
288 _begin.list = this;
289 _end.list = this;
290 #endif // CONFIG_DEVMODE
291 }
292
293 inline void append(Iterator itElement) {
294 Node* pNode = itElement.current;
295 Node* last = _end.prev;
296 last->next = pNode;
297 pNode->prev = last; // if a segfault happens here, then because 'itElement' Iterator became invalidated
298 pNode->next = &_end;
299 _end.prev = pNode;
300 #if CONFIG_DEVMODE
301 pNode->list = this;
302 #endif // CONFIG_DEVMODE
303 }
304
305 inline void append(Iterator itFirst, Iterator itLast) {
306 Node* pFirst = itFirst.current;
307 Node* pLast = itLast.current;
308 Node* last = _end.prev;
309 last->next = pFirst;
310 pFirst->prev = last; // if a segfault happens here, then because 'itFirst' Iterator became invalidated
311 pLast->next = &_end; // if a segfault happens here, then because 'itLast' Iterator became invalidated
312 _end.prev = pLast;
313 #if CONFIG_DEVMODE
314 for (Node* pNode = pFirst; true; pNode = pNode->next) {
315 pNode->list = this;
316 if (pNode == pLast) break;
317 }
318 #endif // CONFIG_DEVMODE
319 }
320
321 inline void prepend(Iterator itElement) {
322 Node* pNode = itElement.current;
323 Node* first = _begin.next;
324 _begin.next = pNode;
325 pNode->prev = &_begin; // if a segfault happens here, then because 'itElement' Iterator became invalidated
326 pNode->next = first;
327 first->prev = pNode;
328 #if CONFIG_DEVMODE
329 pNode->list = this;
330 #endif // CONFIG_DEVMODE
331 }
332
333 inline void prepend(Iterator itFirst, Iterator itLast) {
334 Node* pFirst = itFirst.current;
335 Node* pLast = itLast.current;
336 Node* first = _begin.next;
337 _begin.next = pFirst;
338 pFirst->prev = &_begin; // if a segfault happens here, then because 'itFirst' Iterator became invalidated
339 pLast->next = first; // if a segfault happens here, then because 'itLast' Iterator became invalidated
340 first->prev = pLast;
341 #if CONFIG_DEVMODE
342 for (Node* pNode = pFirst; true; pNode = pNode->next) {
343 pNode->list = this;
344 if (pNode == pLast) break;
345 }
346 #endif // CONFIG_DEVMODE
347 }
348
349 static inline void detach(Iterator itElement) {
350 Node* pNode = itElement.node();
351 Node* prev = pNode->prev; // if a segfault happens here, then because 'itElement' Iterator became invalidated
352 Node* next = pNode->next;
353 prev->next = next;
354 next->prev = prev;
355 }
356
357 static inline void detach(Iterator itFirst, Iterator itLast) {
358 Node* prev = itFirst.node()->prev; // if a segfault happens here, then because 'itFirst' Iterator became invalidated
359 Node* next = itLast.node()->next; // if a segfault happens here, then because 'itLast' Iterator became invalidated
360 prev->next = next;
361 next->prev = prev;
362 }
363
364 friend class _Iterator<T>;
365 friend class RTList<T>;
366 friend class Pool<T>;
367 };
368
369 template<typename T>
370 class RTList : public RTListBase<T> {
371 public:
372 typedef typename RTListBase<T>::Node Node;
373 typedef typename RTListBase<T>::Iterator Iterator;
374
375 /**
376 * Constructor
377 *
378 * @param pPool - pool this list uses for allocation and
379 * deallocation of elements
380 */
381 RTList(Pool<T>* pPool) : RTListBase<T>::RTListBase() {
382 this->pPool = pPool;
383 }
384
385 virtual ~RTList() {
386 clear();
387 }
388
389 inline bool poolIsEmpty() {
390 return pPool->poolIsEmpty();
391 }
392
393 inline Iterator allocAppend() {
394 if (pPool->poolIsEmpty()) return RTListBase<T>::begin();
395 Iterator element = pPool->alloc();
396 append(element);
397 #if CONFIG_DEVMODE
398 element.list = this;
399 #endif // CONFIG_DEVMODE
400 return element;
401 }
402
403 inline Iterator allocPrepend() {
404 if (pPool->poolIsEmpty()) return RTListBase<T>::end();
405 Iterator element = pPool->alloc();
406 prepend(element);
407 #if CONFIG_DEVMODE
408 element.list = this;
409 #endif // CONFIG_DEVMODE
410 return element;
411 }
412
413 inline void free(Iterator& itElement) {
414 itElement.detach();
415 pPool->freeToPool(itElement);
416 itElement.current = itElement.fallback;
417 }
418
419 inline void clear() {
420 if (!RTListBase<T>::isEmpty()) {
421 Node* first = RTListBase<T>::_begin.next;
422 Node* last = RTListBase<T>::_end.prev;
423 RTListBase<T>::detach(first, last);
424 pPool->freeToPool(first, last);
425 }
426 }
427
428 protected:
429 Pool<T>* pPool;
430 };
431
432 template<typename T>
433 class Pool : public RTList<T> {
434 public:
435 typedef typename RTList<T>::Node Node;
436 typedef typename RTList<T>::Iterator Iterator;
437
438 Node* nodes;
439 T* data;
440 RTListBase<T> freelist; // not yet allocated elements
441 int poolsize;
442
443 Pool(int Elements) : RTList<T>::RTList(this) {
444 _init(Elements);
445 }
446
447 virtual ~Pool() {
448 if (nodes) delete[] nodes;
449 if (data) delete[] data;
450 }
451
452 inline bool poolIsEmpty() {
453 return freelist.isEmpty();
454 }
455
456 /**
457 * Returns the current size of the pool, that is the amount of
458 * pre-allocated elements from the operating system. It equals the
459 * amount of elements given to the constructor unless resizePool()
460 * is called.
461 *
462 * @see resizePool()
463 */
464 int poolSize() const {
465 return poolsize;
466 }
467
468 /**
469 * Alters the amount of elements to be pre-allocated from the
470 * operating system for this pool object.
471 *
472 * @e CAUTION: you MUST free all elements in use before calling this
473 * method ( e.g. by calling clear() )! Also make sure that no
474 * references of elements before this call will still be used after this
475 * call, since all elements will be reallocated and their old memory
476 * addresses become invalid!
477 *
478 * @see poolSize()
479 */
480 void resizePool(int Elements) {
481 if (freelist.count() != poolsize) {
482 #if CONFIG_DEVMODE
483 throw std::runtime_error(__err_msg_resize_while_in_use);
484 #else
485 std::cerr << __err_msg_resize_while_in_use << std::endl << std::flush;
486 // if we're here something's terribly wrong, but we try to do the best
487 RTList<T>::clear();
488 #endif
489 }
490 if (nodes) delete[] nodes;
491 if (data) delete[] data;
492 freelist.init();
493 RTListBase<T>::init();
494 _init(Elements);
495 }
496
497 protected:
498 // caution: assumes pool (that is freelist) is not empty!
499 inline Iterator alloc() {
500 Iterator element = freelist.last();
501 element.detach();
502 return element;
503 }
504
505 inline void freeToPool(Iterator itElement) {
506 freelist.append(itElement);
507 }
508
509 inline void freeToPool(Iterator itFirst, Iterator itLast) {
510 freelist.append(itFirst, itLast);
511 }
512
513 friend class RTList<T>;
514
515 private:
516 void _init(int Elements) {
517 data = new T[Elements];
518 nodes = new Node[Elements];
519 for (int i = 0; i < Elements; i++) {
520 nodes[i].data = &data[i];
521 freelist.append(&nodes[i]);
522 }
523 poolsize = Elements;
524 }
525 };
526
527 #endif // __LS_POOL_H__

  ViewVC Help
Powered by ViewVC