From b9b6ab54f3eee0a355c716f07da3c1504812b089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20Gyllebring?= Date: Thu, 13 Nov 2014 11:31:48 +0100 Subject: [PATCH] longs should be enough for everybode. --- Source/Core/CircularQueue.cs | 22 ++++++------ Specs/Cone.Specs/Cone.Specs.csproj | 1 + Specs/Cone.Specs/Core/CircularQueueSpec.cs | 42 ++++++++++++++++++++++ 3 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 Specs/Cone.Specs/Core/CircularQueueSpec.cs diff --git a/Source/Core/CircularQueue.cs b/Source/Core/CircularQueue.cs index 6548e3d..abfe951 100644 --- a/Source/Core/CircularQueue.cs +++ b/Source/Core/CircularQueue.cs @@ -6,25 +6,27 @@ namespace Cone.Core public class CircularQueue { readonly T[] buffer; - int nextAvailable = 0; - int lastWritten = -1; - int nextRead = 0; + public long nextAvailable = 0; + public long head = -1; + public long tail = 0; public CircularQueue(int bufferSize) { buffer = new T[bufferSize]; } public bool TryEnqueue(T value) { - int claimed; + long claimed; do { claimed = nextAvailable; - if(buffer.Length <= (claimed - nextRead)) + if(buffer.Length <= (claimed - tail)) return false; } while(Interlocked.CompareExchange(ref nextAvailable, claimed + 1, claimed) != claimed); buffer[claimed % buffer.Length] = value; - for(int spins = 1, prev = claimed - 1; Interlocked.CompareExchange(ref lastWritten, claimed, prev) != prev; ++spins) { + var prev = claimed - 1; + for(var spins = 1; + Interlocked.CompareExchange(ref head, claimed, prev) != prev; ++spins) { Thread.SpinWait(spins); } @@ -32,14 +34,14 @@ public bool TryEnqueue(T value) { } public bool TryDeque(out T value) { - int pos; + long pos; do { - pos = nextRead; - if(pos == nextAvailable) { + pos = tail; + if(head < pos) { value = default(T); return false; } - } while(Interlocked.CompareExchange(ref nextRead, pos + 1, pos) != pos); + } while(Interlocked.CompareExchange(ref tail, pos + 1, pos) != pos); value = buffer[pos % buffer.Length]; return true; diff --git a/Specs/Cone.Specs/Cone.Specs.csproj b/Specs/Cone.Specs/Cone.Specs.csproj index 12263db..a427e0a 100644 --- a/Specs/Cone.Specs/Cone.Specs.csproj +++ b/Specs/Cone.Specs/Cone.Specs.csproj @@ -51,6 +51,7 @@ + diff --git a/Specs/Cone.Specs/Core/CircularQueueSpec.cs b/Specs/Cone.Specs/Core/CircularQueueSpec.cs new file mode 100644 index 0000000..9148e01 --- /dev/null +++ b/Specs/Cone.Specs/Core/CircularQueueSpec.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Cone.Core +{ + [Describe(typeof(CircularQueue<>))] + public class CircularQueueSpec + { + public void TryEnqueue_fails_when_at_capacity() { + var q = new CircularQueue(1); + Assume.That(() => q.TryEnqueue(0)); + + Check.That(() => !q.TryEnqueue(1)); + } + + public void TryEnqueue_fails_if_write_catches_up_to_read() { + var q = new CircularQueue(2); + int ignored; + Assume.That(() => q.TryEnqueue(0)); + Assume.That(() => q.TryDeque(out ignored)); + + Assume.That(() => q.TryEnqueue(0)); + Assume.That(() => q.TryEnqueue(1)); + Check.That(() => !q.TryEnqueue(2)); + } + + public void is_first_in_first_out() { + var q = new CircularQueue(2); + + Assume.That(() => q.TryEnqueue(0)); + Assume.That(() => q.TryEnqueue(1)); + + int value; + Check.That( + () => q.TryDeque(out value) && value == 0, + () => q.TryDeque(out value) && value == 1 + ); + } + } +}