1 /** 2 A FIFO queue implementation. 3 */ 4 module dscord.util.queue; 5 6 import vibe.core.sync; 7 8 import std.container.dlist, 9 std.array, 10 core.time; 11 12 /** 13 A simple Queue of type T. 14 */ 15 class Queue(T) { 16 private DList!(T) data; 17 18 /// Returns the size of the array 19 private size_t _size; 20 21 void setSize(size_t size) { 22 this._size = size; 23 } 24 25 @property size_t size() { 26 return this._size; 27 } 28 29 /// Returns true if the queue is empty 30 @property bool empty() { 31 return this.data.empty; 32 } 33 34 /// Raw array access 35 @property T[] array() { 36 return this.data.array; 37 } 38 39 /// Clear the entire queue 40 void clear() { 41 this.data.removeFront(this.size); 42 this.setSize(0); 43 } 44 45 /// Push an item to the back of the queue. Returns false if the queue is full. 46 bool push(T item) { 47 this.data.insertBack(item); 48 this.setSize(this.size + 1); 49 return true; 50 } 51 52 /// Push multiple items to the back of the queue. Returns false if the queue is 53 // full. 54 bool push(T[] arr) { 55 this.data.insertBack(arr); 56 this.setSize(this.size + 1); 57 return true; 58 } 59 60 /// Pops a single item off the front of the queue. Throws an exception if the 61 // queue is empty. 62 T pop() { 63 if (this.data.empty) { 64 throw new Exception("Cannot pop from empty Queue"); 65 } 66 67 T v = this.data.front; 68 this.data.removeFront(); 69 this.setSize(this.size - 1); 70 return v; 71 } 72 73 /// Peaks at the last item in the queue. 74 T peakBack() { 75 if (this.data.empty) { 76 throw new Exception("Cannot peak into empty Queue"); 77 } 78 79 return this.data.back; 80 } 81 82 /// Peaks at the first item in the queue. 83 T peakFront() { 84 if (this.data.empty) { 85 throw new Exception("Cannot peak into empty Queue"); 86 } 87 88 return this.data.front; 89 } 90 } 91 92 /** 93 A blocking queue of type T. 94 */ 95 class BlockingQueue(T) : Queue!T { 96 private ManualEvent onInsert; 97 private ManualEvent onModify; 98 99 this() { 100 this.onInsert = createManualEvent(); 101 this.onModify = createManualEvent(); 102 } 103 104 override void setSize(size_t size) { 105 if (this._size < size) { 106 this.onInsert.emit(); 107 } 108 109 this.onModify.emit(); 110 this._size = size; 111 } 112 113 bool wait(Duration timeout) { 114 if (this.onModify.wait(timeout, 0) != 0) { 115 return false; 116 } 117 return true; 118 } 119 120 void wait() { 121 this.onModify.wait(); 122 } 123 124 T pop(Duration timeout) { 125 if (this.onInsert.wait(timeout, 0) != 0) { 126 return null; 127 } 128 129 return this.pop(false); 130 } 131 132 /// Pops a single item off the front of the queue. Throws an exception if the 133 // queue is empty. 134 T pop(bool block=true) { 135 if (this.data.empty) { 136 if (block) { 137 this.onInsert.wait(); 138 } else { 139 return null; 140 } 141 } 142 143 return this.pop(); 144 } 145 146 override T pop() { 147 T v = this.data.front; 148 this.data.removeFront(); 149 this.setSize(this.size - 1); 150 return v; 151 } 152 } 153 154 /** 155 A SizedQueue of type T. 156 */ 157 class SizedQueue(T) : Queue!T { 158 /// Maximum size of the queue 159 size_t maxSize; 160 161 this(size_t maxSize) { 162 this.maxSize = maxSize; 163 } 164 165 /// True if the queue is full 166 @property bool full() { 167 return this.size == this.maxSize; 168 } 169 170 override bool push(T item) { 171 if (this.size == this.maxSize) return false; 172 return super.push(item); 173 } 174 175 override bool push(T[] arr) { 176 if (arr.length + this.size > this.maxSize) return false; 177 return super.push(arr); 178 } 179 }