namespace Invercargill.DataStructures { public class Fifo : Enumerable, Queue { public bool is_unblocked { get { return !is_blocking; } } private bool is_blocking = true; private FifoItem* first_item = null; private FifoItem* last_item = null; public override int? peek_count() { return null; } public override EnumerableInfo get_info() { return new EnumerableInfo.infer_ultimate (this, EnumerableCategory.EXTERNAL); } public void unblock() { mutex.lock(); is_blocking = false; cond.broadcast(); mutex.unlock(); } public void push(owned T item) { mutex.lock(); FifoItem* fifo_item = new FifoItem() { item = item, }; if(first_item == null) { first_item = fifo_item; last_item = fifo_item; } else { last_item->next_item = fifo_item; last_item = fifo_item; } cond.broadcast(); mutex.unlock(); } public void push_all(Enumerable items) { mutex.lock(); foreach (var item in items) { FifoItem* fifo_item = new FifoItem() { item = item, }; if(first_item == null) { first_item = fifo_item; last_item = fifo_item; } else { last_item->next_item = fifo_item; last_item = fifo_item; } } cond.broadcast(); mutex.unlock(); } public T pop() throws SequenceError { mutex.lock(); while(is_blocking && first_item == null){ cond.wait(mutex); } var item = first_item; if(item != null) { first_item = item->next_item; } mutex.unlock(); if(item == null) { throw new SequenceError.NO_ELEMENTS("No elements in unblocked queue to pop"); } var result = item->item; delete item; return result; } public T peek() throws SequenceError { var item = first_item; if(item == null) { throw new SequenceError.NO_ELEMENTS("No elements in queue"); } return item->item; } public void push_start(owned T item) { mutex.lock(); FifoItem* fifo_item = new FifoItem() { next_item = first_item, item = item, }; if(first_item == null) { last_item = fifo_item; } first_item = fifo_item; cond.broadcast(); mutex.unlock(); } private bool has_next() { mutex.lock(); while(is_blocking && first_item == null){ cond.wait(mutex); } var state = first_item != null; mutex.unlock(); return state; } private T get_next() { mutex.lock(); var item = first_item; first_item = item->next_item; mutex.unlock(); var result = item->item; delete item; return result; } private Cond cond = Cond (); private Mutex mutex = Mutex (); public override Tracker get_tracker () { return new LambdaTracker( () => has_next(), () => get_next()); } ~Fifo() { var n = first_item; while(n != null) { var c = n; n = n->next_item; delete c; } } [Compact] private class FifoItem { public T item; public FifoItem* next_item; } } }