#region File Header // // FiniteQueue2N.cs - A generic finite queue (ring/circular buffer) with index [] operator. // // Copyright (C) Javier Valcarce. BSD License #endregion // Uncomment this line to check parameters in each invocation of Enqueue() or Dequeue() operations // and to raises exceptions accordingly. If commented, checks are substituted by Debug.Assert(...) // which disapear in the Release version of the assembly. #define CHECK_QUEUE #region Using Statements using System; using System.Diagnostics; using System.Collections; using System.Collections.Generic; #endregion namespace Arq { /// /// This class implements a generic finite queue (circular/bounded buffer) with index [] /// operator. The [] operator is not very performant, use it sporadically /// public class FiniteQueue : IFiniteQueue { #region Private Members int head; int tail; T[] buff; int count; int space; #endregion #region Constructor /// /// Creates a ring buffer of n elements of type T. /// /// queue's capacity public FiniteQueue(int n) { Debug.Assert(n > 00); buff = new T[n]; Clear(); } /// /// Creates a ring buffer using a T array as the underlaying storage. The length of /// this array must be a power of two between 2^{1} and 2^{22}. /// /// Array of T elements public FiniteQueue(T[] v) { Debug.Assert(v.Length > 0); buff = v; Clear(); } #endregion #region Public Methods /// /// Removes all objects from the RingBuffer]]> /// public void Clear() { head = 0; tail = 0; count = 0; space = buff.Length; } /// /// Enqueue a single object to the end of the RingBuffer]]> /// /// public int Enqueue(T item) { #if CHECK_QUEUE if (space < 1) throw new InvalidOperationException(); #else Debug.Assert(!(space < 1)); #endif buff[tail] = item; // fast modulus operation tail++; if (tail == buff.Length) tail = 0; count++; space--; return 1; } /// /// Enqueue an array of objects to the end of the RingBuffer]]> /// /// public int Enqueue(T[] src, int offset, int count) { #if CHECK_QUEUE if (count > space) throw new InvalidOperationException(); if (count < 1) throw new ArgumentException(); #else Debug.Assert(!(count > space)); Debug.Assert(!(count < 1)); #endif for (int i = 0; i < count; i++) { buff[tail] = src[offset + i]; // fast modulus operation tail++; if (tail == buff.Length) tail = 0; } this.count += count; this.space -= count; return count; } /// /// Removes and returns the object at the beginning of the RingBuffer]]> /// /// public int Dequeue(out T item) { #if CHECK_QUEUE if (this.count < 1) throw new InvalidOperationException(); #else Debug.Assert(!(this.count < 1)); #endif item = buff[head]; head++; if (head == buff.Length) head = 0; this.count--; this.space++; return 1; } public int Dequeue(T[] dst, int offset, int count) { #if CHECK_QUEUE if (count > this.count) throw new InvalidOperationException(); if (count < 1) throw new ArgumentException(); #else Debug.Assert(!(count > this.count)); Debug.Assert(!(count < 1)); #endif for (int i = 0; i < count; i++) { dst[offset + i] = buff[head]; head++; if (head == buff.Length) head = 0; } this.count -= count; this.space += count; return count; } #endregion #region Properties /// /// Index operator /// /// Zero-based index. Index 0 is the head of the queue. No Bound /// Check Is Performed /// The indexed element public T this[int index] { get { #if CHECK_QUEUE if (index >= this.count) throw new InvalidOperationException(); if (index < 0) throw new ArgumentException(); #else Debug.Assert(!(index >= this.count)); Debug.Assert(!(index < 0)); #endif return buff[(head + index) % buff.Length]; } set { #if CHECK_QUEUE if (index >= this.count) throw new InvalidOperationException(); if (index < 0) throw new ArgumentException(); #else Debug.Assert(!(index >= this.count)); Debug.Assert(!(index < 0)); #endif buff[(head + index) % buff.Length] = value; } } /// /// Queues's capacity /// public int Capacity { get { return buff.Length; } } /// /// Number of elements in the queue /// public int Count { get { return count; } } /// /// Available free space in the queue /// public int Space { get { return space; } } #endregion } }