Finialized TrackedQueue
This commit is contained in:
parent
36e5a6ac8d
commit
c39e748749
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
209
Source/LibationWinForms/ProcessQueue/TrackedQueue[T].cs
Normal file
209
Source/LibationWinForms/ProcessQueue/TrackedQueue[T].cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user