summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-02-20 12:01:15 +0100
committerEugen Wissner <belka@caraus.de>2017-02-20 12:01:15 +0100
commit885fca9b5edb9eda3db7b57f8c88c3be5513be7b (patch)
tree04c29cd66ae0cc3bb59688b11fe63857cd004c52
parent074d02762927f706a4e02002a785ef1c7492e0ab (diff)
downloadtanya-885fca9b5edb9eda3db7b57f8c88c3be5513be7b.tar.gz
Add String.reserve and shrink
-rw-r--r--source/tanya/container/string.d126
1 files 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;