From 76bda0ac8df2f9e5d49e126d16d785f5c63c4430 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Wed, 17 Apr 2019 06:27:18 +0200 Subject: [PATCH] Add getAndPopFront()/getAndPopBack() --- source/tanya/algorithm/iteration.d | 5 +- source/tanya/container/array.d | 8 +-- source/tanya/range/primitive.d | 94 ++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 9 deletions(-) diff --git a/source/tanya/algorithm/iteration.d b/source/tanya/algorithm/iteration.d index 0e91c5d..e71d581 100644 --- a/source/tanya/algorithm/iteration.d +++ b/source/tanya/algorithm/iteration.d @@ -756,7 +756,7 @@ if (F.length == 1) * * Returns: Accumulated value. */ - T foldl(R, T)(R range, auto ref T init) + auto foldl(R, T)(R range, auto ref T init) if (isInputRange!R && !isInfinite!R) { if (range.empty) @@ -765,8 +765,7 @@ if (F.length == 1) } else { - auto acc = F[0](init, range.front); - range.popFront; + auto acc = F[0](init, getAndPopFront(range)); return foldl(range, acc); } } diff --git a/source/tanya/container/array.d b/source/tanya/container/array.d index 5b3f522..872d55e 100644 --- a/source/tanya/container/array.d +++ b/source/tanya/container/array.d @@ -16,6 +16,7 @@ module tanya.container.array; import core.checkedint; import tanya.algorithm.comparison; +import tanya.algorithm.iteration; import tanya.algorithm.mutation; import tanya.memory.allocator; import tanya.memory.lifetime; @@ -670,12 +671,7 @@ struct Array(T) { reserve(length + el.length); } - size_t retLength; - foreach (e; el) - { - retLength += insertBack(e); - } - return retLength; + return foldl!((acc, e) => acc + insertBack(e))(el, 0U); } /// ditto diff --git a/source/tanya/range/primitive.d b/source/tanya/range/primitive.d index 82950ac..258d5d5 100644 --- a/source/tanya/range/primitive.d +++ b/source/tanya/range/primitive.d @@ -1545,3 +1545,97 @@ if (isInputRange!Range && hasLvalueElements!Range) assert(!sameHead(r1, r2)); } + +/** + * Returns the first element and advances the range. + * + * If $(D_PARAM range) has lvalue elements, then $(D_PSYMBOL getAndPopFront) + * returns by reference, otherwise the returned element is copied. + * + * Params: + * R = Input range type. + * range = Input range. + * + * Returns: Front range element. + * + * See_Also: $(D_PSYMBOL getAndPopBack). + */ +ElementType!R getAndPopFront(R)(ref R range) +if (isInputRange!R) +in (!range.empty) +{ + static if (hasLvalueElements!R) + { + auto el = (() @trusted => &range.front())(); + } + else + { + auto el = range.front; + } + range.popFront(); + static if (hasLvalueElements!R) + { + return *el; + } + else + { + return el; + } +} + +/// +@nogc nothrow pure @safe unittest +{ + int[3] array = [1, 2, 3]; + auto slice = array[]; + + assert(getAndPopFront(slice) == 1); + assert(slice.length == 2); +} + +/** + * Returns the last element and removes it from the range. + * + * If $(D_PARAM range) has lvalue elements, then $(D_PSYMBOL getAndPopBack) + * returns by reference, otherwise the returned element is copied. + * + * Params: + * R = Bidirectional range type. + * range = Bidirectional range. + * + * Returns: Last range element. + * + * See_Also: $(D_PSYMBOL getAndPopFront). + */ +auto ref getAndPopBack(R)(ref R range) +if (isBidirectionalRange!R) +in (!range.empty) +{ + static if (hasLvalueElements!R) + { + auto el = (() @trusted => &range.back())(); + } + else + { + auto el = range.back; + } + range.popBack(); + static if (hasLvalueElements!R) + { + return *el; + } + else + { + return el; + } +} + +/// +@nogc nothrow pure @trusted unittest +{ + int[3] array = [1, 2, 3]; + auto slice = array[]; + + assert(getAndPopBack(slice) == 3); + assert(slice.length == 2); +}