summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--source/tanya/container/vector.d1699
2 files changed, 973 insertions, 728 deletions
diff --git a/README.md b/README.md
index b05f3a3..4167c9c 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,7 @@ suite, but contains (will contain) algorithm implementations required by TLS.
Online documentation will be published soon.
* Tanya is cross-platform. The development happens on a 64-bit Linux, but it
-* is being tested on Windows and FreeBSD as well.
+is being tested on Windows and FreeBSD as well.
* The library isn't thread-safe. Thread-safity should be added later.
diff --git a/source/tanya/container/vector.d b/source/tanya/container/vector.d
index 96c18f9..69eb310 100644
--- a/source/tanya/container/vector.d
+++ b/source/tanya/container/vector.d
@@ -10,8 +10,10 @@
*/
module tanya.container.vector;
+import core.stdc.string;
import core.exception;
import std.algorithm.comparison;
+import std.conv;
import std.range.primitives;
import std.traits;
public import tanya.enums : IL;
@@ -27,909 +29,1146 @@ version (unittest)
}
}
-/**
- * One dimensional array.
- *
- * Params:
- * T = Content type.
- */
-template Vector(T)
+// Defines the container's primary range.
+private struct Range(E)
{
- /**
- * Defines the container's primary range.
- */
- struct Range(V)
+ private E* begin, end;
+
+ invariant
{
- private alias E = typeof(data.vector[0]);
+ assert(begin <= end);
+ }
- private V* data;
+ private this(E* begin, E* end)
+ in
+ {
+ assert(begin <= end);
+ }
+ body
+ {
+ this.begin = begin;
+ this.end = end;
+ }
- private @property ref inout(V) outer() inout return
- {
- return *data;
- }
+ private this(in E* begin, in E* end) const
+ in
+ {
+ assert(begin <= end);
+ }
+ body
+ {
+ this.begin = begin;
+ this.end = end;
+ }
- private size_t start, end;
+ @property Range save()
+ {
+ return this;
+ }
- invariant
- {
- assert(start <= end);
- }
+ @property bool empty() const
+ {
+ return begin == end;
+ }
+
+ @property size_t length() const
+ {
+ return end - begin;
+ }
+
+ alias opDollar = length;
- private this(ref inout V data, in size_t a, in size_t b) inout
+ @property ref inout(E) front() inout @trusted
+ in
+ {
+ assert(!empty);
+ }
+ body
+ {
+ return *begin;
+ }
+
+ @property ref inout(E) back() inout @trusted
+ in
+ {
+ assert(!empty);
+ }
+ body
+ {
+ return *(end - 1);
+ }
+
+ void popFront() @trusted
+ in
+ {
+ assert(!empty);
+ }
+ body
+ {
+ ++begin;
+ }
+
+ void popBack() @trusted
+ in
+ {
+ assert(!empty);
+ }
+ body
+ {
+ --end;
+ }
+
+ ref inout(E) opIndex(in size_t i) inout @trusted
+ in
+ {
+ assert(i < length);
+ }
+ body
+ {
+ return *(begin + i);
+ }
+
+ Range opIndex()
+ {
+ return typeof(return)(begin, end);
+ }
+
+ const(Range) opIndex() const
+ {
+ return typeof(return)(begin, end);
+ }
+
+ Range opSlice(in size_t i, in size_t j)
+ in
+ {
+ assert(i <= j);
+ assert(j < length);
+ }
+ body
+ {
+ return typeof(return)(begin + i, begin + j);
+ }
+
+ const(Range) opSlice(in size_t i, in size_t j) const
+ in
+ {
+ assert(i <= j);
+ assert(j < length);
+ }
+ body
+ {
+ return typeof(return)(begin + i, begin + j);
+ }
+
+ static if (isMutable!E)
+ {
+ ref E opIndexAssign(ref E value, in size_t pos) @trusted
in
{
- assert(a <= b);
- assert(b <= data.length);
+ assert(length > pos);
}
body
{
- this.data = &data;
- start = a;
- end = b;
+ return *(begin + pos) = value;
}
- @property Range save()
+ /// Ditto.
+ E opIndexAssign(E value, in size_t pos)
{
- return this;
+ return opIndexAssign(value, pos);
}
- @property bool empty() inout const
+ Range opIndexAssign(ref E value) @trusted
{
- return start == end;
+ E* begin = this.begin;
+ for (E* e = this.begin; e != end; ++e)
+ {
+ *e = value;
+ }
+ return typeof(return)(begin, end);
}
- @property size_t length() inout const
+ Range opIndexAssign(E value)
{
- return end - start;
+ return opIndexAssign(value);
}
- alias opDollar = length;
-
- @property ref inout(E) front() inout
+ Range opSliceAssign(ref E value, in size_t i, in size_t j) @trusted
+ in
{
- return outer[start];
+ assert(i <= j);
+ assert(j < length);
}
-
- @property ref inout(E) back() inout
+ body
{
- return outer[end - 1];
+ E* begin = this.begin + i;
+ E* end = this.begin + j;
+ for (E* e = begin; e != end; ++e)
+ {
+ *e = value;
+ }
+ return typeof(return)(begin, end);
}
- void popFront()
- in
- {
- assert(!empty);
- }
- body
+ Range opSliceAssign(E value)
{
- ++start;
+ return opSliceAssign(value);
}
- void popBack()
+ Range opSliceAssign(R)(R value, in size_t i, in size_t j) @trusted
+ if (!isInfinite!R
+ && isInputRange!R
+ && isImplicitlyConvertible!(ElementType!R, T))
in
{
- assert(!empty);
+ assert(j - i == walkLength(value));
}
body
{
- --end;
+ T* begin = this.begin + i;
+ const T* end = this.begin + j;
+ for (T* v = begin; v != end; ++v, value.popFront())
+ {
+ *v = value.front;
+ }
+ return typeof(return)(begin, end);
}
- ref inout(E) opIndex(in size_t i) inout
+ Range opSliceAssign(R)(R value, in size_t i, in size_t j)
+ if ((isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
+ || is(R == Vector))
{
- return outer[start + i];
+ return opSliceAssign(value[], i, j);
}
+ }
+}
- Range opIndex()
- {
- return typeof(return)(outer, start, end);
- }
+/**
+ * One dimensional array.
+ *
+ * Params:
+ * T = Content type.
+ */
+struct Vector(T)
+{
+ private size_t length_;
+ private T* vector;
+ private size_t capacity_;
- Range opSlice(in size_t i, in size_t j)
- in
- {
- assert(i <= j);
- assert(start + j <= end);
- }
- body
+ invariant
+ {
+ assert(length_ <= capacity_);
+ assert(capacity_ == 0 || vector !is null);
+ }
+
+ // Reserves memory to store len objects and initializes it.
+ private void initialize(in size_t len)
+ {
+ reserve(len);
+ if (capacity_ < len)
{
- return typeof(return)(outer, start + i, start + j);
+ onOutOfMemoryError();
}
-
- static if (isMutable!V)
+ const init = typeid(T).initializer();
+ if (init.ptr)
{
- Range opIndexAssign(T value)
+ const T* end = vector + len;
+ for (void* v = vector + length_; v != end; v += init.length)
{
- return outer[start .. end] = value;
+ memcpy(v, init.ptr, init.length);
}
+ }
+ else
+ {
+ memset(vector + length_, 0, len * T.sizeof);
+ }
+ }
- Range opSliceAssign(T value, in size_t i, in size_t j)
- {
- return outer[start + i .. start + j] = value;
- }
+ /**
+ * Creates a new $(D_PSYMBOL Vector).
+ *
+ * Params:
+ * R = Type of the static array with the initial elements.
+ * init = Values to initialize the array with. Use $(D_PSYMBOL IL).
+ * to generate a list.
+ * allocator = Allocator.
+ */
+ this(R)(auto ref R init, shared Allocator allocator = defaultAllocator)
+ if ((isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
+ || is(R == Vector))
+ {
+ this(allocator);
+ insertBack(init[]);
+ }
- Range opSliceAssign(Range value, in size_t i, in size_t j)
- {
- return outer[start + i .. start + j] = value;
- }
+ /// Ditto.
+ this(R)(R init, shared Allocator allocator = defaultAllocator)
+ if (!isInfinite!R
+ && isInputRange!R
+ && isImplicitlyConvertible!(ElementType!R, T))
+ {
+ this(allocator);
+ insertBack(init);
+ }
- Range opSliceAssign(T[] value, in size_t i, in size_t j)
- {
- return outer[start + i .. start + j] = value;
- }
- }
+ private unittest
+ {
+ // Implicitly convertible works.
+ auto v = Vector!int(IL(cast(short) 1, cast(short) 2));
}
- struct Vector
+ /**
+ * Creates a new $(D_PSYMBOL Vector).
+ *
+ * Params:
+ * len = Initial length of the vector.
+ * init = Initial value to fill the vector with.
+ * allocator = Allocator.
+ */
+ this(size_t len, shared Allocator allocator = defaultAllocator) @trusted
{
- private size_t length_;
+ this(allocator);
- invariant
+ vector = cast(T*) allocator.allocate(len * T.sizeof);
+ if (len == 0)
{
- assert(length_ <= vector.length);
+ return;
}
+ initialize(len);
+ capacity_ = length_ = len;
+ }
- /// Internal representation.
- private T[] vector;
+ /// Ditto.
+ this(size_t len, T init, shared Allocator allocator = defaultAllocator) @trusted
+ {
+ this(allocator);
- /**
- * Creates a new $(D_PSYMBOL Vector).
- *
- * Params:
- * U = Type of the static array with the initial elements.
- * params = Values to initialize the array with. Use $(D_PSYMBOL IL)
- * to generate a list.
- * allocator = Allocator.
- */
- this(U)(U init, shared Allocator allocator = defaultAllocator)
- if (isStaticArray!U)
- in
- {
- assert(allocator !is null);
- static assert(init.length > 0);
- }
- body
+ vector = cast(T*) allocator.allocate(len * T.sizeof);
+ if (len == 0)
{
- this(allocator);
- allocator.resize!(T, false)(vector, init.length);
- vector[0 .. $] = init[0 .. $];
- length_ = init.length;
+ return;
}
+ initialize(len);
+ capacity_ = length_ = len;
+ opSliceAssign(init, 0, length_);
+ }
- /// Ditto.
- this(U)(U init, shared Allocator allocator = defaultAllocator) const
- if (isStaticArray!U)
- in
- {
- assert(allocator !is null);
- static assert(init.length > 0);
- }
- body
- {
- allocator_ = cast(const shared Allocator) allocator;
+ /// Ditto.
+ this(shared Allocator allocator)
+ in
+ {
+ assert(allocator !is null);
+ }
+ body
+ {
+ allocator_ = allocator;
+ }
- T[] buf;
- allocator.resize!(T, false)(buf, init.length);
- buf[0 .. $] = init[0 .. $];
- vector = cast(const(T[])) buf;
- length_ = init.length;
- }
+ ///
+ unittest
+ {
+ auto v = Vector!int(IL(3, 8, 2));
- /// Ditto.
- this(U)(U init, shared Allocator allocator = defaultAllocator) immutable
- if (isStaticArray!U)
- in
- {
- assert(allocator !is null);
- static assert(init.length > 0);
- }
- body
- {
- allocator_ = cast(immutable Allocator) allocator;
+ assert(v.capacity == 3);
+ assert(v.length == 3);
+ assert(v[0] == 3 && v[1] == 8 && v[2] == 2);
+ }
- T[] buf;
- allocator.resize!(T, false)(buf, init.length);
- buf[0 .. $] = init[0 .. $];
- vector = cast(immutable(T[])) buf;
- length_ = init.length;
- }
+ ///
+ unittest
+ {
+ auto v = Vector!int(3, 5);
- /// Ditto.
- this(shared Allocator allocator)
- in
- {
- assert(allocator !is null);
- }
- body
+ assert(v.capacity == 3);
+ assert(v.length == 3);
+ assert(v[0] == 5 && v[1] == 5 && v[2] == 5);
+ }
+
+ /**
+ * Destroys this $(D_PSYMBOL Vector).
+ */
+ ~this()
+ {
+ static if (hasElaborateDestructor!T)
{
- allocator_ = allocator;
+ const T* end = vector + length_;
+ for (T* e = vector; e != end; ++e)
+ {
+ destroy(*e);
+ }
}
+ allocator.deallocate(cast(void[]) vector[0 .. capacity_]);
+ vector = null;
+ capacity_ = length_ = 0;
+ }
- ///
- unittest
- {
- auto v = Vector!int(IL(3, 8, 2));
+ private unittest
+ {
+ auto v = Vector!TestA(); // Destructor can destroy empty vectors.
+ }
- assert(v.capacity == 3);
- assert(v.length == 3);
- assert(v[0] == 3 && v[1] == 8 && v[2] == 2);
- }
+ /**
+ * Copies the vector.
+ */
+ this(this) @trusted
+ {
+ auto buf = vector;
+ immutable oldLen = length_;
+ length_ = capacity_ = 0;
+ insertBack(buf[0 .. oldLen]);
+ }
- /**
- * Destroys this $(D_PSYMBOL Vector).
- */
- ~this()
- {
- allocator.dispose(vector);
- }
+ /**
+ * Removes all elements.
+ */
+ void clear()
+ {
+ length_ = 0;
+ }
- /**
- * Removes all elements.
- */
- void clear()
- {
- length = 0;
- }
+ ///
+ unittest
+ {
+ auto v = Vector!int(IL(18, 20, 15));
+ v.clear();
+ assert(v.length == 0);
+ assert(v.capacity == 3);
+ }
- ///
- unittest
- {
- auto v = Vector!int(IL(18, 20, 15));
- v.clear();
- assert(v.length == 0);
- assert(v.capacity == 3);
- }
+ /**
+ * Returns: How many elements the vector can contain without reallocating.
+ */
+ @property size_t capacity() const
+ {
+ return capacity_;
+ }
+
+ /**
+ * Returns: Vector length.
+ */
+ @property size_t length() const
+ {
+ return length_;
+ }
+
+ /// Ditto.
+ size_t opDollar() const
+ {
+ return length;
+ }
- /**
- * Returns: How many elements the vector can contain without reallocating.
- */
- @property size_t capacity() inout const
+ /**
+ * Expands/shrinks the vector.
+ *
+ * Params:
+ * len = New length.
+ */
+ @property void length(in size_t len) @trusted
+ {
+ if (len == length_)
{
- return vector.length;
+ return;
}
-
- /**
- * Returns: Vector length.
- */
- @property size_t length() inout const
+ else if (len > length_)
{
- return length_;
+ initialize(len);
}
-
- /// Ditto.
- alias opDollar = length;
-
- /**
- * Expands/shrinks the vector.
- *
- * Params:
- * len = New length.
- */
- @property void length(in size_t len)
+ else
{
- if (len > length)
- {
- reserve(len);
- vector[length .. len] = T.init;
- }
- else if (len < length)
+ static if (hasElaborateDestructor!T)
{
- static if (hasElaborateDestructor!T)
+ const T* end = vector + length_ - 1;
+ for (T* e = vector + len; e != end; ++e)
{
- foreach (ref e; vector[len - 1 .. length_])
- {
- destroy(e);
- }
+ destroy(*e);
}
}
- else
- {
- return;
- }
- length_ = len;
}
+ length_ = len;
+ }
- ///
- unittest
- {
- Vector!int v;
+ ///
+ unittest
+ {
+ Vector!int v;
- v.length = 5;
- assert(v.length == 5);
- assert(v.capacity == 5);
+ v.length = 5;
+ assert(v.length == 5);
+ assert(v.capacity == 5);
- v.length = 7;
- assert(v.length == 7);
- assert(v.capacity == 7);
+ v.length = 7;
+ assert(v.length == 7);
+ assert(v.capacity == 7);
- assert(v[$ - 1] == 0);
- v[$ - 1] = 3;
- assert(v[$ - 1] == 3);
+ assert(v[$ - 1] == 0);
+ v[$ - 1] = 3;
+ assert(v[$ - 1] == 3);
- v.length = 0;
- assert(v.length == 0);
- assert(v.capacity == 7);
- }
+ v.length = 0;
+ assert(v.length == 0);
+ assert(v.capacity == 7);
+ }
- /**
- * Reserves space for $(D_PARAM size) elements.
- *
- * Params:
- * size = Desired size.
- */
- void reserve(in size_t size) @trusted
+ /**
+ * Reserves space for $(D_PARAM size) elements.
+ *
+ * Params:
+ * size = Desired size.
+ */
+ void reserve(in size_t size) @trusted
+ {
+ if (capacity_ < size)
{
- if (vector.length < size)
- {
- void[] buf = vector;
- allocator.reallocate(buf, size * T.sizeof);
- vector = cast(T[]) buf;
- }
+ void[] buf = vector[0 .. capacity_];
+ allocator.reallocate(buf, size * T.sizeof);
+ vector = cast(T*) buf;
+ capacity_ = size;
}
+ }
- ///
- unittest
- {
- Vector!int v;
- assert(v.capacity == 0);
- assert(v.length == 0);
-
- v.reserve(3);
- assert(v.capacity == 3);
- assert(v.length == 0);
- }
+ ///
+ unittest
+ {
+ Vector!int v;
+ assert(v.capacity == 0);
+ assert(v.length == 0);
- /**
- * Requests the vector to reduce its capacity to fit the $(D_PARAM size).
- *
- * The request is non-binding. The vector won't become smaller than the
- * $(D_PARAM length).
- *
- * Params:
- * size = Desired size.
- */
- void shrink(in size_t size) @trusted
- {
- auto n = max(length, size);
- void[] buf = vector;
- allocator.reallocate(buf, n * T.sizeof);
- vector = cast(T[]) buf;
- }
+ v.reserve(3);
+ assert(v.capacity == 3);
+ assert(v.length == 0);
+ }
- ///
- unittest
- {
- Vector!int v;
- assert(v.capacity == 0);
- assert(v.length == 0);
+ /**
+ * Requests the vector to reduce its capacity to fit the $(D_PARAM size).
+ *
+ * The request is non-binding. The vector won't become smaller than the
+ * $(D_PARAM length).
+ *
+ * Params:
+ * size = Desired size.
+ */
+ void shrink(in size_t size) @trusted
+ {
+ auto n = max(length, size);
+ void[] buf = vector[0 .. capacity_];
+ allocator.reallocate(buf, n * T.sizeof);
+ vector = cast(T*) buf;
+ capacity_ = n;
+ }
- v.reserve(5);
- v.insertBack(1);
- v.insertBack(3);
- assert(v.capacity == 5);
- assert(v.length == 2);
+ ///
+ unittest
+ {
+ Vector!int v;
+ assert(v.capacity == 0);
+ assert(v.length == 0);
+
+ v.reserve(5);
+ v.insertBack(1);
+ v.insertBack(3);
+ assert(v.capacity == 5);
+ assert(v.length == 2);
+
+ v.shrink(4);
+ assert(v.capacity == 4);
+ assert(v.length == 2);
+
+ v.shrink(1);
+ assert(v.capacity == 2);
+ assert(v.length == 2);
+ }
- v.shrink(4);
- assert(v.capacity == 4);
- assert(v.length == 2);
+ /**
+ * Returns: $(D_KEYWORD true) if the vector is empty.
+ */
+ @property bool empty() const
+ {
+ return length_ == 0;
+ }
- v.shrink(1);
- assert(v.capacity == 2);
- assert(v.length == 2);
- }
+ /**
+ * Removes $(D_PARAM howMany) elements from the vector.
+ *
+ * This method doesn't fail if it could not remove $(D_PARAM howMany)
+ * elements. Instead, if $(D_PARAM howMany) is greater than the vector
+ * length, all elements are removed.
+ *
+ * Params:
+ * howMany = How many elements should be removed.
+ *
+ * Returns: The number of elements removed
+ */
+ size_t removeBack(in size_t howMany = 1)
+ {
+ immutable toRemove = min(howMany, length_);
- /**
- * Returns: $(D_KEYWORD true) if the vector is empty.
- */
- @property bool empty() inout const
- {
- return length == 0;
- }
+ length = length_ - toRemove;
- /**
- * Removes $(D_PARAM howMany) elements from the vector.
- *
- * This method doesn't fail if it could not remove $(D_PARAM howMany)
- * elements. Instead, if $(D_PARAM howMany) is greater than the vector
- * length, all elements are removed.
- *
- * Params:
- * howMany = How many elements should be removed.
- *
- * Returns: The number of elements removed
- */
- size_t removeBack(in size_t howMany = 1)
- {
- immutable toRemove = min(howMany, length);
+ return toRemove;
+ }
- length = length - toRemove;
+ /// Ditto.
+ alias remove = removeBack;
- return toRemove;
- }
+ ///
+ unittest
+ {
+ auto v = Vector!int(IL(5, 18, 17));
- /// Ditto.
- alias remove = removeBack;
+ assert(v.removeBack(0) == 0);
+ assert(v.removeBack(2) == 2);
+ assert(v.removeBack(3) == 1);
+ assert(v.removeBack(3) == 0);
+ }
- ///
- unittest
+ /**
+ * Inserts the $(D_PARAM el) into the vector.
+ *
+ * Params:
+ * R = Parameter type (single value or range).
+ * el = Value should be inserted.
+ *
+ * Returns: The number of elements inserted.
+ */
+ size_t insertBack(R)(auto ref R el) @trusted
+ if (isImplicitlyConvertible!(R, T))
+ {
+ reserve(length_ + 1);
+ if (capacity_ <= length_)
{
- auto v = Vector!int(IL(5, 18, 17));
-
- assert(v.removeBack(0) == 0);
- assert(v.removeBack(2) == 2);
- assert(v.removeBack(3) == 1);
- assert(v.removeBack(3) == 0);
+ onOutOfMemoryError();
}
+ emplace(vector + length_, el);
+ ++length_;
+ return 1;
+ }
- /**
- * Inserts the $(D_PARAM el) into the vector.
- *
- * Returns: The number of elements inserted.
- */
- size_t insertBack(T el)
- {
- reserve(length + 1);
- vector[length] = el;
- ++length_;
- return 1;
- }
+ /// Ditto.
+ size_t insertBack(R)(R el) @trusted
+ if (!isInfinite!R
+ && isInputRange!R
+ && isImplicitlyConvertible!(ElementType!R, T))
+ {
+ immutable rLen = walkLength(el);
- /// Ditto.
- size_t insertBack(Range!Vector el)
+ initialize(length_ + rLen);
+ T* pos = vector + length_;
+ foreach (e; el)
{
- immutable newLength = length + el.length;
-
- reserve(newLength);
- vector[length .. newLength] = el.outer.vector[el.start .. el.end];
- length_ = newLength;
-
- return el.length;
+ *pos = e;
+ ++length_, ++pos;
}
+ return rLen;
+ }
- /// Ditto.
- size_t insertBack(R)(R el)
- if (isInputRange!R && isImplicitlyConvertible!(ElementType!R, T))
+ /// Ditto.
+ alias insert = insertBack;
+
+ ///
+ unittest
+ {
+ struct TestRange
{
- immutable rLen = walkLength(el);
+ int counter = 6;
- reserve(length + rLen);
- while (!el.empty)
+ int front()
{
- vector[length_] = el.front;
- el.popFront();
- length_++;
+ return counter;
}
- return rLen;
- }
- /// Ditto.
- alias insert = insertBack;
+ void popFront()
+ {
+ counter -= 2;
+ }
- ///
- unittest
- {
- struct TestRange
+ bool empty()
{
- int counter = 6;
+ return counter == 0;
+ }
+ }
- int front()
- {
- return counter;
- }
+ Vector!int v1;
- void popFront()
- {
- counter -= 2;
- }
+ assert(v1.insertBack(5) == 1);
+ assert(v1.length == 1);
+ assert(v1.capacity == 1);
+ assert(v1.back == 5);
- bool empty()
- {
- return counter == 0;
- }
- }
+ assert(v1.insertBack(TestRange()) == 3);
+ assert(v1.length == 4);
+ assert(v1.capacity == 4);
+ assert(v1[0] == 5 && v1[1] == 6 && v1[2] == 4 && v1[3] == 2);
- Vector!int v1;
-
- assert(v1.insertBack(5) == 1);
- assert(v1.length == 1);
- assert(v1.capacity == 1);
- assert(v1.back == 5);
-
- assert(v1.insertBack(TestRange()) == 3);
- assert(v1.length == 4);
- assert(v1.capacity == 4);
- assert(v1[0] == 5 && v1[1] == 6 && v1[2] == 4 && v1[3] == 2);
-
- auto v2 = Vector!int(IL(34, 234));
- assert(v1.insertBack(v2[]) == 2);
- assert(v1.length == 6);
- assert(v1.capacity == 6);
- assert(v1[4] == 34 && v1[5] == 234);
- }
-
- /**
- * Assigns a value to the element with the index $(D_PARAM pos).
- *
- * Params:
- * value = Value.
- * pos = Position.
- *
- * Returns: Assigned value.
- *
- * Precondition: $(D_INLINECODE length > pos)
- */
- T opIndexAssign(T value, in size_t pos)
- in
- {
- assert(length > pos);
- }
- body
- {
- return vector[pos] = value;
- }
-
- /// Ditto.
- Range!Vector opIndexAssign(T value)
- {
- vector[0 .. $] = value;
- return opIndex();
- }
+ auto v2 = Vector!int(IL(34, 234));
+ assert(v1.insertBack(v2[]) == 2);
+ assert(v1.length == 6);
+ assert(v1.capacity == 6);
+ assert(v1[4] == 34 && v1[5] == 234);
+ }
- ///
- unittest
- {
- auto v1 = Vector!int(IL(12, 1, 7));
+ /**
+ * Assigns a value to the element with the index $(D_PARAM pos).
+ *
+ * Params:
+ * value = Value.
+ * pos = Position.
+ *
+ * Returns: Assigned value.
+ *
+ * Precondition: $(D_INLINECODE length > pos)
+ */
+ ref T opIndexAssign(ref T value, in size_t pos) @trusted
+ in
+ {
+ assert(length > pos);
+ }
+ body
+ {
+ return *(vector + pos) = value;
+ }
- v1[] = 3;
- assert(v1[0] == 3);
- assert(v1[1] == 3);
- assert(v1[2] == 3);
- }
+ /// Ditto.
+ T opIndexAssign(T value, in size_t pos)
+ {
+ return opIndexAssign(value, pos);
+ }
- /**
- * Params:
- * pos = Index.
- *
- * Returns: The value at a specified index.
- *
- * Precondition: $(D_INLINECODE length > pos)
- */
- ref inout(T) opIndex(in size_t pos) inout
- in
- {
- assert(length > pos);
- }
- body
+ /// Ditto.
+ Range!T opIndexAssign(ref T value) @trusted
+ {
+ const T* end = vector + length_;
+ for (T* v = vector; v != end; ++v)
{
- return vector[pos];
+ *v = value;
}
+ return opIndex();
+ }
- /**
- * Returns: Random access range that iterates over elements of the vector, in
- * forward order.
- */
- Range!Vector opIndex()
- {
- return typeof(return)(this, 0, length);
- }
+ /// Ditto.
+ Range!T opIndexAssign(T value)
+ {
+ return opIndexAssign(value);
+ }
- /// Ditto.
- Range!(const Vector) opIndex() const
- {
- return typeof(return)(this, 0, length);
- }
+ ///
+ unittest
+ {
+ auto v1 = Vector!int(IL(12, 1, 7));
- /// Ditto.
- Range!(immutable Vector) opIndex() immutable
- {
- return typeof(return)(this, 0, length);
- }
+ v1[] = 3;
+ assert(v1[0] == 3);
+ assert(v1[1] == 3);
+ assert(v1[2] == 3);
+ }
- ///
- unittest
- {
- const v1 = Vector!int(IL(6, 123, 34, 5));
+ /**
+ * Params:
+ * pos = Index.
+ *
+ * Returns: The value at a specified index.
+ *
+ * Precondition: $(D_INLINECODE length > pos)
+ */
+ ref inout(T) opIndex(in size_t pos) inout @trusted
+ in
+ {
+ assert(length_ > pos);
+ }
+ body
+ {
+ return *(vector + pos);
+ }
- assert(v1[0] == 6);
- assert(v1[1] == 123);
- assert(v1[2] == 34);
- assert(v1[3] == 5);
- static assert(is(typeof(v1[0]) == const(int)));
- static assert(is(typeof(v1[])));
+ /**
+ * Returns: Random access range that iterates over elements of the vector, in
+ * forward order.
+ */
+ Range!T opIndex()
+ {
+ return typeof(return)(vector, vector + length_);
+ }
- auto v2 = immutable Vector!int(IL(6, 123, 34, 5));
- static assert(is(typeof(v2[0]) == immutable(int)));
- static assert(is(typeof(v2[])));
- }
+ /// Ditto.
+ Range!(const T) opIndex() const
+ {
+ return typeof(return)(vector, vector + length_);
+ }
- /**
- * Comparison for equality.
- *
- * Params:
- * o = The vector to compare with.
- *
- * Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
- * otherwise.
- */
- bool opEquals(typeof(this) v) const
- {
- return opEquals(v);
- }
+ ///
+ unittest
+ {
+ const v1 = Vector!int(IL(6, 123, 34, 5));
+
+ assert(v1[0] == 6);
+ assert(v1[1] == 123);
+ assert(v1[2] == 34);
+ assert(v1[3] == 5);
+ static assert(is(typeof(v1[0]) == const(int)));
+ static assert(is(typeof(v1[])));
+ }
- /// Ditto.
- bool opEquals(ref typeof(this) v) const
- {
- return vector == v.vector;
- }
+ /**
+ * Comparison for equality.
+ *
+ * Params:
+ * o = The vector to compare with.
+ *
+ * Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false)
+ * otherwise.
+ */
+ bool opEquals(typeof(this) v) const
+ {
+ return opEquals(v);
+ }
- ///
- unittest
- {
- Vector!int v1, v2;
- assert(v1 == v2);
+ /// Ditto.
+ bool opEquals(ref typeof(this) v) const @trusted
+ {
+ return vector[0 .. length_] == v.vector[0 .. v.length_];
+ }
- v1.length = 1;
- v2.length = 2;
- assert(v1 != v2);
+ ///
+ unittest
+ {
+ Vector!int v1, v2;
+ assert(v1 == v2);
- v1.length = 2;
- v1[0] = v2[0] = 2;
- v1[1] = 3;
- v2[1] = 4;
- assert(v1 != v2);
+ v1.length = 1;
+ v2.length = 2;
+ assert(v1 != v2);
- v2[1] = 3;
- assert(v1 == v2);
- }
+ v1.length = 2;
+ v1[0] = v2[0] = 2;
+ v1[1] = 3;
+ v2[1] = 4;
+ assert(v1 != v2);
- /**
- * $(D_KEYWORD foreach) iteration.
- *
- * Params:
- * dg = $(D_KEYWORD foreach) body.
- */
- int opApply(scope int delegate(ref T) dg)
- {
- int result;
+ v2[1] = 3;
+ assert(v1 == v2);
+ }
- foreach (e; vector)
+ /**
+ * $(D_KEYWORD foreach) iteration.
+ *
+ * Params:
+ * dg = $(D_KEYWORD foreach) body.
+ */
+ int opApply(scope int delegate(ref T) dg)
+ {
+ T* end = vector + length_ - 1;
+ for (T* begin = vector; begin != end; ++begin)
+ {
+ int result = dg(*begin);
+ if (result != 0)
{
- if ((result = dg(e)) != 0)
- {
- return result;
- }
+ return result;
}
- return result;
}
+ return 0;
+ }
- /// Ditto.
- int opApply(scope int delegate(ref size_t i, ref T) dg)
+ /// Ditto.
+ int opApply(scope int delegate(ref size_t i, ref T) dg)
+ {
+ for (size_t i = 0; i < length_; ++i)
{
- int result;
+ assert(i < length_);
+ int result = dg(i, *(vector + i));
- foreach (i, e; vector)
+ if (result != 0)
{
- if ((result = dg(i, e)) != 0)
- {
- return result;
- }
+ return result;
}
- return result;
}
+ return 0;
+ }
- /// Ditto.
- int opApplyReverse(scope int delegate(ref T) dg)
+ /// Ditto.
+ int opApplyReverse(scope int delegate(ref T) dg)
+ {
+ for (T* end = vector + length_ - 1; vector != end; --end)
{
- int result;
-
- foreach_reverse (e; vector)
+ int result = dg(*end);
+ if (result != 0)
{
- if ((result = dg(e)) != 0)
- {
- return result;
- }
+ return result;
}
- return result;
}
+ return 0;
+ }
- /// Ditto.
- int opApplyReverse(scope int delegate(ref size_t i, ref T) dg)
+ /// Ditto.
+ int opApplyReverse(scope int delegate(ref size_t i, ref T) dg)
+ {
+ if (length_ > 0)
{
- int result;
-
- foreach_reverse (i, e; vector)
+ size_t i = length_;
+ do
{
- if ((result = dg(i, e)) != 0)
+ --i;
+ assert(i < length_);
+ int result = dg(i, *(vector + i));
+
+ if (result != 0)
{
return result;
}
}
- return result;
+ while (i > 0);
}
+ return 0;
+ }
- ///
- unittest
- {
- auto v = Vector!int(IL(5, 15, 8));
-
- size_t i;
- foreach (j, ref e; v)
- {
- i = j;
- }
- assert(i == 2);
+ ///
+ unittest
+ {
+ auto v = Vector!int(IL(5, 15, 8));
- foreach (j, e; v)
- {
- assert(j != 0 || e == 5);
- assert(j != 1 || e == 15);
- assert(j != 2 || e == 8);
- }
+ size_t i;
+ foreach (j, ref e; v)
+ {
+ i = j;
}
+ assert(i == 2);
- ///
- unittest
+ foreach (j, e; v)
{
- auto v = Vector!int(IL(5, 15, 8));
- size_t i;
-
- foreach_reverse (j, ref e; v)
- {
- i = j;
- }
- assert(i == 0);
-
- foreach_reverse (j, e; v)
- {
- assert(j != 2 || e == 8);
- assert(j != 1 || e == 15);
- assert(j != 0 || e == 5);
- }
+ assert(j != 0 || e == 5);
+ assert(j != 1 || e == 15);
+ assert(j != 2 || e == 8);
}
+ }
- /**
- * Returns: The first element.
- *
- * Precondition: $(D_INLINECODE length > 0)
- */
- @property ref inout(T) front() inout
- in
+ ///
+ unittest
+ {
+ auto v = Vector!int(IL(5, 15, 8));
+ size_t i;
+
+ foreach_reverse (j, ref e; v)
{
- assert(!empty);
+ i = j;
}
- body
+ assert(i == 0);
+
+ foreach_reverse (j, e; v)
{
- return vector[0];
+ assert(j != 2 || e == 8);
+ assert(j != 1 || e == 15);
+ assert(j != 0 || e == 5);
}
+ }
- ///
- unittest
- {
- auto v = Vector!int(IL(5));
+ /**
+ * Returns: The first element.
+ *
+ * Precondition: $(D_INLINECODE length > 0)
+ */
+ @property ref inout(T) front() inout @trusted
+ in
+ {
+ assert(!empty);
+ }
+ body
+ {
+ return *vector;
+ }
- assert(v.front == 5);
+ ///
+ unittest
+ {
+ auto v = Vector!int(IL(5));
- v.length = 2;
- v[1] = 15;
- assert(v.front == 5);
- }
+ assert(v.front == 5);
- /**
- * Returns: The last element.
- *
- * Precondition: $(D_INLINECODE length > 0)
- */
- @property ref inout(T) back() inout
- in
- {
- assert(!empty);
- }
- body
- {
- return vector[length_ - 1];
- }
+ v.length = 2;
+ v[1] = 15;
+ assert(v.front == 5);
+ }
- ///
- unittest
- {
- auto v = Vector!int(IL(5));
+ /**
+ * Returns: The last element.
+ *
+ * Precondition: $(D_INLINECODE length > 0)
+ */
+ @property ref inout(T) back() inout @trusted
+ in
+ {
+ assert(!empty);
+ }
+ body
+ {
+ return *(vector + length_ - 1);
+ }
- assert(v.back == 5);
+ ///
+ unittest
+ {
+ auto v = Vector!int(IL(5));
- v.length = 2;
- v[1] = 15;
- assert(v.back == 15);
- }
+ assert(v.back == 5);
- /**
- * Params:
- * i = Slice start.
- * j = Slice end.
- *
- * 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)
- */
- Range!Vector opSlice(in size_t i, in size_t j)
- in
- {
- assert(i <= j);
- assert(j <= length);
- }
- body
- {
- return typeof(return)(this, i, j);
- }
-
- /**
- * Slicing assignment.
- *
- * Params:
- * value = New value.
- * i = Slice start.
- * j = Slice end.
- *
- * Returns: Assigned value.
- *
- * Precondition: $(D_INLINECODE i <= j && j <= length);
- * The lenghts of the ranges and slices match.
- */
- Range!Vector opSliceAssign(T value, in size_t i, in size_t j)
- in
- {
- assert(i <= j);
- assert(j <= length);
- }
- body
- {
- vector[i .. j] = value;
- return opSlice(i, j);
- }
+ v.length = 2;
+ v[1] = 15;
+ assert(v.back == 15);
+ }
- /// Ditto.
- Range!Vector opSliceAssign(Range!Vector value, in size_t i, in size_t j)
- in
- {
- assert(j - i == value.length);
- }
- body
- {
- vector[i .. j] = value.outer.vector[value.start .. value.end];
- return opSlice(i, j);
- }
+ /**
+ * Params:
+ * i = Slice start.
+ * j = Slice end.
+ *
+ * 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)
+ */
+ Range!T opSlice(in size_t i, in size_t j)
+ in
+ {
+ assert(i <= j);
+ assert(j <= length_);
+ }
+ body
+ {
+ return typeof(return)(vector + i, vector + j);
+ }
- /// Ditto.
- Range!Vector opSliceAssign(T[] value, in size_t i, in size_t j)
- in
+ /// Ditto.
+ Range!(const T) opSlice(in size_t i, in size_t j) const
+ in
+ {
+ assert(i <= j);
+ assert(j <= length_);
+ }
+ body
+ {
+ return typeof(return)(vector + i, vector + j);
+ }
+
+ ///
+ unittest
+ {
+ Vector!int v;
+ auto r = v[];
+ assert(r.length == 0);
+ assert(r.empty);
+ }
+
+ ///
+ unittest
+ {
+ auto v = Vector!int(IL(1, 2, 3));
+ auto r = v[];
+
+ assert(r.front == 1);
+ assert(r.back == 3);
+
+ r.popFront();
+ assert(r.front == 2);
+
+ r.popBack();
+ assert(r.back == 2);
+
+ assert(r.length == 1);
+ }
+
+ ///
+ unittest
+ {
+ auto v = Vector!int(IL(1, 2, 3, 4));
+ auto r = v[1 .. 4];
+ assert(r.length == 3);
+ assert(r[0] == 2);
+ assert(r[1] == 3);
+ assert(r[2] == 4);
+
+ r = v[0 .. 0];
+ assert(r.length == 0);
+
+ r = v[4 .. 4];
+ assert(r.length == 0);
+ }
+
+ /**
+ * Slicing assignment.
+ *
+ * Params:
+ * value = New value.
+ * i = Slice start.
+ * j = Slice end.
+ *
+ * Returns: Slice with the assigned part of the vector.
+ *
+ * Precondition: $(D_INLINECODE i <= j && j <= length);
+ * The lenghts of the ranges and slices match.
+ */
+ Range!T opSliceAssign(ref T value, in size_t i, in size_t j) @trusted
+ in
+ {
+ assert(i <= j);
+ assert(j <= length);
+ }
+ body
+ {
+ const T* end = vector + j;
+ for (T* v = vector + i; v != end; ++v)
{
- assert(j - i == value.length);
+ *v = value;
}
- body
+ return opSlice(i, j);
+ }
+
+ /// Ditto.
+ Range!T opSliceAssign(T value, in size_t i, in size_t j)
+ {
+ return opSliceAssign(value, i, j);
+ }
+
+ /// Ditto.
+ Range!T opSliceAssign(R)(R value, in size_t i, in size_t j)
+ if (!isInfinite!R
+ && isInputRange!R
+ && isImplicitlyConvertible!(ElementType!R, T))
+ in
+ {
+ assert(j - i == walkLength(value));
+ }
+ body
+ {
+ const T* end = vector + j;
+ for (T* v = vector + i; v != end; ++v, value.popFront())
{
- vector[i .. j] = value;
- return opSlice(i, j);
+ *v = value.front;
}
+ return opSlice(i, j);
+ }
- ///
- unittest
- {
- auto v1 = Vector!int(IL(3, 3, 3));
- auto v2 = Vector!int(IL(1, 2));
+ /// Ditto.
+ Range!T opSliceAssign(R)(R value, in size_t i, in size_t j)
+ if ((isStaticArray!R && isImplicitlyConvertible!(ElementType!R, T))
+ || is(R == Vector))
+ {
+ return opSliceAssign(value[], i, j);
+ }
- v1[0 .. 2] = 286;
- assert(v1[0] == 286);
- assert(v1[1] == 286);
- assert(v1[2] == 3);
+ ///
+ unittest
+ {
+ auto v1 = Vector!int(IL(3, 3, 3));
+ auto v2 = Vector!int(IL(1, 2));
- v2[0 .. $] = v1[1 .. 3];
- assert(v2[0] == 286);
- assert(v2[1] == 3);
- }
+ v1[0 .. 2] = 286;
+ assert(v1[0] == 286);
+ assert(v1[1] == 286);
+ assert(v1[2] == 3);
- mixin DefaultAllocator;
+ v2[0 .. $] = v1[1 .. 3];
+ assert(v2[0] == 286);
+ assert(v2[1] == 3);
}
+
+ mixin DefaultAllocator;
}
///
@@ -940,6 +1179,11 @@ unittest
assert(v.front == 5);
assert(v[1] == 15);
assert(v.back == 8);
+
+ auto r = v[];
+ r[0] = 7;
+ assert(r.front == 7);
+ assert(r.front == v.front);
}
private @nogc unittest
@@ -956,27 +1200,28 @@ private @nogc unittest
const v1 = Vector!int();
const Vector!int v2;
const v3 = Vector!int(IL(1, 5, 8));
- static assert(is(typeof(v3.vector) == const(int[])));
- static assert(is(typeof(v3.vector[0]) == const(int)));
-
- immutable v4 = immutable Vector!int();
- immutable v5 = immutable Vector!int(IL(2, 5, 8));
- static assert(is(typeof(v4.vector) == immutable(int[])));
- static assert(is(typeof(v4.vector[0]) == immutable(int)));
+ static assert(is(PointerTarget!(typeof(v3.vector)) == const(int)));
}
private @nogc unittest
{
- // Test that immutable/const vectors return usable ranges.
- auto v = immutable Vector!int(IL(1, 2, 4));
- auto r = v[];
+ // Test that const vectors return usable ranges.
+ auto v = const Vector!int(IL(1, 2, 4));
+ auto r1 = v[];
+
+ assert(r1.back == 4);
+ r1.popBack();
+ assert(r1.back == 2);
+ r1.popBack();
+ assert(r1.back == 1);
+ r1.popBack();
+ assert(r1.length == 0);
+
+ static assert(!is(typeof(r1[0] = 5)));
+ static assert(!is(typeof(v[0] = 5)));
- assert(r.back == 4);
- r.popBack();
- assert(r.back == 2);
- r.popBack();
- assert(r.back == 1);
- r.popBack();
+ const r2 = r1[];
+ static assert(is(typeof(r2[])));
}
private @nogc unittest