diff --git a/source/tanya/container/entry.d b/source/tanya/container/entry.d index 6fec435..1194f6b 100644 --- a/source/tanya/container/entry.d +++ b/source/tanya/container/entry.d @@ -12,11 +12,11 @@ */ module tanya.container.entry; -package struct Entry(T) +package struct SEntry(T) { /// Item content. T content; /// Next item. - Entry* next; + SEntry* next; } diff --git a/source/tanya/container/list.d b/source/tanya/container/list.d index 0c916c1..9000e74 100644 --- a/source/tanya/container/list.d +++ b/source/tanya/container/list.d @@ -72,7 +72,7 @@ struct SList(T) */ void insertFront(ref T x) { - auto temp = allocator.make!(Entry!T); + auto temp = allocator.make!(SEntry!T); temp.content = x; temp.next = first.next; @@ -233,7 +233,7 @@ struct SList(T) } /// 0th element of the list. - private Entry!T first; + private SEntry!T first; mixin DefaultAllocator; } diff --git a/source/tanya/container/queue.d b/source/tanya/container/queue.d index cb285e1..d94486d 100644 --- a/source/tanya/container/queue.d +++ b/source/tanya/container/queue.d @@ -44,7 +44,7 @@ struct Queue(T) size_t length() const { size_t len; - for (const(Entry!T)* i = first; i !is null; i = i.next) + for (const(SEntry!T)* i = first; i !is null; i = i.next) { ++len; } @@ -72,7 +72,7 @@ struct Queue(T) assert(q.length == 0); } - private void enqueueEntry(ref Entry!T* entry) + private void enqueueEntry(ref SEntry!T* entry) { if (empty) { @@ -85,9 +85,9 @@ struct Queue(T) } } - private Entry!T* allocateEntry() + private SEntry!T* allocateEntry() { - auto temp = cast(Entry!T*) allocator.allocate(Entry!T.sizeof); + auto temp = cast(SEntry!T*) allocator.allocate(SEntry!T.sizeof); if (temp is null) { onOutOfMemoryError(); @@ -107,7 +107,7 @@ struct Queue(T) { auto temp = allocateEntry(); - *temp = Entry!T.init; + *temp = SEntry!T.init; temp.content = x; enqueueEntry(temp); @@ -256,8 +256,8 @@ struct Queue(T) assert(q.empty); } - private Entry!T* first; - private Entry!T* rear; + private SEntry!T* first; + private SEntry!T* rear; mixin DefaultAllocator; } diff --git a/source/tanya/container/vector.d b/source/tanya/container/vector.d index 18fe6e0..077a92b 100644 --- a/source/tanya/container/vector.d +++ b/source/tanya/container/vector.d @@ -169,10 +169,10 @@ struct Vector(T) * to generate a list. * allocator = Allocator. */ - this(size_t R)(in T[R] init, shared Allocator allocator = defaultAllocator) + this(size_t R)(T[R] init, shared Allocator allocator = defaultAllocator) { this(allocator); - insertBack(init); + insertBack!(T[])(init[]); } /// Ditto. @@ -229,12 +229,7 @@ struct Vector(T) { // Move each element. reserve(init.length); - - const T* end = vector + init.length; - for (T* src = init.vector, dest = vector; dest != end; ++src, ++dest) - { - moveEmplace(*src, *dest); - } + moveEmplaceAll(init.vector[0 .. init.length_], vector[0 .. init.length_]); length_ = init.length; // Destructor of init should destroy it here. } @@ -335,21 +330,21 @@ struct Vector(T) /** * Destroys this $(D_PSYMBOL Vector). */ - ~this() + ~this() @trusted { - length = 0; - shrink(0); + clear(); + allocator.deallocate(vector[0 .. capacity_]); } /** * Copies the vector. */ - this(this) @trusted + this(this) { - auto buf = vector; - immutable oldLen = length_; + auto buf = opIndex(); length_ = capacity_ = 0; - insertBack(buf[0 .. oldLen]); + vector = null; + insertBack(buf); } /** @@ -357,7 +352,7 @@ struct Vector(T) */ void clear() { - length_ = 0; + length = 0; } /// @@ -399,11 +394,11 @@ struct Vector(T) */ @property void length(in size_t len) @trusted { - if (len == length_) + if (len == length) { return; } - else if (len > length_) + else if (len > length) { reserve(len); initializeAll(vector[length_ .. len]); @@ -597,70 +592,71 @@ struct Vector(T) Range!T remove(Range!T r) @trusted in { - assert(r.begin >= vector && r.end <= vector + length_); + assert(r.begin >= vector); + assert(r.end <= vector + length_); } body { - const T* end = vector + length_; - T* a = r.begin; - for (T* b = r.end; b != end; ++a, ++b) - { - *a = *b; - } - for (; a != end; ++a) - { - static if (hasElaborateDestructor!T) - { - destroy(*a); - } - --length_; - } + auto end = vector + length_; + moveAll(Range!T(r.end, end), Range!T(r.begin, end)); + length = length - r.length; return r; } /// - unittest + @safe @nogc unittest { auto v = Vector!int([5, 18, 17, 2, 4, 6, 1]); - v.remove(v[1..3]); - assert(v == Vector!int([5, 2, 4, 6, 1])); + assert(v.remove(v[1 .. 3]).length == 2); + assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6 && v[4] == 1); + assert(v.length == 5); - v.remove(v[4..4]); - assert(v == Vector!int([5, 2, 4, 6, 1])); + assert(v.remove(v[4 .. 4]).length == 0); + assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6 && v[4] == 1); + assert(v.length == 5); - v.remove(v[4..5]); - assert(v == Vector!int([5, 2, 4, 6])); + assert(v.remove(v[4 .. 5]).length == 1); + assert(v[0] == 5 && v[1] == 2 && v[2] == 4 && v[3] == 6); + assert(v.length == 4); - v.remove(v[]); + assert(v.remove(v[]).length == 4); assert(v.empty); - v.remove(v[]); + 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_; + } + /** * Inserts the $(D_PARAM el) into the vector. * * Params: - * R = Parameter type (single value, range or static array). - * el = Values should be inserted. + * R = Type of the inserted value(s) (single value, range or static array). + * el = Value(s) 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); static if (__traits(isRef, el)) { + reserve(length + 1); emplace(vector + length_, el); + ++length_; } else { - moveEmplace(el, *(vector + length_)); + moveBack(el); } - ++length_; return 1; } @@ -672,7 +668,7 @@ struct Vector(T) { static if (hasLength!R) { - reserve(length_ + el.length); + reserve(length + el.length); } size_t retLength; foreach (e; el) @@ -683,14 +679,9 @@ struct Vector(T) } /// Ditto. - size_t insertBack(size_t R)(in T[R] el) + size_t insertBack(size_t R)(T[R] el) { - reserve(length_ + el.length); - foreach (e; el) - { - insertBack(e); - } - return el.length; + return insertBack!(T[])(el[]); } /// Ditto. @@ -731,13 +722,191 @@ struct Vector(T) assert(v1.capacity == 4); assert(v1[0] == 5 && v1[1] == 6 && v1[2] == 4 && v1[3] == 2); - auto v2 = Vector!int([34, 234]); - assert(v1.insertBack(v2[]) == 2); + assert(v1.insertBack([34, 234]) == 2); assert(v1.length == 6); assert(v1.capacity == 6); assert(v1[4] == 34 && v1[5] == 234); } + /** + * Inserts $(D_PARAM el) before or after $(D_PARAM r). + * + * Params: + * R = Type of the inserted value(s) (single value, range or static array). + * r = Range originally obtained from this vector. + * el = Value(s) should be inserted. + * + * Returns: The number of elements inserted. + */ + size_t insertAfter(R)(Range!T r, R el) + if (!isInfinite!R + && isInputRange!R + && isImplicitlyConvertible!(ElementType!R, T)) + in + { + assert(r.begin >= vector); + assert(r.end <= vector + length_); + } + body + { + immutable oldLen = length; + immutable offset = r.end - vector; + immutable inserted = insertBack(el); + bringToFront(vector[offset .. oldLen], vector[oldLen .. length]); + return inserted; + } + + /// Ditto. + size_t insertAfter(size_t R)(Range!T r, T[R] el) + { + return insertAfter!(T[])(r, el[]); + } + + /// Ditto. + size_t insertAfter(R)(Range!T r, auto ref R el) + if (isImplicitlyConvertible!(R, T)) + in + { + assert(r.begin >= vector); + assert(r.end <= vector + length_); + } + body + { + immutable oldLen = length; + immutable offset = r.end - vector; + + static if (__traits(isRef, el)) + { + insertBack(el); + } + else + { + moveBack(el); + } + bringToFront(vector[offset .. oldLen], vector[oldLen .. length_]); + + return 1; + } + + /// Ditto. + size_t insertBefore(R)(Range!T r, R el) + if (!isInfinite!R + && isInputRange!R + && isImplicitlyConvertible!(ElementType!R, T)) + in + { + assert(r.begin >= vector); + assert(r.end <= vector + length_); + } + body + { + return insertAfter(Range!T(vector, r.begin), el); + } + + /// Ditto. + size_t insertBefore(size_t R)(Range!T r, T[R] el) + { + return insertBefore!(T[])(r, el[]); + } + + /// Ditto. + size_t insertBefore(R)(Range!T r, auto ref R el) + if (isImplicitlyConvertible!(R, T)) + in + { + assert(r.begin >= vector); + assert(r.end <= vector + length_); + } + body + { + immutable oldLen = length; + immutable offset = r.begin - vector; + + static if (__traits(isRef, el)) + { + insertBack(el); + } + else + { + moveBack(el); + } + bringToFront(vector[offset .. oldLen], vector[oldLen .. length_]); + + return 1; + } + + /// + unittest + { + Vector!int v1; + v1.insertAfter(v1[], [2, 8]); + assert(v1[0] == 2); + assert(v1[1] == 8); + assert(v1.length == 2); + + v1.insertAfter(v1[], [1, 2]); + assert(v1[0] == 2); + assert(v1[1] == 8); + assert(v1[2] == 1); + assert(v1[3] == 2); + assert(v1.length == 4); + + v1.insertAfter(v1[0 .. 0], [1, 2]); + assert(v1[0] == 1); + assert(v1[1] == 2); + assert(v1[2] == 2); + assert(v1[3] == 8); + assert(v1[4] == 1); + assert(v1[5] == 2); + assert(v1.length == 6); + + v1.insertAfter(v1[0 .. 4], 9); + assert(v1[0] == 1); + assert(v1[1] == 2); + assert(v1[2] == 2); + assert(v1[3] == 8); + assert(v1[4] == 9); + assert(v1[5] == 1); + assert(v1[6] == 2); + assert(v1.length == 7); + } + + /// + unittest + { + Vector!int v1; + v1.insertBefore(v1[], [2, 8]); + assert(v1[0] == 2); + assert(v1[1] == 8); + assert(v1.length == 2); + + v1.insertBefore(v1[], [1, 2]); + assert(v1[0] == 1); + assert(v1[1] == 2); + assert(v1[2] == 2); + assert(v1[3] == 8); + assert(v1.length == 4); + + v1.insertBefore(v1[0 .. 1], [1, 2]); + assert(v1[0] == 1); + assert(v1[1] == 2); + assert(v1[2] == 1); + assert(v1[3] == 2); + assert(v1[4] == 2); + assert(v1[5] == 8); + assert(v1.length == 6); + + v1.insertBefore(v1[2 .. $], 9); + assert(v1[0] == 1); + assert(v1[1] == 2); + assert(v1[2] == 9); + assert(v1[3] == 1); + assert(v1[4] == 2); + assert(v1[5] == 2); + assert(v1[6] == 8); + assert(v1.length == 7); + } + /** * Assigns a value to the element with the index $(D_PARAM pos). * @@ -841,13 +1010,13 @@ struct Vector(T) * Returns: Random access range that iterates over elements of the vector, in * forward order. */ - Range!T opIndex() + Range!T opIndex() @trusted { return typeof(return)(vector, vector + length_); } /// Ditto. - Range!(const T) opIndex() const + Range!(const T) opIndex() const @trusted { return typeof(return)(vector, vector + length_); } @@ -874,15 +1043,15 @@ struct Vector(T) * Returns: $(D_KEYWORD true) if the vectors are equal, $(D_KEYWORD false) * otherwise. */ - bool opEquals()(auto ref typeof(this) v) + bool opEquals()(auto ref typeof(this) v) @trusted { - return equal(opIndex(), v[]); + return equal(vector[0 .. length_], v.vector[0 .. v.length_]); } /// Ditto. - bool opEquals()(in auto ref typeof(this) v) const + bool opEquals()(in auto ref typeof(this) v) const @trusted { - return equal(opIndex(), v[]); + return equal(vector[0 .. length_], v.vector[0 .. length_]); } /// Ditto. @@ -1185,8 +1354,9 @@ struct Vector(T) * Precondition: $(D_INLINECODE i <= j && j <= length * && value.length == j - i) */ - Range!T opSliceAssign(R)(R value, in size_t i, in size_t j) - if (!isInfinite!R && isInputRange!R + Range!T opSliceAssign(R)(R value, in size_t i, in size_t j) @trusted + if (!isInfinite!R + && isInputRange!R && isImplicitlyConvertible!(ElementType!R, T)) in { @@ -1196,7 +1366,7 @@ struct Vector(T) } body { - copy(value, opSlice(i, j)); + copy(value, vector[i .. j]); return opSlice(i, j); } @@ -1207,7 +1377,7 @@ struct Vector(T) } /// Ditto. - Range!T opSliceAssign(ref T value, in size_t i, in size_t j) + Range!T opSliceAssign(ref T value, in size_t i, in size_t j) @trusted in { assert(i <= j); @@ -1215,7 +1385,7 @@ struct Vector(T) } body { - fill(opSlice(i, j), value); + fill(vector[i .. j], value); return opSlice(i, j); } @@ -1392,3 +1562,12 @@ unittest } auto v = Vector!SWithDtor(); // Destructor can destroy empty vectors. } + +unittest +{ + class A + { + } + A a1, a2; + auto v1 = Vector!A([a1, a2]); +}