Merge pull request #3395 from nordlow/either-and-every

Add new algorithm: either()
This commit is contained in:
Andrei Alexandrescu 2015-10-29 16:57:59 -04:00
commit 168d96dfd7
2 changed files with 128 additions and 0 deletions

View file

@ -17,6 +17,9 @@ $(T2 clamp,
$(T2 cmp,
$(D cmp("abc", "abcd")) is $(D -1), $(D cmp("abc", "aba")) is $(D 1),
and $(D cmp("abc", "abc")) is $(D 0).)
$(T2 either,
Return first parameter $(D p) that passes an $(D if (p)) test, e.g.
$(D either(0, 42, 43)) returns $(D 42).)
$(T2 equal,
Compares ranges for element-by-element equality, e.g.
$(D equal([1, 2, 3], [1.0, 2.0, 3.0])) returns $(D true).)
@ -60,6 +63,7 @@ import std.range;
import std.traits;
// FIXME
import std.typecons; // : tuple, Tuple, Flag;
import std.meta : allSatisfy;
/**
Find $(D value) _among $(D values), returning the 1-based index
@ -1956,3 +1960,86 @@ bool isPermutation(alias pred = "a == b", Range1, Range2)
[mytuple(2, 3), mytuple(1, 2)]
));
}
/**
Get first parameter $(D p) that passes an $(D if (unaryFun!pred(p))) test. If
no parameter passes the test return the last.
Similar to behaviour of `or` operator in dynamic languages such as Lisp's
`(or ...)` and Python's `a or b or ...` except that the last argument is
returned upon no match.
Simplifies logic, for instance, in parsing rules where a set of alternative
matchers are tried. The first one that matches returns it match result,
typically as an abstract syntax tree (AST).
NOTE: Lazy parameters are currently, too restrictively, inferred by DMD to
always throw eventhough they don't need to be. This makes it impossible to
currently mark $(D either) as $(D nothrow). See issue at
https://issues.dlang.org/show_bug.cgi?id=12647
Returns:
The first parameter that passes the test $(D pred).
*/
CommonType!(T, Ts) either(alias pred = a => a, T, Ts...)(T first, lazy Ts alternatives)
if (alternatives.length >= 1 &&
!is(CommonType!(T, Ts) == void) &&
allSatisfy!(ifTestable, T, Ts))
{
alias predFun = unaryFun!pred;
if (predFun(first)) return first;
foreach (e; alternatives[0 .. $ - 1])
if (predFun(e)) return e;
return alternatives[$ - 1];
}
///
@safe pure unittest
{
const a = 1;
const b = 2;
auto ab = either(a, b);
static assert(is(typeof(ab) == const(int)));
assert(ab == a);
auto c = 2;
const d = 3;
auto cd = either!(a => a == 3)(c, d); // use predicate
static assert(is(typeof(cd) == int));
assert(cd == d);
auto e = 0;
const f = 2;
auto ef = either(e, f);
static assert(is(typeof(ef) == int));
assert(ef == f);
immutable p = 1;
immutable q = 2;
auto pq = either(p, q);
static assert(is(typeof(pq) == immutable(int)));
assert(pq == p);
assert(either(3, 4) == 3);
assert(either(0, 4) == 4);
assert(either(0, 0) == 0);
assert(either("", "a") == "");
string r = null;
assert(either(r, "a") == "a");
assert(either("a", "") == "a");
immutable s = [1, 2];
assert(either(s, s) == s);
assert(either([0, 1], [1, 2]) == [0, 1]);
assert(either([0, 1], [1]) == [0, 1]);
assert(either("a", "b") == "a");
static assert(!__traits(compiles, either(1, "a")));
static assert(!__traits(compiles, either(1.0, "a")));
static assert(!__traits(compiles, either('a', "a")));
}