OpenSimMirror/ThirdParty/SmartThreadPool/PriorityQueue.cs

240 lines
6.6 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace Amib.Threading.Internal
{
#region PriorityQueue class
/// <summary>
/// PriorityQueue class
/// This class is not thread safe because we use external lock
/// </summary>
public sealed class PriorityQueue : IEnumerable
{
#region Private members
/// <summary>
/// The number of queues, there is one for each type of priority
/// </summary>
private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1;
/// <summary>
/// Work items queues. There is one for each type of priority
/// </summary>
private readonly LinkedList<IHasWorkItemPriority>[] _queues = new LinkedList<IHasWorkItemPriority>[_queuesCount];
/// <summary>
/// The total number of work items within the queues
/// </summary>
private int _workItemsCount;
/// <summary>
/// Use with IEnumerable interface
/// </summary>
private int _version;
#endregion
#region Contructor
public PriorityQueue()
{
for(int i = 0; i < _queues.Length; ++i)
{
_queues[i] = new LinkedList<IHasWorkItemPriority>();
}
}
#endregion
#region Methods
/// <summary>
/// Enqueue a work item.
/// </summary>
/// <param name="workItem">A work item</param>
public void Enqueue(IHasWorkItemPriority workItem)
{
Debug.Assert(null != workItem);
int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1;
Debug.Assert(queueIndex >= 0);
Debug.Assert(queueIndex < _queuesCount);
_queues[queueIndex].AddLast(workItem);
++_workItemsCount;
++_version;
}
/// <summary>
/// Dequeque a work item.
/// </summary>
/// <returns>Returns the next work item</returns>
public IHasWorkItemPriority Dequeue()
{
IHasWorkItemPriority workItem = null;
if(_workItemsCount > 0)
{
int queueIndex = GetNextNonEmptyQueue(-1);
Debug.Assert(queueIndex >= 0);
workItem = _queues[queueIndex].First.Value;
_queues[queueIndex].RemoveFirst();
Debug.Assert(null != workItem);
--_workItemsCount;
++_version;
}
return workItem;
}
/// <summary>
/// Find the next non empty queue starting at queue queueIndex+1
/// </summary>
/// <param name="queueIndex">The index-1 to start from</param>
/// <returns>
/// The index of the next non empty queue or -1 if all the queues are empty
/// </returns>
private int GetNextNonEmptyQueue(int queueIndex)
{
for(int i = queueIndex+1; i < _queuesCount; ++i)
{
if(_queues[i].Count > 0)
{
return i;
}
}
return -1;
}
/// <summary>
/// The number of work items
/// </summary>
public int Count
{
get
{
return _workItemsCount;
}
}
/// <summary>
/// Clear all the work items
/// </summary>
public void Clear()
{
if (_workItemsCount > 0)
{
foreach(LinkedList<IHasWorkItemPriority> queue in _queues)
{
queue.Clear();
}
_workItemsCount = 0;
++_version;
}
}
#endregion
#region IEnumerable Members
/// <summary>
/// Returns an enumerator to iterate over the work items
/// </summary>
/// <returns>Returns an enumerator</returns>
public IEnumerator GetEnumerator()
{
return new PriorityQueueEnumerator(this);
}
#endregion
#region PriorityQueueEnumerator
/// <summary>
/// The class the implements the enumerator
/// </summary>
private class PriorityQueueEnumerator : IEnumerator
{
private readonly PriorityQueue _priorityQueue;
private int _version;
private int _queueIndex;
private IEnumerator _enumerator;
public PriorityQueueEnumerator(PriorityQueue priorityQueue)
{
_priorityQueue = priorityQueue;
_version = _priorityQueue._version;
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
if (_queueIndex >= 0)
{
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
}
else
{
_enumerator = null;
}
}
#region IEnumerator Members
public void Reset()
{
_version = _priorityQueue._version;
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
if (_queueIndex >= 0)
{
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
}
else
{
_enumerator = null;
}
}
public object Current
{
get
{
Debug.Assert(null != _enumerator);
return _enumerator.Current;
}
}
public bool MoveNext()
{
if (null == _enumerator)
{
return false;
}
if(_version != _priorityQueue._version)
{
throw new InvalidOperationException("The collection has been modified");
}
if (!_enumerator.MoveNext())
{
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex);
if(-1 == _queueIndex)
{
return false;
}
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
_enumerator.MoveNext();
return true;
}
return true;
}
#endregion
}
#endregion
}
#endregion
}