From 38afeac0719d536e941201f8754a193db703169f Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 12 May 2017 20:55:42 +0200 Subject: [PATCH] Insert String.insertFront and String.insertBack --- source/tanya/container/string.d | 85 +++++++++++++++++++++++++++++++-- source/tanya/container/vector.d | 38 +++++++-------- 2 files changed, 99 insertions(+), 24 deletions(-) diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d index 5cf44c1..5ae4cbc 100644 --- a/source/tanya/container/string.d +++ b/source/tanya/container/string.d @@ -1361,6 +1361,7 @@ struct String * Remove all characters beloning to $(D_PARAM r). * * Params: + * R = $(D_PSYMBOL ByCodeUnit) or $(D_PSYMBOL ByCodePoint). * r = Range originally obtained from this string. * * Returns: A range spanning the remaining characters in the string that @@ -1368,7 +1369,7 @@ struct String * * Precondition: $(D_PARAM r) refers to a region of $(D_KEYWORD this). */ - R remove(R)(R r) pure nothrow @trusted @nogc + R remove(R)(R r) @trusted if (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char)) in { @@ -1387,11 +1388,11 @@ struct String /// @nogc @safe unittest { - auto s = String("Из пословицы слова не выкинешь"); + auto s = String("Из пословицы слова не выкинешь."); - assert(s.remove(s[5 .. 24]).length == 32); - assert(s == "Из слова не выкинешь"); - assert(s.length == 37); + assert(s.remove(s[5 .. 24]).length == 33); + assert(s == "Из слова не выкинешь."); + assert(s.length == 38); auto byCodePoint = s.byCodePoint(); byCodePoint.popFrontN(8); @@ -1405,5 +1406,79 @@ struct String assert(s.remove(s[]).length == 0); } + /** + * Inserts $(D_PARAM el) before or after $(D_PARAM r). + * + * Params: + * R = $(D_PSYMBOL ByCodeUnit) or $(D_PSYMBOL ByCodePoint). + * T = Stringish type. + * r = Range originally obtained from this vector. + * 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(T, R)(R r, T el) @trusted + if ((isSomeChar!T || (!isInfinite!T + && isInputRange!T + && isSomeChar!(ElementEncodingType!T))) + && (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char))) + in + { + assert(r.container is &this); + assert(r.begin >= this.data); + assert(r.end <= this.data + length); + } + body + { + const oldLen = length; + const offset = r.end - this.data; + const inserted = insertBack(el); + bringToFront(this.data[offset .. oldLen], this.data[oldLen .. length]); + return inserted; + } + + /// + @nogc @safe unittest + { + auto s = String("Нельзя казнить помиловать."); + s.insertAfter(s[0 .. 27], ","); + assert(s == "Нельзя казнить, помиловать."); + + s = String("Нельзя казнить помиловать."); + s.insertAfter(s[0 .. 27], ','); + assert(s == "Нельзя казнить, помиловать."); + } + + /// + size_t insertBefore(T, R)(R r, T el) @trusted + if ((isSomeChar!T || (!isInfinite!T + && isInputRange!T + && isSomeChar!(ElementEncodingType!T))) + && (is(R == ByCodeUnit!char) || is(R == ByCodePoint!char))) + in + { + assert(r.container is &this); + assert(r.begin >= this.data); + assert(r.end <= this.data + length); + } + body + { + return insertAfter(R(this, this.data, r.begin), el); + } + + /// + @nogc @safe unittest + { + auto s = String("Нельзя казнить помиловать."); + s.insertBefore(s[27 .. $], ","); + assert(s == "Нельзя казнить, помиловать."); + + s = String("Нельзя казнить помиловать."); + s.insertBefore(s[27 .. $], ','); + assert(s == "Нельзя казнить, помиловать."); + } + mixin DefaultAllocator; } diff --git a/source/tanya/container/vector.d b/source/tanya/container/vector.d index 969720e..7f5e3a5 100644 --- a/source/tanya/container/vector.d +++ b/source/tanya/container/vector.d @@ -32,26 +32,26 @@ struct Range(E) { private E* begin, end; private alias ContainerType = CopyConstness!(E, Vector!(Unqual!E)); - private ContainerType* vector; + private ContainerType* container; invariant { 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); + assert(this.container !is null); + assert(this.begin >= this.container.data); + assert(this.end <= this.container.data + this.container.length); } - private this(ref ContainerType vector, E* begin, E* end) @trusted + private this(ref ContainerType container, E* begin, E* end) @trusted in { assert(begin <= end); - assert(begin >= vector.data); - assert(end <= vector.data + vector.length); + assert(begin >= container.data); + assert(end <= container.data + container.length); } body { - this.vector = &vector; + this.container = &container; this.begin = begin; this.end = end; } @@ -127,12 +127,12 @@ struct Range(E) Range opIndex() { - return typeof(return)(*this.vector, this.begin, this.end); + return typeof(return)(*this.container, this.begin, this.end); } Range!(const E) opIndex() const { - return typeof(return)(*this.vector, this.begin, this.end); + return typeof(return)(*this.container, this.begin, this.end); } Range opSlice(const size_t i, const size_t j) @trusted @@ -143,7 +143,7 @@ struct Range(E) } body { - return typeof(return)(*this.vector, this.begin + i, this.begin + j); + return typeof(return)(*this.container, this.begin + i, this.begin + j); } Range!(const E) opSlice(const size_t i, const size_t j) const @trusted @@ -154,7 +154,7 @@ struct Range(E) } body { - return typeof(return)(*this.vector, this.begin + i, this.begin + j); + return typeof(return)(*this.container, this.begin + i, this.begin + j); } inout(E[]) get() inout @trusted @@ -638,7 +638,7 @@ struct Vector(T) Range!T remove(Range!T r) @trusted in { - assert(r.vector is &this); + assert(r.container is &this); assert(r.begin >= this.data); assert(r.end <= this.data + length); } @@ -791,7 +791,7 @@ struct Vector(T) && isImplicitlyConvertible!(ElementType!R, T)) in { - assert(r.vector is &this); + assert(r.container is &this); assert(r.begin >= this.data); assert(r.end <= this.data + length); } @@ -808,7 +808,7 @@ struct Vector(T) size_t insertAfter(size_t R)(Range!T r, T[R] el) in { - assert(r.vector is &this); + assert(r.container is &this); assert(r.begin >= this.data); assert(r.end <= this.data + length); } @@ -822,7 +822,7 @@ struct Vector(T) if (isImplicitlyConvertible!(R, T)) in { - assert(r.vector is &this); + assert(r.container is &this); assert(r.begin >= this.data); assert(r.end <= this.data + length); } @@ -851,7 +851,7 @@ struct Vector(T) && isImplicitlyConvertible!(ElementType!R, T)) in { - assert(r.vector is &this); + assert(r.container is &this); assert(r.begin >= this.data); assert(r.end <= this.data + length); } @@ -864,7 +864,7 @@ struct Vector(T) size_t insertBefore(size_t R)(Range!T r, T[R] el) in { - assert(r.vector is &this); + assert(r.container is &this); assert(r.begin >= this.data); assert(r.end <= this.data + length); } @@ -878,7 +878,7 @@ struct Vector(T) if (isImplicitlyConvertible!(R, T)) in { - assert(r.vector is &this); + assert(r.container is &this); assert(r.begin >= this.data); assert(r.end <= this.data + length); }