Fix Vector.insertAfter/Before an empty range

This commit is contained in:
Eugen Wissner 2017-04-04 15:11:14 +02:00
parent 9b953198fa
commit b1d2b9bd9e

View File

@ -22,22 +22,42 @@ import std.meta;
import std.traits; import std.traits;
import tanya.memory; import tanya.memory;
// Defines the container's primary range. /**
private struct Range(E) * Random-access range for the $(D_PSYMBOL Vector).
*
* Params:
* E = Element type.
*/
struct Range(E)
{ {
private E* begin, end; private E* begin, end;
private alias ContainerType = CopyConstness!(E, Vector!(Unqual!E));
private ContainerType* vector;
invariant invariant
{ {
assert(begin <= end); assert(this.begin <= this.end);
assert(this.vector !is null);
assert(this.begin >= this.vector.data);
assert(this.end <= this.vector.data + this.vector.length);
} }
private this(E* begin, E* end) private this(ref ContainerType vector, E* begin, E* end) @trusted
in
{ {
assert(begin <= end);
assert(begin >= vector.data);
assert(end <= vector.data + vector.length);
}
body
{
this.vector = &vector;
this.begin = begin; this.begin = begin;
this.end = end; this.end = end;
} }
@disable this();
@property Range save() @property Range save()
{ {
return this; return this;
@ -45,12 +65,12 @@ private struct Range(E)
@property bool empty() const @property bool empty() const
{ {
return begin == end; return this.begin == this.end;
} }
@property size_t length() const @property size_t length() const
{ {
return end - begin; return this.end - this.begin;
} }
alias opDollar = length; alias opDollar = length;
@ -62,7 +82,7 @@ private struct Range(E)
} }
body body
{ {
return *begin; return *this.begin;
} }
@property ref inout(E) back() inout @trusted @property ref inout(E) back() inout @trusted
@ -72,7 +92,7 @@ private struct Range(E)
} }
body body
{ {
return *(end - 1); return *(this.end - 1);
} }
void popFront() @trusted void popFront() @trusted
@ -82,7 +102,7 @@ private struct Range(E)
} }
body body
{ {
++begin; ++this.begin;
} }
void popBack() @trusted void popBack() @trusted
@ -92,7 +112,7 @@ private struct Range(E)
} }
body body
{ {
--end; --this.end;
} }
ref inout(E) opIndex(const size_t i) inout @trusted ref inout(E) opIndex(const size_t i) inout @trusted
@ -102,17 +122,17 @@ private struct Range(E)
} }
body body
{ {
return *(begin + i); return *(this.begin + i);
} }
Range opIndex() Range opIndex()
{ {
return typeof(return)(begin, end); return typeof(return)(*this.vector, this.begin, this.end);
} }
Range!(const E) opIndex() const Range!(const E) opIndex() const
{ {
return typeof(return)(begin, end); return typeof(return)(*this.vector, this.begin, this.end);
} }
Range opSlice(const size_t i, const size_t j) @trusted Range opSlice(const size_t i, const size_t j) @trusted
@ -123,7 +143,7 @@ private struct Range(E)
} }
body body
{ {
return typeof(return)(begin + i, begin + j); return typeof(return)(*this.vector, this.begin + i, this.begin + j);
} }
Range!(const E) opSlice(const size_t i, const size_t j) const @trusted Range!(const E) opSlice(const size_t i, const size_t j) const @trusted
@ -134,12 +154,12 @@ private struct Range(E)
} }
body body
{ {
return typeof(return)(begin + i, begin + j); return typeof(return)(*this.vector, this.begin + i, this.begin + j);
} }
inout(E[]) get() inout @trusted inout(E[]) get() inout @trusted
{ {
return begin[0 .. length]; return this.begin[0 .. length];
} }
} }
@ -152,13 +172,13 @@ private struct Range(E)
struct Vector(T) struct Vector(T)
{ {
private size_t length_; private size_t length_;
private T* vector; private T* data;
private size_t capacity_; private size_t capacity_;
invariant invariant
{ {
assert(length_ <= capacity_); assert(this.length_ <= this.capacity_);
assert(capacity_ == 0 || vector !is null); assert(this.capacity_ == 0 || this.data !is null);
} }
/** /**
@ -224,20 +244,20 @@ struct Vector(T)
if (allocator is init.allocator) if (allocator is init.allocator)
{ {
// Just steal all references and the allocator. // Just steal all references and the allocator.
vector = init.vector; this.data = init.data;
length_ = init.length_; this.length_ = init.length_;
capacity_ = init.capacity_; this.capacity_ = init.capacity_;
// Reset the source vector, so it can't destroy the moved storage. // Reset the source vector, so it can't destroy the moved storage.
init.length_ = init.capacity_ = 0; init.length_ = init.capacity_ = 0;
init.vector = null; init.data = null;
} }
else else
{ {
// Move each element. // Move each element.
reserve(init.length); reserve(init.length_);
moveEmplaceAll(init.vector[0 .. init.length_], vector[0 .. init.length_]); moveEmplaceAll(init.data[0 .. init.length_], this.data[0 .. init.length_]);
length_ = init.length; this.length_ = init.length_;
// Destructor of init should destroy it here. // Destructor of init should destroy it here.
} }
} }
@ -247,7 +267,6 @@ struct Vector(T)
{ {
auto v1 = Vector!int([1, 2, 3]); auto v1 = Vector!int([1, 2, 3]);
auto v2 = Vector!int(v1); auto v2 = Vector!int(v1);
assert(v1.vector !is v2.vector);
assert(v1 == v2); assert(v1 == v2);
auto v3 = Vector!int(Vector!int([1, 2, 3])); auto v3 = Vector!int(Vector!int([1, 2, 3]));
@ -260,7 +279,7 @@ struct Vector(T)
{ {
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);
assert(v1.vector !is v2.vector); assert(v1.data !is v2.data);
assert(v1 == v2); assert(v1 == v2);
auto v3 = const Vector!int(Vector!int([1, 2, 3])); auto v3 = const Vector!int(Vector!int([1, 2, 3]));
@ -281,7 +300,7 @@ struct Vector(T)
{ {
this(allocator); this(allocator);
reserve(len); reserve(len);
uninitializedFill(vector[0 .. len], init); uninitializedFill(this.data[0 .. len], init);
length_ = len; length_ = len;
} }
@ -334,7 +353,7 @@ struct Vector(T)
~this() @trusted ~this() @trusted
{ {
clear(); clear();
allocator.deallocate(vector[0 .. capacity_]); allocator.deallocate(this.data[0 .. capacity]);
} }
/** /**
@ -342,9 +361,9 @@ struct Vector(T)
*/ */
this(this) this(this)
{ {
auto buf = opIndex(); auto buf = this.data[0 .. this.length_];
length_ = capacity_ = 0; this.length_ = capacity_ = 0;
vector = null; this.data = null;
insertBack(buf); insertBack(buf);
} }
@ -409,14 +428,14 @@ struct Vector(T)
else if (len > length) else if (len > length)
{ {
reserve(len); reserve(len);
initializeAll(vector[length_ .. len]); initializeAll(this.data[length_ .. len]);
} }
else else
{ {
static if (hasElaborateDestructor!T) static if (hasElaborateDestructor!T)
{ {
const T* end = vector + length_ - 1; const T* end = this.data + length_ - 1;
for (T* e = vector + len; e != end; ++e) for (T* e = this.data + len; e != end; ++e)
{ {
destroy(*e); destroy(*e);
} }
@ -467,7 +486,7 @@ struct Vector(T)
immutable byteSize = mulu(size, T.sizeof, overflow); immutable byteSize = mulu(size, T.sizeof, overflow);
assert(!overflow); assert(!overflow);
void[] buf = vector[0 .. capacity_]; void[] buf = this.data[0 .. this.capacity_];
if (!allocator.reallocateInPlace(buf, byteSize)) if (!allocator.reallocateInPlace(buf, byteSize))
{ {
buf = allocator.allocate(byteSize); buf = allocator.allocate(byteSize);
@ -479,8 +498,8 @@ struct Vector(T)
{ {
allocator.deallocate(buf); allocator.deallocate(buf);
} }
const T* end = vector + length_; const T* end = this.data + this.length_;
for (T* src = vector, dest = cast(T*) buf; src != end; ++src, ++dest) for (T* src = this.data, dest = cast(T*) buf; src != end; ++src, ++dest)
{ {
moveEmplace(*src, *dest); moveEmplace(*src, *dest);
static if (hasElaborateDestructor!T) static if (hasElaborateDestructor!T)
@ -488,10 +507,10 @@ struct Vector(T)
destroy(*src); destroy(*src);
} }
} }
allocator.deallocate(vector[0 .. capacity_]); allocator.deallocate(this.data[0 .. this.capacity_]);
vector = cast(T*) buf; this.data = cast(T*) buf;
} }
capacity_ = size; this.capacity_ = size;
} }
/// ///
@ -517,15 +536,15 @@ struct Vector(T)
*/ */
void shrink(const size_t size) @trusted void shrink(const size_t size) @trusted
{ {
if (capacity_ <= size) if (capacity <= size)
{ {
return; return;
} }
immutable n = max(length, size); immutable n = max(length, size);
void[] buf = vector[0 .. capacity_]; void[] buf = this.data[0 .. this.capacity_];
if (allocator.reallocateInPlace(buf, n * T.sizeof)) if (allocator.reallocateInPlace(buf, n * T.sizeof))
{ {
capacity_ = n; this.capacity_ = n;
} }
} }
@ -556,7 +575,7 @@ struct Vector(T)
* *
* Returns: The number of elements removed * Returns: The number of elements removed
* *
* Precondition: $(D_INLINECODE !empty) * Precondition: $(D_INLINECODE !empty).
*/ */
void removeBack() void removeBack()
in in
@ -611,22 +630,24 @@ struct Vector(T)
* Params: * Params:
* r = Range originally obtained from this vector. * r = Range originally obtained from this vector.
* *
* Returns: Elements in $(D_PARAM r) after removing. * Returns: A range spanning the remaining elements in the array that
* initially were right after $(D_PARAM r).
* *
* Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this). * Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this).
*/ */
Range!T remove(Range!T r) @trusted Range!T remove(Range!T r) @trusted
in in
{ {
assert(r.begin >= vector); assert(r.vector is &this);
assert(r.end <= vector + length_); assert(r.begin >= this.data);
assert(r.end <= this.data + length);
} }
body body
{ {
auto end = vector + length_; auto end = this.data + this.length;
moveAll(Range!T(r.end, end), Range!T(r.begin, end)); moveAll(Range!T(this, r.end, end), Range!T(this, r.begin, end));
length = length - r.length; length = length - r.length;
return r; return Range!T(this, r.begin, this.data + length);
} }
/// ///
@ -634,31 +655,28 @@ struct Vector(T)
{ {
auto v = Vector!int([5, 18, 17, 2, 4, 6, 1]); auto v = Vector!int([5, 18, 17, 2, 4, 6, 1]);
assert(v.remove(v[1 .. 3]).length == 2); assert(v.remove(v[1 .. 3]).length == 4);
assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6 && v[4] == 1); assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6 && v[4] == 1);
assert(v.length == 5); assert(v.length == 5);
assert(v.remove(v[4 .. 4]).length == 0); assert(v.remove(v[4 .. 4]).length == 1);
assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6 && v[4] == 1); assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6 && v[4] == 1);
assert(v.length == 5); assert(v.length == 5);
assert(v.remove(v[4 .. 5]).length == 1); assert(v.remove(v[4 .. 5]).length == 0);
assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6); assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6);
assert(v.length == 4); assert(v.length == 4);
assert(v.remove(v[]).length == 4);
assert(v.empty);
assert(v.remove(v[]).length == 0); assert(v.remove(v[]).length == 0);
assert(v.empty);
} }
private void moveBack(R)(ref R el) @trusted private void moveBack(R)(ref R el) @trusted
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
reserve(length + 1); reserve(this.length + 1);
moveEmplace(el, *(vector + length_)); moveEmplace(el, *(this.data + this.length_));
++length_; ++this.length_;
} }
/** /**
@ -675,9 +693,9 @@ struct Vector(T)
{ {
static if (__traits(isRef, el)) static if (__traits(isRef, el))
{ {
reserve(length + 1); reserve(this.length_ + 1);
emplace(vector + length_, el); emplace(this.data + this.length_, el);
++length_; ++this.length_;
} }
else else
{ {
@ -763,6 +781,8 @@ struct Vector(T)
* el = Value(s) should be inserted. * el = Value(s) should be inserted.
* *
* Returns: The number of elements inserted. * Returns: The number of elements inserted.
*
* Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this).
*/ */
size_t insertAfter(R)(Range!T r, R el) size_t insertAfter(R)(Range!T r, R el)
if (!isInfinite!R if (!isInfinite!R
@ -770,20 +790,28 @@ struct Vector(T)
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
in in
{ {
assert(r.begin >= vector); assert(r.vector is &this);
assert(r.end <= vector + length_); assert(r.begin >= this.data);
assert(r.end <= this.data + length);
} }
body body
{ {
immutable oldLen = length; immutable oldLen = length;
immutable offset = r.end - vector; immutable offset = r.end - this.data;
immutable inserted = insertBack(el); immutable inserted = insertBack(el);
bringToFront(vector[offset .. oldLen], vector[oldLen .. length]); bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]);
return inserted; return inserted;
} }
/// Ditto. /// Ditto.
size_t insertAfter(size_t R)(Range!T r, T[R] el) size_t insertAfter(size_t R)(Range!T r, T[R] el)
in
{
assert(r.vector is &this);
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
{ {
return insertAfter!(T[])(r, el[]); return insertAfter!(T[])(r, el[]);
} }
@ -793,13 +821,14 @@ struct Vector(T)
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
in in
{ {
assert(r.begin >= vector); assert(r.vector is &this);
assert(r.end <= vector + length_); assert(r.begin >= this.data);
assert(r.end <= this.data + length);
} }
body body
{ {
immutable oldLen = length; immutable oldLen = length;
immutable offset = r.end - vector; immutable offset = r.end - this.data;
static if (__traits(isRef, el)) static if (__traits(isRef, el))
{ {
@ -809,7 +838,7 @@ struct Vector(T)
{ {
moveBack(el); moveBack(el);
} }
bringToFront(vector[offset .. oldLen], vector[oldLen .. length_]); bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]);
return 1; return 1;
} }
@ -821,16 +850,24 @@ struct Vector(T)
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
in in
{ {
assert(r.begin >= vector); assert(r.vector is &this);
assert(r.end <= vector + length_); assert(r.begin >= this.data);
assert(r.end <= this.data + length);
} }
body body
{ {
return insertAfter(Range!T(vector, r.begin), el); return insertAfter(Range!T(this, this.data, r.begin), el);
} }
/// Ditto. /// Ditto.
size_t insertBefore(size_t R)(Range!T r, T[R] el) size_t insertBefore(size_t R)(Range!T r, T[R] el)
in
{
assert(r.vector is &this);
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
{ {
return insertBefore!(T[])(r, el[]); return insertBefore!(T[])(r, el[]);
} }
@ -840,13 +877,14 @@ struct Vector(T)
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
in in
{ {
assert(r.begin >= vector); assert(r.vector is &this);
assert(r.end <= vector + length_); assert(r.begin >= this.data);
assert(r.end <= this.data + length);
} }
body body
{ {
immutable oldLen = length; immutable oldLen = length;
immutable offset = r.begin - vector; immutable offset = r.begin - this.data;
static if (__traits(isRef, el)) static if (__traits(isRef, el))
{ {
@ -856,7 +894,7 @@ struct Vector(T)
{ {
moveBack(el); moveBack(el);
} }
bringToFront(vector[offset .. oldLen], vector[oldLen .. length_]); bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]);
return 1; return 1;
} }
@ -942,7 +980,7 @@ struct Vector(T)
* *
* Returns: Assigned value. * Returns: Assigned value.
* *
* Precondition: $(D_INLINECODE length > pos) * Precondition: $(D_INLINECODE length > pos).
*/ */
ref T opIndexAssign(ref T value, const size_t pos) ref T opIndexAssign(ref T value, const size_t pos)
{ {
@ -983,7 +1021,7 @@ struct Vector(T)
* *
* Returns: Assigned value. * Returns: Assigned value.
* *
* Precondition: $(D_INLINECODE length == value.length) * Precondition: $(D_INLINECODE length == value.length).
*/ */
Range!T opIndexAssign(R)(R value) Range!T opIndexAssign(R)(R value)
if (!isInfinite!R && isInputRange!R if (!isInfinite!R && isInputRange!R
@ -1020,7 +1058,7 @@ struct Vector(T)
* *
* Returns: The value at a specified index. * Returns: The value at a specified index.
* *
* Precondition: $(D_INLINECODE length > pos) * Precondition: $(D_INLINECODE length > pos).
*/ */
ref inout(T) opIndex(const size_t pos) inout @trusted ref inout(T) opIndex(const size_t pos) inout @trusted
in in
@ -1029,7 +1067,7 @@ struct Vector(T)
} }
body body
{ {
return *(vector + pos); return *(this.data + pos);
} }
/** /**
@ -1038,13 +1076,13 @@ struct Vector(T)
*/ */
Range!T opIndex() @trusted Range!T opIndex() @trusted
{ {
return typeof(return)(vector, vector + length_); return typeof(return)(this, this.data, this.data + length);
} }
/// Ditto. /// Ditto.
Range!(const T) opIndex() const @trusted Range!(const T) opIndex() const @trusted
{ {
return typeof(return)(vector, vector + length_); return typeof(return)(this, this.data, this.data + length);
} }
/// ///
@ -1071,13 +1109,13 @@ struct Vector(T)
*/ */
bool opEquals()(auto ref typeof(this) that) @trusted bool opEquals()(auto ref typeof(this) that) @trusted
{ {
return equal(vector[0 .. length_], that.vector[0 .. that.length_]); return equal(this.data[0 .. length], that.data[0 .. that.length]);
} }
/// Ditto. /// Ditto.
bool opEquals()(const auto ref typeof(this) that) const @trusted bool opEquals()(const auto ref typeof(this) that) const @trusted
{ {
return equal(vector[0 .. length_], that.vector[0 .. that.length_]); return equal(this.data[0 .. length], that.data[0 .. that.length]);
} }
/// Ditto. /// Ditto.
@ -1132,8 +1170,8 @@ struct Vector(T)
*/ */
int opApply(scope int delegate(ref T) @nogc dg) int opApply(scope int delegate(ref T) @nogc dg)
{ {
T* end = vector + length_ - 1; T* end = this.data + length - 1;
for (T* begin = vector; begin != end; ++begin) for (T* begin = this.data; begin != end; ++begin)
{ {
int result = dg(*begin); int result = dg(*begin);
if (result != 0) if (result != 0)
@ -1150,7 +1188,7 @@ struct Vector(T)
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)); int result = dg(i, *(this.data + i));
if (result != 0) if (result != 0)
{ {
@ -1163,7 +1201,7 @@ struct Vector(T)
/// Ditto. /// Ditto.
int opApplyReverse(scope int delegate(ref T) dg) int opApplyReverse(scope int delegate(ref T) dg)
{ {
for (T* end = vector + length - 1; vector != end; --end) for (T* end = this.data + length - 1; this.data != end; --end)
{ {
int result = dg(*end); int result = dg(*end);
if (result != 0) if (result != 0)
@ -1184,7 +1222,7 @@ struct Vector(T)
{ {
--i; --i;
assert(i < length); assert(i < length);
int result = dg(i, *(vector + i)); int result = dg(i, *(this.data + i));
if (result != 0) if (result != 0)
{ {
@ -1239,7 +1277,7 @@ struct Vector(T)
/** /**
* Returns: The first element. * Returns: The first element.
* *
* Precondition: $(D_INLINECODE !empty) * Precondition: $(D_INLINECODE !empty).
*/ */
@property ref inout(T) front() inout @property ref inout(T) front() inout
in in
@ -1248,7 +1286,7 @@ struct Vector(T)
} }
body body
{ {
return *vector; return *this.data;
} }
/// ///
@ -1266,7 +1304,7 @@ struct Vector(T)
/** /**
* Returns: The last element. * Returns: The last element.
* *
* Precondition: $(D_INLINECODE !empty) * Precondition: $(D_INLINECODE !empty).
*/ */
@property ref inout(T) back() inout @trusted @property ref inout(T) back() inout @trusted
in in
@ -1275,7 +1313,7 @@ struct Vector(T)
} }
body body
{ {
return *(vector + length_ - 1); return *(this.data + length - 1);
} }
/// ///
@ -1298,7 +1336,7 @@ struct Vector(T)
* Returns: A range that iterates over elements of the container from * Returns: A range that iterates over elements of the container from
* index $(D_PARAM i) up to (excluding) index $(D_PARAM j). * index $(D_PARAM i) up to (excluding) index $(D_PARAM j).
* *
* Precondition: $(D_INLINECODE i <= j && j <= length) * Precondition: $(D_INLINECODE i <= j && j <= length).
*/ */
Range!T opSlice(const size_t i, const size_t j) @trusted Range!T opSlice(const size_t i, const size_t j) @trusted
in in
@ -1308,7 +1346,7 @@ struct Vector(T)
} }
body body
{ {
return typeof(return)(vector + i, vector + j); return typeof(return)(this, this.data + i, this.data + j);
} }
/// Ditto. /// Ditto.
@ -1320,7 +1358,7 @@ struct Vector(T)
} }
body body
{ {
return typeof(return)(vector + i, vector + j); return typeof(return)(this, this.data + i, this.data + j);
} }
/// ///
@ -1394,7 +1432,7 @@ struct Vector(T)
} }
body body
{ {
copy(value, vector[i .. j]); copy(value, this.data[i .. j]);
return opSlice(i, j); return opSlice(i, j);
} }
@ -1413,7 +1451,7 @@ struct Vector(T)
} }
body body
{ {
fill(vector[i .. j], value); fill(this.data[i .. j], value);
return opSlice(i, j); return opSlice(i, j);
} }
@ -1454,7 +1492,7 @@ struct Vector(T)
*/ */
inout(T[]) get() inout @trusted inout(T[]) get() inout @trusted
{ {
return vector[0 .. length]; return this.data[0 .. length];
} }
/// ///
@ -1498,7 +1536,7 @@ struct Vector(T)
ref typeof(this) opAssign(R)(R that) @trusted ref typeof(this) opAssign(R)(R that) @trusted
if (is(R == Vector)) if (is(R == Vector))
{ {
swap(this.vector, that.vector); swap(this.data, that.data);
swap(this.length_, that.length_); swap(this.length_, that.length_);
swap(this.capacity_, that.capacity_); swap(this.capacity_, that.capacity_);
swap(this.allocator_, that.allocator_); swap(this.allocator_, that.allocator_);
@ -1519,7 +1557,7 @@ struct Vector(T)
&& isInputRange!R && isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T)) && isImplicitlyConvertible!(ElementType!R, T))
{ {
this.length = 0; length = 0;
insertBack(that); insertBack(that);
return this; return this;
} }
@ -1596,7 +1634,7 @@ unittest
const v1 = Vector!int(); const v1 = Vector!int();
const Vector!int v2; const Vector!int v2;
const v3 = Vector!int([1, 5, 8]); const v3 = Vector!int([1, 5, 8]);
static assert(is(PointerTarget!(typeof(v3.vector)) == const(int))); static assert(is(PointerTarget!(typeof(v3.data)) == const(int)));
} }
@nogc unittest @nogc unittest