Add insertBefore and remove to SList
This commit is contained in:
parent
7892c1a930
commit
49cae88645
@ -20,16 +20,22 @@ import std.traits;
|
|||||||
import tanya.container.entry;
|
import tanya.container.entry;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
|
|
||||||
private struct Range(E)
|
private struct Range(Entry)
|
||||||
if (__traits(isSame, TemplateOf!E, SEntry))
|
if (__traits(isSame, TemplateOf!Entry, SEntry))
|
||||||
{
|
{
|
||||||
private alias T = typeof(E.content);
|
private alias T = typeof(E.content);
|
||||||
|
private alias E = CopyConstness!(Entry, Entry*);
|
||||||
|
|
||||||
private E* head;
|
private E* head;
|
||||||
|
|
||||||
private this(E* head)
|
invariant
|
||||||
{
|
{
|
||||||
this.head = head;
|
assert(head !is null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private this(ref E head) @trusted
|
||||||
|
{
|
||||||
|
this.head = &head;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property Range save()
|
@property Range save()
|
||||||
@ -44,7 +50,7 @@ private struct Range(E)
|
|||||||
|
|
||||||
@property bool empty() const
|
@property bool empty() const
|
||||||
{
|
{
|
||||||
return head is null;
|
return *head is null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property ref inout(T) front() inout
|
@property ref inout(T) front() inout
|
||||||
@ -54,27 +60,27 @@ private struct Range(E)
|
|||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
return head.content;
|
return (*head).content;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront()
|
void popFront() @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
head = head.next;
|
head = &(*head).next;
|
||||||
}
|
}
|
||||||
|
|
||||||
Range opIndex()
|
Range opIndex()
|
||||||
{
|
{
|
||||||
return typeof(return)(head);
|
return typeof(return)(*head);
|
||||||
}
|
}
|
||||||
|
|
||||||
Range!(const E) opIndex() const
|
Range!(const Entry) opIndex() const
|
||||||
{
|
{
|
||||||
return typeof(return)(head);
|
return typeof(return)(*head);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +143,7 @@ struct SList(T)
|
|||||||
* init = Initial value to fill the list with.
|
* init = Initial value to fill the list with.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*/
|
*/
|
||||||
this(in size_t len, T init, shared Allocator allocator = defaultAllocator) @trusted
|
this(const size_t len, T init, shared Allocator allocator = defaultAllocator) @trusted
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
|
|
||||||
@ -166,7 +172,7 @@ struct SList(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
this(in size_t len, shared Allocator allocator = defaultAllocator)
|
this(const size_t len, shared Allocator allocator = defaultAllocator)
|
||||||
{
|
{
|
||||||
this(len, T.init, allocator);
|
this(len, T.init, allocator);
|
||||||
}
|
}
|
||||||
@ -260,13 +266,13 @@ struct SList(T)
|
|||||||
*/
|
*/
|
||||||
this(this)
|
this(this)
|
||||||
{
|
{
|
||||||
auto buf = opIndex();
|
auto list = typeof(this)(this[], this.allocator);
|
||||||
head = null;
|
this.head = list.head;
|
||||||
insertFront(buf);
|
list.head = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
@safe @nogc unittest
|
||||||
{
|
{
|
||||||
auto l1 = SList!int([5, 1, 234]);
|
auto l1 = SList!int([5, 1, 234]);
|
||||||
auto l2 = l1;
|
auto l2 = l1;
|
||||||
@ -285,7 +291,7 @@ struct SList(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
@safe @nogc unittest
|
||||||
{
|
{
|
||||||
SList!int l = SList!int([8, 5]);
|
SList!int l = SList!int([8, 5]);
|
||||||
|
|
||||||
@ -307,35 +313,40 @@ struct SList(T)
|
|||||||
return head.content;
|
return head.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private size_t moveEntry(R)(ref Entry* head, ref R el) @trusted
|
||||||
* Inserts a new element at the beginning.
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
* R = Type of the inserted value(s).
|
|
||||||
* x = New element.
|
|
||||||
*
|
|
||||||
* Returns: The number of elements inserted.
|
|
||||||
*/
|
|
||||||
size_t insertFront(R)(ref R x) @trusted
|
|
||||||
if (isImplicitlyConvertible!(R, T))
|
|
||||||
{
|
|
||||||
head = allocator.make!Entry(x, head);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ditto.
|
|
||||||
size_t insertFront(R)(R x) @trusted
|
|
||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
{
|
{
|
||||||
auto temp = cast(Entry*) allocator.allocate(Entry.sizeof);
|
auto temp = cast(Entry*) allocator.allocate(Entry.sizeof);
|
||||||
|
|
||||||
x.moveEmplace(temp.content);
|
el.moveEmplace(temp.content);
|
||||||
temp.next = head;
|
temp.next = head;
|
||||||
|
|
||||||
head = temp;
|
head = temp;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a new element at the beginning.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* R = Type of the inserted value(s).
|
||||||
|
* el = New element(s).
|
||||||
|
*
|
||||||
|
* Returns: The number of elements inserted.
|
||||||
|
*/
|
||||||
|
size_t insertFront(ref T el) @trusted
|
||||||
|
{
|
||||||
|
head = allocator.make!Entry(el, head);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
size_t insertFront(R)(R el)
|
||||||
|
if (isImplicitlyConvertible!(R, T))
|
||||||
|
{
|
||||||
|
return moveEntry(head, el);
|
||||||
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
size_t insertFront(R)(R el) @trusted
|
size_t insertFront(R)(R el) @trusted
|
||||||
if (!isInfinite!R
|
if (!isInfinite!R
|
||||||
@ -377,7 +388,7 @@ struct SList(T)
|
|||||||
alias insert = insertFront;
|
alias insert = insertFront;
|
||||||
|
|
||||||
///
|
///
|
||||||
@nogc @safe unittest
|
@safe @nogc unittest
|
||||||
{
|
{
|
||||||
SList!int l1;
|
SList!int l1;
|
||||||
|
|
||||||
@ -395,16 +406,116 @@ struct SList(T)
|
|||||||
assert(l2.front == 9);
|
assert(l2.front == 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool checkRangeBelonging(ref Range!Entry r) const
|
||||||
|
{
|
||||||
|
const(Entry*)* pos;
|
||||||
|
for (pos = &head; pos != r.head && *pos !is null; pos = &(*pos).next)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return pos == r.head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts new elements before $(D_PARAM r).
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* R = Type of the inserted value(s).
|
||||||
|
* el = New element(s).
|
||||||
|
*
|
||||||
|
* Returns: The number of elements inserted.
|
||||||
|
*
|
||||||
|
* Precondition: $(D_PARAM r) is extracted from this list.
|
||||||
|
*/
|
||||||
|
size_t insertBefore(Range!Entry r, ref T el) @trusted
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(checkRangeBelonging(r));
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
*r.head = allocator.make!Entry(el, *r.head);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@safe @nogc unittest
|
||||||
|
{
|
||||||
|
auto l1 = SList!int([234, 5, 1]);
|
||||||
|
auto l2 = SList!int([5, 1]);
|
||||||
|
int var = 234;
|
||||||
|
l2.insertBefore(l2[], var);
|
||||||
|
assert(l1 == l2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
size_t insertBefore(R)(Range!Entry r, R el)
|
||||||
|
if (isImplicitlyConvertible!(R, T))
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(checkRangeBelonging(r));
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
return moveEntry(*r.head, el);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@safe @nogc unittest
|
||||||
|
{
|
||||||
|
auto l1 = SList!int([234, 5, 1]);
|
||||||
|
auto l2 = SList!int([5, 1]);
|
||||||
|
l2.insertBefore(l2[], 234);
|
||||||
|
assert(l1 == l2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
size_t insertBefore(R)(Range!Entry r, R el)
|
||||||
|
if (!isInfinite!R
|
||||||
|
&& isInputRange!R
|
||||||
|
&& isImplicitlyConvertible!(ElementType!R, T))
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(checkRangeBelonging(r));
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
size_t inserted;
|
||||||
|
foreach (e; el)
|
||||||
|
{
|
||||||
|
inserted += insertBefore(r, e);
|
||||||
|
r.popFront();
|
||||||
|
}
|
||||||
|
return inserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@safe @nogc unittest
|
||||||
|
{
|
||||||
|
auto l1 = SList!int([5, 234, 30, 1]);
|
||||||
|
auto l2 = SList!int([5, 1]);
|
||||||
|
auto l3 = SList!int([234, 30]);
|
||||||
|
auto r = l2[];
|
||||||
|
r.popFront();
|
||||||
|
l2.insertBefore(r, l3[]);
|
||||||
|
assert(l1 == l2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
size_t insertBefore(size_t R)(Range!Entry r, T[R] el)
|
||||||
|
{
|
||||||
|
return insertFront!(T[])(el[]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: How many elements are in the list.
|
* Returns: How many elements are in the list.
|
||||||
*/
|
*/
|
||||||
@property size_t length() const
|
@property size_t length() const
|
||||||
{
|
{
|
||||||
return count(opIndex());
|
return count(this[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
@safe @nogc unittest
|
||||||
{
|
{
|
||||||
SList!int l;
|
SList!int l;
|
||||||
|
|
||||||
@ -426,19 +537,13 @@ struct SList(T)
|
|||||||
* Returns: $(D_KEYWORD true) if the lists are equal, $(D_KEYWORD false)
|
* Returns: $(D_KEYWORD true) if the lists are equal, $(D_KEYWORD false)
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
bool opEquals()(auto ref typeof(this) that) @trusted
|
bool opEquals()(auto ref typeof(this) that) inout
|
||||||
{
|
{
|
||||||
return equal(opIndex(), that[]);
|
return equal(this[], that[]);
|
||||||
}
|
|
||||||
|
|
||||||
/// Ditto.
|
|
||||||
bool opEquals()(in auto ref typeof(this) that) const @trusted
|
|
||||||
{
|
|
||||||
return equal(opIndex(), that[]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
@safe @nogc unittest
|
||||||
{
|
{
|
||||||
SList!int l1, l2;
|
SList!int l1, l2;
|
||||||
|
|
||||||
@ -483,14 +588,14 @@ struct SList(T)
|
|||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
auto n = head.next;
|
auto n = this.head.next;
|
||||||
|
|
||||||
allocator.dispose(head);
|
this.allocator.dispose(this.head);
|
||||||
head = n;
|
this.head = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
@safe @nogc unittest
|
||||||
{
|
{
|
||||||
SList!int l;
|
SList!int l;
|
||||||
|
|
||||||
@ -515,7 +620,7 @@ struct SList(T)
|
|||||||
*
|
*
|
||||||
* Returns: The number of elements removed.
|
* Returns: The number of elements removed.
|
||||||
*/
|
*/
|
||||||
size_t removeFront(in size_t howMany)
|
size_t removeFront(const size_t howMany)
|
||||||
out (removed)
|
out (removed)
|
||||||
{
|
{
|
||||||
assert(removed <= howMany);
|
assert(removed <= howMany);
|
||||||
@ -530,23 +635,54 @@ struct SList(T)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
|
||||||
alias remove = removeFront;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
@safe @nogc unittest
|
||||||
{
|
{
|
||||||
SList!int l;
|
SList!int l = SList!int([8, 5, 4]);
|
||||||
|
|
||||||
l.insertFront(8);
|
|
||||||
l.insertFront(5);
|
|
||||||
l.insertFront(4);
|
|
||||||
assert(l.removeFront(0) == 0);
|
assert(l.removeFront(0) == 0);
|
||||||
assert(l.removeFront(2) == 2);
|
assert(l.removeFront(2) == 2);
|
||||||
assert(l.removeFront(3) == 1);
|
assert(l.removeFront(3) == 1);
|
||||||
assert(l.removeFront(3) == 0);
|
assert(l.removeFront(3) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes $(D_PARAM r) from the list.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* r = The range to remove.
|
||||||
|
*
|
||||||
|
* Returns: An empty range.
|
||||||
|
*
|
||||||
|
* Precondition: $(D_PARAM r) is extracted from this list.
|
||||||
|
*/
|
||||||
|
Range!Entry remove(Range!Entry r)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(checkRangeBelonging(r));
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
typeof(this) outOfScopeList;
|
||||||
|
outOfScopeList.head = *r.head;
|
||||||
|
*r.head = null;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@safe @nogc unittest
|
||||||
|
{
|
||||||
|
auto l1 = SList!int([5, 234, 30, 1]);
|
||||||
|
auto l2 = SList!int([5]);
|
||||||
|
auto r = l1[];
|
||||||
|
|
||||||
|
r.popFront();
|
||||||
|
|
||||||
|
assert(l1.remove(r).empty);
|
||||||
|
assert(l1 == l2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* $(D_KEYWORD foreach) iteration.
|
* $(D_KEYWORD foreach) iteration.
|
||||||
*
|
*
|
||||||
@ -590,7 +726,7 @@ struct SList(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
@nogc unittest
|
||||||
{
|
{
|
||||||
SList!int l;
|
SList!int l;
|
||||||
|
|
||||||
@ -619,7 +755,7 @@ struct SList(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
@nogc unittest
|
||||||
{
|
{
|
||||||
SList!int l;
|
SList!int l;
|
||||||
size_t i;
|
size_t i;
|
||||||
@ -637,7 +773,7 @@ unittest
|
|||||||
assert(i == 3);
|
assert(i == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe @nogc private unittest
|
||||||
{
|
{
|
||||||
interface Stuff
|
interface Stuff
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user