Compile-time Counters
From the d forums:
import std;
template counter(){
template access(int i){
//pragma(msg,i,"acess");
enum access=mixin("__LINE__");
}
template get_(int i,int sentinel){
//pragma(msg,i," ",sentinel);
static if(access!(i)>sentinel){
enum get_=i;
} else {
enum get_=get_!(i+1,sentinel);
}}
template get(int i=__LINE__){
enum setty=mixin("__LINE__");
alias get=get_!(0,setty);
}
}
enum x = counter!().get!();
void main(){
counter!().get!().writeln;
counter!().get!().writeln;
counter!().get!().writeln;
writeln(x);
}Output:
$ dmd -mixin=mix -run count.d 1 2 3 0
NB. I don't know how this works, except that it's clearly abusing __LINE__ somehow, and it can't compile without that -mixin=mix argument, despite the code not using the file and the file seeming to be only for logging mixin results.
What's black magic in d is straightforward in Nelua:
## local function count() ## if not comptime_counter then comptime_counter = 0 end in #[comptime_counter]# ## comptime_counter = comptime_counter + 1 ## end local x <comptime> = count!() print(count!()) print(count!()) print(count!()) print(x)
Which is easily confirmed to compile to
int nelua_main(int argc, char** argv) {
nelua_print_1(1);
nelua_print_1(2);
nelua_print_1(3);
nelua_print_1(0);
return 0;
}How does this work as a module?
For d - it doesn't.
/usr/bin/ld: count.o:(.data.rel.ro+0x18): undefined reference to `_D7counter12__ModuleInfoZ'
For Nelua there's only one complication: because this is using a mixed-language macro, with a single line of Nelua code in a Lua function, to use it in multiple libraries you'd need to do one of
- make it a
globalfunction (risk: name conflicts) - make a Nelua instead of a Lua function to have something to
require()(risk: binary bloat) - rewrite it to pure Lua and
- (for something this simple) call it directly
- (for more complex code) inject the expression manually
require()in Lua instead of Nelua
Here's #3, and the simpler case:
-- counter.lua
if not comptime_counter then comptime_counter = -1 end
local function count()
comptime_counter = comptime_counter + 1
return comptime_counter
end
return { count = count }
-- count.nelua
## local count = require('counter').count
local x <comptime> = count!()
print(count!())
print(count!())
print(count!())
print(x)