Skip to content

Instantly share code, notes, and snippets.

@monoman
Created August 16, 2021 21:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monoman/884a6a62f30b6c6843e5cc486999b24c to your computer and use it in GitHub Desktop.
Save monoman/884a6a62f30b6c6843e5cc486999b24c to your computer and use it in GitHub Desktop.
My Take on David Fowler UberQueue Challenge
// 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