Add algorithm.iteration

This commit is contained in:
Eugen Wissner 2018-09-28 05:40:33 +02:00
parent 349e6dfede
commit c5eb2f27be
2 changed files with 176 additions and 9 deletions

View File

@ -407,3 +407,172 @@ if (isInputRange!R)
assert(slice.back == 3);
}
}
/**
* Iterates a bidirectional range backwards.
*
* If $(D_PARAM Range) is a random-access range as well, the resulting range
* is a random-access range too.
*
* Params:
* Range = Bidirectional range type.
* range = Bidirectional range.
*
* Returns: Bidirectional range with the elements order reversed.
*/
auto retro(Range)(Range range)
if (isBidirectionalRange!Range)
{
static struct Retro
{
Range source;
@disable this();
private this(Range source)
{
this.source = source;
}
Retro save()
{
return this;
}
@property auto ref front()
in (!empty)
{
return this.source.back;
}
void popFront()
in (!empty)
{
this.source.popBack();
}
@property auto ref back()
in (!empty)
{
return this.source.front;
}
void popBack()
in (!empty)
{
this.source.popFront();
}
@property bool empty()
{
return this.source.empty;
}
static if (hasLength!Range)
{
@property size_t length()
{
return this.source.length;
}
}
static if (isRandomAccessRange!Range && hasLength!Range)
{
auto ref opIndex(size_t i)
in (i < length)
{
return this.source[$ - ++i];
}
}
static if (hasAssignableElements!Range)
{
@property void front(ref ElementType!Range value)
in (!empty)
{
this.source.back = value;
}
@property void front(ElementType!Range value)
in (!empty)
{
this.source.back = move(value);
}
@property void back(ref ElementType!Range value)
in (!empty)
{
this.source.front = value;
}
@property void back(ElementType!Range value)
in (!empty)
{
this.source.front = move(value);
}
static if (isRandomAccessRange!Range && hasLength!Range)
{
void opIndexAssign(ref ElementType!Range value, size_t i)
in (i < length)
{
this.source[$ - ++i] = value;
}
void opIndexAssign(ElementType!Range value, size_t i)
in (i < length)
{
this.source[$ - ++i] = move(value);
}
}
}
}
return Retro(range);
}
///
@nogc nothrow pure @safe unittest
{
import tanya.algorithm.comparison : equal;
const int[3] given = [1, 2, 3];
const int[3] expected = [3, 2, 1];
auto actual = retro(given[]);
assert(actual.length == expected.length);
assert(!actual.empty);
assert(equal(actual, expected[]));
}
// Elements are accessible in reverse order
@nogc nothrow pure @safe unittest
{
const int[3] given = [1, 2, 3];
auto actual = retro(given[]);
assert(actual.back == given[].front);
assert(actual[0] == 3);
assert(actual[2] == 1);
actual.popBack();
assert(actual.back == 2);
assert(actual[1] == 2);
}
// Elements can be assigned
@nogc nothrow pure @safe unittest
{
int[4] given = [1, 2, 3, 4];
auto actual = retro(given[]);
actual.front = 5;
assert(given[].back == 5);
actual.back = 8;
assert(given[].front == 8);
actual[2] = 10;
assert(given[1] == 10);
}

View File

@ -14,15 +14,16 @@
*/
module tanya.math.mp;
import std.algorithm.mutation : fill, reverse;
import std.range;
import std.algorithm.mutation : fill;
import tanya.algorithm.comparison;
import tanya.algorithm.iteration;
import tanya.algorithm.mutation;
import tanya.container.array;
import tanya.encoding.ascii;
import tanya.memory;
import tanya.meta.trait;
import tanya.meta.transform;
import tanya.range;
/**
* Algebraic sign.
@ -929,7 +930,7 @@ struct Integer
const shift = digitBitCount - bit;
digit carry;
foreach (ref d; this.rep[0 .. this.size].retro)
foreach_reverse (ref d; this.rep[0 .. this.size])
{
const newCarry = d & mask;
d = (d >> bit) | (carry << shift);
@ -1505,14 +1506,11 @@ struct Integer
tmp = this;
}
do
array.length = length;
for (size_t i = array.length - 1; tmp != 0; tmp >>= 8, --i)
{
array.insertBack(cast(ubyte) (tmp.rep[0] & 0xff));
tmp >>= 8;
array[i] = (cast(ubyte) (tmp.rep[0] & 0xff));
}
while (tmp != 0);
array[].reverse();
return array;
}