Merge branch 'master' into utf8string

This commit is contained in:
Eugen Wissner 2017-04-20 17:32:59 +02:00
commit 33d321f0d7
5 changed files with 1762 additions and 1795 deletions

View File

@ -14,5 +14,5 @@ module tanya.container;
public import tanya.container.buffer; public import tanya.container.buffer;
public import tanya.container.list; public import tanya.container.list;
public import tanya.container.vector; public import tanya.container.slice;
public import tanya.container.queue; public import tanya.container.queue;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -129,12 +129,8 @@ struct Integer
* Precondition: $(D_INLINECODE allocator !is null) * Precondition: $(D_INLINECODE allocator !is null)
*/ */
this(R)(const Sign sign, R value, shared Allocator allocator = defaultAllocator) this(R)(const Sign sign, R value, shared Allocator allocator = defaultAllocator)
@trusted
if (isInputRange!R && hasLength!R && is(Unqual!(ElementType!R) == ubyte)) if (isInputRange!R && hasLength!R && is(Unqual!(ElementType!R) == ubyte))
out
{
assert(this.size == 0 || this.rep[0] > 0);
}
body
{ {
this(allocator); this(allocator);
while (!value.empty && value.front == 0) while (!value.empty && value.front == 0)
@ -144,7 +140,14 @@ struct Integer
this.rep = allocator.resize(this.rep[0 .. this.size], value.length).ptr; this.rep = allocator.resize(this.rep[0 .. this.size], value.length).ptr;
this.size = value.length; this.size = value.length;
this.sign = sign; this.sign = sign;
value.copy(this.rep[0 .. this.size]); value.copy(this.rep[0 .. this.size].retro);
}
private @nogc unittest
{
ubyte[5] range = [ 0x02, 0x11, 0x00, 0x00, 0x01 ];
auto integer = Integer(Sign.positive, range[]);
assert(equal(range[].retro, integer.rep[0 .. integer.size]));
} }
/** /**
@ -205,9 +208,9 @@ struct Integer
big-endian format. */ big-endian format. */
mask = 0xff; mask = 0xff;
ubyte shift; ubyte shift;
for (auto i = this.size; i; --i, mask <<= 8, shift += 8) for (size_t i; i < this.size; ++i, mask <<= 8, shift += 8)
{ {
this.rep[i - 1] = cast(ubyte) ((absolute & mask) >> shift); this.rep[i] = cast(ubyte) ((absolute & mask) >> shift);
} }
} }
@ -263,15 +266,15 @@ struct Integer
{ {
auto integer = Integer(1019); auto integer = Integer(1019);
assert(integer.length == 2); assert(integer.length == 2);
assert(integer.rep[0] == 0b00000011 && integer.rep[1] == 0b11111011); assert(integer.rep[1] == 0b00000011 && integer.rep[0] == 0b11111011);
integer = 3337; integer = 3337;
assert(integer.length == 2); assert(integer.length == 2);
assert(integer.rep[0] == 0b00001101 && integer.rep[1] == 0b00001001); assert(integer.rep[1] == 0b00001101 && integer.rep[0] == 0b00001001);
integer = 688; integer = 688;
assert(integer.length == 2); assert(integer.length == 2);
assert(integer.rep[0] == 0b00000010 && integer.rep[1] == 0b10110000); assert(integer.rep[1] == 0b00000010 && integer.rep[0] == 0b10110000);
integer = 0; integer = 0;
assert(integer.length == 0); assert(integer.length == 0);
@ -283,10 +286,8 @@ struct Integer
private void expand() nothrow @trusted @nogc private void expand() nothrow @trusted @nogc
{ {
rep = allocator.resize(this.rep[0 .. this.size], this.size + 1).ptr; rep = allocator.resize(this.rep[0 .. this.size], this.size + 1).ptr;
this.rep[this.size] = 0x01;
++this.size; ++this.size;
auto target = this.rep[1 .. this.size].retro;
this.rep[0 .. this.size - 1].retro.copy(target);
this.rep[0] = 0x01;
} }
/* /*
@ -295,11 +296,12 @@ struct Integer
*/ */
private void contract() nothrow @trusted @nogc private void contract() nothrow @trusted @nogc
{ {
const i = this.rep[0 .. this.size].countUntil!((const ref a) => a != 0); const i = this.rep[0 .. this.size]
.retro
.countUntil!((const ref a) => a != 0);
if (i > 0) if (i > 0)
{ {
this.rep[i .. this.size].copy(this.rep[0 .. this.size - i]);
this.rep = allocator.resize(this.rep[0 .. this.size], this.size - i).ptr; this.rep = allocator.resize(this.rep[0 .. this.size], this.size - i).ptr;
this.size -= i; this.size -= i;
} }
@ -315,28 +317,22 @@ struct Integer
{ {
if (summand.length > this.length) if (summand.length > this.length)
{ {
const delta = summand.size - this.size; this.rep = allocator.resize!ubyte(this.rep[0 .. this.size], summand.size).ptr;
auto tmp = this.rep[0 .. this.size]; this.rep[this.size .. summand.size].initializeAll();
this.rep = allocator.resize!ubyte(null, summand.size).ptr;
tmp.copy(this.rep[delta .. summand.size]);
this.rep[0 .. delta].initializeAll();
allocator.deallocate(tmp[0 .. this.size]);
this.size = summand.size; this.size = summand.size;
} }
bool carry; bool carry;
size_t i = this.size; size_t i;
size_t j = summand.size; size_t j;
do do
{ {
uint sum; uint sum;
--i; if (j < summand.size)
if (j)
{ {
--j;
sum = this.rep[i] + summand.rep[j] + carry; sum = this.rep[i] + summand.rep[j] + carry;
++j;
} }
else else
{ {
@ -346,7 +342,7 @@ struct Integer
carry = sum > 0xff; carry = sum > 0xff;
this.rep[i] = cast(ubyte) sum; this.rep[i] = cast(ubyte) sum;
} }
while (i); while (++i < this.size);
if (carry) if (carry)
{ {
@ -357,19 +353,18 @@ struct Integer
private void subtract(const ref Integer subtrahend) nothrow @trusted @nogc private void subtract(const ref Integer subtrahend) nothrow @trusted @nogc
{ {
size_t i = this.size; size_t i;
size_t j = subtrahend.size; size_t j;
bool borrow; bool borrow;
while (i) while (i < this.size)
{ {
int difference; int difference;
--i;
if (j) if (j < subtrahend.size)
{ {
--j;
difference = this.rep[i] - subtrahend.rep[j] - borrow; difference = this.rep[i] - subtrahend.rep[j] - borrow;
++j;
} }
else else
{ {
@ -377,29 +372,30 @@ struct Integer
} }
borrow = difference < 0; borrow = difference < 0;
this.rep[i] = cast(ubyte) difference; this.rep[i] = cast(ubyte) difference;
++i;
} }
if (borrow && i > 0) if (borrow && i < this.size && this.rep[i])
{ {
if (this.rep[i - 1]) // Don't borrow i --this.rep[i];
{
--this.rep[i - 1];
}
} }
contract(); contract();
} }
private int compare(const ref Integer that) const nothrow @trusted @nogc private int compare(const ref Integer that) const nothrow @trusted @nogc
{ {
if (this.length > that.length) if (length > that.length)
{ {
return 1; return 1;
} }
else if (this.length < that.length) else if (length < that.length)
{ {
return -1; return -1;
} }
return this.rep[0 .. this.size].cmp(that.rep[0 .. that.size]); return this.rep[0 .. this.size]
.retro
.cmp(that.rep[0 .. that.size].retro);
} }
/** /**
@ -508,11 +504,6 @@ struct Integer
* Returns: $(D_KEYWORD this). * Returns: $(D_KEYWORD this).
*/ */
ref Integer opOpAssign(string op : "+")(const auto ref Integer operand) ref Integer opOpAssign(string op : "+")(const auto ref Integer operand)
out
{
assert(this.size == 0 || this.rep[0] > 0);
}
body
{ {
if (this.sign == operand.sign) if (this.sign == operand.sign)
{ {
@ -544,19 +535,19 @@ struct Integer
auto h2 = Integer(3337); auto h2 = Integer(3337);
h1 += h2; h1 += h2;
assert(h1.length == 2); assert(h1.length == 2);
assert(h1.rep[0] == 0x11 && h1.rep[1] == 0x04); assert(h1.rep[1] == 0x11 && h1.rep[0] == 0x04);
} }
{ {
auto h1 = Integer(4356); auto h1 = Integer(4356);
auto h2 = Integer(2_147_483_647); auto h2 = Integer(2_147_483_647);
ubyte[4] expected = [0x80, 0x00, 0x11, 0x03]; ubyte[4] expected = [ 0x03, 0x11, 0x00, 0x80 ];
h1 += h2; h1 += h2;
assert(h1.rep[0 .. h1.size] == expected); assert(h1.rep[0 .. h1.size] == expected);
} }
{ {
auto h1 = Integer(2147488003L); auto h1 = Integer(2147488003L);
auto h2 = Integer(2_147_483_647); auto h2 = Integer(2_147_483_647);
ubyte[5] expected = [0x01, 0x00, 0x00, 0x11, 0x02]; ubyte[5] expected = [ 0x02, 0x11, 0x00, 0x00, 0x01 ];
h1 += h2; h1 += h2;
assert(h1.rep[0 .. h1.size] == expected); assert(h1.rep[0 .. h1.size] == expected);
} }
@ -564,11 +555,6 @@ struct Integer
/// Ditto. /// Ditto.
ref Integer opOpAssign(string op : "-")(const auto ref Integer operand) ref Integer opOpAssign(string op : "-")(const auto ref Integer operand)
out
{
assert(this.size == 0 || this.rep[0] > 0);
}
body
{ {
if (operand.sign == this.sign) if (operand.sign == this.sign)
{ {
@ -608,12 +594,12 @@ struct Integer
h1 -= h2; h1 -= h2;
assert(h1.length == 1); assert(h1.length == 1);
assert(h1.rep[0] == 0x01); assert(h1.rep[0] == 0x01);
assert(h1.sign); assert(h1.sign == Sign.negative);
} }
{ {
auto h1 = Integer(8589934590L); auto h1 = Integer(8589934590L);
auto h2 = Integer(2147483647); auto h2 = Integer(2147483647);
ubyte[5] expected = [0x01, 0x7f, 0xff, 0xff, 0xff]; ubyte[5] expected = [ 0xff, 0xff, 0xff, 0x7f, 0x01 ];
h1 -= h2; h1 -= h2;
assert(h1.rep[0 .. h1.size] == expected); assert(h1.rep[0 .. h1.size] == expected);
@ -621,7 +607,7 @@ struct Integer
{ {
auto h1 = Integer(6442450943); auto h1 = Integer(6442450943);
auto h2 = Integer(4294967294); auto h2 = Integer(4294967294);
ubyte[4] expected = [0x80, 0x00, 0x00, 0x01]; ubyte[4] expected = [ 0x01, 0x00, 0x00, 0x80 ];
h1 -= h2; h1 -= h2;
assert(h1.rep[0 .. h1.size] == expected); assert(h1.rep[0 .. h1.size] == expected);
} }
@ -635,18 +621,13 @@ struct Integer
/// Ditto. /// Ditto.
ref Integer opOpAssign(string op : "*")(const auto ref Integer operand) @trusted ref Integer opOpAssign(string op : "*")(const auto ref Integer operand) @trusted
out
{ {
assert(this.size == 0 || this.rep[0] > 0); size_t i;
}
body
{
size_t i = operand.size;
if (this.length == 0) if (this.length == 0)
{ {
return this; return this;
} }
else if (i == 0) else if (operand.length == 0)
{ {
this = 0; this = 0;
return this; return this;
@ -657,7 +638,6 @@ struct Integer
this = 0; this = 0;
do do
{ {
--i;
for (ubyte mask = 0x01; mask; mask <<= 1) for (ubyte mask = 0x01; mask; mask <<= 1)
{ {
if (mask & operand.rep[i]) if (mask & operand.rep[i])
@ -666,8 +646,9 @@ struct Integer
} }
temp <<= 1; temp <<= 1;
} }
++i;
} }
while (i); while (i < operand.size);
this.sign = sign ? Sign.negative : Sign.positive; this.sign = sign ? Sign.negative : Sign.positive;
@ -691,20 +672,14 @@ struct Integer
/// Ditto. /// Ditto.
ref Integer opOpAssign(string op : "^^")(const auto ref Integer operand) ref Integer opOpAssign(string op : "^^")(const auto ref Integer operand)
@trusted @trusted
out
{ {
assert(this.size == 0 || this.rep[0] > 0); size_t i;
}
body
{
size_t i = operand.size;
auto tmp1 = Integer(this, this.allocator); auto tmp1 = Integer(this, this.allocator);
this = 1; this = 1;
do do
{ {
--i;
for (ubyte mask = 0x01; mask; mask <<= 1) for (ubyte mask = 0x01; mask; mask <<= 1)
{ {
if (operand.rep[i] & mask) if (operand.rep[i] & mask)
@ -715,8 +690,9 @@ struct Integer
auto tmp2 = tmp1; auto tmp2 = tmp1;
tmp1 *= tmp2; tmp1 *= tmp2;
} }
++i;
} }
while (i); while (i < operand.size);
return this; return this;
} }
@ -732,7 +708,7 @@ struct Integer
h1 = Integer(2342); h1 = Integer(2342);
h1 ^^= h2; h1 ^^= h2;
ubyte[6] expected = [0x1b, 0x5c, 0xab, 0x9c, 0x31, 0x10]; ubyte[6] expected = [ 0x10, 0x31, 0x9c, 0xab, 0x5c, 0x1b ];
assert(h1.rep[0 .. h1.size] == expected); assert(h1.rep[0 .. h1.size] == expected);
} }
@ -743,10 +719,6 @@ struct Integer
{ {
assert(operand.length > 0, "Division by zero."); assert(operand.length > 0, "Division by zero.");
} }
out
{
assert(this.size == 0 || this.rep[0] > 0);
}
body body
{ {
auto divisor = Integer(operand, this.allocator); auto divisor = Integer(operand, this.allocator);
@ -774,7 +746,7 @@ struct Integer
subtract(divisor); // dividend -= divisor subtract(divisor); // dividend -= divisor
static if (op == "/") static if (op == "/")
{ {
quotient[bitPosition / 8] |= 0x80 >> (bitPosition % 8); quotient[$ - 1 - bitPosition / 8] |= 0x80 >> (bitPosition % 8);
} }
} }
if (bitSize != 0) if (bitSize != 0)
@ -823,11 +795,6 @@ struct Integer
/// Ditto. /// Ditto.
ref Integer opOpAssign(string op : ">>")(const size_t operand) @trusted ref Integer opOpAssign(string op : ">>")(const size_t operand) @trusted
out
{
assert(this.size == 0 || this.rep[0] > 0);
}
body
{ {
const step = operand / 8; const step = operand / 8;
@ -843,20 +810,18 @@ struct Integer
const bit = operand % 8; const bit = operand % 8;
const delta = 8 - bit; const delta = 8 - bit;
carry = cast(ubyte) (this.rep[0] << delta); for (j = step; j < length - 1; ++i, ++j)
this.rep[0] = this.rep[0] >> bit;
if (rep[0])
{ {
++j; carry = cast(ubyte) (this.rep[i + 1] << delta);
this.rep[i] = (this.rep[i] >> bit) | carry;
} }
for (i = 1; i < this.length; ++i)
this.rep[i] = this.rep[j] >> bit;
size_t newSize = length - step;
if (this.rep[i] == 0)
{ {
immutable oldCarry = carry; --newSize;
carry = cast(ubyte) (this.rep[i] << delta);
this.rep[j] = this.rep[i] >> bit | oldCarry;
++j;
} }
const newSize = this.length - operand / 8 - (i == j ? 0 : 1);
this.rep = allocator.resize(this.rep[0 .. this.size], newSize).ptr; this.rep = allocator.resize(this.rep[0 .. this.size], newSize).ptr;
this.size = newSize; this.size = newSize;
@ -868,21 +833,21 @@ struct Integer
auto integer = Integer(4294967294); auto integer = Integer(4294967294);
integer >>= 10; integer >>= 10;
assert(integer.length == 3); assert(integer.length == 3);
assert(integer.rep[0] == 0x3f && integer.rep[1] == 0xff && integer.rep[2] == 0xff); assert(integer.rep[2] == 0x3f && integer.rep[1] == 0xff && integer.rep[0] == 0xff);
integer = 27336704; integer = 27336704;
integer >>= 1; integer >>= 1;
assert(integer.length == 3); assert(integer.length == 3);
assert(integer.rep[0] == 0xd0 && integer.rep[1] == 0x90 && integer.rep[2] == 0x00); assert(integer.rep[2] == 0xd0 && integer.rep[1] == 0x90 && integer.rep[0] == 0x00);
integer = 4294967294; integer = 4294967294;
integer >>= 20; integer >>= 20;
assert(integer.length == 2); assert(integer.length == 2);
assert(integer.rep[0] == 0x0f && integer.rep[1] == 0xff); assert(integer.rep[1] == 0x0f && integer.rep[0] == 0xff);
integer >>= 0; integer >>= 0;
assert(integer.length == 2); assert(integer.length == 2);
assert(integer.rep[0] == 0x0f && integer.rep[1] == 0xff); assert(integer.rep[1] == 0x0f && integer.rep[0] == 0xff);
integer >>= 20; integer >>= 20;
assert(integer.length == 0); assert(integer.length == 0);
@ -893,7 +858,7 @@ struct Integer
integer = 1431655765; integer = 1431655765;
integer >>= 16; integer >>= 16;
assert(integer.length == 2); assert(integer.length == 2);
assert(integer.rep[0] == 0x55 && integer.rep[1] == 0x55); assert(integer.rep[1] == 0x55 && integer.rep[0] == 0x55);
integer >>= 16; integer >>= 16;
assert(integer.length == 0); assert(integer.length == 0);
@ -901,50 +866,45 @@ struct Integer
/// Ditto. /// Ditto.
ref Integer opOpAssign(string op : "<<")(const size_t operand) @trusted ref Integer opOpAssign(string op : "<<")(const size_t operand) @trusted
out
{ {
assert(this.size == 0 || this.rep[0] > 0);
}
body
{
ubyte carry;
auto i = this.length; auto i = this.length;
size_t j; size_t j;
size_t newSize;
const bit = operand % 8; const bit = operand % 8;
const delta = 8 - bit; const delta = 8 - bit;
const step = operand / 8;
if (cast(ubyte) (this.rep[0] >> delta)) auto carry = cast(ubyte) (this.rep[this.size - 1] >> delta);
if (carry != 0)
{ {
const newSize = i + operand / 8 + 1; newSize = length + step + 1;
this.rep = allocator.resize(this.rep[0 .. this.size], newSize).ptr; this.rep = allocator.resize(this.rep[0 .. this.size], newSize).ptr;
this.size = newSize; this.size = newSize;
j = i + 1; j = newSize - 1;
this.rep[j] = carry;
} }
else else
{ {
const newSize = i + operand / 8; newSize = length + step;
this.rep = allocator.resize(this.rep[0 .. this.size], newSize).ptr; this.rep = allocator.resize(this.rep[0 .. this.size], newSize).ptr;
j = i; this.size = j = newSize;
} }
do
--i, --j;
for (; i > 0; --i, --j)
{ {
--i, --j; this.rep[i] = cast(ubyte) (this.rep[j] << bit) | (this.rep[j - 1] >> delta);
const oldCarry = carry;
carry = rep[i] >> delta;
rep[j] = cast(ubyte) ((this.rep[i] << bit) | oldCarry);
}
while (i);
if (carry)
{
rep[0] = carry;
} }
this.rep[i] = cast(ubyte) (this.rep[j] << bit);
this.rep[0 .. step].fill(cast(ubyte) 0);
return this; return this;
} }
private @nogc unittest private @nogc unittest
{ {
auto integer = Integer(4294967295); auto integer = Integer(4294967295);
ubyte[5] expected = [0x01, 0xff, 0xff, 0xff, 0xfe]; ubyte[5] expected = [ 0xfe, 0xff, 0xff, 0xff, 0x01 ];
integer <<= 1; integer <<= 1;
assert(integer.rep[0 .. integer.size] == expected); assert(integer.rep[0 .. integer.size] == expected);
} }
@ -956,10 +916,9 @@ struct Integer
} }
body body
{ {
auto p = this.rep + this.size; for (ubyte* p = this.rep; p < this.rep + this.size; ++p)
while (p != this.rep)
{ {
--p, --*p; --*p;
if (*p != ubyte.max) if (*p != ubyte.max)
{ {
break; break;
@ -970,16 +929,16 @@ struct Integer
private void increment() nothrow @trusted @nogc private void increment() nothrow @trusted @nogc
{ {
auto p = this.rep + this.size; ubyte* p;
while (p != this.rep) for (p = this.rep; p < this.rep + this.size; ++p)
{ {
--p, ++*p; ++*p;
if (*p > 0) if (*p > 0)
{ {
return; return;
} }
} }
if (p == this.rep) if (p == this.rep + this.size)
{ {
expand(); expand();
} }
@ -1054,11 +1013,6 @@ struct Integer
/// Ditto. /// Ditto.
ref Integer opUnary(string op : "++")() ref Integer opUnary(string op : "++")()
out
{
assert(this.size == 0 || this.rep[0] > 0);
}
body
{ {
if (this.sign) if (this.sign)
{ {
@ -1077,11 +1031,6 @@ struct Integer
/// Ditto. /// Ditto.
ref Integer opUnary(string op : "--")() ref Integer opUnary(string op : "--")()
out
{
assert(this.size == 0 || this.rep[0] > 0);
}
body
{ {
if (this.sign) if (this.sign)
{ {
@ -1108,11 +1057,11 @@ struct Integer
integer = 511; integer = 511;
++integer; ++integer;
assert(integer.length == 2); assert(integer.length == 2);
assert(integer.rep[0] == 0x02 && integer.rep[1] == 0x00); assert(integer.rep[1] == 0x02 && integer.rep[0] == 0x00);
--integer; --integer;
assert(integer.length == 2); assert(integer.length == 2);
assert(integer.rep[0] == 0x01 && integer.rep[1] == 0xff); assert(integer.rep[1] == 0x01 && integer.rep[0] == 0xff);
integer = 79; integer = 79;
++integer; ++integer;
@ -1126,11 +1075,11 @@ struct Integer
integer = 65535; integer = 65535;
++integer; ++integer;
assert(integer.length == 3); assert(integer.length == 3);
assert(integer.rep[0] == 0x01 && integer.rep[1] == 0x00 && integer.rep[2] == 0x00); assert(integer.rep[2] == 0x01 && integer.rep[1] == 0x00 && integer.rep[0] == 0x00);
--integer; --integer;
assert(integer.length == 2); assert(integer.length == 2);
assert(integer.rep[0] == 0xff && integer.rep[1] == 0xff); assert(integer.rep[1] == 0xff && integer.rep[0] == 0xff);
integer = -2; integer = -2;
++integer; ++integer;
@ -1217,10 +1166,11 @@ struct Integer
return 0; return 0;
} }
T ret; T ret;
const(ubyte)* src = this.rep + this.size - 1; const(ubyte)* src = this.rep;
for (ubyte shift; src >= this.rep && shift <= T.sizeof * 8; --src, shift += 8) ubyte shift;
for (; src < this.rep + this.size && shift <= T.sizeof * 8; ++src, shift += 8)
{ {
ret |= cast(T) (*src) << shift; ret |= (cast(T) *src) << shift;
} }
return ret; return ret;
} }

View File

@ -87,21 +87,20 @@ in
} }
body body
{ {
size_t i = y.length; size_t i;
auto tmp1 = Integer(x, x.allocator); auto tmp1 = Integer(x, x.allocator);
auto result = Integer(x.allocator); auto result = Integer(x.allocator);
if (x.length == 0 && i != 0) if (x.length == 0 && y.length != 0)
{ {
i = 0; i = y.length;
} }
else else
{ {
result = 1; result = 1;
} }
while (i) while (i < y.length)
{ {
--i;
for (ubyte mask = 0x01; mask; mask <<= 1) for (ubyte mask = 0x01; mask; mask <<= 1)
{ {
if (y.rep[i] & mask) if (y.rep[i] & mask)
@ -113,6 +112,7 @@ body
tmp1 *= tmp2; tmp1 *= tmp2;
tmp1 %= z; tmp1 %= z;
} }
++i;
} }
return result; return result;
} }