Implement String opAssign
This commit is contained in:
parent
64e0d666ed
commit
e5c7edb72c
@ -15,6 +15,7 @@ module tanya.container.string;
|
|||||||
import core.exception;
|
import core.exception;
|
||||||
import std.algorithm.comparison;
|
import std.algorithm.comparison;
|
||||||
import std.algorithm.mutation;
|
import std.algorithm.mutation;
|
||||||
|
import std.algorithm.searching;
|
||||||
import std.range;
|
import std.range;
|
||||||
import std.traits;
|
import std.traits;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
@ -204,6 +205,127 @@ struct ByCodeUnit(E)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates $(D_PSYMBOL String) by UTF-8 code point.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* E = Element type ($(D_KEYWORD char) or $(D_INLINECODE const(char))).
|
||||||
|
*/
|
||||||
|
struct ByCodePoint(E)
|
||||||
|
if (is(Unqual!E == char))
|
||||||
|
{
|
||||||
|
private E* begin, end;
|
||||||
|
private alias ContainerType = CopyConstness!(E, String);
|
||||||
|
private ContainerType* container;
|
||||||
|
|
||||||
|
invariant
|
||||||
|
{
|
||||||
|
assert(this.begin <= this.end);
|
||||||
|
assert(this.container !is null);
|
||||||
|
assert(this.begin >= this.container.data);
|
||||||
|
assert(this.end <= this.container.data + this.container.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private this(ref ContainerType container, E* begin, E* end) @trusted
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(begin <= end);
|
||||||
|
assert(begin >= container.data);
|
||||||
|
assert(end <= container.data + container.length);
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
this.container = &container;
|
||||||
|
this.begin = begin;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@disable this();
|
||||||
|
|
||||||
|
@property ByCodePoint save()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property bool empty() const
|
||||||
|
{
|
||||||
|
return this.begin == this.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property dchar front() const
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!empty);
|
||||||
|
}
|
||||||
|
out (chr)
|
||||||
|
{
|
||||||
|
assert(chr < 0xd800 || chr > 0xdfff);
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
dchar chr;
|
||||||
|
ubyte units;
|
||||||
|
char mask;
|
||||||
|
const(char)* it = begin;
|
||||||
|
|
||||||
|
if (*it & 0x80)
|
||||||
|
{
|
||||||
|
mask = 0xe0;
|
||||||
|
for (units = 1; (*it & mask) != (mask << 1); ++units)
|
||||||
|
{
|
||||||
|
mask = (mask >> 1) | 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chr = *it++ ^ mask;
|
||||||
|
|
||||||
|
for (; units > 0; --units)
|
||||||
|
{
|
||||||
|
if (begin >= end)
|
||||||
|
{
|
||||||
|
throw defaultAllocator.make!UTFException("Invalid UTF-8 character");
|
||||||
|
}
|
||||||
|
chr = (chr << 6) | (*it++ & 0x3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return chr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void popFront()
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(!empty);
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
if (*begin & 0x80)
|
||||||
|
{
|
||||||
|
char mask = 0xe0;
|
||||||
|
for (auto chr = *begin; (chr & mask) != (mask << 1); ++begin)
|
||||||
|
{
|
||||||
|
if (begin >= end)
|
||||||
|
{
|
||||||
|
throw defaultAllocator.make!UTFException("Invalid UTF-8 character");
|
||||||
|
}
|
||||||
|
mask = (mask >> 1) | 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++begin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByCodePoint opIndex()
|
||||||
|
{
|
||||||
|
return typeof(return)(*this.container, this.begin, this.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByCodePoint!(const E) opIndex() const
|
||||||
|
{
|
||||||
|
return typeof(return)(*this.container, this.begin, this.end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UTF-8 string.
|
* UTF-8 string.
|
||||||
*/
|
*/
|
||||||
@ -222,7 +344,7 @@ struct String
|
|||||||
* Constructs the string from a stringish range.
|
* Constructs the string from a stringish range.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* R = String type.
|
* S = String type.
|
||||||
* str = Initial string.
|
* str = Initial string.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*
|
*
|
||||||
@ -230,10 +352,10 @@ struct String
|
|||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE allocator is null).
|
* Precondition: $(D_INLINECODE allocator is null).
|
||||||
*/
|
*/
|
||||||
this(R)(const R str, shared Allocator allocator = defaultAllocator)
|
this(S)(const S str, shared Allocator allocator = defaultAllocator)
|
||||||
if (!isInfinite!R
|
if (!isInfinite!S
|
||||||
&& isInputRange!R
|
&& isInputRange!S
|
||||||
&& isSomeChar!(ElementEncodingType!R))
|
&& isSomeChar!(ElementEncodingType!S))
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
insertBack(str);
|
insertBack(str);
|
||||||
@ -265,13 +387,15 @@ struct String
|
|||||||
* If $(D_PARAM init) is passed by reference, it will be copied.
|
* If $(D_PARAM init) is passed by reference, it will be copied.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
|
* S = Source string type.
|
||||||
* init = Source string.
|
* init = Source string.
|
||||||
* allocator = Allocator.
|
* allocator = Allocator.
|
||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE allocator is null).
|
* Precondition: $(D_INLINECODE allocator is null).
|
||||||
*/
|
*/
|
||||||
this(String init, shared Allocator allocator = defaultAllocator)
|
this(S)(S init, shared Allocator allocator = defaultAllocator)
|
||||||
nothrow @trusted @nogc
|
nothrow @trusted @nogc
|
||||||
|
if (is(S == String))
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
if (allocator !is init.allocator)
|
if (allocator !is init.allocator)
|
||||||
@ -294,8 +418,9 @@ struct String
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
this(ref const String init, shared Allocator allocator = defaultAllocator)
|
this(S)(ref S init, shared Allocator allocator = defaultAllocator)
|
||||||
nothrow @trusted @nogc
|
nothrow @trusted @nogc
|
||||||
|
if (is(Unqual!S == String))
|
||||||
{
|
{
|
||||||
this(allocator);
|
this(allocator);
|
||||||
reserve(init.length);
|
reserve(init.length);
|
||||||
@ -322,7 +447,8 @@ struct String
|
|||||||
* n = Number of characters to copy.
|
* n = Number of characters to copy.
|
||||||
* chr = Character to fill the string with.
|
* chr = Character to fill the string with.
|
||||||
*/
|
*/
|
||||||
this(C)(const size_t n, const C chr,
|
this(C)(const size_t n,
|
||||||
|
const C chr,
|
||||||
shared Allocator allocator = defaultAllocator) @trusted
|
shared Allocator allocator = defaultAllocator) @trusted
|
||||||
if (isSomeChar!C)
|
if (isSomeChar!C)
|
||||||
{
|
{
|
||||||
@ -351,7 +477,8 @@ struct String
|
|||||||
this.length_ += remaining;
|
this.length_ += remaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
private unittest
|
///
|
||||||
|
unittest
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
auto s = String(1, 'О');
|
auto s = String(1, 'О');
|
||||||
@ -372,7 +499,7 @@ struct String
|
|||||||
*/
|
*/
|
||||||
~this() nothrow @trusted @nogc
|
~this() nothrow @trusted @nogc
|
||||||
{
|
{
|
||||||
allocator.deallocate(this.data[0 .. this.capacity_]);
|
allocator.resize(this.data[0 .. this.capacity_], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void write4Bytes(ref const dchar src)
|
private void write4Bytes(ref const dchar src)
|
||||||
@ -583,7 +710,7 @@ struct String
|
|||||||
|
|
||||||
while (!range.empty)
|
while (!range.empty)
|
||||||
{
|
{
|
||||||
reserve(length + 4);
|
reserve(length + wchar.sizeof * 2);
|
||||||
|
|
||||||
auto ret = insertWideChar(range.front);
|
auto ret = insertWideChar(range.front);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
@ -829,6 +956,20 @@ struct String
|
|||||||
assert(r.length == 8);
|
assert(r.length == 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns: Forward range that iterates over the string by code points.
|
||||||
|
*/
|
||||||
|
ByCodePoint!char byCodePoint() pure nothrow @trusted @nogc
|
||||||
|
{
|
||||||
|
return typeof(return)(this, this.data, this.data + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
ByCodePoint!(const char) byCodePoint() const pure nothrow @trusted @nogc
|
||||||
|
{
|
||||||
|
return typeof(return)(this, this.data, this.data + length);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: $(D_KEYWORD true) if the vector is empty.
|
* Returns: $(D_KEYWORD true) if the vector is empty.
|
||||||
*/
|
*/
|
||||||
@ -901,5 +1042,75 @@ struct String
|
|||||||
assert(r.empty);
|
assert(r.empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns another string.
|
||||||
|
*
|
||||||
|
* If $(D_PARAM that) is passed by value, it won't be copied, but moved.
|
||||||
|
* This string will take the ownership over $(D_PARAM that)'s storage and
|
||||||
|
* the allocator.
|
||||||
|
*
|
||||||
|
* If $(D_PARAM that) is passed by reference, it will be copied.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* S = Content type.
|
||||||
|
* that = The value should be assigned.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD this).
|
||||||
|
*/
|
||||||
|
ref String opAssign(S)(S that) nothrow @safe @nogc
|
||||||
|
if (is(S == String))
|
||||||
|
{
|
||||||
|
swap(this.data, that.data);
|
||||||
|
swap(this.length_, that.length_);
|
||||||
|
swap(this.capacity_, that.capacity_);
|
||||||
|
swap(this.allocator_, that.allocator_);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
ref String opAssig(S)(ref S that) nothrow @trusted @nogc
|
||||||
|
if (is(Unqual!S == String))
|
||||||
|
{
|
||||||
|
reserve(that.length);
|
||||||
|
that.data[0 .. that.length].copy(this.data[0 .. that.length]);
|
||||||
|
this.length_ = that.length;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto s = String("Черная, потом пропахшая выть!");
|
||||||
|
s = String("Как мне тебя не ласкать, не любить?");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns a stringish range.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* S = String type.
|
||||||
|
* that = Initial string.
|
||||||
|
*
|
||||||
|
* Returns: $(D_KEYWORD this).
|
||||||
|
*
|
||||||
|
* Throws: $(D_PSYMBOL UTFException).
|
||||||
|
*/
|
||||||
|
ref String opAssign(S)(S that) nothrow @safe @nogc
|
||||||
|
if (!isInfinite!S
|
||||||
|
&& isInputRange!S
|
||||||
|
&& isSomeChar!(ElementEncodingType!S))
|
||||||
|
{
|
||||||
|
this.length_ = 0;
|
||||||
|
insertBack(that);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto s = String("Оловом светится лужная голь...");
|
||||||
|
s = "Грустная песня, ты - русская боль.";
|
||||||
|
}
|
||||||
|
|
||||||
mixin DefaultAllocator;
|
mixin DefaultAllocator;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user