summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-04-04 15:11:14 +0200
committerEugen Wissner <belka@caraus.de>2017-04-04 15:11:14 +0200
commitb1d2b9bd9e37c043ab382e93f8016231233de13c (patch)
tree8d97990f158fd004dd25059d640f5b4178947391
parent9b953198fafabffb2984df8ffff7d89366d909a7 (diff)
downloadtanya-b1d2b9bd9e37c043ab382e93f8016231233de13c.tar.gz
Fix Vector.insertAfter/Before an empty range
-rw-r--r--source/tanya/container/vector.d250
1 files changed, 144 insertions, 106 deletions
diff --git a/source/tanya/container/vector.d b/source/tanya/container/vector.d
index 4a7b5c3..2bb0171 100644
--- a/source/tanya/container/vector.d
+++ b/source/tanya/container/vector.d
@@ -22,22 +22,42 @@ import std.meta;
import std.traits;
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 alias ContainerType = CopyConstness!(E, Vector!(Unqual!E));
+ private ContainerType* vector;
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.end = end;
}
+ @disable this();
+
@property Range save()
{
return this;
@@ -45,12 +65,12 @@ private struct Range(E)
@property bool empty() const
{
- return begin == end;
+ return this.begin == this.end;
}
@property size_t length() const
{
- return end - begin;
+ return this.end - this.begin;
}
alias opDollar = length;
@@ -62,7 +82,7 @@ private struct Range(E)
}
body
{
- return *begin;
+ return *this.begin;
}
@property ref inout(E) back() inout @trusted
@@ -72,7 +92,7 @@ private struct Range(E)
}
body
{
- return *(end - 1);
+ return *(this.end - 1);
}
void popFront() @trusted
@@ -82,7 +102,7 @@ private struct Range(E)
}
body
{
- ++begin;
+ ++this.begin;
}
void popBack() @trusted
@@ -92,7 +112,7 @@ private struct Range(E)
}
body
{
- --end;
+ --this.end;
}
ref inout(E) opIndex(const size_t i) inout @trusted
@@ -102,17 +122,17 @@ private struct Range(E)
}
body
{
- return *(begin + i);
+ return *(this.begin + i);
}
Range opIndex()
{
- return typeof(return)(begin, end);
+ return typeof(return)(*this.vector, this.begin, this.end);
}
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
@@ -123,7 +143,7 @@ private struct Range(E)
}
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
@@ -134,12 +154,12 @@ private struct Range(E)
}
body
{
- return typeof(return)(begin + i, begin + j);
+ return typeof(return)(*this.vector, this.begin + i, this.begin + j);
}
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)
{
private size_t length_;
- private T* vector;
+ private T* data;
private size_t capacity_;
invariant
{
- assert(length_ <= capacity_);
- assert(capacity_ == 0 || vector !is null);
+ assert(this.length_ <= this.capacity_);
+ assert(this.capacity_ == 0 || this.data !is null);
}
/**
@@ -224,20 +244,20 @@ struct Vector(T)
if (allocator is init.allocator)
{
// Just steal all references and the allocator.
- vector = init.vector;
- length_ = init.length_;
- capacity_ = init.capacity_;
+ this.data = init.data;
+ this.length_ = init.length_;
+ this.capacity_ = init.capacity_;
// Reset the source vector, so it can't destroy the moved storage.
init.length_ = init.capacity_ = 0;
- init.vector = null;
+ init.data = null;
}
else
{
// Move each element.
- reserve(init.length);
- moveEmplaceAll(init.vector[0 .. init.length_], vector[0 .. init.length_]);
- length_ = init.length;
+ reserve(init.length_);
+ moveEmplaceAll(init.data[0 .. init.length_], this.data[0 .. init.length_]);
+ this.length_ = init.length_;
// Destructor of init should destroy it here.
}
}
@@ -247,7 +267,6 @@ struct Vector(T)
{
auto v1 = Vector!int([1, 2, 3]);
auto v2 = Vector!int(v1);
- assert(v1.vector !is v2.vector);
assert(v1 == v2);
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 v2 = Vector!int(v1);
- assert(v1.vector !is v2.vector);
+ assert(v1.data !is v2.data);
assert(v1 == v2);
auto v3 = const Vector!int(Vector!int([1, 2, 3]));
@@ -281,7 +300,7 @@ struct Vector(T)
{
this(allocator);
reserve(len);
- uninitializedFill(vector[0 .. len], init);
+ uninitializedFill(this.data[0 .. len], init);
length_ = len;
}
@@ -334,7 +353,7 @@ struct Vector(T)
~this() @trusted
{
clear();
- allocator.deallocate(vector[0 .. capacity_]);
+ allocator.deallocate(this.data[0 .. capacity]);
}
/**
@@ -342,9 +361,9 @@ struct Vector(T)
*/
this(this)
{
- auto buf = opIndex();
- length_ = capacity_ = 0;
- vector = null;
+ auto buf = this.data[0 .. this.length_];
+ this.length_ = capacity_ = 0;
+ this.data = null;
insertBack(buf);
}
@@ -409,14 +428,14 @@ struct Vector(T)
else if (len > length)
{
reserve(len);
- initializeAll(vector[length_ .. len]);
+ initializeAll(this.data[length_ .. len]);
}
else
{
static if (hasElaborateDestructor!T)
{
- const T* end = vector + length_ - 1;
- for (T* e = vector + len; e != end; ++e)
+ const T* end = this.data + length_ - 1;
+ for (T* e = this.data + len; e != end; ++e)
{
destroy(*e);
}
@@ -467,7 +486,7 @@ struct Vector(T)
immutable byteSize = mulu(size, T.sizeof, overflow);
assert(!overflow);
- void[] buf = vector[0 .. capacity_];
+ void[] buf = this.data[0 .. this.capacity_];
if (!allocator.reallocateInPlace(buf, byteSize))
{
buf = allocator.allocate(byteSize);
@@ -479,8 +498,8 @@ struct Vector(T)
{
allocator.deallocate(buf);
}
- const T* end = vector + length_;
- for (T* src = vector, dest = cast(T*) buf; src != end; ++src, ++dest)
+ const T* end = this.data + this.length_;
+ for (T* src = this.data, dest = cast(T*) buf; src != end; ++src, ++dest)
{
moveEmplace(*src, *dest);
static if (hasElaborateDestructor!T)
@@ -488,10 +507,10 @@ struct Vector(T)
destroy(*src);
}
}
- allocator.deallocate(vector[0 .. capacity_]);
- vector = cast(T*) buf;
+ allocator.deallocate(this.data[0 .. this.capacity_]);
+ this.data = cast(T*) buf;
}
- capacity_ = size;
+ this.capacity_ = size;
}
///
@@ -517,15 +536,15 @@ struct Vector(T)
*/
void shrink(const size_t size) @trusted
{
- if (capacity_ <= size)
+ if (capacity <= size)
{
return;
}
immutable n = max(length, size);
- void[] buf = vector[0 .. capacity_];
+ void[] buf = this.data[0 .. this.capacity_];
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
*
- * Precondition: $(D_INLINECODE !empty)
+ * Precondition: $(D_INLINECODE !empty).
*/
void removeBack()
in
@@ -611,22 +630,24 @@ struct Vector(T)
* Params:
* 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).
*/
Range!T remove(Range!T r) @trusted
in
{
- assert(r.begin >= vector);
- assert(r.end <= vector + length_);
+ assert(r.vector is &this);
+ assert(r.begin >= this.data);
+ assert(r.end <= this.data + length);
}
body
{
- auto end = vector + length_;
- moveAll(Range!T(r.end, end), Range!T(r.begin, end));
+ auto end = this.data + this.length;
+ moveAll(Range!T(this, r.end, end), Range!T(this, r.begin, end));
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]);
- 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.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.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.length == 4);
- assert(v.remove(v[]).length == 4);
- assert(v.empty);
-
assert(v.remove(v[]).length == 0);
- assert(v.empty);
+
}
private void moveBack(R)(ref R el) @trusted
if (isImplicitlyConvertible!(R, T))
{
- reserve(length + 1);
- moveEmplace(el, *(vector + length_));
- ++length_;
+ reserve(this.length + 1);
+ moveEmplace(el, *(this.data + this.length_));
+ ++this.length_;
}
/**
@@ -675,9 +693,9 @@ struct Vector(T)
{
static if (__traits(isRef, el))
{
- reserve(length + 1);
- emplace(vector + length_, el);
- ++length_;
+ reserve(this.length_ + 1);
+ emplace(this.data + this.length_, el);
+ ++this.length_;
}
else
{
@@ -763,6 +781,8 @@ struct Vector(T)
* el = Value(s) should be 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)
if (!isInfinite!R
@@ -770,20 +790,28 @@ struct Vector(T)
&& isImplicitlyConvertible!(ElementType!R, T))
in
{
- assert(r.begin >= vector);
- assert(r.end <= vector + length_);
+ assert(r.vector is &this);
+ assert(r.begin >= this.data);
+ assert(r.end <= this.data + length);
}
body
{
immutable oldLen = length;
- immutable offset = r.end - vector;
+ immutable offset = r.end - this.data;
immutable inserted = insertBack(el);
- bringToFront(vector[offset .. oldLen], vector[oldLen .. length]);
+ bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]);
return inserted;
}
/// Ditto.
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[]);
}
@@ -793,13 +821,14 @@ struct Vector(T)
if (isImplicitlyConvertible!(R, T))
in
{
- assert(r.begin >= vector);
- assert(r.end <= vector + length_);
+ assert(r.vector is &this);
+ assert(r.begin >= this.data);
+ assert(r.end <= this.data + length);
}
body
{
immutable oldLen = length;
- immutable offset = r.end - vector;
+ immutable offset = r.end - this.data;
static if (__traits(isRef, el))
{
@@ -809,7 +838,7 @@ struct Vector(T)
{
moveBack(el);
}
- bringToFront(vector[offset .. oldLen], vector[oldLen .. length_]);
+ bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]);
return 1;
}
@@ -821,16 +850,24 @@ struct Vector(T)
&& isImplicitlyConvertible!(ElementType!R, T))
in
{
- assert(r.begin >= vector);
- assert(r.end <= vector + length_);
+ assert(r.vector is &this);
+ assert(r.begin >= this.data);
+ assert(r.end <= this.data + length);
}
body
{
- return insertAfter(Range!T(vector, r.begin), el);
+ return insertAfter(Range!T(this, this.data, r.begin), el);
}
/// Ditto.
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[]);
}
@@ -840,13 +877,14 @@ struct Vector(T)
if (isImplicitlyConvertible!(R, T))
in
{
- assert(r.begin >= vector);
- assert(r.end <= vector + length_);
+ assert(r.vector is &this);
+ assert(r.begin >= this.data);
+ assert(r.end <= this.data + length);
}
body
{
immutable oldLen = length;
- immutable offset = r.begin - vector;
+ immutable offset = r.begin - this.data;
static if (__traits(isRef, el))
{
@@ -856,7 +894,7 @@ struct Vector(T)
{
moveBack(el);
}
- bringToFront(vector[offset .. oldLen], vector[oldLen .. length_]);
+ bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]);
return 1;
}
@@ -942,7 +980,7 @@ struct Vector(T)
*
* Returns: Assigned value.
*
- * Precondition: $(D_INLINECODE length > pos)
+ * Precondition: $(D_INLINECODE length > pos).
*/
ref T opIndexAssign(ref T value, const size_t pos)
{
@@ -983,7 +1021,7 @@ struct Vector(T)
*
* Returns: Assigned value.
*
- * Precondition: $(D_INLINECODE length == value.length)
+ * Precondition: $(D_INLINECODE length == value.length).
*/
Range!T opIndexAssign(R)(R value)
if (!isInfinite!R && isInputRange!R
@@ -1020,7 +1058,7 @@ struct Vector(T)
*
* 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
in
@@ -1029,7 +1067,7 @@ struct Vector(T)
}
body
{
- return *(vector + pos);
+ return *(this.data + pos);
}
/**
@@ -1038,13 +1076,13 @@ struct Vector(T)
*/
Range!T opIndex() @trusted
{
- return typeof(return)(vector, vector + length_);
+ return typeof(return)(this, this.data, this.data + length);
}
/// Ditto.
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
{
- return equal(vector[0 .. length_], that.vector[0 .. that.length_]);
+ return equal(this.data[0 .. length], that.data[0 .. that.length]);
}
/// Ditto.
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.
@@ -1132,8 +1170,8 @@ struct Vector(T)
*/
int opApply(scope int delegate(ref T) @nogc dg)
{
- T* end = vector + length_ - 1;
- for (T* begin = vector; begin != end; ++begin)
+ T* end = this.data + length - 1;
+ for (T* begin = this.data; begin != end; ++begin)
{
int result = dg(*begin);
if (result != 0)
@@ -1150,7 +1188,7 @@ struct Vector(T)
for (size_t i = 0; i < length; ++i)
{
assert(i < length);
- int result = dg(i, *(vector + i));
+ int result = dg(i, *(this.data + i));
if (result != 0)
{
@@ -1163,7 +1201,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 = this.data + length - 1; this.data != end; --end)
{
int result = dg(*end);
if (result != 0)
@@ -1184,7 +1222,7 @@ struct Vector(T)
{
--i;
assert(i < length);
- int result = dg(i, *(vector + i));
+ int result = dg(i, *(this.data + i));
if (result != 0)
{
@@ -1239,7 +1277,7 @@ struct Vector(T)
/**
* Returns: The first element.
*
- * Precondition: $(D_INLINECODE !empty)
+ * Precondition: $(D_INLINECODE !empty).
*/
@property ref inout(T) front() inout
in
@@ -1248,7 +1286,7 @@ struct Vector(T)
}
body
{
- return *vector;
+ return *this.data;
}
///
@@ -1266,7 +1304,7 @@ struct Vector(T)
/**
* Returns: The last element.
*
- * Precondition: $(D_INLINECODE !empty)
+ * Precondition: $(D_INLINECODE !empty).
*/
@property ref inout(T) back() inout @trusted
in
@@ -1275,7 +1313,7 @@ struct Vector(T)
}
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
* 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
in
@@ -1308,7 +1346,7 @@ struct Vector(T)
}
body
{
- return typeof(return)(vector + i, vector + j);
+ return typeof(return)(this, this.data + i, this.data + j);
}
/// Ditto.
@@ -1320,7 +1358,7 @@ struct Vector(T)
}
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
{
- copy(value, vector[i .. j]);
+ copy(value, this.data[i .. j]);
return opSlice(i, j);
}
@@ -1413,7 +1451,7 @@ struct Vector(T)
}
body
{
- fill(vector[i .. j], value);
+ fill(this.data[i .. j], value);
return opSlice(i, j);
}
@@ -1454,7 +1492,7 @@ struct Vector(T)
*/
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
if (is(R == Vector))
{
- swap(this.vector, that.vector);
+ swap(this.data, that.data);
swap(this.length_, that.length_);
swap(this.capacity_, that.capacity_);
swap(this.allocator_, that.allocator_);
@@ -1519,7 +1557,7 @@ struct Vector(T)
&& isInputRange!R
&& isImplicitlyConvertible!(ElementType!R, T))
{
- this.length = 0;
+ length = 0;
insertBack(that);
return this;
}
@@ -1596,7 +1634,7 @@ unittest
const v1 = Vector!int();
const Vector!int v2;
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