Is it possible to "cache" results of compile-time executions between compiles?
TheFlyingFiddle via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Tue Jan 24 14:48:37 PST 2017
On Tuesday, 24 January 2017 at 21:36:50 UTC, Profile Anaysis
wrote:
> On Tuesday, 24 January 2017 at 16:49:03 UTC, TheFlyingFiddle
> wrote:
>> On Tuesday, 24 January 2017 at 16:41:13 UTC, TheFlyingFiddle
>> wrote:
>>> Everything turned out soooo much better than expected :)
>> Added bonus is that mixin output can be viewed in the
>> generated files :D
>
> Could you post your solution?
>
> I suggest we get a real caching module like above that has the
> extra feature of hashing the mixin strings.
>
> This way the caching mechanism can validate if the mixin
> strings have changed. Put the hash in a comment in the output
> file that used to test if the input string has the same hash.
> If it does, simply use the output file, else, regenerate.
>
> Adds some overhead but keeps things consistent.
>
>
> (Since I'm not sure what Cache!() is, I'm assuming it doesn't
> do this)
This is the solution I through together:
// module mixin_cache.d
mixin template Cache(alias GenSource, string from, string path)
{
import core.internal.hash;
import std.conv : to;
//Hash to keep track of changes
enum h = hashOf(from);
enum p = path ~ h.to!string ~ ".txt";
//Check if the file exists else suppress errors
//The -J flag needs to be set on dmd else
//this always fails
static if(__traits(compiles, import(p)))
{
//Tell the wrapper that we loaded the file p
//_importing is a magic string
pragma(msg, "_importing");
pragma(msg, p);
mixin(import(p));
}
else
{
//We don't have a cached file so generate it
private enum src = GenSource!(from);
static if(__traits(compiles, () { mixin(src); }))
{
//_exporing_start_ tells the wrapper to begin
//outputing the generated source into file p
pragma(msg, "_exported_start_");
pragma(msg, p);
pragma(msg, src);
pragma(msg, "_exported_end_");
}
mixin(src);
}
}
To make this work I wrap dmd in a d script like this:
(ignoring some details as what i've got is not really tested yet)
// dmd_with_mixin_cache.d
void main(string[] args)
{
auto dmdargs = ... //Fix args etc.
auto dmd = pipeProcess(dmdargs, Redirect.stderr);
foreach(line; dmd.stderr.byLine(KeepTerminator.yes))
{
if(line.startsWith("_exported_start_")) {
//Parse file and store source in a file
//Keep going until _exported_end_
} else if(line.startsWith("_importing")) {
//A user imported a file. (don't delete it!)
} else {
//Other output from dmd like errors / other pragma(msg,
...)
}
}
//Files not imported / exported could be stale
//delete them. Unless we got a compile error from dmd
//Then don't delete anything.
}
The cache template and the small wrapper that wraps dmd was all
that were needed.
usage is somthing like this:
template Generate(string source)
{
string Generate()
{
//Do some complex ctfe here
//can't wait for the new ctfe engine!
foreach(i; 0 .. 100_000)
{ }
return source;
}
}
mixin Cache!("Some interesting DSL or similar", __MODULE__);
//some_filename is not really needed but can be nice when
browsing the
//mixin code to see where it came from. (approximately anwyays)
This is it. If you want I can post a full solution sometime later
this week but I want to clean up what I have first.
More information about the Digitalmars-d-learn
mailing list