From 33dbf042c2fcd11a191ce209568d8a836277c6f5 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sun, 26 Feb 2017 22:40:27 +0100 Subject: [PATCH] Add dchar constructor --- source/tanya/container/string.d | 352 ++++++++++++++++++-------------- 1 file changed, 204 insertions(+), 148 deletions(-) diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d index 703da29..07d0c75 100644 --- a/source/tanya/container/string.d +++ b/source/tanya/container/string.d @@ -12,6 +12,7 @@ */ module tanya.container.string; +import core.checkedint; import core.exception; import core.stdc.string; import std.algorithm.comparison; @@ -22,158 +23,213 @@ import tanya.memory; */ struct String { - private size_t length_; - private char* data; - private size_t capacity_; + private size_t length_; + private char* data; + private size_t capacity_; - invariant - { - assert(length_ <= capacity_); - } + invariant + { + assert(length_ <= capacity_); + } + + /** + * Params: + * str = Initial string. + * allocator = Allocator. + */ + this(const(char)[] str, shared Allocator allocator = defaultAllocator) + nothrow @trusted @nogc + { + this(allocator); + reserve(str.length); + length_ = str.length; + memcpy(data, str.ptr, length_); + } + + /// Ditto. + this(const(wchar)[] str, shared Allocator allocator = defaultAllocator) + nothrow @trusted @nogc + { + this(allocator); + } + + /// Ditto. + this(const(dchar)[] str, shared Allocator allocator = defaultAllocator) + nothrow @trusted @nogc + { + this(allocator); + + bool overflow; + auto size = mulu(str.length, 4, overflow); + assert(!overflow); + + reserve(size); + + auto s = data; + foreach (c; str) + { + if (c < 0x80) + { + *s++ = c & 0x7f; + length_ += 1; + } + else if (c < 0x800) + { + *s++ = 0xc0 | (c >> 6) & 0xff; + *s++ = 0x80 | (c & 0x3f); + length_ += 2; + } + else if (c < 0xd800 || c - 0xe000 < 0x2000) + { + *s++ = 0xe0 | (c >> 12) & 0xff; + *s++ = 0x80 | ((c >> 6) & 0x3f); + *s++ = 0x80 | (c & 0x3f); + length_ += 3; + } + else if (c - 0x10000 < 0x100000) + { + *s++ = 0xf0 | (c >> 18); + *s++ = 0x80 | ((c >> 12) & 0x3f); + *s++ = 0x80 | ((c >> 6) & 0x3f); + *s++ = 0x80 | (c & 0x3f); + length_ += 4; + } + } + } + + /// + @nogc @safe unittest + { + auto s = String("Отказаться от вина - в этом страшная вина."d); + assert("Отказаться от вина - в этом страшная вина." == s.get); + } + + /// Ditto. + this(shared Allocator allocator) pure nothrow @safe @nogc + in + { + assert(allocator !is null); + } + body + { + allocator_ = allocator; + } + + /** + * Destroys the string. + */ + ~this() nothrow @trusted @nogc + { + allocator.deallocate(data[0 .. capacity_]); + } + + /** + * Reserves $(D_PARAM size) bytes for the string. + * + * If $(D_PARAM size) is less than or equal to the $(D_PSYMBOL capacity), the + * function call does not cause a reallocation and the string capacity is not + * affected. + * + * Params: + * size = Desired size in bytes. + */ + void reserve(in size_t size) nothrow @trusted @nogc + { + if (capacity_ >= size) + { + return; + } + + void[] buf = data[0 .. capacity_]; + if (!allocator.reallocate(buf, size)) + { + onOutOfMemoryErrorNoGC(); + } + data = cast(char*) buf; + capacity_ = size; + } + + /// + @nogc @safe unittest + { + String s; + assert(s.capacity == 0); + + s.reserve(3); + assert(s.capacity == 3); + + s.reserve(3); + assert(s.capacity == 3); + + s.reserve(1); + assert(s.capacity == 3); + } + + /** + * Requests the string to reduce its capacity to fit the $(D_PARAM size). + * + * The request is non-binding. The string won't become smaller than the + * string byte length. + * + * Params: + * size = Desired size. + */ + void shrink(in size_t size) nothrow @trusted @nogc + { + if (capacity_ <= size) + { + return; + } + + immutable n = max(length_, size); + void[] buf = data[0 .. capacity_]; + if (allocator.reallocate(buf, size)) + { + capacity_ = n; + data = cast(char*) buf; + } + } + + /// + @nogc @safe unittest + { + auto s = String("Die Alten lasen laut."); + assert(s.capacity == 21); + + s.reserve(30); + s.shrink(25); + assert(s.capacity == 25); + + s.shrink(18); + assert(s.capacity == 21); + } + + /** + * Returns: String capacity in bytes. + */ + @property size_t capacity() const pure nothrow @safe @nogc + { + return capacity_; + } + + /// + @nogc @safe unittest + { + auto s = String("In allem Schreiben ist Schamlosigkeit."); + assert(s.capacity == 38); + } /** - * Params: - * str = Initial string. - * allocator = Allocator. - */ - this(const(char)[] str, shared Allocator allocator = defaultAllocator) - nothrow @trusted @nogc - { - this(allocator); - reserve(str.length); - length_ = str.length; - memcpy(data, str.ptr, length_); - } - - /// Ditto. - this(const(wchar)[] str, shared Allocator allocator = defaultAllocator) - nothrow @trusted @nogc - { - this(allocator); - } - - /// Ditto. - this(const(dchar)[] str, shared Allocator allocator = defaultAllocator) - nothrow @trusted @nogc - { - this(allocator); - - } - - /// Ditto. - this(shared Allocator allocator) pure nothrow @safe @nogc - in - { - assert(allocator !is null); - } - body - { - allocator_ = allocator; - } - - /** - * Destroys the string. - */ - ~this() nothrow @trusted @nogc - { - allocator.deallocate(data[0 .. capacity_]); - } - - /** - * Reserves $(D_PARAM size) bytes for the string. + * Returns an array used internally by the string. + * The length of the returned array may be smaller than the size of the + * reserved memory for the string. * - * If $(D_PARAM size) is less than or equal to the $(D_PSYMBOL capacity), the - * function call does not cause a reallocation and the string capacity is not - * affected. - * - * Params: - * size = Desired size in bytes. + * Returns: The array representing the string. */ - void reserve(in size_t size) nothrow @trusted @nogc - { - if (capacity_ >= size) - { - return; - } + inout(char[]) get() inout pure nothrow @trusted @nogc + { + return data[0 .. length_]; + } - void[] buf = data[0 .. capacity_]; - if (!allocator.reallocate(buf, size)) - { - onOutOfMemoryErrorNoGC(); - } - data = cast(char*) buf; - capacity_ = size; - } - - /// - @nogc @safe unittest - { - String s; - assert(s.capacity == 0); - - s.reserve(3); - assert(s.capacity == 3); - - s.reserve(3); - assert(s.capacity == 3); - - s.reserve(1); - assert(s.capacity == 3); - } - - /** - * Requests the string to reduce its capacity to fit the $(D_PARAM size). - * - * The request is non-binding. The string won't become smaller than the - * string byte length. - * - * Params: - * size = Desired size. - */ - void shrink(in size_t size) nothrow @trusted @nogc - { - if (capacity_ <= size) - { - return; - } - - immutable n = max(length_, size); - void[] buf = data[0 .. capacity_]; - if (allocator.reallocate(buf, size)) - { - capacity_ = n; - data = cast(char*) buf; - } - } - - /// - @nogc @safe unittest - { - auto s = String("Die Alten lasen laut."); - assert(s.capacity == 21); - - s.reserve(30); - s.shrink(25); - assert(s.capacity == 25); - - s.shrink(18); - assert(s.capacity == 21); - } - - /** - * Returns: String capacity in bytes. - */ - @property size_t capacity() const pure nothrow @safe @nogc - { - return capacity_; - } - - /// - @nogc @safe unittest - { - auto s = String("In allem Schreiben ist Schamlosigkeit."); - assert(s.capacity == 38); - } - - mixin DefaultAllocator; + mixin DefaultAllocator; }