import std.stdio, std.algorithm, std.range, std.traits, std.typetuple,
std.string, std.conv;
private template Iota(int stop) {
static if (stop <= 0)
alias TypeTuple!() Iota;
else
alias TypeTuple!(Iota!(stop-1), stop-1) Iota;
}
private template IsBoolPredicate(alias fun) {
alias squeezedParams = NoDuplicates!(ParameterTypeTuple!fun);
enum bool IsBoolPredicate =
isCallable!fun &&
is(ReturnType!fun == bool) &&
squeezedParams.length == 1 &&
is(Unqual!(squeezedParams[0]) == bool);
}
void truthTable(alias fun, TOps...)
(in string expression, in TOps operands)
if (IsBoolPredicate!fun &&
TOps.length == ParameterTypeTuple!fun.length &&
NoDuplicates!TOps.length == 1 &&
is(Unqual!(NoDuplicates!TOps[0]) == char)) {
enum nArgs = TOps.length;
writefln("%( %2c %) %s\n", [operands], expression);
static struct Bits {
mixin("bool " ~ format("%(b%d, %)", nArgs.iota) ~ ";");
}
foreach (immutable i; Iota!(2 ^^ nArgs)) {
Bits bits;
foreach (immutable j; Iota!nArgs)
mixin("bits.b" ~ text(j) ~ "=" ~
text(!!(i & (1 << j))) ~ ";");
writefln("%(%2d %) : %d", [bits.tupleof], fun(bits.tupleof));
}
writefln("\n");
}
bool xor(in bool b0, in bool b1) pure nothrow {
return b0 != b1;
}
bool stu(in bool b0, in bool b1, in bool b2) pure nothrow {
return b0 || (b1 ^ b2);
}
bool abcd(in bool b0, in bool b1, in bool b2, in bool b3)
pure nothrow {
return b0 ^ (b1 ^ (b2 ^ b3));
}
void main() {
truthTable!xor("A ^ B", 'A', 'B');
truthTable!stu("S | ( T ^ U )", 'S', 'T', 'U');
truthTable!abcd("A ^ (B ^ (C ^ D))", 'A', 'B', 'C', 'D');
}