none
Circular Buffer in .NET

    Question

  • Is there a collection in .NET that offers a circular buffer?

    If not is there a collection that I can extend that would offer this functionality?

    Thanks

     

    Monday, November 6, 2006 10:15 AM

All replies

  • No there is no circular collection exists in .net . You can implemnt it by using following interface.ICollection, IEnumerable 

     

     

    Monday, November 6, 2006 11:52 AM
  • A Queue is very close to a circular buffer.  You would just have to throw an exception when the Count property gets too large...
    Tuesday, November 7, 2006 12:21 PM
    Moderator
  • My understanding of a circular buffer is that when the Count property has been reached it should overwrite the first element again. So in the longer term the buffer will always be full and the older data would be lost.

    I do not want an exception raised in this case.
    Thursday, November 9, 2006 10:41 AM
  • Hmm not quite sure why nobugz mentioned an exception nevertheless you can still use a queue and dequeue whenever you enqueue.

    Its probably more memory efficient (and very simple) to create an array and an index to refer to the next element to overwrite e.g.

    public class CircularBuffer<T>
    {
      T buffer[];
      int nextFree;

      public CircularBuffer(int length)
      {
        buffer = new buffer[
    length];
       
    nextFree = 0;
      }

      public void Add(T o)
      {
        buffer[
    nextFree] = o;
        nextFree = (nextFree+1) % buffer.Length;
      }
    }



    • Proposed as answer by Raevean Monday, May 31, 2010 5:28 AM
    Thursday, November 9, 2006 12:08 PM
  • Any collection can be used as a buffer. Circularity means insert and remove pointers that wrap to zero when they surpass the desired buffer size.  The remove pointer cannot advance beyond the insert pointer (empty when equal).

    bool empty{ return input == output; }

    void put(T item) { buffer[input++] = item;  input = input == max ? 0 : input; }

    void T get() { empty() ? throw Exception("look before you leap") : return buffer[output++]; output = output > input ? input : output; }

     

    (an array will throw an exception if its size is exceeded but there's nothing circular about that).

     

    Saturday, May 29, 2010 7:33 PM
  • http://en.wikipedia.org/wiki/Circular_buffer

    Contains C# implementation


    Regards
    Sunday, May 30, 2010 3:02 PM
  • Exemple in wikipedia throws exception ... why not use something like that

      public class CircularBuffer<T>
      {
        Queue<T> _queue;
        int _size;
    
        public CircularBuffer(int size)
        {
          _queue = new Queue<T>(size);
          _size = size;
        }
    
        public void Add(T obj)
        {
          if (_queue.Count == _size)
          {
            _queue.Dequeue();
            _queue.Enqueue(obj);
          }
          else
            _queue.Enqueue(obj);
        }
        public T Read() 
        {
          return _queue.Dequeue();
        }
    
        public T Peek()
        {
          return _queue.Peek();
        }
      }
    Monday, May 31, 2010 5:26 AM
  • I think the code above should be (right?):

    public CircularBuffer(int length)
      {
        buffer = new T
    [length];

        nextFree = 0;

      }

    Monday, August 11, 2014 7:11 AM
  • public class CircularBuffer<T>

    {
      T buffer[]; 

    To complete Duncan's answer here is a buffer that can be used to both write into AND read from:

    public class RingBuffer<T>
    {
            T[] m_Buffer;
            int m_NextWrite, m_Tail, m_Head, m_CurrRead;

            public RingBuffer(int length)
            {
                m_Buffer = new T[length];
                m_NextWrite = 0;
                m_Head = m_Tail = m_CurrRead = -1;
            }

            public int Length { get { return m_Buffer.Length;} }

            public void Add(T o)
            {
                if (m_Head == -1) // initial state
                {
                    m_Head = 0;
                    m_Tail = 0;
                    m_CurrRead = 0;
                }
                else
                {
                    m_Tail = m_NextWrite;
                    if (m_Head == m_Tail)
                        m_Head = mod(m_Tail + 1, m_Buffer.Length);
                    if (m_CurrRead == m_Tail)
                        m_CurrRead = -1;
                }
                m_Buffer[m_NextWrite] = o;
                m_NextWrite = mod(m_NextWrite + 1, m_Buffer.Length);
            }

            public T GetHead()
            {
                if (m_Head == -1)
                    return default(T);

                m_CurrRead = m_Head;
                return m_Buffer[m_Head];
            }

            public T GetTail()
            {
                if (m_Head == -1)
                    return default(T);

                m_CurrRead = m_Tail;
                return m_Buffer[m_Tail];
            }

            public T GetNext()
            {
                if (m_CurrRead == -1 || m_CurrRead == m_Tail)
                    return default(T);

                m_CurrRead = mod(m_CurrRead + 1, m_Buffer.Length); ;
                return m_Buffer[m_CurrRead];
            }

            public T GetPrev()
            {
                if (m_CurrRead == -1 || m_CurrRead == m_Head)
                    return default(T);

                m_CurrRead = mod(m_CurrRead - 1, m_Buffer.Length);
                return m_Buffer[m_CurrRead];
            }

            private int mod(int x, int m) // x mod m works for both positive and negative x (unlike x % m).
            {
                return (x % m + m) % m;
            }

    #if DEBUG
            public T[] Raw { get { return (T[])m_Buffer.Clone(); } } // For debugging only.
    #endif

    }

    Saturday, November 22, 2014 12:47 AM
  • refer this codeplex sample

    https://circularbuffer.codeplex.com/

    • Proposed as answer by dotGuru Sunday, February 8, 2015 5:27 AM
    Monday, November 24, 2014 5:44 AM
  • Thanks Duncan Woods, just what I needed
    Sunday, September 13, 2015 10:10 AM
  • My version, as a circular queue to look back in time on a buffered audio samples buffer...

        public class CircularBuffer<T>
        {
            T[] buffer;
            int headIdx;
    
            public CircularBuffer(int length)
            {
                buffer = new T[length];
                headIdx = 0;
            }
    
            /// <summary>
            /// Add n to the buffer.
            /// </summary>
            /// <param name="n"></param>
            public void Add(T n)
            {
                headIdx = (headIdx + 1) % buffer.Length;
                buffer[headIdx] = n;
            }
    
            /// <summary>
            /// Get the sample from samplesBack ticks back.  0 is the latest sample in the Queue.
            /// length - 1 is the oldest sample in the queue.
            /// </summary>
            /// <param name="samplesBack"></param>
            /// <returns></returns>
            public T Ago(int samplesBack)
            {
                if(samplesBack < 0 || samplesBack >= buffer.Length)
                {
                    throw new IndexOutOfRangeException("CircularBuffer:Ago(" + samplesBack + "), samplesBack index must be range 0 to " + (buffer.Length - 1));
                }
                int i = headIdx - samplesBack;
                if(i < 0)
                {
                    i += buffer.Length;
                }
                return buffer[i];
            }

    Sunday, January 13, 2019 1:05 AM
  • Btw, System.Collections.Queue is built in circular buffer implementation, just not a generic collection.
    Monday, January 14, 2019 3:35 AM
    Answerer