On Thursday, 17 March 2016 at 09:59:41 UTC, Dominikus Dittes
Scherkl wrote:
Or you can use an improved opCmp implementation in the
compiler, that only add additional runtime cost, [...]
The compiler could statically fix two cases, ALWAYS without
runtime cost. I think that FPC does this: operand widening by
promoting the unsigned operand to a signed one of a wider type,
POC with a template:
import std.traits;
bool safeIntegralCmp(string op, L, R)(auto ref L lhs, auto ref R
rhs)
if (isIntegral!R && isIntegral!L)
{
// safe
static if (is(Unqual!L == Unqual!R))
{
mixin("return lhs" ~ op ~ "rhs;");
}
else
{
// promote unsigned to bigger signed
static if (isSigned!L && R.sizeof < 8)
{
long widenedRhs = rhs;
mixin("return lhs" ~ op ~ "widenedRhs;");
}
else static if (isSigned!R && L.sizeof < 8)
{
long widenedLhs = lhs;
mixin("return widened" ~ op ~ "rhs;");
}
// not fixable by operand widening
else
{
pragma(msg, "warning, comparing a" ~ L.stringof ~ "
with a" ~ R.stringof
~ " may result into wrong results");
mixin("return lhs" ~ op ~ "rhs;");
}
}
}
unittest
{
int a = -1; uint b;
assert(a > b); // wrong result
assert(safeIntegralCmp!">"(a,b) == false); // fixed by
promotion
long aa = -1; ulong bb;
assert(aa > bb); // wrong result
assert(safeIntegralCmp!">"(aa,bb) == true); // not staticaly
fixable, warning
}
The case where an implicit widening is done a warning could also
be emitted (operand bla bla widened).