/
ex5_meta_deadDuck1.d
148 lines (126 loc) · 3 KB
/
ex5_meta_deadDuck1.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
// Written in the D programming language
// by Nick Sabalausky
//
// Tested on DMD 2.053
//
// Gizmo Example
// Version: Metaprogramming - Dead Duck
import std.datetime;
import std.stdio;
template isIGizmo(T)
{
immutable bool isIGizmo = __traits(compiles,
// This is just an anonymous function.
// We won't actually run it, though.
// We're just making sure all of this compiles for T.
(){
T t;
static assert(T._this_implements_interface_IGizmo_);
int n = t.numPorts;
static if(T.isSpinnable)
int s = t.spinCount;
t.doStuff();
t.spin();
}
);
}
// Almost identical to the original metaprogramming Gizmo
// in 'ex4_metaprogramming.d', but with two little things added:
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;
// Announce that this is a Gizmo.
// An enum takes up no space.
static enum _this_implements_interface_IGizmo_ = true;
// Verify this actually does implement the interface
static assert(
isIGizmo!(Gizmo!(numPorts, isSpinnable)),
"This type fails to implement IGizmo"
);
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!
}
}
struct OutputPort
{
int numZaps;
void zap()
{
numZaps++;
}
}
struct UltraGiz
{
template gizmos(int numPorts, bool isSpinnable)
{
Gizmo!(numPorts, isSpinnable)[] gizmos;
}
int numTimesUsedSpinny;
int numTimesUsedTwoPort;
void useGizmo(T)(ref T gizmo) if(isIGizmo!T)
{
gizmo.doStuff();
gizmo.spin();
if(gizmo.isSpinnable)
numTimesUsedSpinny++;
if(gizmo.numPorts == 2)
numTimesUsedTwoPort++;
}
void run()
{
StopWatch stopWatch;
stopWatch.start();
// Create gizmos
gizmos!(1, false).length = 10_000;
gizmos!(1, true ).length = 10_000;
gizmos!(2, false).length = 10_000;
gizmos!(2, true ).length = 10_000;
gizmos!(5, false).length = 5_000;
gizmos!(5, true ).length = 5_000;
// 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!(5, false)) useGizmo(gizmo);
foreach(ref gizmo; gizmos!(5, true )) useGizmo(gizmo);
}
writeln(stopWatch.peek.msecs, "ms");
assert(numTimesUsedSpinny == 25_000 * 10_000);
assert(numTimesUsedTwoPort == 20_000 * 10_000);
}
}
void main()
{
UltraGiz ultra;
ultra.run();
// Compile time error: A portless Gizmo is useless!
//auto g = Gizmo!(0, true);
}