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