using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace Amib.Threading.Internal { #region PriorityQueue class /// /// PriorityQueue class /// This class is not thread safe because we use external lock /// public sealed class PriorityQueue : IEnumerable { #region Private members /// /// The number of queues, there is one for each type of priority /// private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; /// /// Work items queues. There is one for each type of priority /// private readonly LinkedList[] _queues = new LinkedList[_queuesCount]; /// /// The total number of work items within the queues /// private int _workItemsCount; /// /// Use with IEnumerable interface /// private int _version; #endregion #region Contructor public PriorityQueue() { for(int i = 0; i < _queues.Length; ++i) { _queues[i] = new LinkedList(); } } #endregion #region Methods /// /// Enqueue a work item. /// /// A work item 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; } /// /// Dequeque a work item. /// /// Returns the next work item 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; } /// /// Find the next non empty queue starting at queue queueIndex+1 /// /// The index-1 to start from /// /// The index of the next non empty queue or -1 if all the queues are empty /// private int GetNextNonEmptyQueue(int queueIndex) { for(int i = queueIndex+1; i < _queuesCount; ++i) { if(_queues[i].Count > 0) { return i; } } return -1; } /// /// The number of work items /// public int Count { get { return _workItemsCount; } } /// /// Clear all the work items /// public void Clear() { if (_workItemsCount > 0) { foreach(LinkedList queue in _queues) { queue.Clear(); } _workItemsCount = 0; ++_version; } } #endregion #region IEnumerable Members /// /// Returns an enumerator to iterate over the work items /// /// Returns an enumerator public IEnumerator GetEnumerator() { return new PriorityQueueEnumerator(this); } #endregion #region PriorityQueueEnumerator /// /// The class the implements the enumerator /// 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 }