Skip to content

Instantly share code, notes, and snippets.

@ZachBray
Created November 27, 2014 22:14
Show Gist options
  • Save ZachBray/1dce078d3950d021f7ef to your computer and use it in GitHub Desktop.
Save ZachBray/1dce078d3950d021f7ef to your computer and use it in GitHub Desktop.
Functional style queue in C# - quite ugly
internal class LinkedListNode<T>
{
private readonly T _item;
private readonly LinkedListNode<T> _nextNode;
public LinkedListNode(T item, LinkedListNode<T> nextNode)
{
_item = item;
_nextNode = nextNode;
}
public T Item
{
get { return _item; }
}
public LinkedListNode<T> NextNode
{
get { return _nextNode; }
}
public LinkedListNode<T> Reverse()
{
LinkedListNode<T> reversedNodes = null;
LinkedListNode<T> next = this;
while (next != null)
{
reversedNodes = new LinkedListNode<T>(next.Item, reversedNodes);
next = next.NextNode;
}
return reversedNodes;
}
}
internal class ConcurrentFunctionalQueue<T>
{
// Item1: newest::older, Item2: oldest::newer
private Tuple<LinkedListNode<T>, LinkedListNode<T>> _nodes = new Tuple<LinkedListNode<T>,LinkedListNode<T>>(null, null);
/// <summary>
/// Returns true if the item enqueued was the first item to be enqueued.
/// </summary>
public bool Enqueue(T item)
{
Tuple<LinkedListNode<T>, LinkedListNode<T>> oldNodes;
Tuple<LinkedListNode<T>, LinkedListNode<T>> foundNodes;
do
{
oldNodes = _nodes;
var newNode = new LinkedListNode<T>(item, oldNodes.Item1);
var newNodes = Tuple.Create(newNode, oldNodes.Item2);
foundNodes = Interlocked.CompareExchange(ref _nodes, newNodes, oldNodes);
} while (!ReferenceEquals(foundNodes, oldNodes));
var wasFirstItem = foundNodes.Item1 == null && foundNodes.Item2 == null;
return wasFirstItem;
}
/// <summary>
/// Returns true if the item dequeued was the last item in the queue.
/// </summary>
public bool Dequeue(out T item)
{
T foundItem;
Tuple<LinkedListNode<T>, LinkedListNode<T>> oldNodes;
Tuple<LinkedListNode<T>, LinkedListNode<T>> foundNodes;
Tuple<LinkedListNode<T>, LinkedListNode<T>> newNodes;
do
{
oldNodes = _nodes;
var enqueueSide = oldNodes.Item1;
var hasEnqueueSide = enqueueSide != null;
var dequeueSide = oldNodes.Item2;
var hasDequeueSide = dequeueSide != null;
if (hasDequeueSide)
{
var rest = dequeueSide.NextNode;
foundItem = dequeueSide.Item;
newNodes = Tuple.Create(enqueueSide, rest);
}
else if (hasEnqueueSide)
{
var newDequeueSide = enqueueSide.Reverse();
foundItem = newDequeueSide.Item;
newNodes = Tuple.Create((LinkedListNode<T>)null, newDequeueSide.NextNode);
}
else
{
throw new InvalidOperationException("Queue was empty");
}
foundNodes = Interlocked.CompareExchange(ref _nodes, newNodes, oldNodes);
} while (!ReferenceEquals(foundNodes, oldNodes));
item = foundItem;
return newNodes.Item1 == null && newNodes.Item2 == null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment