From c39e7487494b61d797471099184ee8f98d462d02 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 14 May 2022 01:33:05 -0600 Subject: [PATCH] Finialized TrackedQueue --- .../ProcessQueue/BookQueue.cs | 175 --------------- .../ProcessQueue/TrackedQueue[T].cs | 209 ++++++++++++++++++ 2 files changed, 209 insertions(+), 175 deletions(-) delete mode 100644 Source/LibationWinForms/ProcessQueue/BookQueue.cs create mode 100644 Source/LibationWinForms/ProcessQueue/TrackedQueue[T].cs diff --git a/Source/LibationWinForms/ProcessQueue/BookQueue.cs b/Source/LibationWinForms/ProcessQueue/BookQueue.cs deleted file mode 100644 index c36554ab..00000000 --- a/Source/LibationWinForms/ProcessQueue/BookQueue.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LibationWinForms.ProcessQueue -{ - internal class TrackedQueue where T : class - { - public T Current { get; private set; } - private readonly LinkedList Queued = new(); - private readonly List Completed = new(); - private readonly object lockObject = new(); - - public int Count => Queued.Count + Completed.Count + (Current == null ? 0 : 1); - - public T this[int index] - { - get - { - if (index < Completed.Count) - return Completed[index]; - index -= Completed.Count; - - if (index == 0&& Current != null) return Current; - - if (Current != null) index--; - - if (index < Queued.Count) return Queued.ElementAt(index); - - throw new IndexOutOfRangeException(); - } - } - - public List QueuedItems() - { - lock (lockObject) - return Queued.ToList(); - } - public List CompletedItems() - { - lock (lockObject) - return Completed.ToList(); - } - - public bool QueueCount - { - get - { - lock (lockObject) - return Queued.Count > 0; - } - } - - public bool CompleteCount - { - get - { - lock (lockObject) - return Completed.Count > 0; - } - } - - - public void ClearQueue() - { - lock (lockObject) - { - Queued.Clear(); - } - } - - public void ClearCompleted() - { - lock (lockObject) - { - Completed.Clear(); - } - } - - public bool Any(Func predicate) - { - lock (lockObject) - { - return (Current != null && predicate(Current)) || Completed.Any(predicate) || Queued.Any(predicate); - } - } - - public QueuePosition MoveQueuePosition(T item, QueuePositionRequest requestedPosition) - { - lock (lockObject) - { - if (Queued.Count == 0) - { - - if (Current != null && Current == item) - return QueuePosition.Current; - if (Completed.Contains(item)) - return QueuePosition.Completed; - return QueuePosition.Absent; - } - - var node = Queued.Find(item); - if (node is null) return QueuePosition.Absent; - - if ((requestedPosition == QueuePositionRequest.Fisrt || requestedPosition == QueuePositionRequest.OneUp) && Queued.First.Value == item) - return QueuePosition.Fisrt; - if ((requestedPosition == QueuePositionRequest.Last || requestedPosition == QueuePositionRequest.OneDown) && Queued.Last.Value == item) - return QueuePosition.Last; - - if (requestedPosition == QueuePositionRequest.OneUp) - { - var oneUp = node.Previous; - Queued.Remove(node); - Queued.AddBefore(oneUp, node.Value); - return Queued.First.Value == item? QueuePosition.Fisrt : QueuePosition.OneUp; - } - else if (requestedPosition == QueuePositionRequest.OneDown) - { - var oneDown = node.Next; - Queued.Remove(node); - Queued.AddAfter(oneDown, node.Value); - return Queued.Last.Value == item ? QueuePosition.Last : QueuePosition.OneDown; - } - else if (requestedPosition == QueuePositionRequest.Fisrt) - { - Queued.Remove(node); - Queued.AddFirst(node); - return QueuePosition.Fisrt; - } - else - { - Queued.Remove(node); - Queued.AddLast(node); - return QueuePosition.Last; - } - } - } - - public bool Remove(T item) - { - lock (lockObject) - { - return Queued.Remove(item); - } - } - - public bool MoveNext() - { - lock (lockObject) - { - if (Current != null) - Completed.Add(Current); - if (Queued.Count == 0) return false; - Current = Queued.First.Value; - Queued.RemoveFirst(); - return true; - } - } - public T PeekNext() - { - lock (lockObject) - return Queued.Count > 0 ? Queued.First.Value : default; - } - - public void EnqueueBook(T item) - { - lock (lockObject) - Queued.AddLast(item); - } - - } -} diff --git a/Source/LibationWinForms/ProcessQueue/TrackedQueue[T].cs b/Source/LibationWinForms/ProcessQueue/TrackedQueue[T].cs new file mode 100644 index 00000000..d045f818 --- /dev/null +++ b/Source/LibationWinForms/ProcessQueue/TrackedQueue[T].cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace LibationWinForms.ProcessQueue +{ + public enum QueuePosition + { + Fisrt, + OneUp, + OneDown, + Last + } + + /* + * This data structure is like lifting a metal chain one link at a time. + * Each time you grab and lift a new link, the remaining chain shortens + * by 1 link and the pile of chain at yuor feet grows by one link. The + * index is the link position from the first link you lifted to the last + * one in the chain. + */ + public class TrackedQueue where T : class + { + public event EventHandler CompletedCountChanged; + public event EventHandler QueuededCountChanged; + public T Current { get; private set; } + + public IReadOnlyList Queued => _queued; + public IReadOnlyList Completed => _completed; + + private readonly List _queued = new(); + private readonly List _completed = new(); + private readonly object lockObject = new(); + + public T this[int index] + { + get + { + lock (lockObject) + { + if (index < _completed.Count) + return _completed[index]; + index -= _completed.Count; + + if (index == 0 && Current != null) return Current; + + if (Current != null) index--; + + if (index < _queued.Count) return _queued.ElementAt(index); + + throw new IndexOutOfRangeException(); + } + } + } + + public int Count + { + get + { + lock (lockObject) + { + return _queued.Count + _completed.Count + (Current == null ? 0 : 1); + } + } + } + + public int IndexOf(T item) + { + lock (lockObject) + { + if (_completed.Contains(item)) + return _completed.IndexOf(item); + + if (Current == item) return _completed.Count; + + if (_queued.Contains(item)) + return _queued.IndexOf(item) + (Current is null ? 0 : 1); + return -1; + } + } + + public bool RemoveQueued(T item) + { + lock (lockObject) + { + bool removed = _queued.Remove(item); + if (removed) + QueuededCountChanged?.Invoke(this, _queued.Count); + return removed; + } + } + + public void ClearQueue() + { + lock (lockObject) + { + _queued.Clear(); + QueuededCountChanged?.Invoke(this, 0); + } + } + + public void ClearCompleted() + { + lock (lockObject) + { + _completed.Clear(); + CompletedCountChanged?.Invoke(this, 0); + } + } + + public bool Any(Func predicate) + { + lock (lockObject) + { + return (Current != null && predicate(Current)) || _completed.Any(predicate) || _queued.Any(predicate); + } + } + + public void MoveQueuePosition(T item, QueuePosition requestedPosition) + { + lock (lockObject) + { + if (_queued.Count == 0 || !_queued.Contains(item)) return; + + if ((requestedPosition == QueuePosition.Fisrt || requestedPosition == QueuePosition.OneUp) && _queued[0] == item) + return; + if ((requestedPosition == QueuePosition.Last || requestedPosition == QueuePosition.OneDown) && _queued[^1] == item) + return; + + int queueIndex = _queued.IndexOf(item); + + if (requestedPosition == QueuePosition.OneUp) + { + _queued.RemoveAt(queueIndex); + _queued.Insert(queueIndex - 1, item); + } + else if (requestedPosition == QueuePosition.OneDown) + { + _queued.RemoveAt(queueIndex); + _queued.Insert(queueIndex + 1, item); + } + else if (requestedPosition == QueuePosition.Fisrt) + { + _queued.RemoveAt(queueIndex); + _queued.Insert(0, item); + } + else + { + _queued.RemoveAt(queueIndex); + _queued.Insert(_queued.Count, item); + } + } + } + + public bool MoveNext() + { + lock (lockObject) + { + if (Current != null) + { + _completed.Add(Current); + CompletedCountChanged?.Invoke(this, _completed.Count); + } + if (_queued.Count == 0) + { + Current = null; + return false; + } + Current = _queued[0]; + _queued.RemoveAt(0); + + QueuededCountChanged?.Invoke(this, _queued.Count); + return true; + } + } + + public bool TryPeek(out T item) + { + lock (lockObject) + { + if (_queued.Count == 0) + { + item = null; + return false; + } + item = _queued[0]; + return true; + } + } + + public T Peek() + { + lock (lockObject) + { + if (_queued.Count == 0) throw new InvalidOperationException("Queue empty"); + return _queued.Count > 0 ? _queued[0] : default; + } + } + + public void Enqueue(T item) + { + lock (lockObject) + { + _queued.Add(item); + QueuededCountChanged?.Invoke(this, _queued.Count); + } + } + } +}