65 lines
1.6 KiB
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() {}
|
|
}
|