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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 554 by schoenebeck, Thu May 19 19:25:14 2005 UTC revision 2871 by schoenebeck, Sun Apr 10 18:22:23 2016 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6   *   Copyright (C) 2005 Christian Schoenebeck                              *   *   Copyright (C) 2005 - 2016 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 44  Line 44 
44  const std::string __err_msg_iterator_invalidated = "Pool/RTList iterator invalidated";  const std::string __err_msg_iterator_invalidated = "Pool/RTList iterator invalidated";
45  #endif // CONFIG_DEVMODE  #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  // just symbol prototyping
50  template<typename T> class Pool;  template<typename T> class Pool;
51  template<typename T> class RTList;  template<typename T> class RTList;
# Line 59  class RTListBase { Line 61  class RTListBase {
61              #if CONFIG_DEVMODE              #if CONFIG_DEVMODE
62              RTListBase<T1>* list; // list to which this node currently belongs to              RTListBase<T1>* list; // list to which this node currently belongs to
63              #endif // CONFIG_DEVMODE              #endif // CONFIG_DEVMODE
64                int reincarnation; // just for Pool::fromID()
65    
66              _Node() {              _Node() {
67                  next = NULL;                  next = NULL;
# Line 67  class RTListBase { Line 70  class RTListBase {
70                  #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
71                  list = NULL;                  list = NULL;
72                  #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
73                    reincarnation = 0;
74              }              }
75          };          };
76          typedef _Node<T> Node;          typedef _Node<T> Node;
# Line 143  class RTListBase { Line 147  class RTListBase {
147                      }                      }
148                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
149                      return *current->data;                      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->() {                  inline T1* operator->() {
# Line 160  class RTListBase { Line 177  class RTListBase {
177                      return current->data;                      return current->data;
178                  }                  }
179    
180                  inline bool operator==(const _Iterator<T1> other) {                  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;                      return current == other.current;
196                  }                  }
197    
198                  inline bool operator!=(const _Iterator<T1> other) {                  inline bool operator!=(const _Iterator<T1> other) const {
199                      return current != other.current;                      return current != other.current;
200                  }                  }
201    
# Line 176  class RTListBase { Line 207  class RTListBase {
207                      return !(current && current->data);                      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) {                  inline _Iterator moveToEndOf(RTListBase<T1>* pDstList) {
234                      detach();                      detach();
235                      pDstList->append(*this);                      pDstList->append(*this);
# Line 184  class RTListBase { Line 238  class RTListBase {
238                      return iterOnDstList;                      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) {                  inline _Iterator moveToBeginOf(RTListBase<T1>* pDstList) {
265                      detach();                      detach();
266                      pDstList->prepend(*this);                      pDstList->prepend(*this);
# Line 192  class RTListBase { Line 269  class RTListBase {
269                      return iterOnDstList;                      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                  #if CONFIG_DEVMODE
339                  inline bool isValid() {                  inline bool isValid() const {
340                      return current->list == list;                      return current->list == list;
341                  }                  }
342                  #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
# Line 230  class RTListBase { Line 373  class RTListBase {
373                      #endif // CONFIG_DEVMODE                      #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() {                  inline void detach() {
390                      RTListBase<T1>::detach(*this);                      RTListBase<T1>::detach(*this);
391                  }                  }
# Line 256  class RTListBase { Line 412  class RTListBase {
412              return Iterator(&_end, Iterator::dir_backward);              return Iterator(&_end, Iterator::dir_backward);
413          }          }
414    
415          inline bool isEmpty() {          inline bool isEmpty() const {
416              return _begin.next == &_end;              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:      protected:
426          Node _begin; // fake node (without data) which represents the begin of the list - not the first element!          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!          Node _end;   // fake node (without data) which represents the end of the list - not the last element!
428    
429          RTListBase() {          RTListBase() {
430                init();
431            }
432    
433            void init() {
434              // initialize boundary nodes              // initialize boundary nodes
435              _begin.prev = &_begin;              _begin.prev = &_begin;
436              _begin.next = &_end;              _begin.next = &_end;
# Line 334  class RTListBase { Line 500  class RTListBase {
500              #endif // CONFIG_DEVMODE              #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) {          static inline void detach(Iterator itElement) {
530              Node* pNode = itElement.node();              Node* pNode = itElement.node();
531              Node* prev = pNode->prev; // if a segfault happens here, then because 'itElement' Iterator became invalidated              Node* prev = pNode->prev; // if a segfault happens here, then because 'itElement' Iterator became invalidated
# Line 369  class RTList : public RTListBase<T> { Line 561  class RTList : public RTListBase<T> {
561          RTList(Pool<T>* pPool) : RTListBase<T>::RTListBase() {          RTList(Pool<T>* pPool) : RTListBase<T>::RTListBase() {
562              this->pPool = pPool;              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() {          virtual ~RTList() {
579              clear();              clear();
580          }          }
581    
582          inline bool poolIsEmpty() {          inline bool poolIsEmpty() const {
583              return pPool->poolIsEmpty();              return pPool->poolIsEmpty();
584          }          }
585    
586          inline Iterator allocAppend() {          inline Iterator allocAppend() {
587              if (pPool->poolIsEmpty()) return RTListBase<T>::begin();              if (pPool->poolIsEmpty()) return RTListBase<T>::begin();
588              Iterator element = pPool->alloc();              Iterator element = pPool->alloc();
589              append(element);              this->append(element);
590              #if CONFIG_DEVMODE              #if CONFIG_DEVMODE
591              element.list = this;              element.list = this;
592              #endif // CONFIG_DEVMODE              #endif // CONFIG_DEVMODE
# Line 413  class RTList : public RTListBase<T> { Line 618  class RTList : public RTListBase<T> {
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:      protected:
638          Pool<T>* pPool;          Pool<T>* pPool;
639  };  };
# Line 426  class Pool : public RTList<T> { Line 647  class Pool : public RTList<T> {
647          Node*         nodes;          Node*         nodes;
648          T*            data;          T*            data;
649          RTListBase<T> freelist; // not yet allocated elements          RTListBase<T> freelist; // not yet allocated elements
650            int           poolsize;
651    
652          Pool(int Elements) : RTList<T>::RTList(this) {          Pool(int Elements) : RTList<T>::RTList(this) {
653              data  = new T[Elements];              _init(Elements);
             nodes = new Node[Elements];  
             for (int i = 0; i < Elements; i++) {  
                 nodes[i].data = &data[i];  
                 freelist.append(&nodes[i]);  
             }  
654          }          }
655    
656          virtual ~Pool() {          virtual ~Pool() {
# Line 441  class Pool : public RTList<T> { Line 658  class Pool : public RTList<T> {
658              if (data)  delete[] data;              if (data)  delete[] data;
659          }          }
660    
661          inline bool poolIsEmpty() {          inline bool poolIsEmpty() const {
662              return freelist.isEmpty();              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:      protected:
792          // caution: assumes pool (that is freelist) is not empty!          // caution: assumes pool (that is freelist) is not empty!
793          inline Iterator alloc() {          inline Iterator alloc() {
# Line 454  class Pool : public RTList<T> { Line 797  class Pool : public RTList<T> {
797          }          }
798    
799          inline void freeToPool(Iterator itElement) {          inline void freeToPool(Iterator itElement) {
800                itElement.node()->reincarnation++;
801              freelist.append(itElement);              freelist.append(itElement);
802          }          }
803    
804          inline void freeToPool(Iterator itFirst, Iterator itLast) {          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);              freelist.append(itFirst, itLast);
810          }          }
811    
812          friend class RTList<T>;          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__  #endif // __LS_POOL_H__

Legend:
Removed from v.554  
changed lines
  Added in v.2871

  ViewVC Help
Powered by ViewVC