/[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 2335 by persson, Sat Mar 17 06:19:01 2012 UTC revision 3073 by schoenebeck, Thu Jan 5 16:04:00 2017 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 - 2012 Christian Schoenebeck                       *   *   Copyright (C) 2005 - 2017 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 46  const std::string __err_msg_iterator_inv Line 46  const std::string __err_msg_iterator_inv
46    
47  const std::string __err_msg_resize_while_in_use = "Pool::resizePool() ERROR: elements still in use!";  const std::string __err_msg_resize_while_in_use = "Pool::resizePool() ERROR: elements still in use!";
48    
49    /**
50     * Unique numeric ID for exactly one incarnation of one element allocated from
51     * a Pool. As soon as the respective element is once freed back to the Pool,
52     * the ID becomes invalid. Such an ID may be used to safely store an abstract
53     * reference to one Pool element for longer time. Since the Pool classes
54     * automatically detect whether an ID became invalid, using such an ID is thus
55     * safer than storing an Iterator or even a raw pointer in use case scenarios of
56     * storing long term references to Pool elements.
57     *
58     * This ID type is currently set (constrained) to 32-bit because the current
59     * real-time instrument script infrastructure implementation, which heavily
60     * relies on element IDs, is currently using 32-bit for its integer script
61     * variable type.
62     */
63    typedef uint32_t pool_element_id_t;
64    
65  // just symbol prototyping  // just symbol prototyping
66  template<typename T> class Pool;  template<typename T> class Pool;
67  template<typename T> class RTList;  template<typename T> class RTList;
# Line 61  class RTListBase { Line 77  class RTListBase {
77              #if CONFIG_DEVMODE              #if CONFIG_DEVMODE
78              RTListBase<T1>* list; // list to which this node currently belongs to              RTListBase<T1>* list; // list to which this node currently belongs to
79              #endif // CONFIG_DEVMODE              #endif // CONFIG_DEVMODE
80                uint reincarnation; // just for Pool::fromID()
81    
82              _Node() {              _Node() {
83                  next = NULL;                  next = NULL;
# Line 69  class RTListBase { Line 86  class RTListBase {
86                  #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
87                  list = NULL;                  list = NULL;
88                  #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
89                    reincarnation = 0;
90                }
91    
92                inline void bumpReincarnation(uint bits) {
93                    reincarnation++;
94                    // constrain the bitrange of "reincarnation", because Pool::fromID() will shift up/down for pool_element_id_t and compare this bitwise
95                    reincarnation &= ((1 << bits) - 1);
96              }              }
97          };          };
98          typedef _Node<T> Node;          typedef _Node<T> Node;
99    
100      public:      public:
101            /**
102             * Pointer-like object which allows to iterate over elements of a RTList,
103             * similar to iterators of STL container classes. Note that the main
104             * purpose of this class is to access elements of a list / pool i.e.
105             * within a @c while() loop. If you rather want to keep a reference to
106             * one particular element (i.e. for longer time) then you might
107             * consider using @c pool_element_id_t variables instead.
108             */
109          template<typename T1>          template<typename T1>
110          class _Iterator {          class _Iterator {
111              public:              public:
# Line 145  class RTListBase { Line 177  class RTListBase {
177                      }                      }
178                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
179                      return *current->data;                      return *current->data;
180                    }
181    
182                    inline const T1& operator*() const {
183                        #if CONFIG_DEVMODE
184                        if (!isValid()) { // if iterator became invalidated
185                            #if CONFIG_RT_EXCEPTIONS
186                            throw std::runtime_error(__err_msg_iterator_invalidated);
187                            #else
188                            std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
189                            return *((const T1*)NULL); // force segfault if iterator became invalidated
190                            #endif // CONFIG_RT_EXCEPTIONS
191                        }
192                        #endif // CONFIG_DEVMODE
193                        return *current->data;
194                  }                  }
195    
196                  inline T1* operator->() {                  inline T1* operator->() {
# Line 162  class RTListBase { Line 207  class RTListBase {
207                      return current->data;                      return current->data;
208                  }                  }
209    
210                  inline bool operator==(const _Iterator<T1> other) {                  inline const T1* operator->() const {
211                        #if CONFIG_DEVMODE
212                        if (!isValid()) { // if iterator became invalidated
213                            #if CONFIG_RT_EXCEPTIONS
214                            throw std::runtime_error(__err_msg_iterator_invalidated);
215                            #else
216                            std::cerr << __err_msg_iterator_invalidated << std::endl << std::flush;
217                            return (const T1*)NULL; // force segfault if iterator became invalidated
218                            #endif // CONFIG_RT_EXCEPTIONS
219                        }
220                        #endif // CONFIG_DEVMODE
221                        return current->data;
222                    }
223    
224                    inline bool operator==(const _Iterator<T1> other) const {
225                      return current == other.current;                      return current == other.current;
226                  }                  }
227    
228                  inline bool operator!=(const _Iterator<T1> other) {                  inline bool operator!=(const _Iterator<T1> other) const {
229                      return current != other.current;                      return current != other.current;
230                  }                  }
231    
# Line 178  class RTListBase { Line 237  class RTListBase {
237                      return !(current && current->data);                      return !(current && current->data);
238                  }                  }
239    
240                    /**
241                     * Moves the element pointed by this Iterator from its current
242                     * list to the beginning of the destination list @a pDstList.
243                     *
244                     * @b CAUTION: When this method returns, this Iterator does
245                     * @b NOT point to the element on the new list anymore, instead it
246                     * points at a completely different element! In case of a
247                     * forward Iterator this Iterator object will point to the
248                     * previous element on the source list, in case of a backward
249                     * Iterator it will point to the subsequent element on the
250                     * source list. This behavior is enforced to avoid breaking an
251                     * active loop code working with this Iterator object.
252                     *
253                     * Thus if you intend to continue working with the same element,
254                     * you should do like this:
255                     * @code
256                     * it = it.moveToEndOf(anotherList);
257                     * @endcode
258                     *
259                     * @param pDstList - destination list
260                     * @returns Iterator object pointing at the moved element on
261                     *          the destination list
262                     */
263                  inline _Iterator moveToEndOf(RTListBase<T1>* pDstList) {                  inline _Iterator moveToEndOf(RTListBase<T1>* pDstList) {
264                      detach();                      detach();
265                      pDstList->append(*this);                      pDstList->append(*this);
# Line 186  class RTListBase { Line 268  class RTListBase {
268                      return iterOnDstList;                      return iterOnDstList;
269                  }                  }
270    
271                    /**
272                     * Moves the element pointed by this Iterator from its current
273                     * list to the end of destination list @a pDstList.
274                     *
275                     * @b CAUTION: When this method returns, this Iterator does
276                     * @b NOT point to the element on the new list anymore, instead it
277                     * points at a completely different element! In case of a
278                     * forward Iterator this Iterator object will point to the
279                     * previous element on the source list, in case of a backward
280                     * Iterator it will point to the subsequent element on the
281                     * source list. This behavior is enforced to avoid breaking an
282                     * active loop code working with this Iterator object.
283                     *
284                     * Thus if you intend to continue working with the same element,
285                     * you should do like this:
286                     * @code
287                     * it = it.moveToBeginOf(anotherList);
288                     * @endcode
289                     *
290                     * @param pDstList - destination list
291                     * @returns Iterator object pointing at the moved element on
292                     *          the destination list
293                     */
294                  inline _Iterator moveToBeginOf(RTListBase<T1>* pDstList) {                  inline _Iterator moveToBeginOf(RTListBase<T1>* pDstList) {
295                      detach();                      detach();
296                      pDstList->prepend(*this);                      pDstList->prepend(*this);
# Line 194  class RTListBase { Line 299  class RTListBase {
299                      return iterOnDstList;                      return iterOnDstList;
300                  }                  }
301    
302                    /**
303                     * Moves the element pointed by this Iterator from its current
304                     * position to the position right before @a itDst. That move
305                     * may either be from and to the same list, or to a another
306                     * list.
307                     *
308                     * @b CAUTION: When this method returns, this Iterator does
309                     * @b NOT point to the element on the new list anymore, instead it
310                     * points at a completely different element! In case of a
311                     * forward Iterator this Iterator object will point to the
312                     * previous element on the source list, in case of a backward
313                     * Iterator it will point to the subsequent element on the
314                     * source list. This behavior is enforced to avoid breaking an
315                     * active loop code working with this Iterator object.
316                     *
317                     * Thus if you intend to continue working with the same element,
318                     * you should do like this:
319                     * @code
320                     * itSourceElement = itSourceElement.moveBefore(itDestinationElement);
321                     * @endcode
322                     *
323                     * @param itDst - destination element to be inserted before
324                     * @returns Iterator object pointing at the moved element on
325                     *          the destination list
326                     */
327                    inline _Iterator moveBefore(_Iterator<T1> itDst) {
328                        detach();
329                        RTList<T1>::prependBefore(*this, itDst);
330                        _Iterator iterOnDstList = _Iterator(current);
331                        current = fallback;
332                        return iterOnDstList;
333                    }
334    
335                    /**
336                     * Moves the element pointed by this Iterator from its current
337                     * position to the position right after @a itDst. That move
338                     * may either be from and to the same list, or to a another
339                     * list.
340                     *
341                     * @b CAUTION: When this method returns, this Iterator does
342                     * @b NOT point to the element on the new list anymore, instead it
343                     * points at a completely different element! In case of a
344                     * forward Iterator this Iterator object will point to the
345                     * previous element on the source list, in case of a backward
346                     * Iterator it will point to the subsequent element on the
347                     * source list. This behavior is enforced to avoid breaking an
348                     * active loop code working with this Iterator object.
349                     *
350                     * Thus if you intend to continue working with the same element,
351                     * you should do like this:
352                     * @code
353                     * itSourceElement = itSourceElement.moveAfter(itDestinationElement);
354                     * @endcode
355                     *
356                     * @param itDst - destination element to be inserted after
357                     * @returns Iterator object pointing at the moved element on
358                     *          the destination list
359                     */
360                    inline _Iterator moveAfter(_Iterator<T1> itDst) {
361                        detach();
362                        RTList<T1>::appendAfter(*this, itDst);
363                        _Iterator iterOnDstList = _Iterator(current);
364                        current = fallback;
365                        return iterOnDstList;
366                    }
367    
368                  #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
369                  inline bool isValid() {                  inline bool isValid() const {
370                      return current->list == list;                      return current->list == list;
371                  }                  }
372                  #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
# Line 232  class RTListBase { Line 403  class RTListBase {
403                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
404                  }                  }
405    
406                    inline const Node* node() const {
407                        #if CONFIG_DEVMODE
408                        #if CONFIG_RT_EXCEPTIONS
409                        if (isValid()) return current;
410                        else throw std::runtime_error(__err_msg_iterator_invalidated);
411                        #else
412                        return (isValid()) ? current : (const Node*)NULL; // force segfault if iterator became invalidated
413                        #endif // CONFIG_RT_EXCEPTIONS
414                        #else
415                        return current;
416                        #endif // CONFIG_DEVMODE
417                    }
418    
419                  inline void detach() {                  inline void detach() {
420                      RTListBase<T1>::detach(*this);                      RTListBase<T1>::detach(*this);
421                  }                  }
# Line 258  class RTListBase { Line 442  class RTListBase {
442              return Iterator(&_end, Iterator::dir_backward);              return Iterator(&_end, Iterator::dir_backward);
443          }          }
444    
445          inline bool isEmpty() {          inline bool isEmpty() const {
446              return _begin.next == &_end;              return _begin.next == &_end;
447          }          }
448    
# Line 346  class RTListBase { Line 530  class RTListBase {
530              #endif // CONFIG_DEVMODE              #endif // CONFIG_DEVMODE
531          }          }
532    
533            static inline void prependBefore(Iterator itSrc, Iterator itDst) {
534                Node* src = itSrc.current;
535                Node* dst = itDst.current;
536                Node* prev = dst->prev;
537                prev->next = src;
538                dst->prev  = src;
539                src->prev  = prev;
540                src->next  = dst;
541                #if CONFIG_DEVMODE
542                src->list = this;
543                #endif // CONFIG_DEVMODE
544            }
545    
546            static inline void appendAfter(Iterator itSrc, Iterator itDst) {
547                Node* src = itSrc.current;
548                Node* dst = itDst.current;
549                Node* next = dst->next;
550                next->prev = src;
551                dst->next  = src;
552                src->prev  = dst;
553                src->next  = next;
554                #if CONFIG_DEVMODE
555                src->list = this;
556                #endif // CONFIG_DEVMODE
557            }
558    
559          static inline void detach(Iterator itElement) {          static inline void detach(Iterator itElement) {
560              Node* pNode = itElement.node();              Node* pNode = itElement.node();
561              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 399  class RTList : public RTListBase<T> { Line 609  class RTList : public RTListBase<T> {
609              clear();              clear();
610          }          }
611    
612          inline bool poolIsEmpty() {          inline bool poolIsEmpty() const {
613              return pPool->poolIsEmpty();              return pPool->poolIsEmpty();
614          }          }
615    
# Line 438  class RTList : public RTListBase<T> { Line 648  class RTList : public RTListBase<T> {
648              }              }
649          }          }
650    
651            inline pool_element_id_t getID(const T* obj) const {
652                return pPool->getID(obj);
653            }
654    
655            inline pool_element_id_t getID(const Iterator& it) const {
656                return pPool->getID(&*it);
657            }
658    
659            inline Iterator fromID(pool_element_id_t id) const {
660                return pPool->fromID(id);
661            }
662    
663            inline Iterator fromPtr(const T* obj) const {
664                return pPool->fromPtr(obj);
665            }
666    
667      protected:      protected:
668          Pool<T>* pPool;          Pool<T>* pPool;
669  };  };
# Line 451  class Pool : public RTList<T> { Line 677  class Pool : public RTList<T> {
677          Node*         nodes;          Node*         nodes;
678          T*            data;          T*            data;
679          RTListBase<T> freelist; // not yet allocated elements          RTListBase<T> freelist; // not yet allocated elements
680          int           poolsize;          uint          poolsize;
681            // following 3 used for element ID generation (and vice versa)
682            uint          poolsizebits; ///< Amount of bits required to index all elements of this pool (according to current pool size).
683            uint          reservedbits; ///< 3rd party reserved bits on the left side of id (default: 0).
684            uint          reincarnationbits; ///< Amount of bits allowed for reincarnation counter.
685    
686          Pool(int Elements) : RTList<T>::RTList(this) {          Pool(int Elements) : RTList<T>::RTList(this), reservedbits(0) {
687              _init(Elements);              _init(Elements);
688          }          }
689    
# Line 462  class Pool : public RTList<T> { Line 692  class Pool : public RTList<T> {
692              if (data)  delete[] data;              if (data)  delete[] data;
693          }          }
694    
695          inline bool poolIsEmpty() {          inline bool poolIsEmpty() const {
696              return freelist.isEmpty();              return freelist.isEmpty();
697          }          }
698    
# Line 474  class Pool : public RTList<T> { Line 704  class Pool : public RTList<T> {
704           *           *
705           * @see resizePool()           * @see resizePool()
706           */           */
707          int poolSize() const {          uint poolSize() const {
708              return poolsize;              return poolsize;
709          }          }
710    
# Line 507  class Pool : public RTList<T> { Line 737  class Pool : public RTList<T> {
737              _init(Elements);              _init(Elements);
738          }          }
739    
740            /**
741             * Sets the amount of bits on the left hand side of pool_element_id_t
742             * numbers to be reserved for 3rd party usage. So if you pass @c 1 for
743             * argument @a bits for example, then all generated element IDs will be
744             * maximum 31 bit large.
745             *
746             * By default there are no reserved bits, and thus by default all IDs
747             * are max. 32 bit large.
748             *
749             * @param bits - amount of bits to reserve on every ID for other purposes
750             * @see pool_element_id_t
751             */
752            void setPoolElementIDsReservedBits(uint bits) {
753                reservedbits = bits;
754                updateReincarnationBits();
755            }
756    
757            /**
758             * Returns an abstract, unique numeric ID for the given object of
759             * this pool, it returns 0 in case the passed object is not a member
760             * of this Pool, i.e. because it is simply an invalid pointer or member
761             * of another Pool. The returned ID is unique among all elements of this
762             * Pool and it differs with each reincarnation of an object. That means
763             * each time you free an element to and allocate the same element back
764             * from the Pool, it will have a different ID.
765             *
766             * A valid ID will never be zero, so you may use ID values of 0 in your
767             * data structures for special purposes (i.e. reflecting an invalid
768             * object ID or not yet assigned object).
769             *
770             * Members are always translated both, from Iterators/pointers to IDs,
771             * and from IDs to Iterators/pointers in constant time.
772             *
773             * You might want to use this alternative approach of referencing Pool
774             * members under certain scenarios. For example if you need to expose
775             * an ID to the end user and/or if you want to represent an object of
776             * this pool by a smaller number instead of a native pointer (i.e. 16
777             * bits vs. 64 bits). You can also detect this way whether the object
778             * has already been freed / reallocated from the Pool in the meantime.
779             *
780             * @param obj - raw pointer to a data member of this Pool
781             * @returns unique numeric ID (!= 0) of @a obj or 0 if pointer was invalid
782             */
783            pool_element_id_t getID(const T* obj) const {
784                if (!poolsize) return 0;
785                int index = int( obj - &data[0] );
786                if (index < 0 || index >= poolsize) return 0;
787                return ((nodes[index].reincarnation << poolsizebits) | index) + 1;
788            }
789    
790            /**
791             * Overridden convenience method, behaves like the method above.
792             */
793            pool_element_id_t getID(const Iterator& it) const {
794                return getID(&*it);
795            }
796    
797            /**
798             * Returns an Iterator object of the Pool data member reflected by the
799             * given abstract, unique numeric ID, it returns an invalid Iterator in
800             * case the ID is invalid or if the Pool's data element reflected by
801             * given ID was at least once released/freed back to the Pool in the
802             * meantime.
803             *
804             * Members are always translated both, from Iterators/pointers to IDs,
805             * and from IDs to Iterators/pointers in constant time.
806             *
807             * You might want to use this alternative approach of referencing Pool
808             * members under certain scenarios. For example if you need to expose
809             * an ID to the end user and/or if you want to represent an object of
810             * this pool by a smaller number instead of a native pointer (i.e. 16
811             * bits vs. 64 bits). You can also detect this way whether the object
812             * has already been freed / reallocated from the Pool in the meantime.
813             *
814             * @param id - unique ID (!= 0) of a Pool's data member
815             * @returns Iterator object pointing to Pool's data element, invalid
816             *          Iterator in case ID was invalid or data element was freed
817             */
818            Iterator fromID(pool_element_id_t id) const {
819                //TODO: -1 check here is a relict from older versions of Pool.h, once it is certain that no existing code base is still using -1 for "invalid" Pool elements then this -1 check can be removed
820                if (id == 0 || id == -1) return Iterator(); // invalid iterator
821                id--;
822                const uint bits = poolsizebits;
823                uint index = id & ((1 << bits) - 1);
824                if (index >= poolsize) return Iterator(); // invalid iterator
825                Node* node = &nodes[index];
826                uint reincarnation = id >> bits;
827                if (reincarnation != node->reincarnation) return Iterator(); // invalid iterator
828                return Iterator(node);
829            }
830    
831            /**
832             * Returns an Iterator object for the object pointed by @a obj. This
833             * method will check whether the supplied object is actually part of
834             * this pool, and if it is not part of this pool an invalid Iterator is
835             * returned instead.
836             *
837             * @param obj - raw pointer to an object managed by this pool
838             * @returns Iterator object pointing to the supplied object, invalid
839             *          Iterator in case object is not part of this pool
840             */
841            Iterator fromPtr(const T* obj) const {
842                if (!poolsize) return Iterator(); // invalid iterator
843                int index = int( obj - &data[0] );
844                if (index < 0 || index >= poolsize) return Iterator(); // invalid iterator
845                return Iterator(&nodes[index]);
846            }
847    
848      protected:      protected:
849          // caution: assumes pool (that is freelist) is not empty!          // caution: assumes pool (that is freelist) is not empty!
850          inline Iterator alloc() {          inline Iterator alloc() {
# Line 516  class Pool : public RTList<T> { Line 854  class Pool : public RTList<T> {
854          }          }
855    
856          inline void freeToPool(Iterator itElement) {          inline void freeToPool(Iterator itElement) {
857                itElement.node()->bumpReincarnation(reincarnationbits);
858              freelist.append(itElement);              freelist.append(itElement);
859          }          }
860    
861          inline void freeToPool(Iterator itFirst, Iterator itLast) {          inline void freeToPool(Iterator itFirst, Iterator itLast) {
862                for (Node* n = itFirst.node(); true; n = n->next) {
863                    n->bumpReincarnation(reincarnationbits);
864                    if (n == itLast.node()) break;
865                }
866              freelist.append(itFirst, itLast);              freelist.append(itFirst, itLast);
867          }          }
868    
# Line 534  class Pool : public RTList<T> { Line 877  class Pool : public RTList<T> {
877                  freelist.append(&nodes[i]);                  freelist.append(&nodes[i]);
878              }              }
879              poolsize = Elements;              poolsize = Elements;
880                poolsizebits = bitsForSize(poolsize + 1); // +1 here just because IDs are always incremented by one (to avoid them ever being zero)
881                updateReincarnationBits();
882            }
883    
884            inline void updateReincarnationBits() {
885                reincarnationbits = sizeof(pool_element_id_t) * 8 - poolsizebits - reservedbits;
886            }
887    
888            inline static int bitsForSize(int size) {
889                if (!size) return 0;
890                size--;
891                int bits = 0;
892                for (; size > 1; bits += 2, size >>= 2);
893                return bits + size;
894          }          }
895  };  };
896    

Legend:
Removed from v.2335  
changed lines
  Added in v.3073

  ViewVC Help
Powered by ViewVC