Created
November 27, 2014 22:14
-
-
Save ZachBray/1dce078d3950d021f7ef to your computer and use it in GitHub Desktop.
Functional style queue in C# - quite ugly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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