Add SList.opAssign

This commit is contained in:
Eugen Wissner 2017-03-29 10:35:45 +02:00
parent 4d8b95812e
commit aabb4fb534
2 changed files with 171 additions and 54 deletions

View File

@ -356,18 +356,17 @@ struct SList(T)
size_t retLength; size_t retLength;
Entry* next, newHead; Entry* next, newHead;
foreach (ref e; el) if (!el.empty)
{ {
if (next is null) next = allocator.make!Entry(el.front);
{
next = allocator.make!Entry(e);
newHead = next; newHead = next;
el.popFront();
retLength = 1;
} }
else foreach (ref e; el)
{ {
next.next = allocator.make!Entry(e); next.next = allocator.make!Entry(e);
next = next.next; next = next.next;
}
++retLength; ++retLength;
} }
if (newHead !is null) if (newHead !is null)
@ -406,6 +405,8 @@ struct SList(T)
assert(l2.front == 9); assert(l2.front == 9);
} }
version (assert)
{
private bool checkRangeBelonging(ref Range!Entry r) const private bool checkRangeBelonging(ref Range!Entry r) const
{ {
const(Entry*)* pos; const(Entry*)* pos;
@ -414,6 +415,7 @@ struct SList(T)
} }
return pos == r.head; return pos == r.head;
} }
}
/** /**
* Inserts new elements before $(D_PARAM r). * Inserts new elements before $(D_PARAM r).
@ -741,16 +743,116 @@ struct SList(T)
} }
} }
/**
* Returns: Range that iterates over all elements of the container, in
* forward order.
*/
Range!Entry opIndex() Range!Entry opIndex()
{ {
return typeof(return)(head); return typeof(return)(head);
} }
/// Ditto.
Range!(const Entry) opIndex() const Range!(const Entry) opIndex() const
{ {
return typeof(return)(head); return typeof(return)(head);
} }
/**
* Assigns another list.
*
* If $(D_PARAM that) is passed by value, it won't be copied, but moved.
* This list will take the ownership over $(D_PARAM that)'s storage and
* the allocator.
*
* If $(D_PARAM that) is passed by reference, it will be copied.
*
* Params:
* R = Content type.
* that = The value should be assigned.
*
* Returns: $(D_KEYWORD this).
*/
ref typeof(this) opAssign(R)(const ref R that)
if (is(Unqual!R == SList))
{
return this = that[];
}
/// Ditto.
ref typeof(this) opAssign(R)(const ref R that)
if (is(Unqual!R == SList))
{
swap(this.head, that.head);
swap(this.allocator_, that.allocator_);
}
/**
* Assigns an input range.
*
* Params:
* R = Type of the initial range.
* that = Values to initialize the list with.
*
* Returns: $(D_KEYWORD this).
*/
ref typeof(this) opAssign(R)(R that) @trusted
if (!isInfinite!R
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
{
Entry** next = &head;
foreach (ref e; that)
{
if (*next is null)
{
*next = allocator.make!Entry(e);
}
else
{
(*next).content = e;
}
next = &(*next).next;
}
remove(Range!Entry(*next));
return this;
}
///
@safe @nogc unittest
{
auto l1 = SList!int([5, 4, 9]);
auto l2 = SList!int([9, 4]);
l1 = l2[];
assert(l1 == l2);
}
/**
* Assigns a static array.
*
* Params:
* R = Static array size.
* that = Values to initialize the vector with.
*
* Returns: $(D_KEYWORD this).
*/
ref typeof(this) opAssign(size_t R)(T[R] that)
{
return opAssign!(T[])(that[]);
}
///
@safe @nogc unittest
{
auto l1 = SList!int([5, 4, 9]);
auto l2 = SList!int([9, 4]);
l1 = [9, 4];
assert(l1 == l2);
}
mixin DefaultAllocator; mixin DefaultAllocator;
} }

View File

@ -221,11 +221,29 @@ struct Vector(T)
if (is(R == Vector)) if (is(R == Vector))
{ {
this(allocator); this(allocator);
moveAssign(init); if (allocator is init.allocator)
{
// Just steal all references and the allocator.
vector = init.vector;
length_ = init.length_;
capacity_ = init.capacity_;
// Reset the source vector, so it can't destroy the moved storage.
init.length_ = init.capacity_ = 0;
init.vector = null;
}
else
{
// Move each element.
reserve(init.length);
moveEmplaceAll(init.vector[0 .. init.length_], vector[0 .. init.length_]);
length_ = init.length;
// Destructor of init should destroy it here.
}
} }
/// ///
unittest @trusted @nogc unittest
{ {
auto v1 = Vector!int([1, 2, 3]); auto v1 = Vector!int([1, 2, 3]);
auto v2 = Vector!int(v1); auto v2 = Vector!int(v1);
@ -238,7 +256,7 @@ struct Vector(T)
assert(v3.capacity == 3); assert(v3.capacity == 3);
} }
unittest // const constructor tests private @trusted @nogc unittest // const constructor tests
{ {
auto v1 = const Vector!int([1, 2, 3]); auto v1 = const Vector!int([1, 2, 3]);
auto v2 = Vector!int(v1); auto v2 = Vector!int(v1);
@ -1455,58 +1473,54 @@ struct Vector(T)
assert(data.length == 1); assert(data.length == 1);
} }
private void moveAssign(ref Vector v) @trusted
{
if (allocator is v.allocator)
{
// Just steal all references and the allocator.
vector = v.vector;
length_ = v.length_;
capacity_ = v.capacity_;
// Reset the source vector, so it can't destroy the moved storage.
v.length_ = v.capacity_ = 0;
v.vector = null;
}
else
{
// Move each element.
reserve(v.length);
moveEmplaceAll(v.vector[0 .. v.length_], vector[0 .. v.length_]);
length_ = v.length;
// Destructor of v should destroy it here.
}
}
/** /**
* Assigns content to the vector. * Assigns another vector.
*
* If $(D_PARAM that) is passed by value, it won't be copied, but moved.
* This vector will take the ownership over $(D_PARAM that)'s storage and
* the allocator.
*
* If $(D_PARAM that) is passed by reference, it will be copied.
* *
* Params: * Params:
* R = Content type. * R = Content type.
* init = The value should be assigned. * that = The value should be assigned.
*
* Returns: $(D_KEYWORD this).
*/ */
ref typeof(this) opAssign(R)(const ref R init) ref typeof(this) opAssign(R)(const ref R that)
if (is(Unqual!R == Vector)) if (is(Unqual!R == Vector))
{ {
insertBack(init[]); return this = that[];
return this;
} }
/// Ditto. /// Ditto.
ref typeof(this) opAssign(R)(R init) ref typeof(this) opAssign(R)(R that) @trusted
if (is(R == Vector)) if (is(R == Vector))
{ {
moveAssign(init); swap(this.vector, that.vector);
swap(this.length_, that.length_);
swap(this.capacity_, that.capacity_);
swap(this.allocator_, that.allocator_);
return this; return this;
} }
/// Ditto. /**
ref typeof(this) opAssign(R)(R init) * Assigns a range to the vector.
*
* Params:
* R = Content type.
* that = The value should be assigned.
*
* Returns: $(D_KEYWORD this).
*/
ref typeof(this) opAssign(R)(R that)
if (!isInfinite!R if (!isInfinite!R
&& isInputRange!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
{ {
insertBack(init); this.length = 0;
insertBack(that);
return this; return this;
} }
@ -1540,12 +1554,13 @@ struct Vector(T)
* *
* Params: * Params:
* R = Static array size. * R = Static array size.
* init = Values to initialize the vector with. * that = Values to initialize the vector with.
*
* Returns: $(D_KEYWORD this).
*/ */
ref typeof(this) opAssign(size_t R)(T[R] init) ref typeof(this) opAssign(size_t R)(T[R] that)
{ {
insertBack!(T[])(init[]); return opAssign!(T[])(that[]);
return this;
} }
/// ///