Fix DList.opAssign not changing tail

This commit is contained in:
Eugen Wissner 2017-06-28 08:12:58 +02:00
parent 2af0db04bd
commit a6dfb3a19e

View File

@ -134,9 +134,9 @@ struct SList(T)
* allocator = Allocator. * allocator = Allocator.
*/ */
this(R)(R init, shared Allocator allocator = defaultAllocator) this(R)(R init, shared Allocator allocator = defaultAllocator)
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
{ {
this(allocator); this(allocator);
insertFront(init); insertFront(init);
@ -174,6 +174,12 @@ struct SList(T)
assert(l.front == 3); assert(l.front == 3);
} }
private @safe @nogc unittest
{
auto l = SList!int(0, 0);
assert(l.empty);
}
/// Ditto. /// Ditto.
this(const size_t len, shared Allocator allocator = defaultAllocator) this(const size_t len, shared Allocator allocator = defaultAllocator)
{ {
@ -217,14 +223,14 @@ struct SList(T)
* allocator = Allocator. * allocator = Allocator.
*/ */
this(R)(ref R init, shared Allocator allocator = defaultAllocator) this(R)(ref R init, shared Allocator allocator = defaultAllocator)
if (is(Unqual!R == SList)) if (is(Unqual!R == SList))
{ {
this(init[], allocator); this(init[], allocator);
} }
/// Ditto. /// Ditto.
this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted
if (is(R == SList)) if (is(R == SList))
{ {
this(allocator); this(allocator);
if (allocator is init.allocator) if (allocator is init.allocator)
@ -320,7 +326,7 @@ struct SList(T)
} }
private size_t moveEntry(R)(ref Entry* head, ref R el) @trusted private size_t moveEntry(R)(ref Entry* head, ref R el) @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);
@ -341,14 +347,14 @@ struct SList(T)
* Returns: The number of elements inserted. * Returns: The number of elements inserted.
*/ */
size_t insertFront(R)(R el) size_t insertFront(R)(R el)
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
return moveEntry(this.head, el); return moveEntry(this.head, el);
} }
/// Ditto. /// Ditto.
size_t insertFront(R)(ref R el) @trusted size_t insertFront(R)(ref R el) @trusted
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
this.head = allocator.make!Entry(el, this.head); this.head = allocator.make!Entry(el, this.head);
return 1; return 1;
@ -370,9 +376,9 @@ struct SList(T)
/// Ditto. /// Ditto.
size_t insertFront(R)(R el) @trusted size_t insertFront(R)(R el) @trusted
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
{ {
size_t retLength; size_t retLength;
Entry* next, newHead; Entry* next, newHead;
@ -451,7 +457,7 @@ struct SList(T)
* Precondition: $(D_PARAM r) is extracted from this list. * Precondition: $(D_PARAM r) is extracted from this list.
*/ */
size_t insertBefore(R)(SRange!T r, R el) size_t insertBefore(R)(SRange!T r, R el)
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
in in
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
@ -472,9 +478,9 @@ struct SList(T)
/// Ditto. /// Ditto.
size_t insertBefore(R)(SRange!T r, R el) size_t insertBefore(R)(SRange!T r, R el)
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
in in
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
@ -610,9 +616,7 @@ struct SList(T)
} }
/** /**
* Returns the first element and moves to the next one. * Removes the front element.
*
* Returns: The first element.
* *
* Precondition: $(D_INLINECODE !empty) * Precondition: $(D_INLINECODE !empty)
*/ */
@ -749,33 +753,50 @@ struct SList(T)
* Returns: $(D_KEYWORD this). * Returns: $(D_KEYWORD this).
*/ */
ref typeof(this) opAssign(R)(ref R that) ref typeof(this) opAssign(R)(ref R that)
if (is(Unqual!R == SList)) if (is(Unqual!R == SList))
{ {
return this = that[]; return this = that[];
} }
/// Ditto. /// Ditto.
ref typeof(this) opAssign(R)(R that) ref typeof(this) opAssign(R)(R that)
if (is(R == SList)) if (is(R == SList))
{ {
swap(this.head, that.head); swap(this.head, that.head);
swap(this.allocator_, that.allocator_); swap(this.allocator_, that.allocator_);
return this; return this;
} }
///
@safe @nogc unittest
{
{
auto l1 = SList!int([5, 4, 9]);
auto l2 = SList!int([9, 4]);
l1 = l2;
assert(l1 == l2);
}
{
auto l1 = SList!int([5, 4, 9]);
auto l2 = SList!int([9, 4]);
l1 = SList!int([9, 4]);
assert(l1 == l2);
}
}
/** /**
* Assigns an input range. * Assigns an input range.
* *
* Params: * Params:
* R = Type of the initial range. * R = Type of the initial range.
* that = Values to initialize the list with. * that = Values to initialize the list with.
* *
* Returns: $(D_KEYWORD this). * Returns: $(D_KEYWORD this).
*/ */
ref typeof(this) opAssign(R)(R that) @trusted ref typeof(this) opAssign(R)(R that) @trusted
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
{ {
Entry** next = &this.head; Entry** next = &this.head;
@ -805,12 +826,20 @@ struct SList(T)
assert(l1 == l2); assert(l1 == l2);
} }
private @safe @nogc unittest
{
auto l1 = SList!int();
auto l2 = SList!int([9, 4]);
l1 = l2[];
assert(l1 == l2);
}
/** /**
* Assigns a static array. * Assigns a static array.
* *
* Params: * Params:
* R = Static array size. * R = Static array size.
* that = Values to initialize the vector with. * that = Values to initialize the list with.
* *
* Returns: $(D_KEYWORD this). * Returns: $(D_KEYWORD this).
*/ */
@ -1020,9 +1049,9 @@ struct DList(T)
* allocator = Allocator. * allocator = Allocator.
*/ */
this(R)(R init, shared Allocator allocator = defaultAllocator) this(R)(R init, shared Allocator allocator = defaultAllocator)
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
{ {
this(allocator); this(allocator);
insertFront(init); insertFront(init);
@ -1063,6 +1092,12 @@ struct DList(T)
assert(l.back == 3); assert(l.back == 3);
} }
private @safe @nogc unittest
{
auto l = DList!int(0, 0);
assert(l.empty);
}
/// Ditto. /// Ditto.
this(const size_t len, shared Allocator allocator = defaultAllocator) this(const size_t len, shared Allocator allocator = defaultAllocator)
{ {
@ -1106,14 +1141,14 @@ struct DList(T)
* allocator = Allocator. * allocator = Allocator.
*/ */
this(R)(ref R init, shared Allocator allocator = defaultAllocator) this(R)(ref R init, shared Allocator allocator = defaultAllocator)
if (is(Unqual!R == DList)) if (is(Unqual!R == DList))
{ {
this(init[], allocator); this(init[], allocator);
} }
/// Ditto. /// Ditto.
this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted this(R)(R init, shared Allocator allocator = defaultAllocator) @trusted
if (is(R == DList)) if (is(R == DList))
{ {
this(allocator); this(allocator);
if (allocator is init.allocator) if (allocator is init.allocator)
@ -1238,7 +1273,7 @@ struct DList(T)
} }
private size_t moveEntry(R)(ref Entry* head, ref R el) @trusted private size_t moveEntry(R)(ref Entry* head, ref R el) @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);
@ -1268,14 +1303,14 @@ struct DList(T)
* Returns: The number of elements inserted. * Returns: The number of elements inserted.
*/ */
size_t insertFront(R)(R el) size_t insertFront(R)(R el)
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
return moveEntry(this.head, el); return moveEntry(this.head, el);
} }
/// Ditto. /// Ditto.
size_t insertFront(R)(ref R el) @trusted size_t insertFront(R)(ref R el) @trusted
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
if (this.tail is null) if (this.tail is null)
{ {
@ -1307,9 +1342,9 @@ struct DList(T)
/// Ditto. /// Ditto.
size_t insertFront(R)(R el) @trusted size_t insertFront(R)(R el) @trusted
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
{ {
size_t retLength; size_t retLength;
Entry* next, newHead; Entry* next, newHead;
@ -1356,16 +1391,20 @@ struct DList(T)
assert(l1.insertFront(8) == 1); assert(l1.insertFront(8) == 1);
assert(l1.front == 8); assert(l1.front == 8);
assert(l1.back == 8);
assert(l1.insertFront(9) == 1); assert(l1.insertFront(9) == 1);
assert(l1.front == 9); assert(l1.front == 9);
assert(l1.back == 8);
DList!int l2; DList!int l2;
assert(l2.insertFront([25, 30, 15]) == 3); assert(l2.insertFront([25, 30, 15]) == 3);
assert(l2.front == 25); assert(l2.front == 25);
assert(l2.back == 15);
l2.insertFront(l1[]); l2.insertFront(l1[]);
assert(l2.length == 5); assert(l2.length == 5);
assert(l2.front == 9); assert(l2.front == 9);
assert(l2.back == 15);
} }
/** /**
@ -1378,7 +1417,7 @@ struct DList(T)
* Returns: The number of elements inserted. * Returns: The number of elements inserted.
*/ */
size_t insertBack(R)(R el) @trusted size_t insertBack(R)(R el) @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);
@ -1400,7 +1439,7 @@ struct DList(T)
/// Ditto. /// Ditto.
size_t insertBack(R)(ref R el) @trusted size_t insertBack(R)(ref R el) @trusted
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
if (this.tail is null) if (this.tail is null)
{ {
@ -1432,9 +1471,9 @@ struct DList(T)
/// Ditto. /// Ditto.
size_t insertBack(R)(R el) @trusted size_t insertBack(R)(R el) @trusted
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
{ {
size_t inserted; size_t inserted;
@ -1496,7 +1535,7 @@ struct DList(T)
* Precondition: $(D_PARAM r) is extracted from this list. * Precondition: $(D_PARAM r) is extracted from this list.
*/ */
size_t insertBefore(R)(DRange!T r, R el) size_t insertBefore(R)(DRange!T r, R el)
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
in in
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
@ -1517,9 +1556,9 @@ struct DList(T)
/// Ditto. /// Ditto.
size_t insertBefore(R)(DRange!T r, R el) size_t insertBefore(R)(DRange!T r, R el)
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
in in
{ {
assert(checkRangeBelonging(r)); assert(checkRangeBelonging(r));
@ -1655,9 +1694,7 @@ struct DList(T)
} }
/** /**
* Returns the first element and moves to the next one. * Removes the front element.
*
* Returns: The first element.
* *
* Precondition: $(D_INLINECODE !empty) * Precondition: $(D_INLINECODE !empty)
*/ */
@ -1807,14 +1844,14 @@ struct DList(T)
* Returns: $(D_KEYWORD this). * Returns: $(D_KEYWORD this).
*/ */
ref typeof(this) opAssign(R)(ref R that) ref typeof(this) opAssign(R)(ref R that)
if (is(Unqual!R == DList)) if (is(Unqual!R == DList))
{ {
return this = that[]; return this = that[];
} }
/// Ditto. /// Ditto.
ref typeof(this) opAssign(R)(R that) ref typeof(this) opAssign(R)(R that)
if (is(R == DList)) if (is(R == DList))
{ {
swap(this.head, that.head); swap(this.head, that.head);
swap(this.tail, that.tail); swap(this.tail, that.tail);
@ -1826,32 +1863,32 @@ struct DList(T)
* Assigns an input range. * Assigns an input range.
* *
* Params: * Params:
* R = Type of the initial range. * R = Type of the initial range.
* that = Values to initialize the list with. * that = Values to initialize the list with.
* *
* Returns: $(D_KEYWORD this). * Returns: $(D_KEYWORD this).
*/ */
ref typeof(this) opAssign(R)(R that) @trusted ref typeof(this) opAssign(R)(R that) @trusted
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
{ {
Entry** next = &this.head; Entry** next = &this.head;
foreach (ref e; that) while (!that.empty && *next !is null)
{ {
if (*next is null) (*next).content = that.front;
{
*next = allocator.make!Entry(e);
}
else
{
(*next).content = e;
}
next = &(*next).next; next = &(*next).next;
that.popFront();
}
if (that.empty)
{
remove(DRange!T(*next, this.tail));
}
else
{
insertBack(that);
} }
remove(DRange!T(*next, this.tail));
return this; return this;
} }
@ -1864,12 +1901,20 @@ struct DList(T)
assert(l1 == l2); assert(l1 == l2);
} }
private @safe @nogc unittest
{
auto l1 = DList!int();
auto l2 = DList!int([9, 4]);
l1 = l2[];
assert(l1 == l2);
}
/** /**
* Assigns a static array. * Assigns a static array.
* *
* Params: * Params:
* R = Static array size. * R = Static array size.
* that = Values to initialize the vector with. * that = Values to initialize the list with.
* *
* Returns: $(D_KEYWORD this). * Returns: $(D_KEYWORD this).
*/ */