Port to netstandard.

Nit fixes.
Fixed e2e tests.
Added MIT license.
This commit is contained in:
Alexandru Macocian
2021-03-26 11:58:07 +01:00
parent f6069bd3aa
commit f39e8cf89e
26 changed files with 112 additions and 1034 deletions
@@ -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
}
}
+22
View File
@@ -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
}
}