1 module anansi.container.queue; 2 import std.algorithm, std.conv; 3 4 /** 5 * 6 */ 7 struct FifoQueue(T) { 8 invariant () { 9 assert (_length <= _buffer.length, "Length must always be smaller than capacity."); 10 assert (_length >= (_buffer.length / 2)); 11 } 12 13 @property bool empty() const { 14 return _length == 0; 15 } 16 17 public void push(T value) { 18 if (_length == _buffer.length ) { 19 realloc(1 + ((_buffer.length * 3) / 2)); 20 } 21 _tail = (_tail + 1) % _buffer.length; 22 _buffer[_tail] = value; 23 _length++; 24 } 25 26 public void pop() 27 in { 28 assert (!empty); 29 } 30 body { 31 _buffer[_head] = T.init; 32 _head = (_head + 1) % _buffer.length; // [0, 1] 2, 1, 0 33 _length = _length - 1; // [0, 1] 2, 1, 0 34 auto threshold = _buffer.length / 2; 35 if (_length < threshold) { 36 realloc(_length); 37 } 38 } 39 40 private void realloc(size_t n) { 41 auto newbuffer = new T[n]; 42 if( _length > 0 ) { 43 if( _head == _tail) { 44 newbuffer[0] = move(_buffer[_head]); 45 } 46 else if( _head < _tail ) { 47 moveAll(_buffer[_head .. _tail+1], newbuffer[0 .. _length]); 48 } 49 else { 50 auto trailingItems = _buffer.length - _head; 51 moveAll(_buffer[_head .. $], newbuffer[]); 52 moveAll(_buffer[0 .. _tail+1], newbuffer[trailingItems .. $]); 53 } 54 _head = 0; 55 _tail = (_length - 1); 56 } 57 _buffer = newbuffer; 58 } 59 60 public @property ref inout(T) front() inout 61 in { 62 assert (!empty); 63 } 64 body { 65 return _buffer[_head]; 66 } 67 68 public @property size_t length() const { 69 return _length; 70 } 71 72 public @property size_t capacity() const { 73 return _buffer.length; 74 } 75 76 private T[] _buffer; 77 private size_t _length; 78 private size_t _head = 0; 79 private size_t _tail = 0; 80 } 81 82 version (unittest) { 83 import std.stdio; 84 } 85 86 unittest { 87 writeln("FifoQueue: simple add & remove"); 88 auto q = FifoQueue!int(); 89 foreach(n; 1 .. 11) { 90 q.push(n); 91 assert (q.length == n, 92 "(push) Expected length " ~ to!string(n + 1) ~ 93 ", got " ~ to!string(q.length)); 94 } 95 96 foreach(n; 1 .. 11) { 97 assert (q.front == n, 98 "(pop) Expected front value " ~ to!string(n) ~ 99 ", got " ~ to!string(q.front)); 100 101 q.pop(); 102 } 103 } 104 105 unittest { 106 writeln("FifoQueue: Staggered add & remove"); 107 auto q = FifoQueue!int(); 108 109 q.push(1); 110 q.push(2); 111 assert(q.length == 2, "Expected length == 2"); 112 assert(q.front == 1, "Expected front == 1"); 113 114 q.pop(); 115 assert(q.front == 2, "Expected front == 2"); 116 117 q.push(3); 118 q.push(4); 119 assert(q.length == 3, "Expected length == 3"); 120 assert(q.front == 2, "Expected front == 2"); 121 122 q.pop(); 123 assert(q.length == 2, "Expected length == 2"); 124 assert(q.front == 3, "Expected front == 3"); 125 126 q.push(5); 127 q.push(6); 128 q.push(7); 129 130 assert(q.length == 5, "Expected length == 5"); 131 assert(q.front == 3, "Expected front == 3"); 132 133 q.pop(); 134 q.pop(); 135 136 assert(q.length == 3, "Expected length == 3"); 137 assert(q.front == 5, "Expected front == 5"); 138 139 q.push(8); 140 q.push(9); 141 q.push(10); 142 143 assert(q.length == 6, "Expected length == 6"); 144 assert(q.front == 5, "Expected front == 5"); 145 146 q.pop(); 147 q.push(11); 148 q.push(12); 149 150 assert(q.length == 7, "Expected length == 7"); 151 assert(q.front == 6, "Expected front == 6"); 152 153 int x = 6; size_t l = q.length; 154 while (!q.empty) { 155 assert (x == q.front); 156 assert (l == q.length); 157 q.pop(); 158 x++; 159 l--; 160 } 161 }