How to enforce compile time evaluation (and test if it was done at compile time)
Christian Köstlin via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Mon Feb 27 11:26:06 PST 2017
I have a small example, that can be used to express 3601000ms as 1h 1s
(a much more advanced version has already been done by
https://github.com/nordlow/units-d).
I would like to enforce that the precomputation (multiplying and
inverting the list of scale's) is done at compile time.
Is it enough to put up static immutable modifiers?
How can I make sure, that the calculations are done at compile time?
Thanks in advance,
Christian
public struct Unit {
import std.algorithm.iteration;
import std.range;
public struct Scale {
string name;
long factor;
}
public struct Part {
string name;
long v;
string toString() {
import std.conv;
return v.to!(string) ~ name;
}
}
private string name;
private Scale[] scales;
public this(string name, Scale[] scales) {
this.name = name;
this.scales = cumulativeFold!((result,x) => Scale(x.name,
result.factor * x.factor))(scales).array.retro.array;
}
public Part[] transform(long v) immutable {
import std.array;
auto res = appender!(Part[]);
auto tmp = v;
foreach (Scale scale; scales) {
auto h = tmp / scale.factor;
tmp = v % scale.factor;
res.put(Part(scale.name, h));
}
return res.data;
}
}
Unit.Part[] onlyRelevant(Unit.Part[] parts) {
import std.array;
auto res = appender!(Unit.Part[]);
bool needed = false;
foreach (part; parts) {
if (needed || (part.v > 0)) {
needed = true;
}
if (needed) {
res.put(part);
}
}
return res.data;
}
Unit.Part[] mostSignificant(Unit.Part[] parts, long nr) {
import std.algorithm.comparison;
auto max = min(parts.length, nr);
return parts[0..max];
}
unittest {
static immutable time = Unit("time", [Unit.Scale("ms", 1),
Unit.Scale("s", 1000), Unit.Scale("m", 60), Unit.Scale("h", 60),
Unit.Scale("d", 24)]);
auto res = time.transform(1 + 2*1000 + 3*1000*60 + 4*1000*60*60 + 5 *
1000*60*60*24);
res.length.shouldEqual(5);
res[0].name.shouldEqual("d");
res[0].v.shouldEqual(5);
res[1].name.shouldEqual("h");
res[1].v.shouldEqual(4);
res[2].name.shouldEqual("m");
res[2].v.shouldEqual(3);
res[3].name.shouldEqual("s");
res[3].v.shouldEqual(2);
res[4].name.shouldEqual("ms");
res[4].v.shouldEqual(1);
res = time.transform(2001).onlyRelevant;
res.length.shouldEqual(2);
res[0].name.shouldEqual("s");
res[0].v.shouldEqual(2);
res[1].name.shouldEqual("ms");
res[1].v.shouldEqual(1);
res = time.transform(2001).onlyRelevant.mostSignificant(1);
res.length.shouldEqual(1);
res[0].name.shouldEqual("s");
res[0].v.shouldEqual(2);
}
More information about the Digitalmars-d-learn
mailing list