#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
}
}