/
ex6_meta_flex4_dynamicFallback1.d
202 lines (171 loc) · 4.21 KB
/
ex6_meta_flex4_dynamicFallback1.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Written in the D programming language
// by Nick Sabalausky
//
// Tested on DMD 2.053
//
// Gizmo Example
// Version: Metaprogramming - Flexibility Method #4 - Dynamic Fallback
import std.conv;
import std.datetime;
import std.stdio;
struct Gizmo(int _numPorts, bool _isSpinnable)
{
// So other generic code can determine the
// number of ports and spinnability:
static immutable numPorts = _numPorts;
static immutable isSpinnable = _isSpinnable;
static if(numPorts < 1)
static assert(false, "A portless Gizmo is useless!");
private OutputPort[numPorts] ports;
void doStuff()
{
static if(numPorts == 1)
ports[0].zap();
else static if(numPorts == 2)
{
ports[0].zap();
ports[1].zap();
}
else
{
foreach(port; ports)
port.zap();
}
}
static if(isSpinnable)
int spinCount;
void spin()
{
static if(isSpinnable)
spinCount++; // Spinning! Wheeee!
}
}
// This is identical to the original Gizmo in 'ex1_original.d',
// just with a different name.
struct DynamicGizmo
{
this(int numPorts, bool isSpinnable)
{
if(numPorts < 1)
throw new Exception("A portless Gizmo is useless!");
ports.length = numPorts;
_isSpinnable = isSpinnable;
}
private OutputPort[] ports;
@property int numPorts()
{
return ports.length;
}
void doStuff()
{
foreach(port; ports)
port.zap();
}
private bool _isSpinnable;
@property int isSpinnable()
{
return _isSpinnable;
}
int spinCount;
void spin()
{
// Attempting to spin a non-spinnable Gizmo is OK.
// Like insulting a fishtank, it merely has no effect.
if(isSpinnable)
spinCount++; // Spinning! Wheeee!
}
}
struct OutputPort
{
int numZaps;
void zap()
{
numZaps++;
}
}
struct UltraGiz
{
template gizmos(T)
{
T[] gizmos;
}
// Shortcut for non-dynamic gizmos, so we can still say:
// gizmos!(2, true)
// instead of needing to use the more verbose:
// gizmos!( Gizmos!(2, true) )
template gizmos(int numPorts, bool isSpinnable)
{
alias gizmos!( Gizmo!(numPorts, isSpinnable) ) gizmos;
}
int numTimesUsedSpinny;
int numTimesUsedTwoPort;
void useGizmo(T)(ref T gizmo)
{
gizmo.doStuff();
gizmo.spin();
if(gizmo.isSpinnable)
numTimesUsedSpinny++;
if(gizmo.numPorts == 2)
numTimesUsedTwoPort++;
}
void run(int bigPort, int extrasNumPorts, bool extrasIsSpinnable)
{
StopWatch stopWatch;
stopWatch.start();
// Create gizmos
gizmos!(1, false).length = 10_000;
gizmos!(1, true ).length = 10_000;
gizmos!(2, false).length = 10_000;
// Use the commandline parameters extrasNumPorts and extrasIsSpinnable
// so 8,000 more of these will be made down below as dynamic gizmos.
gizmos!(2, true ).length = 2_000;
gizmos!(DynamicGizmo).length = 18_000;
foreach(i; 0..5_000)
gizmos!(DynamicGizmo)[i] = DynamicGizmo(bigPort, false);
foreach(i; 5_000..10_000)
gizmos!(DynamicGizmo)[i] = DynamicGizmo(bigPort, true);
foreach(i; 10_000..18_000)
gizmos!(DynamicGizmo)[i] = DynamicGizmo(extrasNumPorts, extrasIsSpinnable);
// Use gizmos
foreach(i; 0..10_000)
{
foreach(ref gizmo; gizmos!(1, false)) useGizmo(gizmo);
foreach(ref gizmo; gizmos!(1, true )) useGizmo(gizmo);
foreach(ref gizmo; gizmos!(2, false)) useGizmo(gizmo);
foreach(ref gizmo; gizmos!(2, true )) useGizmo(gizmo);
foreach(ref gizmo; gizmos!DynamicGizmo) useGizmo(gizmo);
}
writeln(stopWatch.peek.msecs, "ms");
}
}
void main(string[] args)
{
// Number of ports on each of the many-port Gizmos.
// Normally 5
int bigPort;
// 8,000 extra Gizmos will be created with
// this many ports and this spinnability.
// Normally 2-port spinnable
int extrasNumPorts;
bool extrasIsSpinnable;
try
{
bigPort = to!int (args[1]);
extrasNumPorts = to!int (args[2]);
extrasIsSpinnable = to!bool(args[3]);
}
catch(Throwable e)
{
writeln("Usage:");
writeln(" ex6_meta_flex4_dynamicFallback1 "~
"{bigPort} {extrasNumPorts} {extrasIsSpinnable}");
writeln("Example: ex6_meta_flex4_dynamicFallback1 5 2 true");
return;
}
UltraGiz ultra;
ultra.run(bigPort, extrasNumPorts, extrasIsSpinnable);
// Compile time error: A portless Gizmo is useless!
//auto g1 = Gizmo!(0, true);
// Runtime error: A portless Gizmo is useless!
//auto g2 = DynamicGizmo(0, true);
}