Finialized TrackedQueue

This commit is contained in:
Michael Bucari-Tovo 2022-05-14 01:33:05 -06:00
parent 36e5a6ac8d
commit c39e748749
2 changed files with 209 additions and 175 deletions

View File

@ -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<T> where T : class
{
public T Current { get; private set; }
private readonly LinkedList<T> Queued = new();
private readonly List<T> 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<T> QueuedItems()
{
lock (lockObject)
return Queued.ToList();
}
public List<T> 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<T, bool> 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);
}
}
}

View File

@ -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<T> where T : class
{
public event EventHandler<int> CompletedCountChanged;
public event EventHandler<int> QueuededCountChanged;
public T Current { get; private set; }
public IReadOnlyList<T> Queued => _queued;
public IReadOnlyList<T> Completed => _completed;
private readonly List<T> _queued = new();
private readonly List<T> _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<T, bool> 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);
}
}
}
}