RosettaCodeData/Task/Queue-Usage/D/queue-usage-2.d

65 lines
1.6 KiB
D

module queue_usage2;
import std.traits: hasIndirections;
struct GrowableCircularQueue(T) {
public size_t length;
private size_t head, tail;
private T[] A = [T.init];
private uint power2 = 0;
bool empty() const pure nothrow {
return length == 0;
}
void push(immutable T item) pure nothrow {
if (length >= A.length) { // Double the queue.
const old = A;
A = new T[A.length * 2];
A[0 .. (old.length - head)] = old[head .. $];
if (head)
A[(old.length - head) .. old.length] = old[0 .. head];
head = 0;
tail = length;
power2++;
}
A[tail] = item;
tail = (tail + 1) & ((cast(size_t)1 << power2) - 1);
length++;
}
T pop() pure {
if (length == 0)
throw new Exception("GrowableCircularQueue is empty.");
auto saved = A[head];
static if (hasIndirections!T)
A[head] = T.init; // Help for the GC.
head = (head + 1) & ((cast(size_t)1 << power2) - 1);
length--;
return saved;
}
}
version (queue_usage2_main) {
unittest {
auto q = new GrowableCircularQueue!int();
q.push(10);
q.push(20);
q.push(30);
assert(q.pop() == 10);
assert(q.pop() == 20);
assert(q.pop() == 30);
assert(q.empty());
uint count = 0;
foreach (immutable i; 1 .. 1_000) {
foreach (immutable j; 0 .. i)
q.push(count++);
foreach (immutable j; 0 .. i)
q.pop();
}
}
void main() {}
}