Created
August 16, 2021 21:34
-
-
Save monoman/884a6a62f30b6c6843e5cc486999b24c to your computer and use it in GitHub Desktop.
My Take on David Fowler UberQueue Challenge
This file contains hidden or 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
// See https://aka.ms/new-console-template for more information | |
using System.Collections; | |
using System.Collections.Generic; | |
Console.WriteLine("Hello, UberQueue!"); | |
var uq = new UberCollections.UberQueue<string>( | |
new TestAsyncQueue(delay: 500, "One", "Two", "Three"), | |
new TestAsyncQueue(delay: 1000, "Four", "Five"), | |
new TestAsyncQueue(delay: 150, "Six", "Seven", "Eight", "Nine") | |
); | |
while (true) | |
{ | |
var item = uq.DequeueAsync().Result; | |
Console.WriteLine(item); | |
} | |
/* results are like | |
Hello, UberQueue! | |
Six | |
Seven | |
Eight | |
One | |
Nine | |
Six | |
Seven | |
Four | |
Two | |
Eight | |
Nine | |
Six | |
Three | |
Seven | |
Eight | |
Nine | |
Five | |
One | |
Six | |
Seven | |
Eight | |
Nine | |
Two | |
... | |
*/ | |
class TestAsyncQueue : UberCollections.IAsyncQueue<string> | |
{ | |
private readonly string[] _words; | |
private readonly int _delay; | |
private int _current; | |
public TestAsyncQueue(int delay, params string[] words) | |
{ | |
_words = words ?? throw new ArgumentNullException(nameof(words)); | |
_delay = delay; | |
_current = 0; | |
} | |
public async Task<string> DequeueAsync() | |
{ | |
await Task.Delay(_delay); | |
if (_current >= _words.Length) | |
_current = 0; | |
return _words[_current++]; | |
} | |
} | |
namespace UberCollections | |
{ | |
public interface IAsyncQueue<T> | |
{ | |
Task<T> DequeueAsync(); | |
} | |
public class UberQueue<T> : IAsyncQueue<T> | |
{ | |
public UberQueue(params IAsyncQueue<T>[] queues) | |
{ | |
var validQueues = queues?.Where(queue => queue is not null).ToArray(); | |
if (validQueues is null || validQueues.Length == 0) | |
throw new NotSupportedException("Can't start with no valid queues"); | |
_queue = validQueues.Length == 1 ? validQueues[0] : new MultipleQueue(validQueues); | |
} | |
public Task<T> DequeueAsync() => _queue.DequeueAsync(); | |
private readonly IAsyncQueue<T> _queue; | |
private class MultipleQueue : IAsyncQueue<T> | |
{ | |
public MultipleQueue(IAsyncQueue<T>[] queues) | |
{ | |
_queues = queues; | |
_tasks = new Task<T>[Length]; | |
_next = -1; | |
} | |
private int Length => _queues.Length; | |
public Task<T> DequeueAsync() | |
{ | |
while (true) | |
{ | |
int current = Next(); | |
Task<T>? task = _tasks[current] ??= _queues[current].DequeueAsync(); | |
if (task is not null && task.IsCompleted) | |
{ | |
_tasks[current] = null; | |
return task; | |
} | |
} | |
} | |
private int Next() | |
{ | |
_next++; | |
if (_next >= _queues.Length) | |
_next = 0; | |
return _next; | |
} | |
private readonly Task<T>?[] _tasks; | |
private int _next; | |
private readonly IAsyncQueue<T>[] _queues; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment