Add String.reserve and shrink

This commit is contained in:
Eugen Wissner 2017-02-20 12:01:15 +01:00
parent 074d027629
commit 885fca9b5e

View File

@ -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;