Add range support for SList

This commit is contained in:
Eugen Wissner 2017-01-24 08:20:07 +01:00
parent a7206cbd02
commit a48d9cb739
2 changed files with 129 additions and 32 deletions

View File

@ -10,9 +10,63 @@
*/
module tanya.container.list;
import std.traits;
import tanya.container.entry;
import tanya.memory;
private struct Range(E)
if (__traits(isSame, TemplateOf!E, SEntry))
{
private alias T = typeof(E.content);
private E* head;
private this(E* head)
{
this.head = head;
}
@property Range save()
{
return this;
}
@property bool empty() const
{
return head is null;
}
@property ref inout(T) front() inout
in
{
assert(!empty);
}
body
{
return head.content;
}
void popFront()
in
{
assert(!empty);
}
body
{
head = head.next;
}
Range opIndex()
{
return typeof(return)(head);
}
Range!(const E) opIndex() const
{
return typeof(return)(head);
}
}
/**
* Singly-linked list.
*
@ -21,6 +75,11 @@ import tanya.memory;
*/
struct SList(T)
{
private alias Entry = SEntry!T;
// 0th element of the list.
private Entry* head;
/**
* Removes all elements from the list.
*/
@ -36,7 +95,7 @@ struct SList(T)
{
while (!empty)
{
popFront();
removeFront();
}
}
@ -61,7 +120,7 @@ struct SList(T)
}
body
{
return first.next.content;
return head.content;
}
/**
@ -72,11 +131,11 @@ struct SList(T)
*/
void insertFront(ref T x)
{
auto temp = allocator.make!(SEntry!T);
auto temp = allocator.make!Entry;
temp.content = x;
temp.next = first.next;
first.next = temp;
temp.next = head;
head = temp;
}
/// Ditto.
@ -104,25 +163,27 @@ struct SList(T)
*/
@property bool empty() const
{
return first.next is null;
return head is null;
}
/**
* Returns the first element and moves to the next one.
*
* Returns: The first element.
*
* Precondition: $(D_INLINECODE !empty)
*/
void popFront()
void removeFront()
in
{
assert(!empty);
}
body
{
auto n = first.next.next;
auto n = head.next;
allocator.dispose(first.next);
first.next = n;
allocator.dispose(head);
head = n;
}
///
@ -133,14 +194,16 @@ struct SList(T)
l.insertFront(8);
l.insertFront(9);
assert(l.front == 9);
l.popFront();
l.removeFront();
assert(l.front == 8);
l.removeFront();
assert(l.empty);
}
/**
* Removes $(D_PARAM howMany) elements from the list.
*
* Unlike $(D_PSYMBOL popFront()), this method doesn't fail, if it could not
* Unlike $(D_PSYMBOL removeFront()), this method doesn't fail, if it could not
* remove $(D_PARAM howMany) elements. Instead, if $(D_PARAM howMany) is
* greater than the list length, all elements are removed.
*
@ -149,12 +212,17 @@ struct SList(T)
*
* Returns: The number of elements removed.
*/
size_t removeFront(in size_t howMany = 1)
size_t removeFront(in size_t howMany)
out (removed)
{
assert(removed <= howMany);
}
body
{
size_t i;
for (; i < howMany && !empty; ++i)
{
popFront();
removeFront();
}
return i;
}
@ -182,12 +250,12 @@ struct SList(T)
* Params:
* dg = $(D_KEYWORD foreach) body.
*/
int opApply(scope int delegate(ref size_t i, ref T) dg)
int opApply(scope int delegate(ref size_t i, ref T) @nogc dg)
{
int result;
size_t i;
for (auto pos = first.next; pos; pos = pos.next, ++i)
for (auto pos = head; pos; pos = pos.next, ++i)
{
result = dg(i, pos.content);
@ -200,11 +268,11 @@ struct SList(T)
}
/// Ditto.
int opApply(scope int delegate(ref T) dg)
int opApply(scope int delegate(ref T) @nogc dg)
{
int result;
for (auto pos = first.next; pos; pos = pos.next)
for (auto pos = head; pos; pos = pos.next)
{
result = dg(pos.content);
@ -232,8 +300,15 @@ struct SList(T)
}
}
/// 0th element of the list.
private SEntry!T first;
Range!Entry opIndex()
{
return typeof(return)(head);
}
Range!(const Entry) opIndex() const
{
return typeof(return)(head);
}
mixin DefaultAllocator;
}
@ -257,7 +332,7 @@ unittest
assert(i == 3);
}
private unittest
unittest
{
interface Stuff
{

View File

@ -547,6 +547,23 @@ struct Vector(T)
return length == 0;
}
/**
* Removes the value at the back of the vector.
*
* Returns: The number of elements removed
*
* Precondition: $(D_INLINECODE !empty)
*/
void removeBack()
in
{
assert(!empty);
}
body
{
length = length - 1;
}
/**
* Removes $(D_PARAM howMany) elements from the vector.
*
@ -559,11 +576,16 @@ struct Vector(T)
*
* Returns: The number of elements removed
*/
size_t removeBack(in size_t howMany = 1)
size_t removeBack(in size_t howMany)
out (removed)
{
immutable toRemove = min(howMany, length_);
assert(removed <= howMany);
}
body
{
immutable toRemove = min(howMany, length);
length = length_ - toRemove;
length = length - toRemove;
return toRemove;
}
@ -1119,9 +1141,9 @@ struct Vector(T)
/// Ditto.
int opApply(scope int delegate(ref size_t i, ref T) @nogc dg)
{
for (size_t i = 0; i < length_; ++i)
for (size_t i = 0; i < length; ++i)
{
assert(i < length_);
assert(i < length);
int result = dg(i, *(vector + i));
if (result != 0)
@ -1135,7 +1157,7 @@ struct Vector(T)
/// Ditto.
int opApplyReverse(scope int delegate(ref T) dg)
{
for (T* end = vector + length_ - 1; vector != end; --end)
for (T* end = vector + length - 1; vector != end; --end)
{
int result = dg(*end);
if (result != 0)
@ -1149,13 +1171,13 @@ struct Vector(T)
/// Ditto.
int opApplyReverse(scope int delegate(ref size_t i, ref T) dg)
{
if (length_ > 0)
if (length > 0)
{
size_t i = length_;
size_t i = length;
do
{
--i;
assert(i < length_);
assert(i < length);
int result = dg(i, *(vector + i));
if (result != 0)
@ -1211,7 +1233,7 @@ struct Vector(T)
/**
* Returns: The first element.
*
* Precondition: $(D_INLINECODE length > 0)
* Precondition: $(D_INLINECODE !empty)
*/
@property ref inout(T) front() inout
in
@ -1238,7 +1260,7 @@ struct Vector(T)
/**
* Returns: The last element.
*
* Precondition: $(D_INLINECODE length > 0)
* Precondition: $(D_INLINECODE !empty)
*/
@property ref inout(T) back() inout @trusted
in