Add dchar constructor

This commit is contained in:
Eugen Wissner 2017-02-26 22:40:27 +01:00
parent 885fca9b5e
commit 33dbf042c2
1 changed files with 204 additions and 148 deletions

View File

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