-
Notifications
You must be signed in to change notification settings - Fork 0
/
generators.d
107 lines (89 loc) · 2.69 KB
/
generators.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// License: public domain
module generators;
import std.traits, std.typetuple, core.thread;
import std.conv : text;
void yield(alias var)(typeof(var) value)
{
static assert(__traits(isOut, var), "Yield works only with OUT arguments");
auto fiber = Fiber.getThis();
if (!fiber)
return; // do nothing
var = value;
Fiber.yield();
}
private template Generator(T...)
if (T.length >= 1 && isCallable!(T[0]))
{
alias T[0] F;
alias ParameterTypeTuple!F AllParams;
alias ParameterStorageClassTuple!F Stc;
template StripOutParams(size_t i)
{
static if (i < AllParams.length)
{
static if (Stc[i] != ParameterStorageClass.out_)
alias TypeTuple!(AllParams[i], StripOutParams!(i + 1)) StripOutParams;
else
alias StripOutParams!(i + 1) StripOutParams;
}
else
alias TypeTuple!() StripOutParams;
}
alias StripOutParams!0 Params;
static assert(AllParams.length - Params.length == 1, "Generator function must have exactly one OUT argument");
static assert(is(ReturnType!F == void), F.stringof ~ ", does not return void");
static assert(Params.length == T.length - 1, text("Generator ", F.stringof, " expects ", Params.length,
" argument(s), not ", T.length - 1));
template OutParamIndex(size_t i)
{
static if (i < AllParams.length)
{
static if (Stc[i] == ParameterStorageClass.out_)
enum OutParamIndex = i;
else
enum OutParamIndex = OutParamIndex!(i + 1);
}
else
enum OutParamIndex = -1;
}
enum outIndex = OutParamIndex!0;
alias AllParams[outIndex] ValueType;
class Generator : Fiber
{
F fn;
AllParams allParams;
this(F fn, Params params)
{
super(&fiberMain);
this.fn = fn;
foreach (i, param; allParams)
{
static if (i < outIndex)
allParams[i] = params[i];
else static if (i > outIndex)
allParams[i] = params[i - 1];
}
call();
}
void fiberMain()
{
fn(allParams);
}
@property bool empty()
{
return state == State.TERM;
}
void popFront()
{
call();
}
@property pure nothrow ValueType front()
{
return allParams[outIndex];
}
}
}
auto generator(T...)(T t)
{
return new Generator!T(t);
}