From 4a2a2da60754f54d990800eb246112933907b1b7 Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Sat, 8 Jul 2017 01:40:36 +0200 Subject: [PATCH 1/2] Make std.algorithm.searching.skipOver an eponymous template --- std/algorithm/searching.d | 143 ++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 84 deletions(-) diff --git a/std/algorithm/searching.d b/std/algorithm/searching.d index cd67bdcf21d..27560fdefa0 100644 --- a/std/algorithm/searching.d +++ b/std/algorithm/searching.d @@ -3913,72 +3913,81 @@ Do nothing if there is no match. Params: pred = The predicate that determines whether elements from each respective range match. Defaults to equality $(D "a == b"). +*/ +template skipOver(alias pred = "a == b") +{ + /** r1 = The $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to move forward. r2 = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) representing the initial segment of $(D r1) to skip over. + e = The element to match. -Returns: -true if the initial segment of $(D r1) matches $(D r2) or $(D pred) evaluates to true, -and $(D r1) has been advanced to the point past this segment; otherwise false, and -$(D r1) is left in its original position. - */ -bool skipOver(R1, R2)(ref R1 r1, R2 r2) -if (isForwardRange!R1 && isInputRange!R2 - && is(typeof(r1.front == r2.front))) -{ - static if (is(typeof(r1[0 .. $] == r2) : bool) - && is(typeof(r2.length > r1.length) : bool) - && is(typeof(r1 = r1[r2.length .. $]))) + Returns: + true if the initial segment of $(D r1) matches $(D r2) or $(D pred) evaluates to true, + and $(D r1) has been advanced to the point past this segment; otherwise false, and + $(D r1) is left in its original position. + */ + bool skipOver(R1, R2)(ref R1 r1, R2 r2) + if (is(typeof(binaryFun!pred(r1.front, r2.front))) && + isForwardRange!R1 && + isInputRange!R2) { - if (r2.length > r1.length || r1[0 .. r2.length] != r2) + static if (is(typeof(pred) : string) && pred == "a == b" + && is(typeof(r1[0 .. $] == r2) : bool) + && is(typeof(r2.length > r1.length) : bool) + && is(typeof(r1 = r1[r2.length .. $]))) { - return false; + if (r2.length > r1.length || r1[0 .. r2.length] != r2) + { + return false; + } + r1 = r1[r2.length .. $]; + return true; + } + else + { + static if (hasLength!R1 && hasLength!R2) + { + // Shortcut opportunity! + if (r2.length > r1.length) + return false; + } + auto r = r1.save; + while (!r2.empty && !r.empty && binaryFun!pred(r.front, r2.front)) + { + r.popFront(); + r2.popFront(); + } + if (r2.empty) + r1 = r; + return r2.empty; } - r1 = r1[r2.length .. $]; - return true; - } - else - { - return skipOver!((a, b) => a == b)(r1, r2); } -} -/// Ditto -bool skipOver(alias pred, R1, R2)(ref R1 r1, R2 r2) -if (is(typeof(binaryFun!pred(r1.front, r2.front))) && - isForwardRange!R1 && - isInputRange!R2) -{ - static if (hasLength!R1 && hasLength!R2) + /// Ditto + bool skipOver(R)(ref R r1) + if (isForwardRange!R && + ifTestable!(typeof(r1.front), unaryFun!pred)) { - // Shortcut opportunity! - if (r2.length > r1.length) + if (r1.empty || !unaryFun!pred(r1.front)) return false; + + do + r1.popFront(); + while (!r1.empty && unaryFun!pred(r1.front)); + return true; } - auto r = r1.save; - while (!r2.empty && !r.empty && binaryFun!pred(r.front, r2.front)) + + /// Ditto + bool skipOver(R, E)(ref R r, E e) + if (is(typeof(binaryFun!pred(r.front, e))) && isInputRange!R) { + if (r.empty || !binaryFun!pred(r.front, e)) + return false; r.popFront(); - r2.popFront(); + return true; } - if (r2.empty) - r1 = r; - return r2.empty; -} - -/// Ditto -bool skipOver(alias pred, R)(ref R r1) -if (isForwardRange!R && - ifTestable!(typeof(r1.front), unaryFun!pred)) -{ - if (r1.empty || !unaryFun!pred(r1.front)) - return false; - - do - r1.popFront(); - while (!r1.empty && unaryFun!pred(r1.front)); - return true; } /// @@ -4009,40 +4018,6 @@ if (isForwardRange!R && assert(s4.skipOver!isWhite && s3.empty); } -/** -Skip over the first element of the given range if it matches the given element, -otherwise do nothing. - -Params: - pred = The predicate that determines whether an element from the range - matches the given element. - - r = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to skip - over. - - e = The element to match. - -Returns: -true if the first element matches the given element according to the given -predicate, and the range has been advanced by one element; otherwise false, and -the range is left untouched. - */ -bool skipOver(R, E)(ref R r, E e) -if (isInputRange!R && is(typeof(r.front == e) : bool)) -{ - return skipOver!((a, b) => a == b)(r, e); -} - -/// Ditto -bool skipOver(alias pred, R, E)(ref R r, E e) -if (is(typeof(binaryFun!pred(r.front, e))) && isInputRange!R) -{ - if (r.empty || !binaryFun!pred(r.front, e)) - return false; - r.popFront(); - return true; -} - /// @safe unittest { From 7fb31acf4fa8c725f7632aabc5c397fbd7e8c1a9 Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Sat, 8 Jul 2017 02:33:06 +0200 Subject: [PATCH 2/2] Add unittest for partial instantiation --- std/algorithm/searching.d | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/std/algorithm/searching.d b/std/algorithm/searching.d index 27560fdefa0..078cc61dab8 100644 --- a/std/algorithm/searching.d +++ b/std/algorithm/searching.d @@ -4039,6 +4039,22 @@ template skipOver(alias pred = "a == b") assert(!s2.skipOver('a')); } +/// Partial instantiation +@safe unittest +{ + import std.ascii : isWhite; + import std.range.primitives : empty; + + alias whitespaceSkiper = skipOver!isWhite; + + auto s2 = "\t\tvalue"; + auto s3 = ""; + auto s4 = "\t\t\t"; + assert(whitespaceSkiper(s2) && s2 == "value"); + assert(!whitespaceSkiper(s2)); + assert(whitespaceSkiper(s4) && s3.empty); +} + /** Checks whether the given $(REF_ALTTEXT input range, isInputRange, std,range,primitives) starts with (one