From c5eb2f27be3a524f9c6e7de356e286146d00ed49 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 28 Sep 2018 05:40:33 +0200 Subject: [PATCH] Add algorithm.iteration --- source/tanya/algorithm/iteration.d | 169 +++++++++++++++++++++++++++++ source/tanya/math/mp.d | 16 ++- 2 files changed, 176 insertions(+), 9 deletions(-) diff --git a/source/tanya/algorithm/iteration.d b/source/tanya/algorithm/iteration.d index 9d0a4a8..27fce71 100644 --- a/source/tanya/algorithm/iteration.d +++ b/source/tanya/algorithm/iteration.d @@ -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); +} diff --git a/source/tanya/math/mp.d b/source/tanya/math/mp.d index ed47c1e..5ee1f39 100644 --- a/source/tanya/math/mp.d +++ b/source/tanya/math/mp.d @@ -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; }