From 3468d6ea008dd119a862b7b6afb221ffadf5e6d6 Mon Sep 17 00:00:00 2001 From: Eugene Wissner Date: Thu, 26 Apr 2018 08:06:06 +0200 Subject: [PATCH] Accept/return as inout in min/max --- source/tanya/algorithm/comparison.d | 88 ++++++++++++++++++----------- 1 file changed, 55 insertions(+), 33 deletions(-) diff --git a/source/tanya/algorithm/comparison.d b/source/tanya/algorithm/comparison.d index 6af08a0..43e9ffb 100644 --- a/source/tanya/algorithm/comparison.d +++ b/source/tanya/algorithm/comparison.d @@ -14,10 +14,27 @@ */ module tanya.algorithm.comparison; +import tanya.meta.metafunction; import tanya.meta.trait; +import tanya.meta.transform; import tanya.range.array; import tanya.range.primitive; +private ref inout(Args[0]) minMax(alias cmp, Args...)(ref inout Args args) +{ + auto actual = ((ref inout arg) @trusted => &arg)(args[0]); + + foreach (i, arg; args[1 .. $]) + { + if (cmp(arg, *actual)) + { + actual = ((ref inout arg) @trusted => &arg)(args[i + 1]); + } + } + + return *actual; +} + /** * Finds the smallest element in the argument list or a range. * @@ -37,27 +54,21 @@ import tanya.range.primitive; * * Returns: The smallest element. */ -Args[0] min(Args...)(Args args) -if (Args.length > 0 && isOrderingComparable!(Args[0]) && allSameType!Args) +inout(Unqual!(Args[0])) min(Args...)(inout Args args) +if (Args.length > 0 + && isOrderingComparable!(Args[0]) + && allSameType!(Map!(Unqual, Args))) { - return min!Args(args); + return minMax!((a, b) => a < b)(args); } /// ditto -ref Args[0] min(Args...)(ref Args args) -if (Args.length > 0 && isOrderingComparable!(Args[0]) && allSameType!Args) +ref inout(Unqual!(Args[0])) min(Args...)(ref inout Args args) +if (Args.length > 0 + && isOrderingComparable!(Args[0]) + && allSameType!(Map!(Unqual, Args))) { - auto actual = (() @trusted => &args[0])(); - - foreach (arg; args[1 .. $]) - { - if (arg < *actual) - { - actual = (() @trusted => &arg)(); - } - } - - return *actual; + return minMax!((a, b) => a < b)(args); } @nogc nothrow pure @safe unittest @@ -105,7 +116,7 @@ if (isForwardRange!Range && isOrderingComparable!(ElementType!Range)) { assert(min(cast(ubyte[]) []).empty); } - + /** * Finds the largest element in the argument list or a range. * @@ -125,27 +136,21 @@ if (isForwardRange!Range && isOrderingComparable!(ElementType!Range)) * * Returns: The largest element. */ -Args[0] max(Args...)(Args args) -if (Args.length > 0 && isOrderingComparable!(Args[0]) && allSameType!Args) +inout(Unqual!(Args[0])) max(Args...)(inout Args args) +if (Args.length > 0 + && isOrderingComparable!(Args[0]) + && allSameType!(Map!(Unqual, Args))) { - return max!Args(args); + return minMax!((a, b) => a > b)(args); } /// ditto -ref Args[0] max(Args...)(ref Args args) -if (Args.length > 0 && isOrderingComparable!(Args[0]) && allSameType!Args) +ref inout(Unqual!(Args[0])) max(Args...)(ref inout Args args) +if (Args.length > 0 + && isOrderingComparable!(Args[0]) + && allSameType!(Map!(Unqual, Args))) { - auto actual = (() @trusted => &args[0])(); - - foreach (arg; args[1 .. $]) - { - if (arg > *actual) - { - actual = (() @trusted => &arg)(); - } - } - - return *actual; + return minMax!((a, b) => a > b)(args); } @nogc nothrow pure @safe unittest @@ -193,3 +198,20 @@ if (isForwardRange!Range && isOrderingComparable!(ElementType!Range)) { assert(max(cast(ubyte[]) []).empty); } + +// min/max compare const and mutable structs. +@nogc nothrow pure @safe unittest +{ + static struct S + { + int s; + + int opCmp(typeof(this) that) const @nogc nothrow pure @safe + { + return this.s - that.s; + } + } + const s1 = S(1); + assert(min(s1, S(2)).s == 1); + assert(max(s1, S(2)).s == 2); +}