summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEugene Wissner <belka@caraus.de>2018-04-26 08:06:06 +0200
committerEugene Wissner <belka@caraus.de>2018-04-26 08:06:06 +0200
commit3468d6ea008dd119a862b7b6afb221ffadf5e6d6 (patch)
tree3ae088eb6720a25c1af2e313789e5cbcc60c8599 /source
parented5fa91e64d028c010ef73bc8f3fc5cf1891856f (diff)
downloadtanya-3468d6ea008dd119a862b7b6afb221ffadf5e6d6.tar.gz
Accept/return as inout in min/max
Diffstat (limited to 'source')
-rw-r--r--source/tanya/algorithm/comparison.d88
1 files 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);
+}