From 0a973b46ba399e238324620a6a0b117ec5e510b3 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Wed, 24 Apr 2019 06:53:08 +0200 Subject: [PATCH] Add algorithm.iteration.foldr --- source/tanya/algorithm/iteration.d | 60 ++++++++++++++++++++++++++++++ source/tanya/container/hashtable.d | 8 +--- source/tanya/container/list.d | 8 +--- 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/source/tanya/algorithm/iteration.d b/source/tanya/algorithm/iteration.d index e71d581..0b1a31c 100644 --- a/source/tanya/algorithm/iteration.d +++ b/source/tanya/algorithm/iteration.d @@ -779,3 +779,63 @@ if (F.length == 1) assert(actual == 6); } + +/** + * Accumulates all elements of a range using a function. + * + * $(D_PSYMBOL foldr) takes a function, an input range and the initial value. + * The function takes this initial value and the first element of the range (in + * this order), puts them together and returns the result. The return + * type of the function should be the same as the type of the initial value. + * This is than repeated for all the remaining elements of the range, whereby + * the value returned by the passed function is used at the place of the + * initial value. + * + * $(D_PSYMBOL foldr) accumulates from right to left. + * + * Params: + * F = Callable accepting the accumulator and a range element. + */ +template foldr(F...) +if (F.length == 1) +{ + /** + * Params: + * R = Bidirectional range type. + * T = Type of the accumulated value. + * range = Bidirectional range. + * init = Initial value. + * + * Returns: Accumulated value. + */ + auto foldr(R, T)(R range, auto ref T init) + if (isBidirectionalRange!R) + { + if (range.empty) + { + return init; + } + else + { + auto acc = F[0](init, getAndPopBack(range)); + return foldr(range, acc); + } + } +} + +/// +@nogc nothrow pure @safe unittest +{ + int[3] range = [1, 2, 3]; + int[3] output; + const int[3] expected = [3, 2, 1]; + + alias f = (acc, x) { + acc.front = x; + acc.popFront; + return acc; + }; + const actual = foldr!f(range[], output[]); + + assert(output[] == expected[]); +} diff --git a/source/tanya/container/hashtable.d b/source/tanya/container/hashtable.d index 2ae18db..349e681 100644 --- a/source/tanya/container/hashtable.d +++ b/source/tanya/container/hashtable.d @@ -14,6 +14,7 @@ */ module tanya.container.hashtable; +import tanya.algorithm.iteration; import tanya.algorithm.mutation; import tanya.container.array; import tanya.container.entry; @@ -718,12 +719,7 @@ if (isHashFunction!(hasher, Key)) size_t insert(R)(scope R range) if (isForwardRange!R && is(ElementType!R == KeyValue) && !isInfinite!R) { - size_t count; - foreach (e; range) - { - count += insert(e); - } - return count; + return foldl!((acc, x) => acc + insert(x))(range, 0U); } /// diff --git a/source/tanya/container/list.d b/source/tanya/container/list.d index c01b863..31ddfd5 100644 --- a/source/tanya/container/list.d +++ b/source/tanya/container/list.d @@ -16,6 +16,7 @@ module tanya.container.list; import tanya.algorithm.comparison; +import tanya.algorithm.iteration; import tanya.container.entry; import tanya.memory.allocator; import tanya.memory.lifetime; @@ -1690,12 +1691,7 @@ struct DList(T) && isImplicitlyConvertible!(ElementType!R, T)) in (checkRangeBelonging(r)) { - size_t inserted; - foreach (e; el) - { - inserted += insertAfter(r, e); - } - return inserted; + return foldl!((acc, x) => acc + insertAfter(r, x))(el, 0U); } ///