Implement string slice assignments
This commit is contained in:
parent
db12f03264
commit
a6a6f496eb
@ -252,7 +252,7 @@ struct ByCodePoint(E)
|
|||||||
return this.begin == this.end;
|
return this.begin == this.end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property dchar front() const
|
@property dchar front() const @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
@ -264,55 +264,60 @@ struct ByCodePoint(E)
|
|||||||
body
|
body
|
||||||
{
|
{
|
||||||
dchar chr;
|
dchar chr;
|
||||||
ubyte units;
|
ubyte units, mask;
|
||||||
char mask;
|
const(char)* it = this.begin;
|
||||||
const(char)* it = begin;
|
|
||||||
|
|
||||||
if (*it & 0x80)
|
if (*it & 0x80)
|
||||||
{
|
{
|
||||||
mask = 0xe0;
|
mask = 0xe0;
|
||||||
for (units = 1; (*it & mask) != (mask << 1); ++units)
|
for (units = 2; ((*it << units) & 0x80) != 0; ++units)
|
||||||
{
|
{
|
||||||
mask = (mask >> 1) | 0x80;
|
mask = (mask >> 1) | 0x80;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chr = *it++ ^ mask;
|
if (this.begin + units > end || units > 4)
|
||||||
|
{
|
||||||
for (; units > 0; --units)
|
throw defaultAllocator.make!UTFException("Invalid UTF-8 character");
|
||||||
|
}
|
||||||
|
chr = *it++ & ~mask;
|
||||||
|
|
||||||
|
for (; units > 1; --units)
|
||||||
{
|
{
|
||||||
if (begin >= end)
|
|
||||||
{
|
|
||||||
throw defaultAllocator.make!UTFException("Invalid UTF-8 character");
|
|
||||||
}
|
|
||||||
chr = (chr << 6) | (*it++ & 0x3f);
|
chr = (chr << 6) | (*it++ & 0x3f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return chr;
|
return chr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront()
|
void popFront() @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
if (*begin & 0x80)
|
ubyte units;
|
||||||
|
if ((*begin & 0x80) == 0)
|
||||||
{
|
{
|
||||||
char mask = 0xe0;
|
units = 1;
|
||||||
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
|
else if ((*begin & 0xc0) == 0xc0)
|
||||||
{
|
{
|
||||||
++begin;
|
units = 2;
|
||||||
}
|
}
|
||||||
|
else if ((*begin & 0xe0) == 0xe0)
|
||||||
|
{
|
||||||
|
units = 3;
|
||||||
|
}
|
||||||
|
else if ((*begin & 0xf0) == 0xf0)
|
||||||
|
{
|
||||||
|
units = 4;
|
||||||
|
}
|
||||||
|
if (units == 0 || this.begin + units > this.end)
|
||||||
|
{
|
||||||
|
throw defaultAllocator.make!UTFException("Invalid UTF-8 character");
|
||||||
|
}
|
||||||
|
this.begin += units;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByCodePoint opIndex()
|
ByCodePoint opIndex()
|
||||||
@ -865,6 +870,68 @@ struct String
|
|||||||
assert(s.capacity == 38);
|
assert(s.capacity == 38);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slicing assignment.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* R = Type of the assigned slice.
|
||||||
|
* value = New value (single value, range or string).
|
||||||
|
* i = Slice start.
|
||||||
|
* j = Slice end.
|
||||||
|
*
|
||||||
|
* Returns: Slice with the assigned part of the string.
|
||||||
|
*
|
||||||
|
* Precondition: $(D_INLINECODE i <= j && j <= length
|
||||||
|
* && value.length == j - i)
|
||||||
|
*/
|
||||||
|
ByCodeUnit!char opSliceAssign(R)(ByCodeUnit!R value,
|
||||||
|
const size_t i,
|
||||||
|
const size_t j) @trusted
|
||||||
|
if (is(Unqual!R == char))
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(i <= j);
|
||||||
|
assert(j <= length);
|
||||||
|
assert(j - i == value.length);
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
copy(value, this.data[i .. j]);
|
||||||
|
return opSlice(i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
ByCodeUnit!char opSliceAssign(const char[] value,
|
||||||
|
const size_t i,
|
||||||
|
const size_t j)
|
||||||
|
pure nothrow @trusted @nogc
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(i <= j);
|
||||||
|
assert(j <= length);
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
copy(value[], this.data[i .. j]);
|
||||||
|
return opSlice(i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
ByCodeUnit!char opSliceAssign(const char value,
|
||||||
|
const size_t i,
|
||||||
|
const size_t j)
|
||||||
|
pure nothrow @trusted @nogc
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(i <= j);
|
||||||
|
assert(j <= length);
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
fill(this.data[i .. j], value);
|
||||||
|
return opSlice(i, j);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array used internally by the string.
|
* Returns an array used internally by the string.
|
||||||
* The length of the returned array may be smaller than the size of the
|
* The length of the returned array may be smaller than the size of the
|
||||||
@ -970,8 +1037,30 @@ struct String
|
|||||||
return typeof(return)(this, this.data, this.data + length);
|
return typeof(return)(this, this.data, this.data + length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@safe @nogc unittest
|
||||||
|
{
|
||||||
|
auto s = String("Высоцкий");
|
||||||
|
auto cp = s.byCodePoint();
|
||||||
|
assert(cp.front == 'В');
|
||||||
|
cp.popFront();
|
||||||
|
assert(cp.front == 'ы');
|
||||||
|
cp.popFront();
|
||||||
|
assert(cp.front == 'с');
|
||||||
|
|
||||||
|
s = String("€");
|
||||||
|
cp = s.byCodePoint();
|
||||||
|
assert(cp.front == '€');
|
||||||
|
assert(s.length == 3);
|
||||||
|
|
||||||
|
s = String("\U00024B62");
|
||||||
|
cp = s.byCodePoint();
|
||||||
|
assert(cp.front == '\U00024B62');
|
||||||
|
assert(s.length == 4);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: $(D_KEYWORD true) if the vector is empty.
|
* Returns: $(D_KEYWORD true) if the string is empty.
|
||||||
*/
|
*/
|
||||||
@property bool empty() const pure nothrow @safe @nogc
|
@property bool empty() const pure nothrow @safe @nogc
|
||||||
{
|
{
|
||||||
@ -1068,7 +1157,7 @@ struct String
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
ref String opAssig(S)(ref S that) @trusted
|
ref String opAssign(S)(ref S that) @trusted
|
||||||
if (is(Unqual!S == String))
|
if (is(Unqual!S == String))
|
||||||
{
|
{
|
||||||
reserve(that.length);
|
reserve(that.length);
|
||||||
@ -1219,5 +1308,51 @@ struct String
|
|||||||
assert(s == "У меня на сердце");
|
assert(s == "У меня на сердце");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns a value to the character with the index $(D_PARAM pos).
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* value = Value.
|
||||||
|
* pos = Position.
|
||||||
|
*
|
||||||
|
* Returns: Assigned value.
|
||||||
|
*
|
||||||
|
* Precondition: $(D_INLINECODE length > pos).
|
||||||
|
*/
|
||||||
|
ref char opIndexAssign(const char value, const size_t pos)
|
||||||
|
pure nothrow @safe @nogc
|
||||||
|
{
|
||||||
|
return opIndex(pos) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns a range or a string.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* R = Value type.
|
||||||
|
* value = Value.
|
||||||
|
*
|
||||||
|
* Returns: Assigned value.
|
||||||
|
*
|
||||||
|
* Precondition: $(D_INLINECODE length == value.length).
|
||||||
|
*/
|
||||||
|
ByCodeUnit!char opIndexAssign(R)(ByCodeUnit!R value)
|
||||||
|
if (is(Unqual!R == char))
|
||||||
|
{
|
||||||
|
return opSliceAssign(value, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
ByCodeUnit!char opIndexAssign(const char value) pure nothrow @safe @nogc
|
||||||
|
{
|
||||||
|
return opSliceAssign(value, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
ByCodeUnit!char opIndexAssign(const char[] value) pure nothrow @safe @nogc
|
||||||
|
{
|
||||||
|
return opSliceAssign(value, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
mixin DefaultAllocator;
|
mixin DefaultAllocator;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user