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

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

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

revision 969 by schoenebeck, Wed Feb 9 01:22:18 2005 UTC revision 970 by schoenebeck, Wed Dec 6 22:28:17 2006 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, 2006 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 29  Line 30 
30    
31  #include "atomic.h"  #include "atomic.h"
32    
33  template<class T>  /** @brief Real-time safe and type safe RingBuffer implementation.
34     *
35     * This constant size buffer can be used to send data from exactly one
36     * sender / writing thread to exactly one receiver / reading thread. It is
37     * real-time safe due to the fact that data is only allocated when this
38     * RingBuffer is created and no system level mechanisms are used for
39     * ensuring thread safety of this class.
40     *
41     * <b>Important:</b> There are two distinct behaviors of this RingBuffer
42     * which has to be given as template argument @c T_DEEP_COPY, which is a
43     * boolean flag:
44     *
45     * - @c true: The RingBuffer will copy elements of type @c T by using type
46     *   @c T's assignment operator. This behavior is mandatory for all data
47     *   structures (classes) which additionally allocate memory on the heap.
48     *   Type @c T's needs to have an assignment operator implementation though,
49     *   otherwise this will cause a compilation error. This behavior is more
50     *   safe, but usually slower (except for very small buffer sizes, where it
51     *   might be even faster).
52     * - @c false: The RingBuffer will copy elements of type @c T by flatly
53     *   copying their structural data ( i.e. with @c memcpy() ) in one piece.
54     *   This will only work if class @c T (and all of its subelements) does not
55     *   allocate any additional data on the heap by itself. So use this option
56     *   with great care, because otherwise it will result in very ugly behavior
57     *   and crashes! For larger buffer sizes, this behavior will most probably
58     *   be faster.
59     */
60    template<class T, bool T_DEEP_COPY>
61  class RingBuffer  class RingBuffer
62  {  {
63  public:  public:
# Line 58  public: Line 86  public:
86       * Sets all remaining write space elements to zero. The write pointer       * Sets all remaining write space elements to zero. The write pointer
87       * will currently not be incremented after, but that might change in       * will currently not be incremented after, but that might change in
88       * future.       * future.
89         *
90         * @e Caution: for @c T_DEEP_COPY=true you might probably @e NOT want
91         * to call this method at all, at least not in case type @c T allocates
92         * any additional data on the heap by itself.
93       */       */
94      inline void fill_write_space_with_null() {      inline void fill_write_space_with_null() {
95               int w = atomic_read(&write_ptr),               int w = atomic_read(&write_ptr),
# Line 122  public: Line 154  public:
154                 w += cnt;                 w += cnt;
155                 if(w >= size) {                 if(w >= size) {
156                   w -= size;                   w -= size;
157                   memcpy(&buf[0], &buf[size], w*sizeof(T));                   copy(&buf[0], &buf[size], w);
158  //printf("DEBUG !!!! increment_write_ptr_with_wrap: buffer wrapped, elements wrapped = %d (wrap_elements %d)\n",w,wrap_elements);  //printf("DEBUG !!!! increment_write_ptr_with_wrap: buffer wrapped, elements wrapped = %d (wrap_elements %d)\n",w,wrap_elements);
159                 }                 }
160                 atomic_set(&write_ptr, w);                 atomic_set(&write_ptr, w);
# Line 254  public: Line 286  public:
286       * allows to read from a RingBuffer without being forced to free read       * allows to read from a RingBuffer without being forced to free read
287       * data while reading / positioning.       * data while reading / positioning.
288       */       */
289      template<class T1>      template<class T1, bool T1_DEEP_COPY>
290      class _NonVolatileReader {      class _NonVolatileReader {
291          public:          public:
292              int read_space() {              int read_space() {
# Line 339  public: Line 371  public:
371                      n2 = 0;                      n2 = 0;
372                  }                  }
373    
374                  memcpy(dest, &pBuf->buf[priv_read_ptr], n1 * sizeof(T));                  copy(dest, &pBuf->buf[priv_read_ptr], n1);
375                  priv_read_ptr = (priv_read_ptr + n1) & pBuf->size_mask;                  priv_read_ptr = (priv_read_ptr + n1) & pBuf->size_mask;
376    
377                  if (n2) {                  if (n2) {
378                      memcpy(dest+n1, pBuf->buf, n2 * sizeof(T));                      copy(dest+n1, pBuf->buf, n2);
379                      priv_read_ptr = n2;                      priv_read_ptr = n2;
380                  }                  }
381    
# Line 363  public: Line 395  public:
395              }              }
396    
397          protected:          protected:
398              _NonVolatileReader(RingBuffer<T1>* pBuf) {              _NonVolatileReader(RingBuffer<T1,T1_DEEP_COPY>* pBuf) {
399                  this->pBuf     = pBuf;                  this->pBuf     = pBuf;
400                  this->read_ptr = atomic_read(&pBuf->read_ptr);                  this->read_ptr = atomic_read(&pBuf->read_ptr);
401              }              }
402    
403              RingBuffer<T1>* pBuf;              RingBuffer<T1,T1_DEEP_COPY>* pBuf;
404              int read_ptr;              int read_ptr;
405    
406              friend class RingBuffer<T1>;              friend class RingBuffer<T1,T1_DEEP_COPY>;
407      };      };
408    
409      typedef _NonVolatileReader<T> NonVolatileReader;      typedef _NonVolatileReader<T,T_DEEP_COPY> NonVolatileReader;
410    
411      NonVolatileReader get_non_volatile_reader() { return NonVolatileReader(this); }      NonVolatileReader get_non_volatile_reader() { return NonVolatileReader(this); }
412    
# Line 384  public: Line 416  public:
416      atomic_t read_ptr;      atomic_t read_ptr;
417      int size_mask;      int size_mask;
418    
419      friend class _NonVolatileReader<T>;      /**
420         * Copies \a n amount of elements from the buffer given by
421         * \a pSrc to the buffer given by \a pDst.
422         */
423        inline static void copy(T* pDst, T* pSrc, int n);
424    
425        friend class _NonVolatileReader<T,T_DEEP_COPY>;
426  };  };
427    
428  template<class T> T *  template<class T, bool T_DEEP_COPY>
429  RingBuffer<T>::get_write_ptr (void) {  T* RingBuffer<T,T_DEEP_COPY>::get_write_ptr (void) {
430    return(&buf[atomic_read(&write_ptr)]);    return(&buf[atomic_read(&write_ptr)]);
431  }  }
432    
433  template<class T> T *  template<class T, bool T_DEEP_COPY>
434  RingBuffer<T>::get_buffer_begin (void) {  T* RingBuffer<T,T_DEEP_COPY>::get_buffer_begin (void) {
435    return(buf);    return(buf);
436  }  }
437    
438    
439    
440  template<class T> int  template<class T, bool T_DEEP_COPY>
441  RingBuffer<T>::read (T *dest, int cnt)  int RingBuffer<T,T_DEEP_COPY>::read(T* dest, int cnt)
   
442  {  {
443          int free_cnt;          int free_cnt;
444          int cnt2;          int cnt2;
# Line 427  RingBuffer<T>::read (T *dest, int cnt) Line 464  RingBuffer<T>::read (T *dest, int cnt)
464                  n2 = 0;                  n2 = 0;
465          }          }
466    
467          memcpy (dest, &buf[priv_read_ptr], n1 * sizeof (T));          copy(dest, &buf[priv_read_ptr], n1);
468          priv_read_ptr = (priv_read_ptr + n1) & size_mask;          priv_read_ptr = (priv_read_ptr + n1) & size_mask;
469    
470          if (n2) {          if (n2) {
471                  memcpy (dest+n1, buf, n2 * sizeof (T));                  copy(dest+n1, buf, n2);
472                  priv_read_ptr = n2;                  priv_read_ptr = n2;
473          }          }
474    
# Line 439  RingBuffer<T>::read (T *dest, int cnt) Line 476  RingBuffer<T>::read (T *dest, int cnt)
476          return to_read;          return to_read;
477  }  }
478    
479  template<class T> int  template<class T, bool T_DEEP_COPY>
480  RingBuffer<T>::write (T *src, int cnt)  int RingBuffer<T,T_DEEP_COPY>::write(T* src, int cnt)
   
481  {  {
482          int free_cnt;          int free_cnt;
483          int cnt2;          int cnt2;
# Line 467  RingBuffer<T>::write (T *src, int cnt) Line 503  RingBuffer<T>::write (T *src, int cnt)
503                  n2 = 0;                  n2 = 0;
504          }          }
505    
506          memcpy (&buf[priv_write_ptr], src, n1 * sizeof (T));          copy(&buf[priv_write_ptr], src, n1);
507          priv_write_ptr = (priv_write_ptr + n1) & size_mask;          priv_write_ptr = (priv_write_ptr + n1) & size_mask;
508    
509          if (n2) {          if (n2) {
510                  memcpy (buf, src+n1, n2 * sizeof (T));                  copy(buf, src+n1, n2);
511                  priv_write_ptr = n2;                  priv_write_ptr = n2;
512          }          }
513          atomic_set(&write_ptr, priv_write_ptr);          atomic_set(&write_ptr, priv_write_ptr);
514          return to_write;          return to_write;
515  }  }
516    
517    template<class T, bool T_DEEP_COPY>
518    void RingBuffer<T,T_DEEP_COPY>::copy(T* pDst, T* pSrc, int n) {
519        if (T_DEEP_COPY) { // deep copy - won't work for data structures without assignment operator implementation
520            for (int i = 0; i < n; i++) pDst[i] = pSrc[i];
521        } else { // flat copy - won't work for complex data structures !
522            memcpy(pDst, pSrc, n * sizeof(T));
523        }
524    }
525    
526  #endif /* RINGBUFFER_H */  #endif /* RINGBUFFER_H */

Legend:
Removed from v.969  
changed lines
  Added in v.970

  ViewVC Help
Powered by ViewVC