remove manual memory management from queue
This commit is contained in:
parent
04e2c3baab
commit
b16a3338b5
|
@ -47,9 +47,6 @@ struct Queue(T)
|
||||||
/// Cursor pointing to the current node in iteration.
|
/// Cursor pointing to the current node in iteration.
|
||||||
Node* cursor_ = null;
|
Node* cursor_ = null;
|
||||||
|
|
||||||
/// The first element of a linked list of freed Nodes available for recycling.
|
|
||||||
Node* freeList_ = null;
|
|
||||||
|
|
||||||
/// Length of the queue.
|
/// Length of the queue.
|
||||||
size_t length_ = 0;
|
size_t length_ = 0;
|
||||||
|
|
||||||
|
@ -58,20 +55,6 @@ struct Queue(T)
|
||||||
@disable bool opEquals(ref Queue);
|
@disable bool opEquals(ref Queue);
|
||||||
@disable int opCmp(ref Queue);
|
@disable int opCmp(ref Queue);
|
||||||
|
|
||||||
/// Destroy the queue, deallocating all its elements.
|
|
||||||
@trusted nothrow ~this()
|
|
||||||
{
|
|
||||||
while(!empty) { pop(); }
|
|
||||||
while(freeList_ !is null)
|
|
||||||
{
|
|
||||||
auto toFree = freeList_;
|
|
||||||
freeList_ = toFree.next_;
|
|
||||||
free(toFree);
|
|
||||||
}
|
|
||||||
cursor_ = last_ = first_ = null;
|
|
||||||
length_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Start iterating over the queue.
|
/// Start iterating over the queue.
|
||||||
void startIteration() @safe pure nothrow @nogc
|
void startIteration() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
|
@ -101,7 +84,7 @@ struct Queue(T)
|
||||||
/// Push new item to the queue.
|
/// Push new item to the queue.
|
||||||
void push(T item) @trusted nothrow
|
void push(T item) @trusted nothrow
|
||||||
{
|
{
|
||||||
Node* newLast = newNode(item, null);
|
Node* newLast = new Node(item, null);
|
||||||
if(last_ !is null) { last_.next_ = newLast; }
|
if(last_ !is null) { last_.next_ = newLast; }
|
||||||
if(first_ is null) { first_ = newLast; }
|
if(first_ is null) { first_ = newLast; }
|
||||||
last_ = newLast;
|
last_ = newLast;
|
||||||
|
@ -118,7 +101,7 @@ struct Queue(T)
|
||||||
{
|
{
|
||||||
if(idx == 0)
|
if(idx == 0)
|
||||||
{
|
{
|
||||||
first_ = newNode(item, first_);
|
first_ = new Node(item, first_);
|
||||||
++length_;
|
++length_;
|
||||||
}
|
}
|
||||||
// Adding before last added element, so we can just push.
|
// Adding before last added element, so we can just push.
|
||||||
|
@ -130,7 +113,7 @@ struct Queue(T)
|
||||||
foreach(i; 1 .. idx) { current = current.next_; }
|
foreach(i; 1 .. idx) { current = current.next_; }
|
||||||
|
|
||||||
// Insert a new node after current, and put current.next_ behind it.
|
// Insert a new node after current, and put current.next_ behind it.
|
||||||
current.next_ = newNode(item, current.next_);
|
current.next_ = new Node(item, current.next_);
|
||||||
++length_;
|
++length_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,9 +130,6 @@ struct Queue(T)
|
||||||
Node* popped = first_;
|
Node* popped = first_;
|
||||||
first_ = first_.next_;
|
first_ = first_.next_;
|
||||||
|
|
||||||
Node* oldFree = freeList_;
|
|
||||||
freeList_ = popped;
|
|
||||||
freeList_.next_ = oldFree;
|
|
||||||
if(--length_ == 0)
|
if(--length_ == 0)
|
||||||
{
|
{
|
||||||
assert(first_ is null);
|
assert(first_ is null);
|
||||||
|
@ -181,43 +161,6 @@ struct Queue(T)
|
||||||
{
|
{
|
||||||
return length_;
|
return length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
/// Get a new (or recycled) node with specified item and next node pointer.
|
|
||||||
///
|
|
||||||
/// Tries to reuse a node from freeList_, allocates a new node if not possible.
|
|
||||||
Node* newNode(ref T item, Node* next) @trusted nothrow
|
|
||||||
{
|
|
||||||
if(freeList_ !is null)
|
|
||||||
{
|
|
||||||
auto node = freeList_;
|
|
||||||
freeList_ = freeList_.next_;
|
|
||||||
*node = Node(item, next);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
return allocate!Node(item, next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
/// Allocate a struct, passing arguments to its constructor or default initializer.
|
|
||||||
T* allocate(T, Args...)(Args args) @system nothrow
|
|
||||||
{
|
|
||||||
T* ptr = cast(T*)malloc(T.sizeof);
|
|
||||||
*ptr = T(args);
|
|
||||||
// The struct might contain references to GC-allocated memory, so tell the GC about it.
|
|
||||||
static if(hasIndirections!T) { GC.addRange(cast(void*)ptr, T.sizeof); }
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deallocate struct pointed at by specified pointer.
|
|
||||||
void free(T)(T* ptr) @system nothrow
|
|
||||||
{
|
|
||||||
// GC doesn't need to care about any references in this struct anymore.
|
|
||||||
static if(hasIndirections!T) { GC.removeRange(cast(void*)ptr); }
|
|
||||||
core.stdc.stdlib.free(ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@safe unittest
|
@safe unittest
|
||||||
|
|
Loading…
Reference in a new issue