From 885fca9b5edb9eda3db7b57f8c88c3be5513be7b Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 20 Feb 2017 12:01:15 +0100 Subject: [PATCH] Add String.reserve and shrink --- source/tanya/container/string.d | 126 +++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 12 deletions(-) diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d index 05f9e70..703da29 100644 --- a/source/tanya/container/string.d +++ b/source/tanya/container/string.d @@ -3,6 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** + * UTF-8 string. + * * Copyright: Eugene Wissner 2016-2017. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). @@ -12,6 +14,7 @@ module tanya.container.string; import core.exception; import core.stdc.string; +import std.algorithm.comparison; import tanya.memory; /** @@ -19,26 +22,27 @@ import tanya.memory; */ struct String { - private char[] data; private size_t length_; + private char* data; + private size_t capacity_; invariant { - assert(length_ <= data.length); + assert(length_ <= capacity_); } - /// Ditto. + /** + * Params: + * str = Initial string. + * allocator = Allocator. + */ this(const(char)[] str, shared Allocator allocator = defaultAllocator) nothrow @trusted @nogc { this(allocator); - - data = cast(char[]) allocator.allocate(str.length); - if (str.length > 0 && data is null) - { - onOutOfMemoryErrorNoGC(); - } - memcpy(data.ptr, str.ptr, str.length); + reserve(str.length); + length_ = str.length; + memcpy(data, str.ptr, length_); } /// Ditto. @@ -46,7 +50,6 @@ struct String nothrow @trusted @nogc { this(allocator); - } /// Ditto. @@ -68,9 +71,108 @@ struct String allocator_ = allocator; } + /** + * Destroys the string. + */ ~this() nothrow @trusted @nogc { - allocator.deallocate(data); + 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); } mixin DefaultAllocator;