mirror of
https://github.com/AlexMacocian/SystemExtensions.git
synced 2026-07-22 17:19:30 +00:00
Port to netstandard.
Nit fixes. Fixed e2e tests. Added MIT license.
This commit is contained in:
@@ -0,0 +1,389 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// AVL tree implementation.
|
||||
/// Thanks to Karim Oumghar for the implementation example.
|
||||
/// Read on https://simpledevcode.wordpress.com/2014/09/16/avl-tree-in-c/
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class AVLTree<T> : ICollection<T> where T : IComparable<T>
|
||||
{
|
||||
#region Fields
|
||||
[Serializable]
|
||||
private class AVLNode<TKey>
|
||||
{
|
||||
public TKey Value;
|
||||
public AVLNode<TKey> Left;
|
||||
public AVLNode<TKey> Right;
|
||||
public AVLNode(TKey value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
}
|
||||
AVLNode<T> root;
|
||||
private int count = 0;
|
||||
private readonly bool isReadOnly = false;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of items currently stored in the tree.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return count;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// True if the collection is readonly. False otherwise.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => isReadOnly;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of an AVLTree collection.
|
||||
/// </summary>
|
||||
public AVLTree()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds the value to the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added to the tree.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
count++;
|
||||
AVLNode<T> newItem = new AVLNode<T>(value);
|
||||
if (root == null)
|
||||
{
|
||||
root = newItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
root = RecursiveInsertion(root, newItem);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if the key is contained into the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be checked if present in the tree.</param>
|
||||
/// <returns>True if the value is in the tree.</returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
AVLNode<T> node = Find(value, root);
|
||||
if (node == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (node.Value.CompareTo(value) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes the specified value from the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be deleted.</param>
|
||||
public bool Remove(T value)
|
||||
{
|
||||
root = Delete(root, value);
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the tree.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(root);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
AVLNode<T> currentNode = queue.Dequeue();
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
currentNode.Left = null;
|
||||
count--;
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
currentNode.Right = null;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
root = null;
|
||||
count--;
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the tree onto the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to store the values in the tree.</param>
|
||||
/// <param name="arrayIndex">Starting index of the provided array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(root);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
AVLNode<T> currentNode = queue.Dequeue();
|
||||
array[arrayIndex++] = currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the tree.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return GetEnumerator(root);
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the tree structure into an array.
|
||||
/// </summary>
|
||||
/// <returns>Array containing the values contained in the tree.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] array = new T[count];
|
||||
CopyTo(array, 0);
|
||||
return array;
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private AVLNode<T> RecursiveInsertion(AVLNode<T> current, AVLNode<T> n)
|
||||
{
|
||||
if (current == null)
|
||||
{
|
||||
current = n;
|
||||
return current;
|
||||
}
|
||||
else if (n.Value.CompareTo(current.Value) < 0)
|
||||
{
|
||||
current.Left = RecursiveInsertion(current.Left, n);
|
||||
current = BalanceTree(current);
|
||||
}
|
||||
else if (n.Value.CompareTo(current.Value) > 0)
|
||||
{
|
||||
current.Right = RecursiveInsertion(current.Right, n);
|
||||
current = BalanceTree(current);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T> BalanceTree(AVLNode<T> current)
|
||||
{
|
||||
int b_factor = BalanceFactor(current);
|
||||
if (b_factor > 1)
|
||||
{
|
||||
if (BalanceFactor(current.Left) > 0)
|
||||
{
|
||||
current = RotateLL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = RotateLR(current);
|
||||
}
|
||||
}
|
||||
else if (b_factor < -1)
|
||||
{
|
||||
if (BalanceFactor(current.Right) > 0)
|
||||
{
|
||||
current = RotateRL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = RotateRR(current);
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T> Delete(AVLNode<T> current, T target)
|
||||
{
|
||||
AVLNode<T> parent;
|
||||
if (current == null)
|
||||
{ return null; }
|
||||
else
|
||||
{
|
||||
//left subtree
|
||||
if (target.CompareTo(current.Value) < 0)
|
||||
{
|
||||
current.Left = Delete(current.Left, target);
|
||||
if (BalanceFactor(current) == -2)//here
|
||||
{
|
||||
if (BalanceFactor(current.Right) <= 0)
|
||||
{
|
||||
current = RotateRR(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = RotateRL(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
//right subtree
|
||||
else if (target.CompareTo(current.Value) > 0)
|
||||
{
|
||||
current.Right = Delete(current.Right, target);
|
||||
if (BalanceFactor(current) == 2)
|
||||
{
|
||||
if (BalanceFactor(current.Left) >= 0)
|
||||
{
|
||||
current = RotateLL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = RotateLR(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
//if target is found
|
||||
else
|
||||
{
|
||||
count--;
|
||||
if (current.Right != null)
|
||||
{
|
||||
//delete its inorder successor
|
||||
parent = current.Right;
|
||||
while (parent.Left != null)
|
||||
{
|
||||
parent = parent.Left;
|
||||
}
|
||||
current.Value = parent.Value;
|
||||
current.Right = Delete(current.Right, parent.Value);
|
||||
if (BalanceFactor(current) == 2)//rebalancing
|
||||
{
|
||||
if (BalanceFactor(current.Left) >= 0)
|
||||
{
|
||||
current = RotateLL(current);
|
||||
}
|
||||
else { current = RotateLR(current); }
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //if current.left != null
|
||||
return current.Left;
|
||||
}
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T> Find(T target, AVLNode<T> current)
|
||||
{
|
||||
if (current == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (target.CompareTo(current.Value) < 0)
|
||||
{
|
||||
if (target.CompareTo(current.Value) == 0)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
else
|
||||
return Find(target, current.Left);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target.CompareTo(current.Value) == 0)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
else
|
||||
return Find(target, current.Right);
|
||||
}
|
||||
|
||||
}
|
||||
private int Max(int l, int r)
|
||||
{
|
||||
return l > r ? l : r;
|
||||
}
|
||||
private int GetHeight(AVLNode<T> current)
|
||||
{
|
||||
int height = 0;
|
||||
if (current != null)
|
||||
{
|
||||
int l = GetHeight(current.Left);
|
||||
int r = GetHeight(current.Right);
|
||||
int m = Max(l, r);
|
||||
height = m + 1;
|
||||
}
|
||||
return height;
|
||||
}
|
||||
private int BalanceFactor(AVLNode<T> current)
|
||||
{
|
||||
int l = GetHeight(current.Left);
|
||||
int r = GetHeight(current.Right);
|
||||
int b_factor = l - r;
|
||||
return b_factor;
|
||||
}
|
||||
private AVLNode<T> RotateRR(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Right;
|
||||
parent.Right = pivot.Left;
|
||||
pivot.Left = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLL(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Left;
|
||||
parent.Left = pivot.Right;
|
||||
pivot.Right = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLR(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Left;
|
||||
parent.Left = RotateRR(pivot);
|
||||
return RotateLL(parent);
|
||||
}
|
||||
private AVLNode<T> RotateRL(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Right;
|
||||
parent.Right = RotateLL(pivot);
|
||||
return RotateRR(parent);
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(AVLNode<T> rootNode)
|
||||
{
|
||||
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(rootNode);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
AVLNode<T> currentNode = queue.Dequeue();
|
||||
yield return currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Binary heap implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class BinaryHeap<T> : IEnumerable<T> where T : IComparable<T>
|
||||
{
|
||||
#region Fields
|
||||
T[] items;
|
||||
private int capacity;
|
||||
private int count;
|
||||
private readonly int initialCapacity;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Minimum value from the heap.
|
||||
/// </summary>
|
||||
public T Min
|
||||
{
|
||||
get
|
||||
{
|
||||
return items[1];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Maximum value from the heap.
|
||||
/// </summary>
|
||||
public T Max
|
||||
{
|
||||
get
|
||||
{
|
||||
return items[count];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Capacity of the heap.
|
||||
/// </summary>
|
||||
public int Capacity
|
||||
{
|
||||
get => capacity;
|
||||
set
|
||||
{
|
||||
if (value > capacity)
|
||||
{
|
||||
Array.Resize(ref items, value);
|
||||
capacity = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Number of elements in the heap.
|
||||
/// </summary>
|
||||
public int Count { get => count; }
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
public BinaryHeap()
|
||||
{
|
||||
capacity = 10;
|
||||
initialCapacity = capacity;
|
||||
items = new T[capacity];
|
||||
}
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Initial capacity of the heap. Used for initial alocation of the array.</param>
|
||||
public BinaryHeap(int capacity)
|
||||
{
|
||||
this.capacity = capacity;
|
||||
initialCapacity = capacity;
|
||||
items = new T[capacity];
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds value to the queue.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
if (count == Capacity - 1)
|
||||
{
|
||||
Capacity = 2 * Capacity;
|
||||
}
|
||||
int position = ++count;
|
||||
for (; position > 1 && value.CompareTo(items[position / 2]) < 0; position /= 2)
|
||||
{
|
||||
items[position] = items[position / 2];
|
||||
}
|
||||
items[position] = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes the item at the root. Throws exception if there are no items in the heap.
|
||||
/// </summary>
|
||||
/// <returns>Value removed.</returns>
|
||||
public T Remove()
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
T min = items[1];
|
||||
items[1] = items[count--];
|
||||
BubbleDown(1);
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Peeks at the item at the root. Throws exception if there are no items in the heap.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public T Peek()
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
T min = items[1];
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Return the heap structure as an array
|
||||
/// </summary>
|
||||
/// <returns>Array with values sorted as in heap</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] newArray = new T[count];
|
||||
Array.Copy(items, 1, newArray, 0, count);
|
||||
return newArray;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the heap contains specified value
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the heap</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return items.Contains(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the heap
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the heap.
|
||||
/// </summary>
|
||||
/// <param name="completeClear">Specifies if the underlying array should be cleared as well</param>
|
||||
public void Clear(bool completeClear)
|
||||
{
|
||||
count = 0;
|
||||
if (completeClear)
|
||||
{
|
||||
capacity = initialCapacity;
|
||||
items = new T[initialCapacity];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates over the heap.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the heap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
yield return items[i + 1];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Bubble the specified element to its position
|
||||
/// </summary>
|
||||
/// <param name="index">Index of element to bubble</param>
|
||||
private void BubbleDown(int index)
|
||||
{
|
||||
T temp = items[index];
|
||||
int childIndex;
|
||||
for (; 2 * index <= count; index = childIndex)
|
||||
{
|
||||
childIndex = 2 * index;
|
||||
if (childIndex != Count && items[childIndex].CompareTo(items[childIndex + 1]) > 0)
|
||||
{
|
||||
childIndex++;
|
||||
}
|
||||
if (temp.CompareTo(items[childIndex]) > 0)
|
||||
{
|
||||
items[index] = items[childIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
items[index] = temp;
|
||||
}
|
||||
/// <summary>
|
||||
/// Implementation of IEnumerator.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator over the array.</returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,560 @@
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Fibonacci Heap implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type</typeparam>
|
||||
[Serializable]
|
||||
public sealed class FibonacciHeap<T> : IEnumerable<T> where T : IComparable<T>
|
||||
{
|
||||
#region Fields
|
||||
private FibonacciNode<T> root;
|
||||
private int count;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of values in the heap.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return count;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Minimal value contained in the heap.
|
||||
/// </summary>
|
||||
public T Minimum
|
||||
{
|
||||
get
|
||||
{
|
||||
return root.Value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for Fibonacci heap data structure.
|
||||
/// </summary>
|
||||
public FibonacciHeap()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds value to the heap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
FibonacciNode<T> node = new FibonacciNode<T>
|
||||
{
|
||||
Value = value,
|
||||
Marked = false,
|
||||
Child = null,
|
||||
Parent = null,
|
||||
Degree = 0
|
||||
};
|
||||
node.Previous = node.Next = node;
|
||||
root = this.Merge(root, node);
|
||||
count++;
|
||||
}
|
||||
/// <summary>
|
||||
/// Merge current heap with another heap. The other heap will be disposed at the end of this method.
|
||||
/// </summary>
|
||||
/// <param name="otherHeap">The heap to be merged with the current heap.</param>
|
||||
public void Merge(FibonacciHeap<T> otherHeap)
|
||||
{
|
||||
root = Merge(root, otherHeap.root);
|
||||
otherHeap.root = null;
|
||||
count += otherHeap.count;
|
||||
}
|
||||
/// <summary>
|
||||
/// Remove the minimum value from the heap.
|
||||
/// </summary>
|
||||
/// <returns>Minimum value.</returns>
|
||||
public T Remove()
|
||||
{
|
||||
FibonacciNode<T> currentRoot = root;
|
||||
if (currentRoot != null)
|
||||
{
|
||||
root = RemoveMinimum(root);
|
||||
count--;
|
||||
return currentRoot.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Decrease the old value to a new provided value.
|
||||
/// </summary>
|
||||
/// <param name="oldValue">Old value used to find the node to have its key decreased.</param>
|
||||
/// <param name="value">New value to be assigned to the node.</param>
|
||||
public void DecreaseKey(T oldValue, T value)
|
||||
{
|
||||
FibonacciNode<T> node = Find(root, oldValue);
|
||||
root = DecreaseKey(root, node, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the heap contains a specified value.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the heap.</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return Find(root, value) != null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the heap.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
count = 0;
|
||||
Remove(root);
|
||||
root.Next = root.Previous = root.Parent = root.Child = null;
|
||||
root = null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Return the heap structure as an array. Array is not sorted other than the
|
||||
/// actual structure of the heap.
|
||||
/// </summary>
|
||||
/// <returns>Array with values from the heap.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
T[] array = new T[count];
|
||||
if (count == 1)
|
||||
{
|
||||
array[0] = root.Value;
|
||||
return array;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = 0;
|
||||
RecursiveFillArray(root, ref array, ref index);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the heap. Note that the values are not sorted in any way.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the heap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return GetEnumerator(root);
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Recursively traverse the heap and copy its contents to an array.
|
||||
/// </summary>
|
||||
/// <param name="currentNode">Current node.</param>
|
||||
/// <param name="array">Array to be filled with contents of heap.</param>
|
||||
/// <param name="index">Index of the next unintialized element in the array.</param>
|
||||
private void RecursiveFillArray(FibonacciNode<T> currentNode, ref T[] array, ref int index)
|
||||
{
|
||||
FibonacciNode<T> oldNode = currentNode;
|
||||
do
|
||||
{
|
||||
array[index] = currentNode.Value;
|
||||
index++;
|
||||
if (currentNode.HasChildren())
|
||||
{
|
||||
RecursiveFillArray(currentNode.Child, ref array, ref index);
|
||||
}
|
||||
currentNode = currentNode.Previous;
|
||||
} while (currentNode != oldNode);
|
||||
}
|
||||
/// <summary>
|
||||
/// Recursively enumerates over the tree.
|
||||
/// </summary>
|
||||
/// <param name="currentNode">Current node in the iteration.</param>
|
||||
private IEnumerator<T> GetEnumerator(FibonacciNode<T> currentNode)
|
||||
{
|
||||
Queue<FibonacciNode<T>> queue = new Queue<FibonacciNode<T>>();
|
||||
queue.Enqueue(currentNode);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
currentNode = queue.Dequeue();
|
||||
FibonacciNode<T> oldNode = currentNode;
|
||||
do
|
||||
{
|
||||
yield return currentNode.Value;
|
||||
if (currentNode.HasChildren())
|
||||
{
|
||||
queue.Enqueue(currentNode.Child);
|
||||
}
|
||||
currentNode = currentNode.Previous;
|
||||
} while (currentNode != oldNode);
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Recursively remove the node and its children from the heap.
|
||||
/// </summary>
|
||||
/// <param name="node">Node to be removed.</param>
|
||||
private void Remove(FibonacciNode<T> node)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
FibonacciNode<T> current = node;
|
||||
do
|
||||
{
|
||||
Remove(current.Child);
|
||||
if (current.Parent != null)
|
||||
{
|
||||
current.Parent.Child = null;
|
||||
}
|
||||
current = current.Next;
|
||||
} while (current != node);
|
||||
current.Next = current.Previous = current.Child = current.Parent = null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Merge two heaps into a larger heap.
|
||||
/// </summary>
|
||||
/// <param name="node1">Root of first heap.</param>
|
||||
/// <param name="node2">Root of second heap.</param>
|
||||
private FibonacciNode<T> Merge(FibonacciNode<T> node1, FibonacciNode<T> node2)
|
||||
{
|
||||
if (node1 == null)
|
||||
{
|
||||
return node2;
|
||||
}
|
||||
if (node2 == null)
|
||||
{
|
||||
return node1;
|
||||
}
|
||||
if (node1.Value.CompareTo(node2.Value) > 0)
|
||||
{
|
||||
FibonacciNode<T> temp = node1;
|
||||
node1 = node2;
|
||||
node2 = temp;
|
||||
}
|
||||
FibonacciNode<T> node1Next = node1.Next;
|
||||
FibonacciNode<T> node2Prev = node2.Previous;
|
||||
node1.Next = node2;
|
||||
node2.Previous = node1;
|
||||
node1Next.Previous = node2Prev;
|
||||
node2Prev.Next = node1Next;
|
||||
return node1;
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds child to the parent.
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent node to accept child.</param>
|
||||
/// <param name="child">Child node to be added to the parent.</param>
|
||||
private void AddChild(FibonacciNode<T> parent, FibonacciNode<T> child)
|
||||
{
|
||||
child.Previous = child.Next = child;
|
||||
child.Parent = parent;
|
||||
parent.Degree++;
|
||||
parent.Child = Merge(parent.Child, child);
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes the parent of the specified node.
|
||||
/// </summary>
|
||||
/// <param name="node">Node to be removed from its parent.</param>
|
||||
private void RemoveParent(FibonacciNode<T> node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
FibonacciNode<T> current = node;
|
||||
do
|
||||
{
|
||||
current.Marked = false;
|
||||
current.Parent = null;
|
||||
current = current.Next;
|
||||
} while (current != node);
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes the minimum node from the provided tree.
|
||||
/// </summary>
|
||||
/// <param name="node">Root of the provided tree.</param>
|
||||
/// <returns></returns>
|
||||
private FibonacciNode<T> RemoveMinimum(FibonacciNode<T> node)
|
||||
{
|
||||
RemoveParent(node.Child);
|
||||
if (node.Next == node)
|
||||
{
|
||||
node = node.Child;
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Next.Previous = node.Previous;
|
||||
node.Previous.Next = node.Next;
|
||||
node = Merge(node.Next, node.Child);
|
||||
}
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
FibonacciNode<T>[] trees = new FibonacciNode<T>[64];
|
||||
while (true)
|
||||
{
|
||||
if (trees[node.Degree] != null)
|
||||
{
|
||||
FibonacciNode<T> t = trees[node.Degree];
|
||||
if (t == node)
|
||||
{
|
||||
break;
|
||||
}
|
||||
trees[node.Degree] = null;
|
||||
if (node.Value.CompareTo(t.Value) < 0)
|
||||
{
|
||||
t.Previous.Next = t.Next;
|
||||
t.Next.Previous = t.Previous;
|
||||
AddChild(node, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
t.Previous.Next = t.Next;
|
||||
t.Next.Previous = t.Previous;
|
||||
if (node.Next == node)
|
||||
{
|
||||
t.Next = t.Previous = t;
|
||||
AddChild(t, node);
|
||||
node = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Previous.Next = t;
|
||||
node.Next.Previous = t;
|
||||
t.Next = node.Next;
|
||||
t.Previous = node.Previous;
|
||||
AddChild(t, node);
|
||||
node = t;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
trees[node.Degree] = node;
|
||||
}
|
||||
node = node.Next;
|
||||
}
|
||||
FibonacciNode<T> min = node;
|
||||
FibonacciNode<T> start = node;
|
||||
do
|
||||
{
|
||||
if (node.Value.CompareTo(min.Value) < 0)
|
||||
{
|
||||
min = node;
|
||||
}
|
||||
node = node.Next;
|
||||
} while (node != start);
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Cut node from heap.
|
||||
/// </summary>
|
||||
/// <param name="root">Root of heap.</param>
|
||||
/// <param name="node">Node to be cut.</param>
|
||||
/// <returns></returns>
|
||||
private FibonacciNode<T> Cut(FibonacciNode<T> root, FibonacciNode<T> node)
|
||||
{
|
||||
if (node.Next == node)
|
||||
{
|
||||
node.Parent.Child = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Next.Previous = node.Previous;
|
||||
node.Previous.Next = node.Next;
|
||||
node.Parent.Child = node.Next;
|
||||
}
|
||||
node.Next = node.Previous = node;
|
||||
node.Marked = false;
|
||||
return Merge(root, node);
|
||||
}
|
||||
/// <summary>
|
||||
/// Decrease value of provided node substituting it with the provided value.
|
||||
/// </summary>
|
||||
/// <param name="root">Root of the heap.</param>
|
||||
/// <param name="node">Node to have value decreased.</param>
|
||||
/// <param name="value">New value of the node. It is only applied if the value is lower than the previous value.</param>
|
||||
/// <returns></returns>
|
||||
private FibonacciNode<T> DecreaseKey(FibonacciNode<T> root, FibonacciNode<T> node, T value)
|
||||
{
|
||||
if (node.Value.CompareTo(value) < 0)
|
||||
{
|
||||
return root;
|
||||
}
|
||||
node.Value = value;
|
||||
if (node.Parent != null)
|
||||
{
|
||||
if (node.Value.CompareTo(node.Parent.Value) < 0)
|
||||
{
|
||||
root = Cut(root, node);
|
||||
FibonacciNode<T> parent = node.Parent;
|
||||
node.Parent = null;
|
||||
while (parent != null && parent.Marked)
|
||||
{
|
||||
root = Cut(root, parent);
|
||||
node = parent;
|
||||
parent = node.Parent;
|
||||
node.Parent = null;
|
||||
}
|
||||
if (parent != null && parent.Parent != null)
|
||||
{
|
||||
parent.Marked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.Value.CompareTo(root.Value) < 0)
|
||||
{
|
||||
root = node;
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
/// <summary>
|
||||
/// Find the node that has the specified value in the heap.
|
||||
/// </summary>
|
||||
/// <param name="root">Root of the heap.</param>
|
||||
/// <param name="value">Value to be found.</param>
|
||||
/// <returns></returns>
|
||||
private FibonacciNode<T> Find(FibonacciNode<T> root, T value)
|
||||
{
|
||||
FibonacciNode<T> node = root;
|
||||
if (node == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
do
|
||||
{
|
||||
if (node.Value.CompareTo(value) == 0)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
FibonacciNode<T> ret = Find(node.Child, value);
|
||||
if (ret != null)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
node = node.Next;
|
||||
} while (node != root);
|
||||
return null;
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
[Serializable]
|
||||
internal sealed class FibonacciNode<T>
|
||||
{
|
||||
#region Fields
|
||||
private FibonacciNode<T> previous;
|
||||
private FibonacciNode<T> next;
|
||||
private FibonacciNode<T> child;
|
||||
private FibonacciNode<T> parent;
|
||||
private T value;
|
||||
private int degree;
|
||||
private bool marked;
|
||||
#endregion
|
||||
#region Properties
|
||||
public FibonacciNode<T> Previous
|
||||
{
|
||||
get
|
||||
{
|
||||
return previous;
|
||||
}
|
||||
set
|
||||
{
|
||||
previous = value;
|
||||
}
|
||||
}
|
||||
public FibonacciNode<T> Next
|
||||
{
|
||||
get
|
||||
{
|
||||
return next;
|
||||
}
|
||||
set
|
||||
{
|
||||
next = value;
|
||||
}
|
||||
}
|
||||
public FibonacciNode<T> Child
|
||||
{
|
||||
get
|
||||
{
|
||||
return child;
|
||||
}
|
||||
set
|
||||
{
|
||||
child = value;
|
||||
}
|
||||
}
|
||||
public FibonacciNode<T> Parent
|
||||
{
|
||||
get
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
set
|
||||
{
|
||||
parent = value;
|
||||
}
|
||||
}
|
||||
public bool Marked
|
||||
{
|
||||
get
|
||||
{
|
||||
return marked;
|
||||
}
|
||||
set
|
||||
{
|
||||
marked = value;
|
||||
}
|
||||
}
|
||||
public T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return value;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
public int Degree
|
||||
{
|
||||
get
|
||||
{
|
||||
return degree;
|
||||
}
|
||||
set
|
||||
{
|
||||
degree = value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
public bool HasChildren()
|
||||
{
|
||||
return child != null;
|
||||
}
|
||||
public bool HasParent()
|
||||
{
|
||||
return parent != null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for queue implementations.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
public interface IQueue<T> : IEnumerable<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the number of items in the queue.
|
||||
/// </summary>
|
||||
int Count { get; }
|
||||
/// <summary>
|
||||
/// Inserts item into the queue.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be inserted.</param>
|
||||
void Enqueue(T item);
|
||||
/// <summary>
|
||||
/// Remove the first item in the queue.
|
||||
/// </summary>
|
||||
/// <returns>First item in the queue.</returns>
|
||||
T Dequeue();
|
||||
/// <summary>
|
||||
/// Looks up the first item from the queue without removing it.
|
||||
/// </summary>
|
||||
/// <returns>First item from the queue.</returns>
|
||||
T Peek();
|
||||
/// <summary>
|
||||
/// Clears the contents of the queue.
|
||||
/// </summary>
|
||||
void Clear();
|
||||
/// <summary>
|
||||
/// Checks if queue contains an item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if queue contains provided item. False otherwise.</returns>
|
||||
bool Contains(T item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Priority Queue data structure. The implementation is based on an array-based implementation of Binary Heap.
|
||||
/// Exposes some of the functionality of the Binary Heap as a queue.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class PriorityQueue<T> : IQueue<T> where T : IComparable<T>
|
||||
{
|
||||
#region Fields
|
||||
private readonly BinaryHeap<T> binaryHeap;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Returns the number of elements stored into the queue.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return binaryHeap.Count;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for priority queue data structure.
|
||||
/// </summary>
|
||||
public PriorityQueue()
|
||||
{
|
||||
binaryHeap = new BinaryHeap<T>();
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Add provided value to the queue.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added to the queue.</param>
|
||||
public void Enqueue(T value)
|
||||
{
|
||||
binaryHeap.Add(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Pops the queue and removes the highest priority value from the queue.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue</returns>
|
||||
public T Dequeue()
|
||||
{
|
||||
if (Count > 0)
|
||||
{
|
||||
return binaryHeap.Remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IndexOutOfRangeException("Queue is empty!");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Looks up the highest priority value from the queue. Doesn't alter the queue in any way.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue.</returns>
|
||||
public T Peek()
|
||||
{
|
||||
return binaryHeap.Min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the queue contents, removing any value stored into the queue.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
binaryHeap.Clear();
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if queue contains provided item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if queue contains the provided item. False otherwise.</returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return binaryHeap.Contains(item);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates over the queue.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the queue.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return binaryHeap.GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Necesarry for the implementatio of IQueue.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Skip list implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class SkipList<T> : ICollection<T> where T : IComparable<T>
|
||||
{
|
||||
#region Fields
|
||||
[Serializable]
|
||||
private class NodeSet<TKey>
|
||||
{
|
||||
public TKey Key;
|
||||
public int Level;
|
||||
public NodeSet<TKey>[] Next;
|
||||
|
||||
public NodeSet(TKey key, int level)
|
||||
{
|
||||
this.Key = key;
|
||||
this.Level = level;
|
||||
Next = new NodeSet<TKey>[level + 1];
|
||||
}
|
||||
}
|
||||
private int count;
|
||||
private readonly Random random;
|
||||
private readonly NodeSet<T> head;
|
||||
private readonly NodeSet<T> end;
|
||||
private readonly int maxLevel = 10;
|
||||
private int level;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Number of elements in the list.
|
||||
/// </summary>
|
||||
public int Count { get => count; }
|
||||
/// <summary>
|
||||
/// Specifies if the collection can be modified.
|
||||
/// </summary>
|
||||
public bool IsReadOnly { get; set; }
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a new instance of SkipList collection.
|
||||
/// </summary>
|
||||
/// <param name="maxLevel">Maximum level of the skip list.</param>
|
||||
public SkipList(int maxLevel = 10)
|
||||
{
|
||||
this.maxLevel = maxLevel;
|
||||
random = new Random();
|
||||
head = new NodeSet<T>(default, maxLevel);
|
||||
end = head;
|
||||
for (int i = 0; i <= maxLevel; i++)
|
||||
{
|
||||
head.Next[i] = end;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds an item to the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be added.</param>
|
||||
public void Add(T item)
|
||||
{
|
||||
NodeSet<T> curNode = head;
|
||||
int newLevel = 0;
|
||||
while (random.Next(0, 2) > 0 && newLevel < maxLevel)
|
||||
{
|
||||
newLevel++;
|
||||
}
|
||||
if (newLevel > level)
|
||||
{
|
||||
level = newLevel;
|
||||
}
|
||||
NodeSet<T> newNode = new NodeSet<T>(item, newLevel);
|
||||
for (var i = 0; i <= newLevel; i++)
|
||||
{
|
||||
if (i > curNode.Level)
|
||||
{
|
||||
curNode = head;
|
||||
}
|
||||
while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0)
|
||||
{
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
newNode.Next[i] = curNode.Next[i];
|
||||
curNode.Next[i] = newNode;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes provided item from the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be removed.</param>
|
||||
/// <returns>True if removal was successful.</returns>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
bool removed = false;
|
||||
NodeSet<T> curNode = head;
|
||||
for (var i = 0; i <= maxLevel; i++)
|
||||
{
|
||||
if (i > curNode.Level)
|
||||
{
|
||||
curNode = head;
|
||||
}
|
||||
while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0)
|
||||
{
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
if (curNode.Next[i].Key.CompareTo(item) == 0) //Item is present on this level
|
||||
{
|
||||
curNode.Next[i] = curNode.Next[i].Next[i];
|
||||
removed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (removed)
|
||||
{
|
||||
count--;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the collection.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
for (int i = 0; i < maxLevel; i++)
|
||||
{
|
||||
head.Next[i] = end;
|
||||
}
|
||||
count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if item is present in the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if item is present in the collection.</returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
if (Find(item) != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the skip list contents onto the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to hold the values from the list.</param>
|
||||
/// <param name="arrayIndex">Index to start insertion in the array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
NodeSet<T> node = head.Next[0];
|
||||
while (node != end)
|
||||
{
|
||||
array[arrayIndex] = node.Key;
|
||||
arrayIndex++;
|
||||
node = node.Next[0];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the elements from the collection into an array.
|
||||
/// </summary>
|
||||
/// <returns>Array filled with elements from the collection.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] array = new T[count];
|
||||
int index = 0;
|
||||
NodeSet<T> curNode = head.Next[0];
|
||||
while (curNode != end)
|
||||
{
|
||||
array[index] = curNode.Key;
|
||||
index++;
|
||||
curNode = curNode.Next[0];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
NodeSet<T> curNode = head.Next[0];
|
||||
while (curNode != end)
|
||||
{
|
||||
yield return curNode.Key;
|
||||
curNode = curNode.Next[0];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private NodeSet<T> Find(T key)
|
||||
{
|
||||
NodeSet<T> curNode = head;
|
||||
|
||||
for (int i = level; i >= 0; i--)
|
||||
{
|
||||
while (curNode.Next[i] != end)
|
||||
{
|
||||
if (curNode.Next[i].Key.CompareTo(key) > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (curNode.Next[i].Key.CompareTo(key) == 0)
|
||||
{
|
||||
return curNode.Next[i];
|
||||
}
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
}
|
||||
|
||||
curNode = curNode.Next[0];
|
||||
if (curNode != end && curNode.Key.CompareTo(key) == 0)
|
||||
{
|
||||
return curNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Treap implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class Treap<T> : ICollection<T> where T : IComparable<T>
|
||||
{
|
||||
#region Fields
|
||||
[Serializable]
|
||||
private class Node<TKey>
|
||||
{
|
||||
public TKey Key;
|
||||
public int Priority;
|
||||
public Node<TKey> Left, Right;
|
||||
public Node(TKey key, int priority)
|
||||
{
|
||||
Key = key;
|
||||
Priority = priority;
|
||||
Left = null;
|
||||
Right = null;
|
||||
}
|
||||
}
|
||||
private readonly Random randomGen;
|
||||
private Node<T> root;
|
||||
private int count;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of values in the treap.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return count;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Not implemented.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => false;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for treap.
|
||||
/// </summary>
|
||||
public Treap()
|
||||
{
|
||||
randomGen = new Random();
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds value to the treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
root = InsertNode(root, value);
|
||||
count++;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes value from treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be removed.</param>
|
||||
public bool Remove(T value)
|
||||
{
|
||||
root = RemoveNode(root, value);
|
||||
count--;
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the treap.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
Clear(root);
|
||||
root = null;
|
||||
count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the treap contains the specified value.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the treap.</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return Find(root, value) != null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the treap structure as an ordered array.
|
||||
/// </summary>
|
||||
/// <returns>Ordered array containing the values stored in the treap.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
if (root != null)
|
||||
{
|
||||
T[] array = new T[count];
|
||||
int index = 0;
|
||||
ToArray(root, ref array, ref index);
|
||||
return array;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copy the treap into the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to be populated with the values contained in the array.</param>
|
||||
/// <param name="arrayIndex">Starting index of the array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
ToArray(root, ref array, ref arrayIndex);
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the treap. Note that the values are not guaranteed to be sorted.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the treap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return GetEnumerator(root);
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private Node<T> InsertNode(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
node = new Node<T>(key, randomGen.Next(0, 100));
|
||||
return node;
|
||||
}
|
||||
else if (key.CompareTo(node.Key) <= 0)
|
||||
{
|
||||
node.Left = InsertNode(node.Left, key);
|
||||
if (node.Left.Priority > node.Priority)
|
||||
{
|
||||
node = RotateRight(node);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Right = InsertNode(node.Right, key);
|
||||
if (node.Right.Priority > node.Priority)
|
||||
{
|
||||
node = RotateLeft(node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
private Node<T> RemoveNode(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
if (key.CompareTo(node.Key) < 0)
|
||||
{
|
||||
node.Left = RemoveNode(node.Left, key);
|
||||
}
|
||||
else if (key.CompareTo(node.Key) > 0)
|
||||
{
|
||||
node.Right = RemoveNode(node.Right, key);
|
||||
}
|
||||
else if (node.Left == null)
|
||||
{
|
||||
node = node.Right;
|
||||
}
|
||||
else if (node.Right == null)
|
||||
{
|
||||
node = node.Left;
|
||||
}
|
||||
else if (node.Left.Priority < node.Right.Priority)
|
||||
{
|
||||
node = RotateLeft(node);
|
||||
node.Left = RemoveNode(node.Left, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = RotateRight(node);
|
||||
node.Right = RemoveNode(node.Right, key);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
private Node<T> RotateRight(Node<T> node)
|
||||
{
|
||||
Node<T> temp = node.Left, temp2 = temp.Right;
|
||||
temp.Right = node;
|
||||
node.Left = temp2;
|
||||
return temp;
|
||||
}
|
||||
private Node<T> RotateLeft(Node<T> node)
|
||||
{
|
||||
Node<T> temp = node.Right, temp2 = temp.Left;
|
||||
temp.Left = node;
|
||||
node.Right = temp2;
|
||||
return temp;
|
||||
}
|
||||
private void Clear(Node<T> node)
|
||||
{
|
||||
if (node.Left != null)
|
||||
{
|
||||
Clear(node.Left);
|
||||
}
|
||||
if (node.Right != null)
|
||||
{
|
||||
Clear(node.Right);
|
||||
}
|
||||
node.Left = node.Right = null;
|
||||
}
|
||||
private Node<T> Find(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.Key.CompareTo(key) < 0)
|
||||
{
|
||||
Node<T> found = Find(node.Left, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = Find(node.Right, key);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
else if (node.Key.CompareTo(key) > 0)
|
||||
{
|
||||
Node<T> found = Find(node.Right, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = Find(node.Left, key);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
else
|
||||
{
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void ToArray(Node<T> node, ref T[] array, ref int index)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
ToArray(node.Left, ref array, ref index);
|
||||
array[index] = node.Key;
|
||||
index++;
|
||||
ToArray(node.Right, ref array, ref index);
|
||||
}
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(Node<T> currentNode)
|
||||
{
|
||||
Queue<Node<T>> queue = new Queue<Node<T>>();
|
||||
queue.Enqueue(currentNode);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
currentNode = queue.Dequeue();
|
||||
yield return currentNode.Key;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2021
|
||||
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the “Software”), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
|
||||
namespace System.Structures.BitStructures
|
||||
{
|
||||
public struct Int32BitStruct : IEquatable<Int32BitStruct>
|
||||
{
|
||||
public Int32BitStruct(uint value) => this.Value = value;
|
||||
public Int32BitStruct(int value) { unchecked { this.Value = (uint)value; } }
|
||||
public uint Value { get; set; }
|
||||
public uint Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1U) | (0x1 & value)); }
|
||||
public uint Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1U << 1)) | ((0x1 & value) << 1); }
|
||||
public uint Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1U << 2)) | ((0x1 & value) << 2); }
|
||||
public uint Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1U << 3)) | ((0x1 & value) << 3); }
|
||||
public uint Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1U << 4)) | ((0x1 & value) << 4); }
|
||||
public uint Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1U << 5)) | ((0x1 & value) << 5); }
|
||||
public uint Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1U << 6)) | ((0x1 & value) << 6); }
|
||||
public uint Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1U << 7)) | ((0x1 & value) << 7); }
|
||||
public uint Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1U << 8)) | ((0x1 & value) << 8); }
|
||||
public uint Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1U << 9)) | ((0x1 & value) << 9); }
|
||||
public uint Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1U << 10)) | ((0x1 & value) << 10); }
|
||||
public uint Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1U << 11)) | ((0x1 & value) << 11); }
|
||||
public uint Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1U << 12)) | ((0x1 & value) << 12); }
|
||||
public uint Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1U << 13)) | ((0x1 & value) << 13); }
|
||||
public uint Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1U << 14)) | ((0x1 & value) << 14); }
|
||||
public uint Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1U << 15)) | ((0x1 & value) << 15); }
|
||||
public uint Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1U << 16)) | ((0x1 & value) << 16); }
|
||||
public uint Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1U << 17)) | ((0x1 & value) << 17); }
|
||||
public uint Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1U << 18)) | ((0x1 & value) << 18); }
|
||||
public uint Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1U << 19)) | ((0x1 & value) << 19); }
|
||||
public uint Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1U << 20)) | ((0x1 & value) << 20); }
|
||||
public uint Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1U << 21)) | ((0x1 & value) << 21); }
|
||||
public uint Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1U << 22)) | ((0x1 & value) << 22); }
|
||||
public uint Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1U << 23)) | ((0x1 & value) << 23); }
|
||||
public uint Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1U << 24)) | ((0x1 & value) << 24); }
|
||||
public uint Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1U << 25)) | ((0x1 & value) << 25); }
|
||||
public uint Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1U << 26)) | ((0x1 & value) << 26); }
|
||||
public uint Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1U << 27)) | ((0x1 & value) << 27); }
|
||||
public uint Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1U << 28)) | ((0x1 & value) << 28); }
|
||||
public uint Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1U << 29)) | ((0x1 & value) << 29); }
|
||||
public uint Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1U << 30)) | ((0x1 & value) << 30); }
|
||||
public uint Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1U << 31)) | ((0x1 & value) << 31); }
|
||||
|
||||
public static implicit operator Int32BitStruct(uint value) => new Int32BitStruct(value);
|
||||
public static implicit operator Int32BitStruct(int value) => new Int32BitStruct(value);
|
||||
public static implicit operator int(Int32BitStruct value) => (int)value.Value;
|
||||
public static implicit operator uint(Int32BitStruct value) => value.Value;
|
||||
public static bool operator ==(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value == second.Value;
|
||||
}
|
||||
|
||||
public static bool operator !=(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value != second.Value;
|
||||
}
|
||||
|
||||
public static bool operator ==(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value == second;
|
||||
}
|
||||
|
||||
public static bool operator !=(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value != second;
|
||||
}
|
||||
|
||||
public static bool operator ==(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value == (uint)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator !=(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value != (uint)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value >= second.Value;
|
||||
}
|
||||
|
||||
public static bool operator <=(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value <= second.Value;
|
||||
}
|
||||
|
||||
public static bool operator >=(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value >= (uint)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <=(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value <= (uint)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value >= second;
|
||||
}
|
||||
|
||||
public static bool operator <=(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value <= second;
|
||||
}
|
||||
|
||||
public static bool operator >(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value > second.Value;
|
||||
}
|
||||
|
||||
public static bool operator <(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value < second.Value;
|
||||
}
|
||||
|
||||
public static bool operator >(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value > (uint)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value < (uint)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value > second;
|
||||
}
|
||||
|
||||
public static bool operator <(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value < second;
|
||||
}
|
||||
|
||||
public bool Equals(Int32BitStruct other)
|
||||
{
|
||||
return this.Value == other.Value;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Int32BitStruct)
|
||||
{
|
||||
return this.Equals((Int32BitStruct)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.Equals(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (this.Value).GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
using System;
|
||||
|
||||
namespace System.Structures.BitStructures
|
||||
{
|
||||
public struct Int64BitStruct : IEquatable<Int64BitStruct>
|
||||
{
|
||||
public Int64BitStruct(uint low, uint high)
|
||||
{
|
||||
this.Value = low + ((ulong)high << 32);
|
||||
}
|
||||
|
||||
public Int64BitStruct(int low, int high)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
this.Value = (uint)low + ((ulong)high << 32);
|
||||
}
|
||||
}
|
||||
|
||||
public Int64BitStruct(long value)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
this.Value = (ulong)value;
|
||||
}
|
||||
}
|
||||
|
||||
public Int64BitStruct(ulong value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public ulong Value { get; set; }
|
||||
public uint Low { get => (uint)(this.Value & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF)) | (0xFFFFFFFF & value); }
|
||||
public uint High { get => (uint)((this.Value >> 32) & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF00000000)) | ((ulong)(0xFFFFFFFF & value) << 32); }
|
||||
public ulong Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1UL) | (0x1 & value)); }
|
||||
public ulong Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 1)) | ((0x1 & value) << 1); }
|
||||
public ulong Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 2)) | ((0x1 & value) << 2); }
|
||||
public ulong Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 3)) | ((0x1 & value) << 3); }
|
||||
public ulong Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 4)) | ((0x1 & value) << 4); }
|
||||
public ulong Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 5)) | ((0x1 & value) << 5); }
|
||||
public ulong Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 6)) | ((0x1 & value) << 6); }
|
||||
public ulong Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 7)) | ((0x1 & value) << 7); }
|
||||
public ulong Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 8)) | ((0x1 & value) << 8); }
|
||||
public ulong Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 9)) | ((0x1 & value) << 9); }
|
||||
public ulong Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 10)) | ((0x1 & value) << 10); }
|
||||
public ulong Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 11)) | ((0x1 & value) << 11); }
|
||||
public ulong Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 12)) | ((0x1 & value) << 12); }
|
||||
public ulong Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 13)) | ((0x1 & value) << 13); }
|
||||
public ulong Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 14)) | ((0x1 & value) << 14); }
|
||||
public ulong Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 15)) | ((0x1 & value) << 15); }
|
||||
public ulong Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 16)) | ((0x1 & value) << 16); }
|
||||
public ulong Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 17)) | ((0x1 & value) << 17); }
|
||||
public ulong Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 18)) | ((0x1 & value) << 18); }
|
||||
public ulong Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 19)) | ((0x1 & value) << 19); }
|
||||
public ulong Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 20)) | ((0x1 & value) << 20); }
|
||||
public ulong Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 21)) | ((0x1 & value) << 21); }
|
||||
public ulong Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 22)) | ((0x1 & value) << 22); }
|
||||
public ulong Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 23)) | ((0x1 & value) << 23); }
|
||||
public ulong Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 24)) | ((0x1 & value) << 24); }
|
||||
public ulong Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 25)) | ((0x1 & value) << 25); }
|
||||
public ulong Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 26)) | ((0x1 & value) << 26); }
|
||||
public ulong Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 27)) | ((0x1 & value) << 27); }
|
||||
public ulong Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 28)) | ((0x1 & value) << 28); }
|
||||
public ulong Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 29)) | ((0x1 & value) << 29); }
|
||||
public ulong Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 30)) | ((0x1 & value) << 30); }
|
||||
public ulong Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 31)) | ((0x1 & value) << 31); }
|
||||
public ulong Bit32 { get => this.Value >> 32 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 32)) | ((0x1 & value) << 32); }
|
||||
public ulong Bit33 { get => this.Value >> 33 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 33)) | ((0x1 & value) << 33); }
|
||||
public ulong Bit34 { get => this.Value >> 34 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 34)) | ((0x1 & value) << 34); }
|
||||
public ulong Bit35 { get => this.Value >> 35 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 35)) | ((0x1 & value) << 35); }
|
||||
public ulong Bit36 { get => this.Value >> 36 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 36)) | ((0x1 & value) << 36); }
|
||||
public ulong Bit37 { get => this.Value >> 37 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 37)) | ((0x1 & value) << 37); }
|
||||
public ulong Bit38 { get => this.Value >> 38 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 38)) | ((0x1 & value) << 38); }
|
||||
public ulong Bit39 { get => this.Value >> 39 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 39)) | ((0x1 & value) << 39); }
|
||||
public ulong Bit40 { get => this.Value >> 40 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 40)) | ((0x1 & value) << 40); }
|
||||
public ulong Bit41 { get => this.Value >> 41 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 41)) | ((0x1 & value) << 41); }
|
||||
public ulong Bit42 { get => this.Value >> 42 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 42)) | ((0x1 & value) << 42); }
|
||||
public ulong Bit43 { get => this.Value >> 43 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 43)) | ((0x1 & value) << 43); }
|
||||
public ulong Bit44 { get => this.Value >> 44 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 44)) | ((0x1 & value) << 44); }
|
||||
public ulong Bit45 { get => this.Value >> 45 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 45)) | ((0x1 & value) << 45); }
|
||||
public ulong Bit46 { get => this.Value >> 46 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 46)) | ((0x1 & value) << 46); }
|
||||
public ulong Bit47 { get => this.Value >> 47 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 47)) | ((0x1 & value) << 47); }
|
||||
public ulong Bit48 { get => this.Value >> 48 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 48)) | ((0x1 & value) << 48); }
|
||||
public ulong Bit49 { get => this.Value >> 49 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 49)) | ((0x1 & value) << 49); }
|
||||
public ulong Bit50 { get => this.Value >> 50 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 50)) | ((0x1 & value) << 50); }
|
||||
public ulong Bit51 { get => this.Value >> 51 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 51)) | ((0x1 & value) << 51); }
|
||||
public ulong Bit52 { get => this.Value >> 52 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 52)) | ((0x1 & value) << 52); }
|
||||
public ulong Bit53 { get => this.Value >> 53 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 53)) | ((0x1 & value) << 53); }
|
||||
public ulong Bit54 { get => this.Value >> 54 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 54)) | ((0x1 & value) << 54); }
|
||||
public ulong Bit55 { get => this.Value >> 55 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 55)) | ((0x1 & value) << 55); }
|
||||
public ulong Bit56 { get => this.Value >> 56 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 56)) | ((0x1 & value) << 56); }
|
||||
public ulong Bit57 { get => this.Value >> 57 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 57)) | ((0x1 & value) << 57); }
|
||||
public ulong Bit58 { get => this.Value >> 58 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 58)) | ((0x1 & value) << 58); }
|
||||
public ulong Bit59 { get => this.Value >> 59 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 59)) | ((0x1 & value) << 59); }
|
||||
public ulong Bit60 { get => this.Value >> 60 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 60)) | ((0x1 & value) << 60); }
|
||||
public ulong Bit61 { get => this.Value >> 61 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 61)) | ((0x1 & value) << 61); }
|
||||
public ulong Bit62 { get => this.Value >> 62 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 62)) | ((0x1 & value) << 62); }
|
||||
public ulong Bit63 { get => this.Value >> 63 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 63)) | ((0x1 & value) << 63); }
|
||||
|
||||
public static implicit operator Int64BitStruct(ulong value) => new Int64BitStruct(value);
|
||||
public static implicit operator Int64BitStruct(long value) => new Int64BitStruct(value);
|
||||
public static implicit operator long(Int64BitStruct value) => (long)value.Value;
|
||||
public static implicit operator ulong(Int64BitStruct value) => value.Value;
|
||||
public static bool operator ==(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value == second.Value;
|
||||
}
|
||||
|
||||
public static bool operator !=(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value != second.Value;
|
||||
}
|
||||
|
||||
public static bool operator ==(Int64BitStruct first, ulong second)
|
||||
{
|
||||
return first.Value == second;
|
||||
}
|
||||
|
||||
public static bool operator !=(Int64BitStruct first, ulong second)
|
||||
{
|
||||
return first.Value != second;
|
||||
}
|
||||
|
||||
public static bool operator ==(Int64BitStruct first, long second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value == (ulong)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator !=(Int64BitStruct first, long second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value != (ulong)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value >= second.Value;
|
||||
}
|
||||
|
||||
public static bool operator <=(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value <= second.Value;
|
||||
}
|
||||
|
||||
public static bool operator >=(Int64BitStruct first, long second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value >= (ulong)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <=(Int64BitStruct first, long second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value <= (ulong)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Int64BitStruct first, ulong second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value >= second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <=(Int64BitStruct first, ulong second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value <= second;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(Int64BitStruct other)
|
||||
{
|
||||
return this.Value == other.Value;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Int64BitStruct)
|
||||
{
|
||||
return this.Equals((Int64BitStruct)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.Equals(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Value.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0</TargetFrameworks>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageLicenseFile>License.txt</PackageLicenseFile>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="License.txt">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,601 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace System.Threading
|
||||
{
|
||||
/// <summary>
|
||||
/// Threadpool implementation that uses a priority queue as the queue for the tasks to execute.
|
||||
/// Features both an automated algorithm to calibrate the number of active threads and a Constructor for constructing
|
||||
/// a threadpool manually, without the auto-managed pool algorithm.
|
||||
/// </summary>
|
||||
public class PriorityThreadPool : IDisposable
|
||||
{
|
||||
private class QueueEntry : IComparable<QueueEntry>
|
||||
{
|
||||
public TaskPriority TaskPriority { get; }
|
||||
public WaitCallback WaitCallback { get; }
|
||||
public object Object { get; }
|
||||
public QueueEntry(TaskPriority priority, WaitCallback callback, object obj)
|
||||
{
|
||||
this.TaskPriority = priority;
|
||||
this.WaitCallback = callback;
|
||||
this.Object = obj;
|
||||
}
|
||||
|
||||
public int CompareTo(QueueEntry other)
|
||||
{
|
||||
int priority1 = 0, priority2 = 0;
|
||||
switch (this.TaskPriority)
|
||||
{
|
||||
case TaskPriority.Highest:
|
||||
priority1 = 4;
|
||||
break;
|
||||
case TaskPriority.AboveNormal:
|
||||
priority1 = 3;
|
||||
break;
|
||||
case TaskPriority.Normal:
|
||||
priority1 = 2;
|
||||
break;
|
||||
case TaskPriority.BelowNormal:
|
||||
priority1 = 1;
|
||||
break;
|
||||
case TaskPriority.Lowest:
|
||||
priority1 = 0;
|
||||
break;
|
||||
}
|
||||
switch (other.TaskPriority)
|
||||
{
|
||||
case TaskPriority.Highest:
|
||||
priority2 = 4;
|
||||
break;
|
||||
case TaskPriority.AboveNormal:
|
||||
priority2 = 3;
|
||||
break;
|
||||
case TaskPriority.Normal:
|
||||
priority2 = 2;
|
||||
break;
|
||||
case TaskPriority.BelowNormal:
|
||||
priority2 = 1;
|
||||
break;
|
||||
case TaskPriority.Lowest:
|
||||
priority2 = 0;
|
||||
break;
|
||||
}
|
||||
if (priority1 == priority2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (priority1 > priority2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Enum
|
||||
/// <summary>
|
||||
/// Enum for priority of task scheduled
|
||||
/// </summary>
|
||||
public enum TaskPriority
|
||||
{
|
||||
/// <summary>
|
||||
/// Highest priority of a task.
|
||||
/// </summary>
|
||||
Highest,
|
||||
/// <summary>
|
||||
/// Priority level above the default level.
|
||||
/// </summary>
|
||||
AboveNormal,
|
||||
/// <summary>
|
||||
/// Default priority level of all tasks without a specified priority level.
|
||||
/// </summary>
|
||||
Normal,
|
||||
/// <summary>
|
||||
/// Priority level below the default level.
|
||||
/// </summary>
|
||||
BelowNormal,
|
||||
/// <summary>
|
||||
/// Lowest priority level.
|
||||
/// </summary>
|
||||
Lowest
|
||||
}
|
||||
#endregion
|
||||
#region Fields
|
||||
/// <summary>
|
||||
/// List that contains current running threads and their status.
|
||||
/// </summary>
|
||||
private volatile List<WorkerThread> threadpool;
|
||||
private volatile PriorityQueue<QueueEntry> tasks;
|
||||
private Thread observer;
|
||||
private int maxThreads;
|
||||
private readonly object tasksLock = new object();
|
||||
private struct WorkerThread
|
||||
{
|
||||
public Thread thread;
|
||||
public bool running, working;
|
||||
}
|
||||
private struct Statistics
|
||||
{
|
||||
public bool Initialized;
|
||||
public int PerformanceCounter;
|
||||
public DateTime LastUpdate;
|
||||
public double LoopFrequency;
|
||||
}
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Returns the number of active threads in the threadpool.
|
||||
/// </summary>
|
||||
public int NumberOfThreads
|
||||
{
|
||||
get
|
||||
{
|
||||
return threadpool.Count;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns true if there are no tasks queued.
|
||||
/// </summary>
|
||||
public bool Empty
|
||||
{
|
||||
get
|
||||
{
|
||||
return tasks.Count == 0;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Maximum amount of threads that the pool can utilize
|
||||
/// </summary>
|
||||
public int MaxThreads
|
||||
{
|
||||
set
|
||||
{
|
||||
maxThreads = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
return maxThreads;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor that initializes a threadpool using default values. All threads run at the same priority.
|
||||
/// The maximum number of threads is equal to System.Environment.ProcessorCount
|
||||
/// </summary>
|
||||
public PriorityThreadPool()
|
||||
{
|
||||
threadpool = new List<WorkerThread>();
|
||||
tasks = new PriorityQueue<QueueEntry>();
|
||||
maxThreads = System.Environment.ProcessorCount;
|
||||
for (int i = 0; i < maxThreads; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
observer = new Thread(() =>
|
||||
{
|
||||
ObserverLoop();
|
||||
});
|
||||
observer.Name = "ThreadPool ObserverThread";
|
||||
observer.Priority = ThreadPriority.BelowNormal;
|
||||
observer.Start();
|
||||
}
|
||||
/// <summary>
|
||||
/// Constructor that initializes a threadpool with a number of threads, all of the same priority.
|
||||
/// </summary>
|
||||
/// <param name="maxThreads">Maximum number of threads</param>
|
||||
public PriorityThreadPool(int maxThreads)
|
||||
{
|
||||
threadpool = new List<WorkerThread>();
|
||||
tasks = new PriorityQueue<QueueEntry>();
|
||||
this.maxThreads = Math.Max(maxThreads, 1);
|
||||
for (int i = 0; i < maxThreads; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
observer = new Thread(() =>
|
||||
{
|
||||
ObserverLoop();
|
||||
});
|
||||
observer.Name = "ThreadPool ObserverThread";
|
||||
observer.Priority = ThreadPriority.BelowNormal;
|
||||
observer.Start();
|
||||
}
|
||||
/// <summary>
|
||||
/// Constructor for a manually-configured threadpool that runs a specified number of threads.
|
||||
/// This threadpool with not be automatically managed and will always run the specified amount of threads
|
||||
/// </summary>
|
||||
/// <param name="lowest">Number of threads with Lowest priority.</param>
|
||||
/// <param name="belowNormal">Number of threads with BelowNormal priority.</param>
|
||||
/// <param name="normal">Number of threads with Normal priority.</param>
|
||||
/// <param name="aboveNormal">Number of threads with AboveNormal priority.</param>
|
||||
/// <param name="highest">Number of threads with Highest priority.</param>
|
||||
public PriorityThreadPool(int lowest, int belowNormal, int normal, int aboveNormal, int highest)
|
||||
{
|
||||
threadpool = new List<WorkerThread>();
|
||||
tasks = new PriorityQueue<QueueEntry>();
|
||||
for (int i = 0; i < lowest; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.Lowest;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
for (int i = 0; i < belowNormal; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.BelowNormal;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
for (int i = 0; i < normal; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.Normal;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
for (int i = 0; i < aboveNormal; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.AboveNormal;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
for (int i = 0; i < highest; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.Highest;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Add a work item into the queue.
|
||||
/// </summary>
|
||||
/// <param name="waitCallback">WaitCallBack delegate that will be invoked by the threads.</param>
|
||||
/// <param name="callbackState">State used as parameter during invoke.</param>
|
||||
/// <param name="taskPriority">Priority of task. Affects its position into the queue.</param>
|
||||
public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState, TaskPriority taskPriority)
|
||||
{
|
||||
while (!Monitor.TryEnter(tasksLock)) ;
|
||||
tasks.Enqueue(new QueueEntry(taskPriority, waitCallback, callbackState));
|
||||
Monitor.Exit(tasksLock);
|
||||
}
|
||||
/// <summary>
|
||||
/// Add a work item into the queue.
|
||||
/// </summary>
|
||||
/// <param name="waitCallback">WaitCallBack delegate that will be invoked by the threads.</param>
|
||||
/// <param name="callbackState">State used as parameter during invoke.</param>
|
||||
public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState)
|
||||
{
|
||||
QueueUserWorkItem(waitCallback, callbackState, TaskPriority.Normal);
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Main loop that a thread from the pool is running.
|
||||
/// </summary>
|
||||
/// <threadId>Id of thread</threadId>
|
||||
private void ThreadMainLoop(ref WorkerThread thisWorkerThread)
|
||||
{
|
||||
thisWorkerThread.running = true;
|
||||
while (thisWorkerThread.running)
|
||||
{
|
||||
//Check if there are tasks
|
||||
|
||||
if (tasks.Count > 0)
|
||||
{
|
||||
//If there are tasks, acquire a lock onto the list
|
||||
//and try to dequeue the highest priority task.
|
||||
//Finally, release the lock and invoke the task.
|
||||
|
||||
thisWorkerThread.working = true;
|
||||
QueueEntry task = null;
|
||||
while (!Monitor.TryEnter(tasksLock)) ;
|
||||
if (tasks.Count > 0)
|
||||
{
|
||||
task = tasks.Dequeue();
|
||||
}
|
||||
Monitor.Exit(tasksLock);
|
||||
if (task != null)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.Name + " - Running task!");
|
||||
WaitCallback waitCallback = task.WaitCallback;
|
||||
waitCallback.Invoke(task.Object);
|
||||
}
|
||||
thisWorkerThread.working = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Loop of the thread that adjusts and manipulates the threadpool
|
||||
/// </summary>
|
||||
private void ObserverLoop()
|
||||
{
|
||||
Statistics statistics = new Statistics();
|
||||
while (true)
|
||||
{
|
||||
//Observer operates on a 100ms loop. Due to the low priority of the thread itself, this loop will almost always take
|
||||
//considerably longer than 100ms.
|
||||
//Checks if the queue is empty. If yes, counter is decremented, else, counter is incremented.
|
||||
//If counter exceeds 5, it will try to add another thread to the thread, unless the threadpool has reached max size.
|
||||
//If counter is under -10, it will try to remove a thread from the threadpool, unless the threadpool has reached less than
|
||||
//max size / 4.
|
||||
|
||||
//This part of code updates the statistics of the threadpool.
|
||||
if (statistics.Initialized)
|
||||
{
|
||||
double loopDuration = (DateTime.Now - statistics.LastUpdate).TotalMilliseconds;
|
||||
if (statistics.LoopFrequency == 0)
|
||||
{
|
||||
statistics.LoopFrequency = loopDuration;
|
||||
}
|
||||
else
|
||||
{
|
||||
statistics.LoopFrequency = (statistics.LoopFrequency + loopDuration) / 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
statistics.Initialized = true;
|
||||
}
|
||||
statistics.LastUpdate = DateTime.Now;
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
|
||||
//This part of code adjusts the performance counter. Ideally, the value should be 0.
|
||||
if (tasks.Count > 0)
|
||||
{
|
||||
statistics.PerformanceCounter++;
|
||||
if (statistics.PerformanceCounter > 5)
|
||||
{
|
||||
statistics.PerformanceCounter = 5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
statistics.PerformanceCounter--;
|
||||
if (statistics.PerformanceCounter < -10)
|
||||
{
|
||||
statistics.PerformanceCounter = -10;
|
||||
}
|
||||
}
|
||||
|
||||
//This part of code adjusts thread priorities based on the current performance of the threadpool
|
||||
if (tasks.Count > 0)
|
||||
{
|
||||
//If there are tasks pending, find a thread with priority under Normal and upgrade its priority.
|
||||
Thread t = FindThreadWithLowPriority();
|
||||
if (t != null)
|
||||
{
|
||||
UpgradeThreadPriority(t);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//If there are no tasks pending, find a thread with priority above Lowest and downgrade its priority.
|
||||
Thread t = FindThreadWithAcceptablePriority();
|
||||
if (t != null)
|
||||
{
|
||||
DowngradeThreadPriority(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//This part of code modifies the number of active threads based on the current performance of the threadpool
|
||||
if (statistics.PerformanceCounter >= 5)
|
||||
{
|
||||
if (threadpool.Count < this.maxThreads)
|
||||
{
|
||||
//Add a thread to the threadpool.
|
||||
//Reset counter to 0.
|
||||
statistics.PerformanceCounter = 0;
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
}
|
||||
else if (statistics.PerformanceCounter <= -10)
|
||||
{
|
||||
if (threadpool.Count > maxThreads / 4)
|
||||
{
|
||||
//Remove the last thread in the threadpool.
|
||||
//If thread is currently working, notify it to close.
|
||||
//Else, abort the thread.
|
||||
//Reset counter to 0.
|
||||
WorkerThread worker = threadpool[threadpool.Count - 1];
|
||||
if (worker.working)
|
||||
{
|
||||
worker.running = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
worker.thread.Abort();
|
||||
}
|
||||
threadpool.RemoveAt(threadpool.Count - 1);
|
||||
statistics.PerformanceCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Find a thread with Lowest or BelowNormal priority.
|
||||
/// </summary>
|
||||
/// <returns>Thread with low priority.</returns>
|
||||
private Thread FindThreadWithLowPriority()
|
||||
{
|
||||
foreach (WorkerThread t in threadpool)
|
||||
{
|
||||
if (t.thread.Priority == ThreadPriority.Lowest || t.thread.Priority == ThreadPriority.BelowNormal)
|
||||
{
|
||||
return t.thread;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Find a thread with BelowNormal or Normal priority.
|
||||
/// </summary>
|
||||
/// <returns>Thread with BelowNormal or Normal priority.</returns>
|
||||
private Thread FindThreadWithAcceptablePriority()
|
||||
{
|
||||
foreach (WorkerThread t in threadpool)
|
||||
{
|
||||
if (t.thread.Priority == ThreadPriority.Normal || t.thread.Priority == ThreadPriority.BelowNormal)
|
||||
{
|
||||
return t.thread;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Downgrades the priority of a thread one level.
|
||||
/// </summary>
|
||||
/// <param name="t">Thread to have its priority level downgraded.</param>
|
||||
/// <returns></returns>
|
||||
private void DowngradeThreadPriority(Thread t)
|
||||
{
|
||||
switch (t.Priority)
|
||||
{
|
||||
case ThreadPriority.Highest:
|
||||
t.Priority = ThreadPriority.AboveNormal;
|
||||
break;
|
||||
case ThreadPriority.AboveNormal:
|
||||
t.Priority = ThreadPriority.Normal;
|
||||
break;
|
||||
case ThreadPriority.Normal:
|
||||
t.Priority = ThreadPriority.BelowNormal;
|
||||
break;
|
||||
case ThreadPriority.BelowNormal:
|
||||
t.Priority = ThreadPriority.Lowest;
|
||||
break;
|
||||
case ThreadPriority.Lowest:
|
||||
t.Priority = ThreadPriority.Lowest;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Upgrades the priority of a thread one level.
|
||||
/// </summary>
|
||||
/// <param name="t">Thread to have its priority level upgraded.</param>
|
||||
/// <returns></returns>
|
||||
private void UpgradeThreadPriority(Thread t)
|
||||
{
|
||||
switch (t.Priority)
|
||||
{
|
||||
case ThreadPriority.Highest:
|
||||
t.Priority = ThreadPriority.Highest;
|
||||
break;
|
||||
case ThreadPriority.AboveNormal:
|
||||
t.Priority = ThreadPriority.Highest;
|
||||
break;
|
||||
case ThreadPriority.Normal:
|
||||
t.Priority = ThreadPriority.AboveNormal;
|
||||
break;
|
||||
case ThreadPriority.BelowNormal:
|
||||
t.Priority = ThreadPriority.Normal;
|
||||
break;
|
||||
case ThreadPriority.Lowest:
|
||||
t.Priority = ThreadPriority.BelowNormal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false;
|
||||
/// <summary>
|
||||
/// Disposes of the tasks as well as aborts all threads. Called by the public Dispose() method.
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (observer != null)
|
||||
{
|
||||
observer.Abort();
|
||||
}
|
||||
foreach (WorkerThread worker in threadpool)
|
||||
{
|
||||
worker.thread.Abort();
|
||||
}
|
||||
threadpool.Clear();
|
||||
tasks.Clear();
|
||||
}
|
||||
threadpool = null;
|
||||
tasks = null;
|
||||
observer = null;
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Disposes of the tasks as well as aborts all threads.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user